From 85dd573908b1a0f1702580fa543ab46e8468b33a Mon Sep 17 00:00:00 2001 From: yoganandhan Date: Wed, 7 Jan 2026 18:05:25 +0530 Subject: [PATCH] first commit --- .gitattributes | 2 + .gitignore | 33 + .mvn/wrapper/maven-wrapper.properties | 3 + mvnw | 295 ++ mvnw.cmd | 189 ++ pom.xml | 84 + .../gcc/flagpoles/FlagpolesApplication.java | 13 + .../flagpoles/configuration/AppConfig.java | 66 + .../configuration/RefundScheduler.java | 472 +++ .../gcc/flagpoles/constants/AppConstants.java | 15 + .../flagpoles/controller/ApiController.java | 762 +++++ .../flagpoles/controller/DateTimeUtil.java | 35 + .../controller/DropDownApiController.java | 77 + .../flagpoles/controller/MainController.java | 281 ++ .../controller/RefundController.java | 179 ++ .../gcc/flagpoles/service/BookingService.java | 19 + .../flagpoles/service/DropDownService.java | 183 ++ .../gcc/flagpoles/service/PaymentService.java | 154 + .../gcc/flagpoles/service/RefundService.java | 323 ++ .../gcc/flagpoles/service/RequestService.java | 1337 +++++++++ .../com/gcc/flagpoles/service/SMSService.java | 39 + .../service/WhatsappMessageService.java | 147 + src/main/resources/application-dev.properties | 33 + .../resources/application-prod.properties | 31 + src/main/resources/application.properties | 1 + .../templates/fragments/details.html | 188 ++ .../acknowledgement.html | 178 ++ .../modules/flagpolesregistration/index.html | 195 ++ .../flagpolesregistration/nodatafound.html | 101 + .../paymentrequestform.html | 252 ++ .../flagpolesregistration/razor-pay.html | 135 + .../flagpolesregistration/requestform.html | 2590 +++++++++++++++++ .../modules/flagpolesregistration/status.html | 1068 +++++++ .../flagpoles/FlagpolesApplicationTests.java | 13 + 34 files changed, 9493 insertions(+) create mode 100644 .gitattributes create mode 100644 .gitignore create mode 100644 .mvn/wrapper/maven-wrapper.properties create mode 100644 mvnw create mode 100644 mvnw.cmd create mode 100644 pom.xml create mode 100644 src/main/java/com/gcc/flagpoles/FlagpolesApplication.java create mode 100644 src/main/java/com/gcc/flagpoles/configuration/AppConfig.java create mode 100644 src/main/java/com/gcc/flagpoles/configuration/RefundScheduler.java create mode 100644 src/main/java/com/gcc/flagpoles/constants/AppConstants.java create mode 100644 src/main/java/com/gcc/flagpoles/controller/ApiController.java create mode 100644 src/main/java/com/gcc/flagpoles/controller/DateTimeUtil.java create mode 100644 src/main/java/com/gcc/flagpoles/controller/DropDownApiController.java create mode 100644 src/main/java/com/gcc/flagpoles/controller/MainController.java create mode 100644 src/main/java/com/gcc/flagpoles/controller/RefundController.java create mode 100644 src/main/java/com/gcc/flagpoles/service/BookingService.java create mode 100644 src/main/java/com/gcc/flagpoles/service/DropDownService.java create mode 100644 src/main/java/com/gcc/flagpoles/service/PaymentService.java create mode 100644 src/main/java/com/gcc/flagpoles/service/RefundService.java create mode 100644 src/main/java/com/gcc/flagpoles/service/RequestService.java create mode 100644 src/main/java/com/gcc/flagpoles/service/SMSService.java create mode 100644 src/main/java/com/gcc/flagpoles/service/WhatsappMessageService.java create mode 100644 src/main/resources/application-dev.properties create mode 100644 src/main/resources/application-prod.properties create mode 100644 src/main/resources/application.properties create mode 100644 src/main/resources/templates/fragments/details.html create mode 100644 src/main/resources/templates/modules/flagpolesregistration/acknowledgement.html create mode 100644 src/main/resources/templates/modules/flagpolesregistration/index.html create mode 100644 src/main/resources/templates/modules/flagpolesregistration/nodatafound.html create mode 100644 src/main/resources/templates/modules/flagpolesregistration/paymentrequestform.html create mode 100644 src/main/resources/templates/modules/flagpolesregistration/razor-pay.html create mode 100644 src/main/resources/templates/modules/flagpolesregistration/requestform.html create mode 100644 src/main/resources/templates/modules/flagpolesregistration/status.html create mode 100644 src/test/java/com/gcc/flagpoles/FlagpolesApplicationTests.java diff --git a/.gitattributes b/.gitattributes new file mode 100644 index 0000000..3b41682 --- /dev/null +++ b/.gitattributes @@ -0,0 +1,2 @@ +/mvnw text eol=lf +*.cmd text eol=crlf diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..667aaef --- /dev/null +++ b/.gitignore @@ -0,0 +1,33 @@ +HELP.md +target/ +.mvn/wrapper/maven-wrapper.jar +!**/src/main/**/target/ +!**/src/test/**/target/ + +### STS ### +.apt_generated +.classpath +.factorypath +.project +.settings +.springBeans +.sts4-cache + +### IntelliJ IDEA ### +.idea +*.iws +*.iml +*.ipr + +### NetBeans ### +/nbproject/private/ +/nbbuild/ +/dist/ +/nbdist/ +/.nb-gradle/ +build/ +!**/src/main/**/build/ +!**/src/test/**/build/ + +### VS Code ### +.vscode/ diff --git a/.mvn/wrapper/maven-wrapper.properties b/.mvn/wrapper/maven-wrapper.properties new file mode 100644 index 0000000..c0bcafe --- /dev/null +++ b/.mvn/wrapper/maven-wrapper.properties @@ -0,0 +1,3 @@ +wrapperVersion=3.3.4 +distributionType=only-script +distributionUrl=https://repo.maven.apache.org/maven2/org/apache/maven/apache-maven/3.9.11/apache-maven-3.9.11-bin.zip diff --git a/mvnw b/mvnw new file mode 100644 index 0000000..bd8896b --- /dev/null +++ b/mvnw @@ -0,0 +1,295 @@ +#!/bin/sh +# ---------------------------------------------------------------------------- +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you 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 +# +# http://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. +# ---------------------------------------------------------------------------- + +# ---------------------------------------------------------------------------- +# Apache Maven Wrapper startup batch script, version 3.3.4 +# +# Optional ENV vars +# ----------------- +# JAVA_HOME - location of a JDK home dir, required when download maven via java source +# MVNW_REPOURL - repo url base for downloading maven distribution +# MVNW_USERNAME/MVNW_PASSWORD - user and password for downloading maven +# MVNW_VERBOSE - true: enable verbose log; debug: trace the mvnw script; others: silence the output +# ---------------------------------------------------------------------------- + +set -euf +[ "${MVNW_VERBOSE-}" != debug ] || set -x + +# OS specific support. +native_path() { printf %s\\n "$1"; } +case "$(uname)" in +CYGWIN* | MINGW*) + [ -z "${JAVA_HOME-}" ] || JAVA_HOME="$(cygpath --unix "$JAVA_HOME")" + native_path() { cygpath --path --windows "$1"; } + ;; +esac + +# set JAVACMD and JAVACCMD +set_java_home() { + # For Cygwin and MinGW, ensure paths are in Unix format before anything is touched + 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" + JAVACCMD="$JAVA_HOME/jre/sh/javac" + else + JAVACMD="$JAVA_HOME/bin/java" + JAVACCMD="$JAVA_HOME/bin/javac" + + if [ ! -x "$JAVACMD" ] || [ ! -x "$JAVACCMD" ]; then + echo "The JAVA_HOME environment variable is not defined correctly, so mvnw cannot run." >&2 + echo "JAVA_HOME is set to \"$JAVA_HOME\", but \"\$JAVA_HOME/bin/java\" or \"\$JAVA_HOME/bin/javac\" does not exist." >&2 + return 1 + fi + fi + else + JAVACMD="$( + 'set' +e + 'unset' -f command 2>/dev/null + 'command' -v java + )" || : + JAVACCMD="$( + 'set' +e + 'unset' -f command 2>/dev/null + 'command' -v javac + )" || : + + if [ ! -x "${JAVACMD-}" ] || [ ! -x "${JAVACCMD-}" ]; then + echo "The java/javac command does not exist in PATH nor is JAVA_HOME set, so mvnw cannot run." >&2 + return 1 + fi + fi +} + +# hash string like Java String::hashCode +hash_string() { + str="${1:-}" h=0 + while [ -n "$str" ]; do + char="${str%"${str#?}"}" + h=$(((h * 31 + $(LC_CTYPE=C printf %d "'$char")) % 4294967296)) + str="${str#?}" + done + printf %x\\n $h +} + +verbose() { :; } +[ "${MVNW_VERBOSE-}" != true ] || verbose() { printf %s\\n "${1-}"; } + +die() { + printf %s\\n "$1" >&2 + exit 1 +} + +trim() { + # MWRAPPER-139: + # Trims trailing and leading whitespace, carriage returns, tabs, and linefeeds. + # Needed for removing poorly interpreted newline sequences when running in more + # exotic environments such as mingw bash on Windows. + printf "%s" "${1}" | tr -d '[:space:]' +} + +scriptDir="$(dirname "$0")" +scriptName="$(basename "$0")" + +# parse distributionUrl and optional distributionSha256Sum, requires .mvn/wrapper/maven-wrapper.properties +while IFS="=" read -r key value; do + case "${key-}" in + distributionUrl) distributionUrl=$(trim "${value-}") ;; + distributionSha256Sum) distributionSha256Sum=$(trim "${value-}") ;; + esac +done <"$scriptDir/.mvn/wrapper/maven-wrapper.properties" +[ -n "${distributionUrl-}" ] || die "cannot read distributionUrl property in $scriptDir/.mvn/wrapper/maven-wrapper.properties" + +case "${distributionUrl##*/}" in +maven-mvnd-*bin.*) + MVN_CMD=mvnd.sh _MVNW_REPO_PATTERN=/maven/mvnd/ + case "${PROCESSOR_ARCHITECTURE-}${PROCESSOR_ARCHITEW6432-}:$(uname -a)" in + *AMD64:CYGWIN* | *AMD64:MINGW*) distributionPlatform=windows-amd64 ;; + :Darwin*x86_64) distributionPlatform=darwin-amd64 ;; + :Darwin*arm64) distributionPlatform=darwin-aarch64 ;; + :Linux*x86_64*) distributionPlatform=linux-amd64 ;; + *) + echo "Cannot detect native platform for mvnd on $(uname)-$(uname -m), use pure java version" >&2 + distributionPlatform=linux-amd64 + ;; + esac + distributionUrl="${distributionUrl%-bin.*}-$distributionPlatform.zip" + ;; +maven-mvnd-*) MVN_CMD=mvnd.sh _MVNW_REPO_PATTERN=/maven/mvnd/ ;; +*) MVN_CMD="mvn${scriptName#mvnw}" _MVNW_REPO_PATTERN=/org/apache/maven/ ;; +esac + +# apply MVNW_REPOURL and calculate MAVEN_HOME +# maven home pattern: ~/.m2/wrapper/dists/{apache-maven-,maven-mvnd--}/ +[ -z "${MVNW_REPOURL-}" ] || distributionUrl="$MVNW_REPOURL$_MVNW_REPO_PATTERN${distributionUrl#*"$_MVNW_REPO_PATTERN"}" +distributionUrlName="${distributionUrl##*/}" +distributionUrlNameMain="${distributionUrlName%.*}" +distributionUrlNameMain="${distributionUrlNameMain%-bin}" +MAVEN_USER_HOME="${MAVEN_USER_HOME:-${HOME}/.m2}" +MAVEN_HOME="${MAVEN_USER_HOME}/wrapper/dists/${distributionUrlNameMain-}/$(hash_string "$distributionUrl")" + +exec_maven() { + unset MVNW_VERBOSE MVNW_USERNAME MVNW_PASSWORD MVNW_REPOURL || : + exec "$MAVEN_HOME/bin/$MVN_CMD" "$@" || die "cannot exec $MAVEN_HOME/bin/$MVN_CMD" +} + +if [ -d "$MAVEN_HOME" ]; then + verbose "found existing MAVEN_HOME at $MAVEN_HOME" + exec_maven "$@" +fi + +case "${distributionUrl-}" in +*?-bin.zip | *?maven-mvnd-?*-?*.zip) ;; +*) die "distributionUrl is not valid, must match *-bin.zip or maven-mvnd-*.zip, but found '${distributionUrl-}'" ;; +esac + +# prepare tmp dir +if TMP_DOWNLOAD_DIR="$(mktemp -d)" && [ -d "$TMP_DOWNLOAD_DIR" ]; then + clean() { rm -rf -- "$TMP_DOWNLOAD_DIR"; } + trap clean HUP INT TERM EXIT +else + die "cannot create temp dir" +fi + +mkdir -p -- "${MAVEN_HOME%/*}" + +# Download and Install Apache Maven +verbose "Couldn't find MAVEN_HOME, downloading and installing it ..." +verbose "Downloading from: $distributionUrl" +verbose "Downloading to: $TMP_DOWNLOAD_DIR/$distributionUrlName" + +# select .zip or .tar.gz +if ! command -v unzip >/dev/null; then + distributionUrl="${distributionUrl%.zip}.tar.gz" + distributionUrlName="${distributionUrl##*/}" +fi + +# verbose opt +__MVNW_QUIET_WGET=--quiet __MVNW_QUIET_CURL=--silent __MVNW_QUIET_UNZIP=-q __MVNW_QUIET_TAR='' +[ "${MVNW_VERBOSE-}" != true ] || __MVNW_QUIET_WGET='' __MVNW_QUIET_CURL='' __MVNW_QUIET_UNZIP='' __MVNW_QUIET_TAR=v + +# normalize http auth +case "${MVNW_PASSWORD:+has-password}" in +'') MVNW_USERNAME='' MVNW_PASSWORD='' ;; +has-password) [ -n "${MVNW_USERNAME-}" ] || MVNW_USERNAME='' MVNW_PASSWORD='' ;; +esac + +if [ -z "${MVNW_USERNAME-}" ] && command -v wget >/dev/null; then + verbose "Found wget ... using wget" + wget ${__MVNW_QUIET_WGET:+"$__MVNW_QUIET_WGET"} "$distributionUrl" -O "$TMP_DOWNLOAD_DIR/$distributionUrlName" || die "wget: Failed to fetch $distributionUrl" +elif [ -z "${MVNW_USERNAME-}" ] && command -v curl >/dev/null; then + verbose "Found curl ... using curl" + curl ${__MVNW_QUIET_CURL:+"$__MVNW_QUIET_CURL"} -f -L -o "$TMP_DOWNLOAD_DIR/$distributionUrlName" "$distributionUrl" || die "curl: Failed to fetch $distributionUrl" +elif set_java_home; then + verbose "Falling back to use Java to download" + javaSource="$TMP_DOWNLOAD_DIR/Downloader.java" + targetZip="$TMP_DOWNLOAD_DIR/$distributionUrlName" + cat >"$javaSource" <<-END + public class Downloader extends java.net.Authenticator + { + protected java.net.PasswordAuthentication getPasswordAuthentication() + { + return new java.net.PasswordAuthentication( System.getenv( "MVNW_USERNAME" ), System.getenv( "MVNW_PASSWORD" ).toCharArray() ); + } + public static void main( String[] args ) throws Exception + { + setDefault( new Downloader() ); + java.nio.file.Files.copy( java.net.URI.create( args[0] ).toURL().openStream(), java.nio.file.Paths.get( args[1] ).toAbsolutePath().normalize() ); + } + } + END + # For Cygwin/MinGW, switch paths to Windows format before running javac and java + verbose " - Compiling Downloader.java ..." + "$(native_path "$JAVACCMD")" "$(native_path "$javaSource")" || die "Failed to compile Downloader.java" + verbose " - Running Downloader.java ..." + "$(native_path "$JAVACMD")" -cp "$(native_path "$TMP_DOWNLOAD_DIR")" Downloader "$distributionUrl" "$(native_path "$targetZip")" +fi + +# If specified, validate the SHA-256 sum of the Maven distribution zip file +if [ -n "${distributionSha256Sum-}" ]; then + distributionSha256Result=false + if [ "$MVN_CMD" = mvnd.sh ]; then + echo "Checksum validation is not supported for maven-mvnd." >&2 + echo "Please disable validation by removing 'distributionSha256Sum' from your maven-wrapper.properties." >&2 + exit 1 + elif command -v sha256sum >/dev/null; then + if echo "$distributionSha256Sum $TMP_DOWNLOAD_DIR/$distributionUrlName" | sha256sum -c - >/dev/null 2>&1; then + distributionSha256Result=true + fi + elif command -v shasum >/dev/null; then + if echo "$distributionSha256Sum $TMP_DOWNLOAD_DIR/$distributionUrlName" | shasum -a 256 -c >/dev/null 2>&1; then + distributionSha256Result=true + fi + else + echo "Checksum validation was requested but neither 'sha256sum' or 'shasum' are available." >&2 + echo "Please install either command, or disable validation by removing 'distributionSha256Sum' from your maven-wrapper.properties." >&2 + exit 1 + fi + if [ $distributionSha256Result = false ]; then + echo "Error: Failed to validate Maven distribution SHA-256, your Maven distribution might be compromised." >&2 + echo "If you updated your Maven version, you need to update the specified distributionSha256Sum property." >&2 + exit 1 + fi +fi + +# unzip and move +if command -v unzip >/dev/null; then + unzip ${__MVNW_QUIET_UNZIP:+"$__MVNW_QUIET_UNZIP"} "$TMP_DOWNLOAD_DIR/$distributionUrlName" -d "$TMP_DOWNLOAD_DIR" || die "failed to unzip" +else + tar xzf${__MVNW_QUIET_TAR:+"$__MVNW_QUIET_TAR"} "$TMP_DOWNLOAD_DIR/$distributionUrlName" -C "$TMP_DOWNLOAD_DIR" || die "failed to untar" +fi + +# Find the actual extracted directory name (handles snapshots where filename != directory name) +actualDistributionDir="" + +# First try the expected directory name (for regular distributions) +if [ -d "$TMP_DOWNLOAD_DIR/$distributionUrlNameMain" ]; then + if [ -f "$TMP_DOWNLOAD_DIR/$distributionUrlNameMain/bin/$MVN_CMD" ]; then + actualDistributionDir="$distributionUrlNameMain" + fi +fi + +# If not found, search for any directory with the Maven executable (for snapshots) +if [ -z "$actualDistributionDir" ]; then + # enable globbing to iterate over items + set +f + for dir in "$TMP_DOWNLOAD_DIR"/*; do + if [ -d "$dir" ]; then + if [ -f "$dir/bin/$MVN_CMD" ]; then + actualDistributionDir="$(basename "$dir")" + break + fi + fi + done + set -f +fi + +if [ -z "$actualDistributionDir" ]; then + verbose "Contents of $TMP_DOWNLOAD_DIR:" + verbose "$(ls -la "$TMP_DOWNLOAD_DIR")" + die "Could not find Maven distribution directory in extracted archive" +fi + +verbose "Found extracted Maven distribution directory: $actualDistributionDir" +printf %s\\n "$distributionUrl" >"$TMP_DOWNLOAD_DIR/$actualDistributionDir/mvnw.url" +mv -- "$TMP_DOWNLOAD_DIR/$actualDistributionDir" "$MAVEN_HOME" || [ -d "$MAVEN_HOME" ] || die "fail to move MAVEN_HOME" + +clean || : +exec_maven "$@" diff --git a/mvnw.cmd b/mvnw.cmd new file mode 100644 index 0000000..92450f9 --- /dev/null +++ b/mvnw.cmd @@ -0,0 +1,189 @@ +<# : batch portion +@REM ---------------------------------------------------------------------------- +@REM Licensed to the Apache Software Foundation (ASF) under one +@REM or more contributor license agreements. See the NOTICE file +@REM distributed with this work for additional information +@REM regarding copyright ownership. The ASF licenses this file +@REM to you under the Apache License, Version 2.0 (the +@REM "License"); you may not use this file except in compliance +@REM with the License. You may obtain a copy of the License at +@REM +@REM http://www.apache.org/licenses/LICENSE-2.0 +@REM +@REM Unless required by applicable law or agreed to in writing, +@REM software distributed under the License is distributed on an +@REM "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +@REM KIND, either express or implied. See the License for the +@REM specific language governing permissions and limitations +@REM under the License. +@REM ---------------------------------------------------------------------------- + +@REM ---------------------------------------------------------------------------- +@REM Apache Maven Wrapper startup batch script, version 3.3.4 +@REM +@REM Optional ENV vars +@REM MVNW_REPOURL - repo url base for downloading maven distribution +@REM MVNW_USERNAME/MVNW_PASSWORD - user and password for downloading maven +@REM MVNW_VERBOSE - true: enable verbose log; others: silence the output +@REM ---------------------------------------------------------------------------- + +@IF "%__MVNW_ARG0_NAME__%"=="" (SET __MVNW_ARG0_NAME__=%~nx0) +@SET __MVNW_CMD__= +@SET __MVNW_ERROR__= +@SET __MVNW_PSMODULEP_SAVE=%PSModulePath% +@SET PSModulePath= +@FOR /F "usebackq tokens=1* delims==" %%A IN (`powershell -noprofile "& {$scriptDir='%~dp0'; $script='%__MVNW_ARG0_NAME__%'; icm -ScriptBlock ([Scriptblock]::Create((Get-Content -Raw '%~f0'))) -NoNewScope}"`) DO @( + IF "%%A"=="MVN_CMD" (set __MVNW_CMD__=%%B) ELSE IF "%%B"=="" (echo %%A) ELSE (echo %%A=%%B) +) +@SET PSModulePath=%__MVNW_PSMODULEP_SAVE% +@SET __MVNW_PSMODULEP_SAVE= +@SET __MVNW_ARG0_NAME__= +@SET MVNW_USERNAME= +@SET MVNW_PASSWORD= +@IF NOT "%__MVNW_CMD__%"=="" ("%__MVNW_CMD__%" %*) +@echo Cannot start maven from wrapper >&2 && exit /b 1 +@GOTO :EOF +: end batch / begin powershell #> + +$ErrorActionPreference = "Stop" +if ($env:MVNW_VERBOSE -eq "true") { + $VerbosePreference = "Continue" +} + +# calculate distributionUrl, requires .mvn/wrapper/maven-wrapper.properties +$distributionUrl = (Get-Content -Raw "$scriptDir/.mvn/wrapper/maven-wrapper.properties" | ConvertFrom-StringData).distributionUrl +if (!$distributionUrl) { + Write-Error "cannot read distributionUrl property in $scriptDir/.mvn/wrapper/maven-wrapper.properties" +} + +switch -wildcard -casesensitive ( $($distributionUrl -replace '^.*/','') ) { + "maven-mvnd-*" { + $USE_MVND = $true + $distributionUrl = $distributionUrl -replace '-bin\.[^.]*$',"-windows-amd64.zip" + $MVN_CMD = "mvnd.cmd" + break + } + default { + $USE_MVND = $false + $MVN_CMD = $script -replace '^mvnw','mvn' + break + } +} + +# apply MVNW_REPOURL and calculate MAVEN_HOME +# maven home pattern: ~/.m2/wrapper/dists/{apache-maven-,maven-mvnd--}/ +if ($env:MVNW_REPOURL) { + $MVNW_REPO_PATTERN = if ($USE_MVND -eq $False) { "/org/apache/maven/" } else { "/maven/mvnd/" } + $distributionUrl = "$env:MVNW_REPOURL$MVNW_REPO_PATTERN$($distributionUrl -replace "^.*$MVNW_REPO_PATTERN",'')" +} +$distributionUrlName = $distributionUrl -replace '^.*/','' +$distributionUrlNameMain = $distributionUrlName -replace '\.[^.]*$','' -replace '-bin$','' + +$MAVEN_M2_PATH = "$HOME/.m2" +if ($env:MAVEN_USER_HOME) { + $MAVEN_M2_PATH = "$env:MAVEN_USER_HOME" +} + +if (-not (Test-Path -Path $MAVEN_M2_PATH)) { + New-Item -Path $MAVEN_M2_PATH -ItemType Directory | Out-Null +} + +$MAVEN_WRAPPER_DISTS = $null +if ((Get-Item $MAVEN_M2_PATH).Target[0] -eq $null) { + $MAVEN_WRAPPER_DISTS = "$MAVEN_M2_PATH/wrapper/dists" +} else { + $MAVEN_WRAPPER_DISTS = (Get-Item $MAVEN_M2_PATH).Target[0] + "/wrapper/dists" +} + +$MAVEN_HOME_PARENT = "$MAVEN_WRAPPER_DISTS/$distributionUrlNameMain" +$MAVEN_HOME_NAME = ([System.Security.Cryptography.SHA256]::Create().ComputeHash([byte[]][char[]]$distributionUrl) | ForEach-Object {$_.ToString("x2")}) -join '' +$MAVEN_HOME = "$MAVEN_HOME_PARENT/$MAVEN_HOME_NAME" + +if (Test-Path -Path "$MAVEN_HOME" -PathType Container) { + Write-Verbose "found existing MAVEN_HOME at $MAVEN_HOME" + Write-Output "MVN_CMD=$MAVEN_HOME/bin/$MVN_CMD" + exit $? +} + +if (! $distributionUrlNameMain -or ($distributionUrlName -eq $distributionUrlNameMain)) { + Write-Error "distributionUrl is not valid, must end with *-bin.zip, but found $distributionUrl" +} + +# prepare tmp dir +$TMP_DOWNLOAD_DIR_HOLDER = New-TemporaryFile +$TMP_DOWNLOAD_DIR = New-Item -Itemtype Directory -Path "$TMP_DOWNLOAD_DIR_HOLDER.dir" +$TMP_DOWNLOAD_DIR_HOLDER.Delete() | Out-Null +trap { + if ($TMP_DOWNLOAD_DIR.Exists) { + try { Remove-Item $TMP_DOWNLOAD_DIR -Recurse -Force | Out-Null } + catch { Write-Warning "Cannot remove $TMP_DOWNLOAD_DIR" } + } +} + +New-Item -Itemtype Directory -Path "$MAVEN_HOME_PARENT" -Force | Out-Null + +# Download and Install Apache Maven +Write-Verbose "Couldn't find MAVEN_HOME, downloading and installing it ..." +Write-Verbose "Downloading from: $distributionUrl" +Write-Verbose "Downloading to: $TMP_DOWNLOAD_DIR/$distributionUrlName" + +$webclient = New-Object System.Net.WebClient +if ($env:MVNW_USERNAME -and $env:MVNW_PASSWORD) { + $webclient.Credentials = New-Object System.Net.NetworkCredential($env:MVNW_USERNAME, $env:MVNW_PASSWORD) +} +[Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls12 +$webclient.DownloadFile($distributionUrl, "$TMP_DOWNLOAD_DIR/$distributionUrlName") | Out-Null + +# If specified, validate the SHA-256 sum of the Maven distribution zip file +$distributionSha256Sum = (Get-Content -Raw "$scriptDir/.mvn/wrapper/maven-wrapper.properties" | ConvertFrom-StringData).distributionSha256Sum +if ($distributionSha256Sum) { + if ($USE_MVND) { + Write-Error "Checksum validation is not supported for maven-mvnd. `nPlease disable validation by removing 'distributionSha256Sum' from your maven-wrapper.properties." + } + Import-Module $PSHOME\Modules\Microsoft.PowerShell.Utility -Function Get-FileHash + if ((Get-FileHash "$TMP_DOWNLOAD_DIR/$distributionUrlName" -Algorithm SHA256).Hash.ToLower() -ne $distributionSha256Sum) { + Write-Error "Error: Failed to validate Maven distribution SHA-256, your Maven distribution might be compromised. If you updated your Maven version, you need to update the specified distributionSha256Sum property." + } +} + +# unzip and move +Expand-Archive "$TMP_DOWNLOAD_DIR/$distributionUrlName" -DestinationPath "$TMP_DOWNLOAD_DIR" | Out-Null + +# Find the actual extracted directory name (handles snapshots where filename != directory name) +$actualDistributionDir = "" + +# First try the expected directory name (for regular distributions) +$expectedPath = Join-Path "$TMP_DOWNLOAD_DIR" "$distributionUrlNameMain" +$expectedMvnPath = Join-Path "$expectedPath" "bin/$MVN_CMD" +if ((Test-Path -Path $expectedPath -PathType Container) -and (Test-Path -Path $expectedMvnPath -PathType Leaf)) { + $actualDistributionDir = $distributionUrlNameMain +} + +# If not found, search for any directory with the Maven executable (for snapshots) +if (!$actualDistributionDir) { + Get-ChildItem -Path "$TMP_DOWNLOAD_DIR" -Directory | ForEach-Object { + $testPath = Join-Path $_.FullName "bin/$MVN_CMD" + if (Test-Path -Path $testPath -PathType Leaf) { + $actualDistributionDir = $_.Name + } + } +} + +if (!$actualDistributionDir) { + Write-Error "Could not find Maven distribution directory in extracted archive" +} + +Write-Verbose "Found extracted Maven distribution directory: $actualDistributionDir" +Rename-Item -Path "$TMP_DOWNLOAD_DIR/$actualDistributionDir" -NewName $MAVEN_HOME_NAME | Out-Null +try { + Move-Item -Path "$TMP_DOWNLOAD_DIR/$MAVEN_HOME_NAME" -Destination $MAVEN_HOME_PARENT | Out-Null +} catch { + if (! (Test-Path -Path "$MAVEN_HOME" -PathType Container)) { + Write-Error "fail to move MAVEN_HOME" + } +} finally { + try { Remove-Item $TMP_DOWNLOAD_DIR -Recurse -Force | Out-Null } + catch { Write-Warning "Cannot remove $TMP_DOWNLOAD_DIR" } +} + +Write-Output "MVN_CMD=$MAVEN_HOME/bin/$MVN_CMD" diff --git a/pom.xml b/pom.xml new file mode 100644 index 0000000..d18e818 --- /dev/null +++ b/pom.xml @@ -0,0 +1,84 @@ + + + 4.0.0 + + org.springframework.boot + spring-boot-starter-parent + 3.5.7 + + + com.gcc + flagpoles + 0.0.1-SNAPSHOT + flagpoles + flag poles + + + + + + + + + + + + + + + 17 + + + + org.springframework.boot + spring-boot-starter-data-jdbc + + + org.springframework.boot + spring-boot-starter-thymeleaf + + + org.springframework.boot + spring-boot-starter-web + + + org.json + json + 20231013 + + + + + org.springframework.boot + spring-boot-devtools + runtime + true + + + com.mysql + mysql-connector-j + runtime + + + com.razorpay + razorpay-java + 1.4.3 + + + org.springframework.boot + spring-boot-starter-test + test + + + + + + + org.springframework.boot + spring-boot-maven-plugin + + + + + diff --git a/src/main/java/com/gcc/flagpoles/FlagpolesApplication.java b/src/main/java/com/gcc/flagpoles/FlagpolesApplication.java new file mode 100644 index 0000000..f7b7617 --- /dev/null +++ b/src/main/java/com/gcc/flagpoles/FlagpolesApplication.java @@ -0,0 +1,13 @@ +package com.gcc.flagpoles; + +import org.springframework.boot.SpringApplication; +import org.springframework.boot.autoconfigure.SpringBootApplication; + +@SpringBootApplication +public class FlagpolesApplication { + + public static void main(String[] args) { + SpringApplication.run(FlagpolesApplication.class, args); + } + +} diff --git a/src/main/java/com/gcc/flagpoles/configuration/AppConfig.java b/src/main/java/com/gcc/flagpoles/configuration/AppConfig.java new file mode 100644 index 0000000..df0ddbc --- /dev/null +++ b/src/main/java/com/gcc/flagpoles/configuration/AppConfig.java @@ -0,0 +1,66 @@ +package com.gcc.flagpoles.configuration; + +import org.springframework.beans.factory.annotation.Value; + +import org.springframework.boot.context.properties.ConfigurationProperties; +import org.springframework.context.annotation.Bean; +import org.springframework.stereotype.Component; +import org.springframework.web.client.RestTemplate; + +@Component +@ConfigurationProperties(prefix = "app") +public class AppConfig { + + @Bean + public RestTemplate restTemplate() { + return new RestTemplate(); + } + + private String title; + private String baseUrl; + private String getOtpUrl; + private String erpUrl; + + @Value("${payment.razorpay.my_key_id}") + private String keyId; + + public String getTitle() { + return title; + } + + public void setTitle(String title) { + this.title = title; + } + + public String getBaseUrl() { + return baseUrl; + } + + public void setBaseUrl(String baseUrl) { + this.baseUrl = baseUrl; + } + + public String getGetOtpUrl() { + return getOtpUrl; + } + + public void setGetOtpUrl(String getOtpUrl) { + this.getOtpUrl = getOtpUrl; + } + + public String getErpUrl() { + return erpUrl; + } + + public void setErpUrl(String erpUrl) { + this.erpUrl = erpUrl; + } + + public String getKeyId() { + return keyId; + } + + public void setKeyId(String keyId) { + this.keyId = keyId; + } +} \ No newline at end of file diff --git a/src/main/java/com/gcc/flagpoles/configuration/RefundScheduler.java b/src/main/java/com/gcc/flagpoles/configuration/RefundScheduler.java new file mode 100644 index 0000000..defd2b1 --- /dev/null +++ b/src/main/java/com/gcc/flagpoles/configuration/RefundScheduler.java @@ -0,0 +1,472 @@ +// package com.gcc.flagpoles.configuration; + +// import com.gcc.flagpoles.constants.AppConstants; +// import com.gcc.flagpoles.service.BookingService; +// import com.gcc.flagpoles.service.PaymentService; +// import com.gcc.flagpoles.service.RefundService; +// import com.razorpay.Order; +// import com.razorpay.Payment; +// import com.razorpay.RazorpayClient; +// import com.razorpay.RazorpayException; +// import org.json.JSONObject; +// import org.springframework.beans.factory.annotation.Autowired; +// import org.springframework.context.annotation.Lazy; +// import org.springframework.dao.DataAccessException; +// import org.springframework.dao.EmptyResultDataAccessException; +// import org.springframework.http.ResponseEntity; +// import org.springframework.jdbc.core.JdbcTemplate; +// import org.springframework.scheduling.annotation.EnableScheduling; +// import org.springframework.scheduling.annotation.Scheduled; +// import org.springframework.stereotype.Component; +// import org.springframework.stereotype.Service; + +// import java.time.Instant; +// import java.time.LocalDate; +// import java.time.LocalDateTime; +// import java.time.ZoneId; +// import java.time.format.DateTimeFormatter; +// import java.util.*; + +// @Component +// @EnableScheduling +// public class RefundScheduler { +// @Autowired +// @Lazy +// RefundService refundService; + +// @Autowired +// PaymentService paymentService; + +// @Autowired +// public JdbcTemplate jdbcTemplate; + +// // @Scheduled(cron = "0 0 1 * * *", zone = "Asia/Kolkata") // runs every 30 +// // seconds (adjust as needed) +// @Scheduled(cron = "0 30 23 * * *", zone = "Asia/Kolkata") // 11:30 PM IST +// (Asia/Kolkata) +// public void updateOrderPaymentStatus() { +// System.out.println("Fetching payment status from Razorpay..."); + +// try { +// // Query orders with NULL order_status +// String sql = "SELECT order_id, cdate FROM order_log WHERE (order_status IS +// NULL OR order_status = '') AND is_counter_booking = 0 and cdate < CURDATE() +// ORDER BY id ";// +// List> orders = jdbcTemplate.queryForList(sql); + +// if (orders.isEmpty()) { +// System.out.println("No orders with NULL status."); +// return; +// } + +// // Collect orderIds into a list +// List orderIds = new ArrayList<>(); +// for (Map order : orders) { +// orderIds.add((String) order.get("order_id")); +// } + +// // Fetch payment status for all orders using the fetchPayments API for +// multiple +// // orderIds +// fetchAndUpdatePaymentStatus(orderIds); +// } catch (Exception e) { +// System.err.println("Error fetching payment status: " + e.getMessage()); +// e.printStackTrace(); +// } +// } + +// public void fetchAndUpdatePaymentStatus(List orderIds) { +// try { +// System.out.println("Fetching payment status for multiple orders..."); + +// RazorpayClient razorpayClient = new RazorpayClient(AppConstants.key_id, +// AppConstants.key_secret); + +// // Fetch payments for the specified orderIds +// for (String orderId : orderIds) { +// List payments = razorpayClient.orders.fetchPayments(orderId); +// System.out.println("Payment response line :100 :" + payments); + +// String ps = "Not Processed"; + +// // Check if there are payments for the order +// if (payments != null && !payments.isEmpty()) { +// int i = 0; +// int c = 0; +// for (Payment payment : payments) { +// String paymentStatus = (payment.get("status") != null) ? +// payment.get("status").toString() : ""; +// String paymentId = (payment.get("id") != null) ? payment.get("id").toString() +// : ""; +// String amount = (payment.get("amount") != null) ? +// payment.get("amount").toString() : "0"; +// String captured_at = ""; // (payment.get("captured_at") != null) ? +// // payment.get("captured_at").toString() : "0"; +// String contactNo = (payment.get("contact") != null) ? +// payment.get("contact").toString() : "0"; + +// System.out.println("contactno line 157--> " + contactNo); +// System.out.println("payments==================" + payment); + +// String paymentDate = ""; +// Object createdAtObj = null; +// // Date Convention +// try { +// // Object createdAtObj = payment.has("captured_at") ? +// payment.get("captured_at") +// // : null; +// createdAtObj = payment.get("captured_at") != null ? +// payment.get("captured_at") : null; + +// if (createdAtObj != null) { +// Instant createdAtInstant = (createdAtObj instanceof Date) +// ? ((Date) createdAtObj).toInstant() +// : (createdAtObj instanceof Number) +// ? Instant.ofEpochSecond(((Number) createdAtObj).longValue()) +// : Instant.ofEpochMilli(System.currentTimeMillis()); + +// paymentDate = createdAtInstant +// .atZone(ZoneId.of("Asia/Kolkata")) +// .toLocalDateTime() +// .format(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss")); + +// // Convert to formatted datetime (e.g., 2025-04-19 17:00:00) +// LocalDateTime dateTime = createdAtInstant +// .atZone(ZoneId.of("Asia/Kolkata")) +// .toLocalDateTime(); +// } +// } catch (Exception e) { +// e.printStackTrace(); +// } +// // End of Date Convention + +// System.out.println("Payment Status for Order ID " + orderId + ": " + +// paymentStatus); + +// if (payments.size() == 1) { +// // Update the order status in the order_log table based on payment status +// payment.get("id").toString(); +// updateOrderStatusInOrderLog(orderId, paymentStatus, payments.size(), +// paymentId, amount, +// paymentDate, contactNo); +// c = 1; +// } else if (paymentStatus.equals("captured") && i == 0) { +// updateOrderStatusInOrderLog(orderId, paymentStatus, payments.size(), +// paymentId, amount, +// paymentDate, contactNo); +// c = 1; + +// } else if (ps.equals(paymentStatus) && paymentStatus.equals("captured")) { +// // refund logic to be implemented +// // razorpay will handle this scenario +// c = 1; +// } else if (paymentStatus.equals("captured") && c == 0) { +// updateOrderStatusInOrderLog(orderId, paymentStatus, payments.size(), +// paymentId, amount, +// paymentDate, contactNo); +// c = 1; +// } + +// ps = paymentStatus; +// i++; +// } +// System.out.println("line :-193 :--->" + ps); +// if (c == 0) { +// updateOrderStatusInOrderLog(orderId, ps, payments.size(), null, null, null, +// null); +// } +// } else { +// System.out.println("No payments found for Order ID: " + orderId); +// updateOrderStatusInOrderLog(orderId, ps, payments.size(), null, null, null, +// null); + +// } +// } +// } catch (RazorpayException e) { +// System.err.println("Error fetching payment status: " + e.getMessage()); +// } +// } + +// public void updateOrderStatusInOrderLog(String orderId, String paymentStatus, +// int pay_attemp, +// String paymentId, String amountStr, String paymentDateTicks, String +// contactNo) { +// // SQL query to update the order status in order_log table +// String sqlUpdate = "UPDATE order_log SET order_status = ? WHERE order_id = +// ?"; +// double amount = 0; + +// try { +// // Check the payment status and update accordingly +// if ("captured".equalsIgnoreCase(paymentStatus)) { +// // Update status to 'PAID' +// jdbcTemplate.update(sqlUpdate, "captured", orderId); + +// if (amountStr != null && !amountStr.equals("0")) { +// amount = Double.parseDouble(amountStr) / 100.0; +// } + +// String sqlGetTempId = "SELECT temp_booking_id FROM order_log WHERE order_id = +// ?"; +// String tempid = jdbcTemplate.queryForObject(sqlGetTempId, String.class, +// orderId); +// System.out.println("==========tempid==========" + tempid); +// insertPaymentDetails(orderId, paymentId, paymentStatus, paymentDateTicks, +// contactNo, amount, tempid); + +// System.out.println("Updated Order ID: " + orderId + " to PAID"); +// } else if ("failed".equalsIgnoreCase(paymentStatus)) { +// // Update status to 'FAILED' +// jdbcTemplate.update(sqlUpdate, "failed", orderId); +// System.out.println("Updated Order ID: " + orderId + " to FAILED"); + +// } else if ("refunded".equalsIgnoreCase(paymentStatus)) { +// // Update status to 'FAILED' +// jdbcTemplate.update(sqlUpdate, "refunded", orderId); +// System.out.println("Updated Order ID: " + orderId + " to refunded"); + +// } else { +// jdbcTemplate.update(sqlUpdate, paymentStatus, orderId); + +// System.out.println("Payment status for Order ID " + orderId +// + " is not 'captured' or 'failed'. No update performed."); +// } +// } catch (DataAccessException e) { +// System.err.println("Error while updating order status: " + e.getMessage()); +// } +// } + +// public void insertPaymentDetails(String orderId, String paymentId, String +// paymentStatus, +// String paymentDate, String mobileNumber, double amount, String tempid) { + +// Integer pid = null; +// int bookingId = 0; +// try { +// // Step 1: Check if order_id already exists in payment table +// String checkSql = "SELECT * FROM payment WHERE order_id = ?"; +// List> ids = jdbcTemplate.queryForList(checkSql, orderId); + +// if (!ids.isEmpty()) { +// // Already exists — pick first +// pid = (Integer) ids.get(0).get("id"); +// bookingId = ids.get(0).get("booking_id") != null ? (Integer) +// ids.get(0).get("booking_id") : 0; +// if (bookingId == 0) { +// // checkBookingAndUpdateStatus(orderId, paymentStatus); +// initiateRefund(orderId, bookingId); +// } else { +// String bkStatus = "success"; +// bkStatus = jdbcTemplate.queryForObject("SELECT booking_status FROM booking +// WHERE booking_id = ?", +// String.class, bookingId); + +// if ("pending".equalsIgnoreCase(bkStatus) || bkStatus == null) { +// // checkBookingAndUpdateStatus(orderId, paymentStatus); +// initiateRefund(orderId, bookingId); +// } +// } + +// System.out.println("⚠️ Payment already exists for order_id: " + orderId + ", +// using pid: " + pid); +// } else { +// // Step 2: Normalize payment status +// if ("captured".equalsIgnoreCase(paymentStatus)) { +// paymentStatus = "paid"; // ✅ convert captured to paid +// } + +// // Step 3: Insert new payment + +// String paymentIdStr = +// String.valueOf(paymentService.savePayment(String.valueOf(amount), paymentId, +// orderId, paymentStatus, String.valueOf(bookingId), mobileNumber)); +// System.out.println("✅ Inserted new payment record for order_id: " + orderId); +// System.out.println("======================>>>>>>" + paymentIdStr); + +// initiateRefund(orderId, bookingId); +// } + +// } catch (Exception e) { +// System.err.println("❌ Error during insertPaymentDetails for order_id: " + +// orderId); +// e.printStackTrace(); +// } +// } + +// /* +// * public void checkBookingAndUpdateStatus(String orderId, String +// paymentStatus) +// * { +// * // SQL to check the booking status for this order +// * String sqlBookingStatus = "SELECT b.booking_id, b.booking_status, py.id " + +// * "FROM order_log ol " + +// * "JOIN payment py ON ol.order_id = py.order_id " + +// * "JOIN booking b ON py.booking_id = b.booking_id " + +// * "WHERE ol.order_id = ?"; +// * +// * +// * try { +// * // Get the booking information +// * List> bookingInfo = +// * jdbcTemplate.queryForList(sqlBookingStatus, orderId); +// * +// * int bookingId = 0; +// * if (!bookingInfo.isEmpty()) { +// * Map bookingDetails = bookingInfo.get(0); +// * String bookingStatus = (String) bookingDetails.get("booking_status"); +// * bookingId = bookingDetails.get("booking_id")!=null?(Integer) +// * bookingDetails.get("booking_id"):0; +// * +// * System.out.println("Booking Status for Order ID " + orderId + ": " + +// * bookingId); +// * +// * // Case 1: If booking status is "null" or "pending", initiate refund +// * // Case 2: If payment status is "captured" (Paid) but no status in the +// * booking table, initiate refund +// * System.out.println("Booking status for Order ID " + orderId + +// * " is confirmed. No update required."); +// * initiateRefund(orderId, bookingId); +// * +// * } else { +// * System.out.println("No booking information found for Order ID: " + +// orderId); +// * initiateRefund(orderId, 0); +// * } +// * } catch (DataAccessException e) { +// * System.err.println("Error while checking and updating booking status: " + +// * e.getMessage()); +// * } +// * } +// */ + +// // Method to initiate refund process +// private void initiateRefund(String orderId, int bookingId) { +// try { +// System.out.println("Initiating refund for Order ID: " + orderId); + +// // Fetch the primary key (`id`) from the `payment` table +// String sql = "SELECT id FROM payment WHERE booking_id = ? and order_id = ? "; +// List paymentIds = jdbcTemplate.queryForList(sql, Integer.class, +// bookingId, orderId); + +// if (!paymentIds.isEmpty()) { +// int paymentId = paymentIds.get(0); // ✅ Get the first result +// System.out.println("Payment ID found: " + paymentId); + +// // Call refundProcessOrder() with correct int pid +// ResponseEntity response = refundService.refundProcessOrder("Refund +// Initiated", bookingId, paymentId); +// System.out.println("Refund API Response: " + response.getBody()); +// } else { +// System.err.println("No payment record found for Booking ID: " + bookingId); +// } +// } catch (Exception e) { +// System.err.println("Error initiating refund for Order ID: " + orderId + ": " +// + e.getMessage()); +// e.printStackTrace(); +// } +// } + +// // @Scheduled(fixedRate = 3000) // 300000 milliseconds = 5 minutes +// @Scheduled(cron = "0 0 1 * * *", zone = "Asia/Kolkata") +// public void refundRrnScheduler() { +// System.out.println("yes....REFUNDStatus_Check_Intiated"); +// List> list = +// refundService.getbyrefundstatus("REFUND_PROCESSED"); +// for (Map map : list) { +// // System.out.println(map); +// if (map.get("refund_id") != null) { +// String refund_id = (String) map.get("refund_id"); +// String rrn = refundStatus(refund_id); +// if (!rrn.equals("error")) { +// int id = Integer.parseInt(map.get("id") + ""); +// refundService.updateRefundRrnStatus(id, map.get("refund_id").toString(), rrn, +// "REFUNDED"); +// } + +// } + +// } +// } + +// public String refundStatus(String refund_id) { +// System.out.println("yes....REFUND_PROCESSED "); +// try { +// RazorpayClient razorpayClient = new RazorpayClient(AppConstants.key_id, +// AppConstants.key_secret); +// com.razorpay.Refund refunds = razorpayClient.refunds.fetch(refund_id); +// System.out.println(refunds.get("acquirer_data").toString()); +// // if(refunds.get("acquirer_data")!= null){ +// JSONObject map = refunds.get("acquirer_data"); +// System.out.println(map); +// if (map.get("rrn") != null && !map.get("rrn").equals("")) { +// System.out.println(map.get("rrn")); +// return map.get("rrn").toString(); +// } + +// // } + +// } catch (Exception e) { +// e.printStackTrace(); +// return "error"; +// } +// return "error"; + +// } + +// /* +// * public void checkBookingStatus(String orderId) { +// * System.out.println("🔍 Checking booking status for order_id: " + orderId); +// * +// * try { +// * // Step 1: Fetch booking_id from payment table using order_id +// * String getBookingIdSql = "SELECT booking_id FROM payment WHERE order_id = +// ?"; +// * Integer bookingId = jdbcTemplate.queryForObject(getBookingIdSql, +// * Integer.class, orderId); +// * +// * if (bookingId != null) { +// * // Step 2: Fetch booking status using booking_id +// * String getBookingStatusSql = +// * "SELECT booking_status FROM booking WHERE booking_id = ?"; +// * String bookingStatus = jdbcTemplate.queryForObject(getBookingStatusSql, +// * String.class, bookingId); +// * +// * System.out.println("➡ Booking ID: " + bookingId + " | Status: " + +// * bookingStatus); +// * +// * // If status is success, do nothing +// * if ("success".equalsIgnoreCase(bookingStatus)) { +// * System.out.println("✅ Booking is successful. No refund required."); +// * } else { +// * System.out.println("⚠️ Booking is not successful. Initiating refund..."); +// * +// * initiateRefund(orderId, bookingId); +// * } +// * } else { +// * +// * System.out.println("⚠️ No booking_id found for order_id: " + orderId + +// * ". Initiating refund..."); +// * initiateRefund(orderId, 0); +// * } +// * +// * } catch (EmptyResultDataAccessException e) { +// * System.out.println("⚠️ No booking_id or status found for order_id: " + +// * orderId + ". Initiating refund..."); +// * initiateRefund(orderId, 0); +// * } catch (Exception e) { +// * System.err.println("❌ Error in checkBookingStatus for order_id: " + +// orderId); +// * e.printStackTrace(); +// * } +// * } +// */ + +// // public void initiateRefundlog(String orderId, Integer bookingId) { +// // System.out.println("yes....REFUNDStatus_Check_Intiated"); +// // // String refundStatus = "refunded"; +// // String sql = "INSERT INTO refund_log (order_id, booking_id) VALUES (?, +// ?)"; +// // } + +// } diff --git a/src/main/java/com/gcc/flagpoles/constants/AppConstants.java b/src/main/java/com/gcc/flagpoles/constants/AppConstants.java new file mode 100644 index 0000000..73ec15c --- /dev/null +++ b/src/main/java/com/gcc/flagpoles/constants/AppConstants.java @@ -0,0 +1,15 @@ +package com.gcc.flagpoles.constants; + +public final class AppConstants { + // for Production +// public static String key_id="rzp_live_66FhxMUNAb9McO"; +// public static String key_secret="aoIzMGQE3xOxin92rYaK75jV"; + + + //uncomment for testing payment + public static String key_id="rzp_test_TADBzz8BXbBpos"; + public static String key_secret="3es3YZ3DFVYdibbGLBtL8nBB"; + + + +} diff --git a/src/main/java/com/gcc/flagpoles/controller/ApiController.java b/src/main/java/com/gcc/flagpoles/controller/ApiController.java new file mode 100644 index 0000000..0c91295 --- /dev/null +++ b/src/main/java/com/gcc/flagpoles/controller/ApiController.java @@ -0,0 +1,762 @@ +package com.gcc.flagpoles.controller; + +import java.time.LocalDate; +import java.time.LocalDateTime; + +import java.time.format.DateTimeFormatter; +import java.util.ArrayList; +import java.util.Collections; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.Random; + +import com.gcc.flagpoles.configuration.AppConfig; +//import org.json.JSONObject; +import com.gcc.flagpoles.constants.AppConstants; +import com.gcc.flagpoles.service.PaymentService; +import com.razorpay.Order; +import com.razorpay.RazorpayClient; +import com.razorpay.RazorpayException; +import org.json.JSONObject; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.format.annotation.DateTimeFormat; +import org.springframework.http.HttpStatus; +import org.springframework.http.ResponseEntity; +import org.springframework.jdbc.core.JdbcTemplate; +import org.springframework.transaction.annotation.Transactional; +import org.springframework.ui.Model; +import org.springframework.util.LinkedMultiValueMap; +import org.springframework.util.MultiValueMap; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.PostMapping; +import org.springframework.web.bind.annotation.RequestBody; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RequestParam; +import org.springframework.web.bind.annotation.RequestPart; +import org.springframework.web.bind.annotation.ResponseBody; +import org.springframework.web.bind.annotation.RestController; +import org.springframework.web.client.RestTemplate; +import org.springframework.web.multipart.MultipartFile; + +import com.fasterxml.jackson.databind.ObjectMapper; +import com.gcc.flagpoles.service.RequestService; + +// import com.dumpregistration.configuration.AppConfig; +// import com.dumpregistration.constants.AppConstants; +// import com.dumpregistration.service.PaymentService; +// import com.dumpregistration.service.RequestService; +// import com.fasterxml.jackson.databind.ObjectMapper; +// import com.razorpay.Order; +// import com.razorpay.RazorpayClient; +// import com.razorpay.RazorpayException; + +import jakarta.servlet.http.HttpServletRequest; +import jakarta.servlet.http.HttpSession; + +@RestController +@RequestMapping("/flagpolesregistration/api") +public class ApiController { + + @Autowired + private RequestService requestService; + + @Autowired + private JdbcTemplate jdbcTemplate; + + @Autowired + private PaymentService paymentService; + + // @Autowired + // private PaymentService paymentService ; + + @Autowired + private AppConfig appConfig; + + /* ///////////////// otp configuration ///////////////////// */ + + // send otp for registered user + @GetMapping(value = "/sendOTPforregistereduser") + public String sendOtpforregistereduser(HttpServletRequest request, @RequestParam String mobile) { + + // Create an ObjectMapper instance + ObjectMapper objectMapper = new ObjectMapper(); + + // Create a response map + Map response = new HashMap<>(); + + String MobileNo = mobile; + System.out.print("\n MobileNo---:" + mobile); + Random rand = new Random(); + // int otp = rand.nextInt(90000) + 10000; + + int otp = 22222; + System.out.print("\n otp---:" + otp); + DateTimeFormatter dtf = DateTimeFormatter.ofPattern("dd-MMM-yyyy%20HH:mm"); + LocalDateTime now = LocalDateTime.now(); + System.out.println(dtf.format(now)); + // String generatedToken = "Welcome to GCC! Your OTP for C%26D waste collectors + // Registration process is "+otp; + + // String generatedToken = "Welcome to GCC "+otp+" is your OTP for gcc QR + // System"; + + // String generatedToken = "Welcome to GCC! Your OTP for C and D waste + // collectors Registration process is " + otp; + // // String key="qxg4mklD"; + // String key = "pfTEYN6H"; + // String urlString = appConfig.getGetOtpUrl() + "from=GCCCRP&key=" + key + + // "&sender=GCCCRP&to=" + MobileNo + // + "&body=" + generatedToken + + // "&entityid=1401572690000011081&templateid=1407172967243483268"; + + String key = "pfTEYN6H"; + String entityId = "1401572690000011081"; + String templateId = "1407175765770900925"; + String appName = "Flagpoles"; + + String generatedMessage = "Welcome to GCC! Your OTP for " + appName + " is " + otp + "."; + String urlString = appConfig.getGetOtpUrl() + "from=GCCCRP" + "&key=" + key + "&sender=GCCCRP" + "&to=" + + MobileNo + "&body=" + + generatedMessage + "&entityid=" + entityId + "&templateid=" + templateId; + + // String urlString = + // "https://tmegov.onex-aura.com/api/sms?from=GCCCRP&key=pfTEYN6H&sender=GCCCRP&to=9360777472&body=Welcome%20to%20GCC!%20Your%20OTP%20for%20C%26D%20waste%20collectors%20Registration%20process%20is%20"+otp+"&entityid=1401572690000011081&templateid=1407172959127552127"; + // String urlString= + // appConfig.getGetOtpUrl()+"from=GCCCRP&key="+key+"&sender=GCCCRP&to="+MobileNo+"&body="+generatedToken+"&entityid=1401572690000011081&templateid=1407168250479102852"; + // String + // urlString=appConfig.getGetOtpUrl()+"user=GCCtrans&authkey=92kOC1RBGBIws&sender=GCCCRP&mobile="+MobileNo+"&text="+generatedToken+"&rpt=1&summary=1&output=json&entityid=1401572690000011081&templateid=1407168250479102852"; + System.out.print("\n urlString---: " + urlString); + String bodyMessage = ""; + try { + RestTemplate restTemplate = new RestTemplate(); + String Response = restTemplate.getForObject(urlString, String.class); + bodyMessage = Response; + System.out.println("\n bodyMessage" + bodyMessage); + + System.out.println("OTP sent successfully!"); + + } catch (Exception e) { + System.out.print("ERROR---: " + e); + bodyMessage = "Error"; + } + HttpSession session = request.getSession(); + session.setAttribute("otp", otp); + return bodyMessage; + + } + + // verify without registered user + + @GetMapping(value = "/sendOTP") + public String sendOtp(HttpServletRequest request, @RequestParam String mobile) { + + // Create an ObjectMapper instance + ObjectMapper objectMapper = new ObjectMapper(); + + // Check if mobile number is already registered + // List registrations = + // wasteregistrationrepo.findByMobileNo(mobile); + + // Create a response map + Map response = new HashMap<>(); + + // if (registrations.isEmpty()) { + // // If mobile number is not registered + // response.put("status", "NOT_REGISTERED"); + // response.put("mobile", mobile); // Return the mobile number + // try { + // return objectMapper.writeValueAsString(response); // Use the instance to + // convert map to JSON string + // } catch (Exception e) { + // // Handle JSON conversion error + // return "{\"status\": \"ERROR\", \"message\": \"Could not convert response to + // JSON.\"}"; + // } + // } + + String MobileNo = mobile; + System.out.print("\n MobileNo---:" + mobile); + Random rand = new Random(); + // int otp = rand.nextInt(90000) + 10000; + + int otp = 22222; + System.out.print("\n otp---:" + otp); + DateTimeFormatter dtf = DateTimeFormatter.ofPattern("dd-MMM-yyyy%20HH:mm"); + LocalDateTime now = LocalDateTime.now(); + System.out.println(dtf.format(now)); + // String generatedToken = "Welcome to GCC! Your OTP for C%26D waste collectors + // Registration process is "+otp; + + // String generatedToken = "Welcome to GCC "+otp+" is your OTP for gcc QR + // System"; + + // String generatedToken = "Welcome to GCC! Your OTP for C and D waste + // collectors Registration process is " + otp; + // // String key="qxg4mklD"; + // String key = "pfTEYN6H"; + // String urlString = appConfig.getGetOtpUrl() + "from=GCCCRP&key=" + key + + // "&sender=GCCCRP&to=" + MobileNo + // + "&body=" + generatedToken + + // "&entityid=1401572690000011081&templateid=1407172967243483268"; + + String key = "pfTEYN6H"; + String entityId = "1401572690000011081"; + String templateId = "1407175765770900925"; + String appName = "Flagpoles"; + + String generatedMessage = "Welcome to GCC! Your OTP for " + appName + " is " + otp + "."; + String urlString = appConfig.getGetOtpUrl() + "from=GCCCRP" + "&key=" + key + "&sender=GCCCRP" + "&to=" + + MobileNo + "&body=" + + generatedMessage + "&entityid=" + entityId + "&templateid=" + templateId; + + // String urlString = + // "https://tmegov.onex-aura.com/api/sms?from=GCCCRP&key=pfTEYN6H&sender=GCCCRP&to=9360777472&body=Welcome%20to%20GCC!%20Your%20OTP%20for%20C%26D%20waste%20collectors%20Registration%20process%20is%20"+otp+"&entityid=1401572690000011081&templateid=1407172959127552127"; + // String urlString= + // appConfig.getGetOtpUrl()+"from=GCCCRP&key="+key+"&sender=GCCCRP&to="+MobileNo+"&body="+generatedToken+"&entityid=1401572690000011081&templateid=1407168250479102852"; + // String + // urlString=appConfig.getGetOtpUrl()+"user=GCCtrans&authkey=92kOC1RBGBIws&sender=GCCCRP&mobile="+MobileNo+"&text="+generatedToken+"&rpt=1&summary=1&output=json&entityid=1401572690000011081&templateid=1407168250479102852"; + System.out.print("\n urlString---: " + urlString); + String bodyMessage = ""; + try { + RestTemplate restTemplate = new RestTemplate(); + String Response = restTemplate.getForObject(urlString, String.class); + bodyMessage = Response; + System.out.println("\n bodyMessage" + bodyMessage); + + System.out.println("OTP sent successfully!"); + + } catch (Exception e) { + System.out.print("ERROR---: " + e); + bodyMessage = "Error"; + } + HttpSession session = request.getSession(); + session.setAttribute("otp", otp); + return bodyMessage; + + } + + @GetMapping(value = "/verifyOTP") + public String verifyOtp(HttpServletRequest request, @RequestParam String otp) { + HttpSession session = request.getSession(); + try { + Integer session_otp = (Integer) session.getAttribute("otp"); + System.out.println("session_otp---:" + session_otp); + Integer entered_otp = Integer.parseInt(otp); + + if (session_otp != null && session_otp.equals(entered_otp)) { + System.out.println("Entered OTP Correct"); + session.setAttribute("verifiedotp", "success"); + return "Success"; + } else { + System.out.println("Incorrect OTP. Please enter correct OTPs."); + session.setAttribute("verifiedotp", "error"); + return "Error"; + } + } catch (NumberFormatException e) { + System.out.println("Invalid OTP format: " + otp); + return "Error"; + } catch (Exception e) { + System.out.println("Error verifying OTP: " + e.getMessage()); + return "Error"; + } + } + + @PostMapping("/saveRequest") + public ResponseEntity saveRequest(@RequestParam MultiValueMap params) { + try { + // ✅ 1. Extract Applicant Info + Map applicant = new HashMap<>(); + applicant.put("name", params.getFirst("name")); + applicant.put("mobileNumber", params.getFirst("mobileNumber")); + applicant.put("address", params.getFirst("address")); + + if (applicant.get("name") == null || applicant.get("mobileNumber") == null + || applicant.get("address") == null) { + return ResponseEntity.badRequest().body(Map.of( + "status", "error", + "message", "Applicant details are incomplete.")); + } + + // ✅ 2. Extract Event Info (with cost-related fields) + Map event = new HashMap<>(); + event.put("type", params.getFirst("eventType")); + event.put("date", params.getFirst("eventDate")); + event.put("description", params.getFirst("description")); + event.put("totalPoles", params.getFirst("totalPoles")); + // event.put("deposit", params.getFirst("deposit")); + event.put("totalCost", params.getFirst("totalCost")); + + if (event.get("type") == null || event.get("date") == null || event.get("description") == null) { + return ResponseEntity.badRequest().body(Map.of( + "status", "error", + "message", "Event details are incomplete.")); + } + + // ✅ 3. Build List of Streets + List> streets = new ArrayList<>(); + int index = 0; + + String globalRatePerPole = params.getFirst("ratePerPole"); // top-level + while (true) { + String prefix = "streets[" + index + "]."; + if (params.getFirst(prefix + "streetName") == null) + break; + + Map s = new HashMap<>(); + s.put("streetName", params.getFirst(prefix + "streetName")); + s.put("zoneId", params.getFirst(prefix + "zone")); + s.put("wardId", params.getFirst(prefix + "ward")); + s.put("noOfPoles", params.getFirst(prefix + "noOfPoles")); + s.put("poleHeight", params.getFirst(prefix + "poleHeight")); + s.put("poleMaterial", params.getFirst(prefix + "poleMaterial")); + s.put("flagMaterial", params.getFirst(prefix + "flagMaterial")); + s.put("spacing", params.getFirst(prefix + "spacing")); + s.put("durationDays", params.getFirst(prefix + "durationDays")); + + // ✅ Ensure latitude/longitude keys match your service + s.put("lat", params.getFirst(prefix + "lat")); + s.put("long", params.getFirst(prefix + "long")); + // ✅ Fix here: use top-level rate if per-street is null + String rate = params.getFirst(prefix + "ratePerPole"); + s.put("ratePerPole", rate != null ? rate : globalRatePerPole); + + // ⚙️ Optional validation + if (s.get("lat") == null || s.get("long") == null) { + return ResponseEntity.badRequest().body(Map.of( + "status", "error", + "message", "Latitude and Longitude are required for all streets.")); + } + + streets.add(s); + index++; + } + + if (streets.isEmpty()) { + return ResponseEntity.badRequest().body(Map.of( + "status", "error", + "message", "No street data found in request.")); + } + + // System.out.println("applicant" + applicant); + // System.out.println("streets" + streets); + // System.out.println("events" + event); + // ✅ 4. Save request (Service internally checks for nearby requests) + // String userReqId = requestService.saveFlagPoleRequest(applicant, event, + // streets); + String tempRefId = requestService.saveTempBooking(applicant, event, streets); + + // ✅ 5. Return Success Response + return ResponseEntity.ok(Map.of( + "status", "success", + "message", "Application saved successfully.", + "request_id", tempRefId)); + + } catch (IllegalArgumentException iae) { + // ⛔ Custom validation or nearby request check failure + return ResponseEntity.badRequest().body(Map.of( + "status", "error", + "message", iae.getMessage())); + + } catch (Exception e) { + // ⛔ Unexpected errors + e.printStackTrace(); + return ResponseEntity.internalServerError().body(Map.of( + "status", "error", + "message", "Server error: " + e.getMessage())); + } + } + + @GetMapping("/searchRequestStatus") + public ResponseEntity searchRequestStatus( + @RequestParam(required = false) String refId, + @RequestParam(required = false) String mobileNo) { + + try { + List> result = requestService.searchRequestsByRefIdOrMobile(refId, mobileNo); + + return ResponseEntity.ok( + Map.of( + "status", "success", + "count", result.size(), + "data", result)); + } catch (Exception e) { + return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR) + .body( + Map.of( + "status", "error", + "message", "Failed to fetch data", + "error", e.getMessage())); + } + } + + @GetMapping("/getFineDetails") + public ResponseEntity getFineDetails( + @RequestParam String refId) { + + try { + List> result = requestService.getFineDetails(refId); + + return ResponseEntity.ok( + Map.of( + "status", "success", + "count", result.size(), + "data", result)); + } catch (Exception e) { + return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR) + .body( + Map.of( + "status", "error", + "message", "Failed to fetch data", + "error", e.getMessage())); + } + } + + // Helper method for bad requests + private ResponseEntity> badRequest(String message) { + return ResponseEntity.badRequest().body(Map.of("status", "error", "message", message)); + } + + private boolean isEmpty(Object val) { + return val == null || val.toString().trim().isEmpty(); + } + + // payment related api + // // old + // @PostMapping("/create_order") + // @ResponseBody + // public String createOrder(@RequestBody Map data) throws + // RazorpayException { + + // System.out.println("Received JSON Body: " + data); + + // String ref_id = data.get("id").toString(); + // // double amount=Double.parseDouble("50"); + + // System.out.println("ref_id>>>>>>>>>>>>>" + ref_id); + + // // List> userDetails = + // // requestService.getUserDetails(ref_id); + // List> userDetails = + // requestService.getUserDetailsfromTemp(ref_id); + // System.out.println("Fetched User Details: " + userDetails); + + // Map userDetail = userDetails.get(0); // Get first map + // Object chargeObj = userDetail.get("total_cost"); + + // System.out.println(); + // double amount = Math.ceil(Double.parseDouble(chargeObj.toString()) * 100); + + // // var client= new + // // RazorpayClient("rzp_live_ySI5Ns54Y7qOcJ","Nwf1TjhUtaskof8vePkRR8Sb"); + // // var client= new + // // RazorpayClient("rzp_test_tDkHFEqWXmuEi8","cBQUjMcKZ4J6vmOKSyNZ92py"); + + // System.out.println("amount:-->" + amount); + // // To enable testing mode in appConstants if required for testing & + // // development + // var client = new RazorpayClient(AppConstants.key_id, + // AppConstants.key_secret); + + // // System.out.println("client details " + client); + // JSONObject options = new JSONObject(); + // options.put("amount", amount); + // options.put("currency", "INR"); + // // options.put("receipt","Pet_ID/"+pet_id); + // Order od = client.orders.create(options); + // // paymentService.saveorderLog("FP" + od.get("id").toString(), od.toString(), + // // ref_id); + // paymentService.saveorderLog(od.get("id").toString(), od.toString(), ref_id); + // System.out.println(od); + // return od.toString(); + + // } + + @PostMapping("/create_order") + @ResponseBody + public String createOrder(@RequestBody Map data) + throws RazorpayException { + + String refId = data.get("id").toString(); + + // 🔥 Detect where data exists + boolean isFinal = requestService.existsInFinal(refId); + + List> list = isFinal + ? requestService.getFinalDetailsByRefId(refId) + : requestService.getDetailsByRequestIdTemp(refId); + + if (list.isEmpty()) { + throw new RuntimeException("No payment details found"); + } + + Map d = list.get(0); + + String bookingStatus = (String) d.get("booking_payment_status"); + String fineStatus = (String) d.get("fine_payment_status"); + String restorationStatus = (String) d.get("restoration_payment_status"); + + double amount; + + boolean bookingPaid = "PAID".equalsIgnoreCase(bookingStatus) + || "COMPLETED".equalsIgnoreCase(bookingStatus); + + /* ================= PAYMENT PRIORITY ================= */ + + // 1️⃣ Booking + if (!bookingPaid) { + amount = Double.parseDouble(d.get("total_cost").toString()); + } + // 2️⃣ Fine + else if (fineStatus != null && "PENDING".equalsIgnoreCase(fineStatus)) { + amount = Double.parseDouble(d.get("fine_amount").toString()); + } + // 3️⃣ Restoration + else if (restorationStatus != null && "PENDING".equalsIgnoreCase(restorationStatus)) { + amount = Double.parseDouble(d.get("restoration_amount").toString()); + } else { + throw new RuntimeException("No pending payment"); + } + + long paise = Math.round(amount * 100); + + RazorpayClient client = new RazorpayClient(AppConstants.key_id, AppConstants.key_secret); + + JSONObject options = new JSONObject(); + options.put("amount", paise); + options.put("currency", "INR"); + + Order order = client.orders.create(options); + + // ✅ Save order log with SAME refId (FINAL or TEMP) + paymentService.saveorderLog( + order.get("id").toString(), + order.toString(), + refId); + + return order.toString(); + } + + // @PostMapping("/Confirm") + // public ResponseEntity updateOrder(@RequestBody Map data) { + + // String tempRefId = data.get("id").toString(); + // String refId = (String) data.get("id"); + // String pay_id = data.get("payment_id").toString(); + // String order_id = data.get("order_id").toString(); + // String status = data.get("status").toString(); + // String amt = data.get("amt").toString(); + // String mobileNumber = data.get("mobile_no").toString(); + // DateTimeFormatter dtf = DateTimeFormatter.ofPattern("yyyy/MM/dd HH:mm:ss"); + // LocalDateTime now = LocalDateTime.now(); + + // System.out.println(data); + // // Move temp → final + + // paymentService.savePayment( + // data.get("amt").toString(), + // data.get("payment_id").toString(), + // data.get("order_id").toString(), + // data.get("status").toString(), + // tempRefId, + // data.get("mobile_no").toString()); + // String finalRefId = requestService.moveTempToFinal(tempRefId); + // // paymentService.savePayment(amt, pay_id, order_id, status, refId, + // // mobileNumber); + // return ResponseEntity.ok(Map.of("msg", "updated")); + + // } + + // old yogi + // @PostMapping("/Confirm") + // @Transactional + // public ResponseEntity confirmPayment(@RequestBody Map + // data) { + + // String tempRefId = data.get("id").toString(); + + // // Save payment + // paymentService.savePayment( + // data.get("amt").toString(), + // data.get("payment_id").toString(), + // data.get("order_id").toString(), + // data.get("status").toString(), + // tempRefId, + // data.get("mobile_no").toString()); + + // // 2 Update TEMP payment status + // requestService.updateTempPaymentStatus(tempRefId, "COMPLETED"); + // // Move temp → final + // String finalRefId = requestService.moveTempToFinal(tempRefId); + + // return ResponseEntity.ok(Map.of( + // "status", "success", + // "request_id", finalRefId)); + // } + + // @PostMapping("/Confirm") + // @Transactional + // public ResponseEntity confirmPayment(@RequestBody Map + // data) { + + // String tempRefId = data.get("id").toString(); + // String amount = data.get("amt").toString(); + + // // 🔹 Get temp details + // Map details = + // requestService.getDetailsByRequestIdTemp(tempRefId).get(0); + + // String bookingStatus = (String) details.get("booking_payment_status"); + // boolean bookingPaid = "PAID".equalsIgnoreCase(bookingStatus) + // || "COMPLETED".equalsIgnoreCase(bookingStatus); + + // /* 🔴 BOOKING PAYMENT */ + // if (!bookingPaid) { + + // // 1️⃣ Update TEMP payment status + // requestService.updateTempPaymentStatus(tempRefId, "COMPLETED"); + + // // 2️⃣ Move TEMP → FINAL and get finalRefId + // String finalRefId = requestService.moveTempToFinal(tempRefId); + + // // 3️⃣ NOW save payment with FINAL refId ✅ + // paymentService.savePayment( + // amount, + // data.get("payment_id").toString(), + // data.get("order_id").toString(), + // data.get("status").toString(), + // finalRefId, // ✅ IMPORTANT + // data.get("mobile_no").toString()); + + // return ResponseEntity.ok(Map.of( + // "status", "success", + // "paymentType", "BOOKING", + // "request_id", finalRefId)); + // } + + // throw new IllegalStateException("Invalid payment state"); + // } + + @PostMapping("/Confirm") + @Transactional + public ResponseEntity confirmPayment(@RequestBody Map data) { + + String refId = data.get("id").toString(); + String amount = data.get("amt").toString(); + + boolean isFinal = requestService.existsInFinal(refId); + + Map details = isFinal + ? requestService.getFinalDetailsByRefId(refId).get(0) + : requestService.getDetailsByRequestIdTemp(refId).get(0); + + String bookingStatus = (String) details.get("booking_payment_status"); + String fineStatus = (String) details.get("fine_payment_status"); + String restorationStatus = (String) details.get("restoration_payment_status"); + + /* ================= BOOKING ================= */ + if (!"PAID".equalsIgnoreCase(bookingStatus) + && !"COMPLETED".equalsIgnoreCase(bookingStatus)) { + + requestService.updateTempPaymentStatus(refId, "COMPLETED"); + String finalRefId = requestService.moveTempToFinal(refId); + + paymentService.savePayment( + amount, + data.get("payment_id").toString(), + data.get("order_id").toString(), + data.get("status").toString(), + finalRefId, + data.get("mobile_no").toString(), + "BOOKING" // ✅ + ); + + return ResponseEntity.ok(Map.of( + "status", "success", + "paymentType", "BOOKING", + "request_id", finalRefId)); + } + + /* ================= FINE ================= */ + if ("PENDING".equalsIgnoreCase(fineStatus)) { + + requestService.updateFinePaymentStatus(refId); + + paymentService.savePayment( + amount, + data.get("payment_id").toString(), + data.get("order_id").toString(), + data.get("status").toString(), + refId, + data.get("mobile_no").toString(), + "FINE" // ✅ + ); + + return ResponseEntity.ok(Map.of( + "status", "success", + "paymentType", "FINE", + "request_id", refId)); + } + + /* ================= RESTORATION ================= */ + if ("PENDING".equalsIgnoreCase(restorationStatus)) { + + requestService.updateRestorationPaymentStatus(refId); + + paymentService.savePayment( + amount, + data.get("payment_id").toString(), + data.get("order_id").toString(), + data.get("status").toString(), + refId, + data.get("mobile_no").toString(), + "RESTORATION" // ✅ + ); + + return ResponseEntity.ok(Map.of( + "status", "success", + "paymentType", "RESTORATION", + "request_id", refId)); + } + + throw new IllegalStateException("No pending payment"); + } + + // 🔴 CANCEL EVENT + @PostMapping("/cancelEvent") + public ResponseEntity> cancelEvent( + @RequestParam String refId) { + + String result = requestService.cancelEvent(refId); + + return ResponseEntity.ok(Map.of("status", result)); + } + + // 🟡 POSTPONE EVENT + @PostMapping("/postponeEvent") + public ResponseEntity> postponeEvent( + @RequestParam String refId, + @RequestParam @DateTimeFormat(iso = DateTimeFormat.ISO.DATE) LocalDate newDate) { + + String result = requestService.postponeEvent(refId, newDate); + + return ResponseEntity.ok(Map.of("status", result)); + } + + @GetMapping("/checkUserExists") + public Map checkUserExists(@RequestParam String mobile) { + + Map response = new HashMap<>(); + + boolean exists = requestService.isUserExistsByMobile(mobile); + + response.put("exists", exists); + + if (!exists) { + response.put("message", "Mobile number not registered. Please register first."); + } + + return response; + } + +} diff --git a/src/main/java/com/gcc/flagpoles/controller/DateTimeUtil.java b/src/main/java/com/gcc/flagpoles/controller/DateTimeUtil.java new file mode 100644 index 0000000..2da3382 --- /dev/null +++ b/src/main/java/com/gcc/flagpoles/controller/DateTimeUtil.java @@ -0,0 +1,35 @@ +// package com.gcc.flagpoles.controller; + +// import org.springframework.stereotype.Service; + +// import java.time.LocalDateTime; +// import java.time.format.DateTimeFormatter; + +// @Service +// public class DateTimeUtil { +// public static String getCurrentDateTime() { +// DateTimeFormatter formatter = DateTimeFormatter.ofPattern("ddMMyyyyHHmmss"); +// LocalDateTime now = LocalDateTime.now(); +// return now.format(formatter); +// } +// public static String getCurrentYear() { +// DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy"); +// LocalDateTime now = LocalDateTime.now(); +// return now.format(formatter); +// } +// public static String getCurrentMonth() { +// DateTimeFormatter formatter = DateTimeFormatter.ofPattern("MM"); +// LocalDateTime now = LocalDateTime.now(); +// return now.format(formatter); +// } +// public static String getCurrentDay() { +// DateTimeFormatter formatter = DateTimeFormatter.ofPattern("dd"); +// LocalDateTime now = LocalDateTime.now(); +// return now.format(formatter); +// } +// public static String getCurrentDateTimeMysql() { +// DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss"); +// LocalDateTime now = LocalDateTime.now(); +// return now.format(formatter); +// } +// } diff --git a/src/main/java/com/gcc/flagpoles/controller/DropDownApiController.java b/src/main/java/com/gcc/flagpoles/controller/DropDownApiController.java new file mode 100644 index 0000000..58d80a3 --- /dev/null +++ b/src/main/java/com/gcc/flagpoles/controller/DropDownApiController.java @@ -0,0 +1,77 @@ +package com.gcc.flagpoles.controller; + +import java.util.Collections; +import java.util.List; + +import java.util.Map; + +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.http.HttpStatus; +import org.springframework.http.ResponseEntity; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RequestParam; +import org.springframework.web.bind.annotation.RestController; + +import com.gcc.flagpoles.service.DropDownService; + +@RestController +@RequestMapping("/flagpolesregistration/dropdown/api") +public class DropDownApiController { + + @Autowired + private DropDownService dropDownService; + + @GetMapping("/getpolemateriallist") + public List> getPoleMaterialList() { + return dropDownService.getPoleMaterialList(); + } + + @GetMapping("/geteventtype") + public List> getEventTypesList() { + return dropDownService.getEventTypes(); + } + + // get the vehicles + @GetMapping("/getallflagmaterial") + public List> getFlagMaterialList() { + return dropDownService.getFlagMaterialList(); + } + + // GET: /flagpoles/api/location/getZoneWard?streetName=Velachery + @GetMapping("/getZoneWard") + public Map getZoneAndWard(@RequestParam String streetName) { + + // System.out.println("Received street name: " + streetName); + return dropDownService.getZoneAndWardByStreet(streetName); + } + + // get the waste charges + @GetMapping("/getallcharges") + public List> getpaymentcharges() { + return dropDownService.getAllcharges(); + } + + @GetMapping("/getallzones") + public ResponseEntity getAllZones() { + try { + List> response = dropDownService.getZonesList(); + return ResponseEntity.ok(response); + } catch (Exception e) { + return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR) + .body(Collections.singletonMap("error", "Failed to fetch data: " + e.getMessage())); + } + } + + @GetMapping("/getwardsbyzone") + public ResponseEntity getWardsByZone(@RequestParam int zoneId) { + try { + List> response = dropDownService.getWardsByZoneId(zoneId); + return ResponseEntity.ok(response); + } catch (Exception e) { + return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR) + .body(Collections.singletonMap("error", "Failed to fetch data: " + e.getMessage())); + } + } + +} diff --git a/src/main/java/com/gcc/flagpoles/controller/MainController.java b/src/main/java/com/gcc/flagpoles/controller/MainController.java new file mode 100644 index 0000000..7b66d77 --- /dev/null +++ b/src/main/java/com/gcc/flagpoles/controller/MainController.java @@ -0,0 +1,281 @@ +package com.gcc.flagpoles.controller; + +import java.util.List; +import java.util.Map; + +import com.gcc.flagpoles.service.RequestService; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Controller; +import org.springframework.ui.Model; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RequestParam; + +@Controller +@RequestMapping(value = { "/flagpolesregistration" }) +public class MainController { + + @Autowired + private RequestService requestService; + + @GetMapping(value = { "", "/", "/index" }) + + public String requestform() { + return "modules/flagpolesregistration/index"; + } + + // @GetMapping("/paymentform") + // public String paymentform(@RequestParam("requestId") String requestId, Model + // model) { + // List> detailsList = + // requestService.getDetailsByRequestId(requestId); + + // if (!detailsList.isEmpty()) { + // Map requestData = detailsList.get(0); + // model.addAttribute("requestData", requestData); // + + // String paymentStatus = (String) requestData.get("payment_status"); + // if ("pending".equalsIgnoreCase(paymentStatus)) { + // return "modules/dumpwastecollector/paymentrequestform"; + // } else { + // return "modules/dumpwastecollector/acknowledgement"; + // } + // } + + // model.addAttribute("message", "No details found for Request ID: " + + // requestId); + // return "modules/dumpwastecollector/nodatafound"; + // } + + // Register pages flagpoles + @GetMapping("/register") + public String wastecollectorsregister(Model model) { + + return "modules/flagpolesregistration/requestform"; + } + + // Status pages flagpoles + @GetMapping("/status") + public String wastecollectorsstatus(Model model) { + + return "modules/flagpolesregistration/status"; + } + + // old payment form + // @GetMapping("/paymentform") + // public String paymentform(@RequestParam("requestId") String requestId, Model + // model) { + + // boolean isFinal = requestService.existsInFinal(requestId); + + // List> list = isFinal + // ? requestService.getFinalDetailsByRefId(requestId) + // : requestService.getDetailsByRequestIdTemp(requestId); + + // if (list.isEmpty()) { + // model.addAttribute("message", "No details found"); + // return "modules/flagpolesregistration/nodatafound"; + // } + + // Map data = list.get(0); + // model.addAttribute("requestData", data); + + // List> streetList = isFinal + // ? requestService.getFinalStreetDetails(requestId) + // : requestService.getTempStreetDetails(requestId); + + // model.addAttribute("streetList", streetList); + + // String bookingStatus = (String) data.get("booking_payment_status"); + // String fineStatus = (String) data.get("fine_payment_status"); + // String restorationStatus = (String) data.get("restoration_payment_status"); + + // boolean bookingPaid = "PAID".equalsIgnoreCase(bookingStatus) + // || "COMPLETED".equalsIgnoreCase(bookingStatus); + + // /* BOOKING PAYMENT */ + // if (!bookingPaid) { + + // model.addAttribute("paymentType", "FLAGPOLE BOOKING"); + // model.addAttribute("paymentDesc", "Flagpole Booking Charges"); + // model.addAttribute("displayAmount", data.get("total_cost")); + + // return "modules/flagpolesregistration/paymentrequestform"; + // } + + // /* FINE PAYMENT */ + // if (fineStatus != null && "PENDING".equalsIgnoreCase(fineStatus)) { + + // model.addAttribute("paymentType", "FLAGPOLE FINE"); + // model.addAttribute("paymentDesc", "Flagpole Fine Charges"); + // model.addAttribute("displayAmount", data.get("fine_amount")); + + // return "modules/flagpolesregistration/paymentrequestform"; + // } + + // /* RESTORATION PAYMENT */ + + // if (restorationStatus != null && + // "PENDING".equalsIgnoreCase(restorationStatus)) { + // model.addAttribute("paymentType", "FLAGPOLE RESTORATION"); + // model.addAttribute("paymentDesc", "Flagpole Restoration Charges"); + // model.addAttribute("displayAmount", data.get("restoration_amount")); + + // return "modules/flagpolesregistration/paymentrequestform"; + // } + // /* ACKNOWLEDGEMENT */ + // if (fineStatus != null) { + // model.addAttribute("paymentType", "FLAGPOLE FINE COLLECTION"); + // model.addAttribute("paymentDesc", "Flagpole Fine Charges"); + // } else if (restorationStatus != null) { + // model.addAttribute("paymentType", "FLAGPOLE RESTORATION COLLECTION"); + // model.addAttribute("paymentDesc", "Flagpole Restoration Charges"); + // } else { + // model.addAttribute("paymentType", "FLAGPOLE BOOKING "); + // model.addAttribute("paymentDesc", "Flagpole Booking Charges"); + // } + + // return "modules/flagpolesregistration/acknowledgement"; + // } + + // payment related api + + @GetMapping("/paymentform") + public String paymentform( + @RequestParam("requestId") String requestId, + @RequestParam(value = "type", required = false) String type, + Model model) { + + boolean isFinal = requestService.existsInFinal(requestId); + + List> list = isFinal + ? requestService.getFinalDetailsByRefId(requestId) + : requestService.getDetailsByRequestIdTemp(requestId); + + if (list.isEmpty()) { + model.addAttribute("message", "No details found"); + return "modules/flagpolesregistration/nodatafound"; + } + + Map data = list.get(0); + model.addAttribute("requestData", data); + + List> streetList = isFinal + ? requestService.getFinalStreetDetails(requestId) + : requestService.getTempStreetDetails(requestId); + model.addAttribute("streetList", streetList); + + String bookingStatus = (String) data.get("booking_payment_status"); + String fineStatus = (String) data.get("fine_payment_status"); + String restorationStatus = (String) data.get("restoration_payment_status"); + + boolean bookingPaid = "PAID".equalsIgnoreCase(bookingStatus) + || "COMPLETED".equalsIgnoreCase(bookingStatus); + + boolean fineApplicable = fineStatus != null; + boolean finePaid = fineApplicable && + ("PAID".equalsIgnoreCase(fineStatus) || "COMPLETED".equalsIgnoreCase(fineStatus)); + + boolean restorationApplicable = restorationStatus != null; + boolean restorationPaid = restorationApplicable && + ("PAID".equalsIgnoreCase(restorationStatus) || "COMPLETED".equalsIgnoreCase(restorationStatus)); + + /* ================= ACKNOWLEDGEMENT MODE ================= */ + + if (type != null) { + + String paymentTypeKey = type.toUpperCase(); + Map payment = null; + + switch (paymentTypeKey) { + + case "BOOKING": + if (!bookingPaid) { + model.addAttribute("message", "Booking payment not completed"); + return "modules/flagpolesregistration/nodatafound"; + } + + payment = requestService.getPaymentByRefIdAndType(requestId, "BOOKING"); + + model.addAttribute("paymentType", "FLAGPOLE BOOKING"); + model.addAttribute("paymentDesc", "Flagpole Booking Charges"); + model.addAttribute("displayAmount", data.get("total_cost")); + break; + + case "FINE": + if (!fineApplicable) { + model.addAttribute("message", "Fine is not applicable for this request"); + return "modules/flagpolesregistration/nodatafound"; + } + if (!finePaid) { + model.addAttribute("message", "Fine payment not completed"); + return "modules/flagpolesregistration/nodatafound"; + } + + payment = requestService.getPaymentByRefIdAndType(requestId, "FINE"); + + model.addAttribute("paymentType", "FLAGPOLE FINE COLLECTION"); + model.addAttribute("paymentDesc", "Flagpole Fine Charges"); + model.addAttribute("displayAmount", data.get("fine_amount")); + break; + + case "RESTORATION": + if (!restorationApplicable) { + model.addAttribute("message", "Restoration is not applicable for this request"); + return "modules/flagpolesregistration/nodatafound"; + } + if (!restorationPaid) { + model.addAttribute("message", "Restoration payment not completed"); + return "modules/flagpolesregistration/nodatafound"; + } + + payment = requestService.getPaymentByRefIdAndType(requestId, "RESTORATION"); + + model.addAttribute("paymentType", "FLAGPOLE RESTORATION COLLECTION"); + model.addAttribute("paymentDesc", "Flagpole Restoration Charges"); + model.addAttribute("displayAmount", data.get("restoration_amount")); + break; + + default: + model.addAttribute("message", "Invalid payment type"); + return "modules/flagpolesregistration/nodatafound"; + } + + // ✅ Final safety check + if (payment == null) { + model.addAttribute("message", "Payment record not found"); + return "modules/flagpolesregistration/nodatafound"; + } + + model.addAttribute("payment", payment); + return "modules/flagpolesregistration/acknowledgement"; + } + + /* ================= PAYMENT FLOW ================= */ + + if (!bookingPaid) { + model.addAttribute("paymentType", "FLAGPOLE BOOKING"); + model.addAttribute("paymentDesc", "Flagpole Booking Charges"); + model.addAttribute("displayAmount", data.get("total_cost")); + return "modules/flagpolesregistration/paymentrequestform"; + } + + if (fineApplicable && "PENDING".equalsIgnoreCase(fineStatus)) { + model.addAttribute("paymentType", "FLAGPOLE FINE"); + model.addAttribute("paymentDesc", "Flagpole Fine Charges"); + model.addAttribute("displayAmount", data.get("fine_amount")); + return "modules/flagpolesregistration/paymentrequestform"; + } + + if (restorationApplicable && "PENDING".equalsIgnoreCase(restorationStatus)) { + model.addAttribute("paymentType", "FLAGPOLE RESTORATION"); + model.addAttribute("paymentDesc", "Flagpole Restoration Charges"); + model.addAttribute("displayAmount", data.get("restoration_amount")); + return "modules/flagpolesregistration/paymentrequestform"; + } + + model.addAttribute("message", "No pending payments"); + return "modules/flagpolesregistration/nodatafound"; + } + +} diff --git a/src/main/java/com/gcc/flagpoles/controller/RefundController.java b/src/main/java/com/gcc/flagpoles/controller/RefundController.java new file mode 100644 index 0000000..677244a --- /dev/null +++ b/src/main/java/com/gcc/flagpoles/controller/RefundController.java @@ -0,0 +1,179 @@ +package com.gcc.flagpoles.controller; + +import com.gcc.flagpoles.constants.AppConstants; +import com.gcc.flagpoles.service.BookingService; +import com.gcc.flagpoles.service.RefundService; +import com.razorpay.RazorpayClient; +import com.razorpay.RazorpayException; +import com.razorpay.Refund; +import org.json.JSONObject; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.dao.EmptyResultDataAccessException; +import org.springframework.http.ResponseEntity; +import org.springframework.jdbc.core.JdbcTemplate; +import org.springframework.transaction.annotation.Transactional; +import org.springframework.web.bind.annotation.*; + +import java.time.Instant; +import java.time.LocalDate; +import java.time.LocalDateTime; +import java.time.ZoneId; +import java.util.*; + +@RestController +@RequestMapping("/flagpolesregistration/book/api") +public class RefundController { + + @Autowired + private RefundService refundService; + // @Autowired + // private RefundScheduler refundScheduler; + + @Autowired + BookingService bookingService; + + @Autowired + JdbcTemplate jdbcTemplate; + + @PostMapping("/initiateRefund") + public ResponseEntity initiateRefund( + @RequestParam("refId") String refId, + @RequestParam(value = "reason", defaultValue = "Event cancelled by user") String reason) { + + try { + // 1️⃣ Fetch booking + payment data + Map booking = refundService.getBookingForRefund(refId); + System.out.println("Booking: " + booking); + + // 2️⃣ Validate eligibility + refundService.validateRefundEligibility(booking); + + // 3️⃣ Razorpay refund + Refund refund = refundService.initiateRazorpayRefund( + (String) booking.get("payment_id"), + ((Number) booking.get("amount")).doubleValue()); + System.out.println("Refund: " + refund); + + // 4️⃣ Extract refund amount + double refundAmount = refund.get("amount") != null + ? ((Number) refund.get("amount")).doubleValue() / 100 + : ((Number) booking.get("amount")).doubleValue(); + + System.out.println("Refund Amount: " + refundAmount); + // 5️⃣ Finalize refund ✅ FIXED + refundService.finalizeRefund( + refId, + ((Number) booking.get("booking_id")).intValue(), + ((Number) booking.get("payment_db_id")).intValue(), + (String) booking.get("order_id"), + refundAmount, + refund.get("id").toString(), + refund.get("status").toString(), + reason); + + return ResponseEntity.ok(Map.of( + "status", "REFUND_INITIATED", + "refund_id", refund.get("id").toString(), + "refund_status", refund.get("status").toString())); + + } catch (IllegalStateException e) { + return ResponseEntity.badRequest().body(e.getMessage()); + } catch (RazorpayException e) { + return ResponseEntity.status(500) + .body("Razorpay Error: " + e.getMessage()); + } catch (Exception e) { + return ResponseEntity.status(500) + .body("Refund Failed: " + e.getMessage()); + } + } + + // @PostMapping("/initiateRefund") + // public ResponseEntity initiateRefund( + // @RequestParam("orderId") String orderId, + // @RequestParam("bookingId") int bookingId, + // @RequestParam(value = "reason", defaultValue = "Manual refund") String + // reason) { + // try { + // // Step 1: Get payment ID and amount using orderId + // String sql = "SELECT id, payment_id, amount FROM payment WHERE order_id = ?"; + // Map result = jdbcTemplate.queryForMap(sql, orderId); + + // int pid = (int) result.get("id"); + // String paymentId = (String) result.get("payment_id"); + // double amount = Double.parseDouble(result.get("amount").toString()); + + // // Step 2: Initiate refund via Razorpay + // RazorpayClient razorpayClient = new RazorpayClient(AppConstants.key_id, + // AppConstants.key_secret); + // JSONObject refundRequest = new JSONObject(); + // refundRequest.put("amount", (int) (amount * 100)); // Razorpay expects paise + + // Refund refund = razorpayClient.payments.refund(paymentId, refundRequest); + + // // Step 3: Extract refund response details + // String refundId = refund.get("id"); + // String refundStatus = refund.get("status"); + // double refundAmount = Double.parseDouble(refund.get("amount").toString()) / + // 100.0; + + // Object createdAtObj = refund.get("created_at"); + // long createdAtEpoch; + // if (createdAtObj instanceof Number) { + // createdAtEpoch = ((Number) createdAtObj).longValue(); + // } else if (createdAtObj instanceof Date) { + // createdAtEpoch = ((Date) createdAtObj).toInstant().getEpochSecond(); + // } else { + // throw new IllegalArgumentException("Unexpected type for created_at: " + + // createdAtObj.getClass()); + // } + + // LocalDateTime createdAt = Instant.ofEpochSecond(createdAtEpoch) + // .atZone(ZoneId.of("Asia/Kolkata")) + // .toLocalDateTime(); + + // // Step 4: Save refund record + // refundService.saveRefund(bookingId, pid, refundAmount, refundId, + // refundStatus, reason); + + // // Step 5: Update status in payment and order_log tables + // // jdbcTemplate.update("UPDATE order_log SET order_status = ? WHERE order_id + // = + // // ?", "" orderId); + // jdbcTemplate.update("UPDATE payment SET payment_status = ? WHERE order_id = + // ?", "refunded", orderId); + + // // Step 6: Print refund info to console + // System.out.println("✅ Refund initiated successfully:"); + // System.out.println("Refund ID : " + refundId); + // System.out.println("Payment ID : " + paymentId); + // System.out.println("Refund Amount : ₹" + refundAmount); + // System.out.println("Refund Status : " + refundStatus); + // System.out.println("Refunded At : " + createdAt); + // System.out.println("📝 payment tables updated to 'refund'."); + + // // Step 7: Return response + // Map responseMap = new HashMap<>(); + // responseMap.put("refund_id", refundId); + // responseMap.put("status", refundStatus); + // responseMap.put("amount", refundAmount); + // responseMap.put("created_at", createdAt.toString()); + + // return ResponseEntity.ok(responseMap); + + // } catch (RazorpayException e) { + // e.printStackTrace(); + // String errorMsg = e.getMessage(); + // System.err.println("Razorpay Error: " + errorMsg); + + // if (errorMsg.contains("already")) { + // return ResponseEntity.status(400).body("Refund already completed for this + // payment."); + // } + // return ResponseEntity.status(500).body("Razorpay Error: " + e.getMessage()); + // } catch (Exception e) { + // e.printStackTrace(); + // return ResponseEntity.status(500).body("Error: " + e.getMessage()); + // } + // } + +} diff --git a/src/main/java/com/gcc/flagpoles/service/BookingService.java b/src/main/java/com/gcc/flagpoles/service/BookingService.java new file mode 100644 index 0000000..29fb81a --- /dev/null +++ b/src/main/java/com/gcc/flagpoles/service/BookingService.java @@ -0,0 +1,19 @@ +package com.gcc.flagpoles.service; + +import java.util.Map; + +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.jdbc.core.JdbcTemplate; +import org.springframework.stereotype.Service; + +@Service +public class BookingService { + @Autowired + private JdbcTemplate jdbcTemplate; + + public Map getTempBookingByTempId(int tempbookid) { + String sql = "SELECT * FROM temp_request_details where tempbookid = ?"; + return jdbcTemplate.queryForMap(sql, tempbookid); + } + +} diff --git a/src/main/java/com/gcc/flagpoles/service/DropDownService.java b/src/main/java/com/gcc/flagpoles/service/DropDownService.java new file mode 100644 index 0000000..2a9aaeb --- /dev/null +++ b/src/main/java/com/gcc/flagpoles/service/DropDownService.java @@ -0,0 +1,183 @@ +package com.gcc.flagpoles.service; + +import java.net.URI; +import java.net.URLEncoder; +import java.nio.charset.StandardCharsets; +import java.util.HashMap; +import java.util.LinkedHashMap; +import java.util.List; +import java.util.Map; + +import org.json.JSONObject; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.http.ResponseEntity; +import org.springframework.jdbc.core.JdbcTemplate; +import org.springframework.stereotype.Service; +import org.springframework.web.client.RestTemplate; +import org.springframework.web.util.UriComponentsBuilder; +import org.springframework.web.util.UriUtils; + +import com.fasterxml.jackson.databind.JsonNode; +import com.fasterxml.jackson.databind.ObjectMapper; + +@Service +public class DropDownService { + + @Autowired + private JdbcTemplate jdbcTemplate; + + // @Autowired + // private RestTemplate restTemplate; + + // @Autowired + // private AppConfig appConfig; + + private final RestTemplate restTemplate = new RestTemplate(); + private final ObjectMapper objectMapper = new ObjectMapper(); + + private static final String STREET_API = "https://gccservices.in/gccrestservices/api/location/getDetails?address="; + + public List> getPoleMaterialList() { + String sql = " SELECT * FROM pole_material where is_active = '1' "; + return jdbcTemplate.queryForList(sql); + } + + public List> getEventTypes() { + String sql = " SELECT * FROM event_type where is_active = '1' "; + return jdbcTemplate.queryForList(sql); + } + + public List> getFlagMaterialList() { + String sql = "SELECT * FROM flag_material where is_active = '1' "; + return jdbcTemplate.queryForList(sql); + } + + public Map getZoneAndWardByStreet(String streetName) { + Map responseMap = new LinkedHashMap<>(); + RestTemplate restTemplate = new RestTemplate(); + + try { + if (streetName == null || streetName.trim().isEmpty()) { + responseMap.put("status", "error"); + responseMap.put("message", "Street name is required."); + return responseMap; + } + + // Step 1️⃣: Get latitude & longitude + String encodedStreet = URLEncoder.encode(streetName.trim(), StandardCharsets.UTF_8); + String url1 = STREET_API + encodedStreet; + + ResponseEntity response1 = restTemplate.getForEntity(url1, String.class); + JSONObject json1 = new JSONObject(response1.getBody()); + System.out.println("Response from STREET_API: " + json1); + + String latitude = json1.optString("latitude", ""); + String longitude = json1.optString("longitude", ""); + + if (latitude.isEmpty() || longitude.isEmpty()) { + responseMap.put("status", "error"); + responseMap.put("message", "Latitude/Longitude not found for this street."); + return responseMap; + } + + // Step 2️⃣: Encode geometry safely + String geometryJson = String.format("{\"y\":%s,\"x\":%s}", latitude, longitude); + String encodedGeometry = URLEncoder.encode(geometryJson, StandardCharsets.UTF_8); + + String url2 = "https://gisgcc.chennaicorporation.gov.in/server/rest/services/GCCDepts/EDPMobile2025/FeatureServer/2/query" + + + "?where=&objectIds=&time=&geometry=" + encodedGeometry + + "&geometryType=esriGeometryPoint" + + "&inSR=4326" + + "&defaultSR=4326" + + "&spatialRel=esriSpatialRelIntersects" + + "&distance=1" + + "&units=esriSRUnit_Meter" + + "&relationParam=&outFields=zone,ward" + + "&returnGeometry=false" + + "&returnDistinctValues=false" + + "&returnIdsOnly=false" + + "&returnCountOnly=false" + + "&returnExtentOnly=false" + + "&orderByFields=&groupByFieldsForStatistics=&outStatistics=" + + "&returnZ=false&returnM=false" + + "&multipatchOption=xyFootprint" + + "&resultOffset=&resultRecordCount=" + + "&returnTrueCurves=false" + + "&returnExceededLimitFeatures=false" + + "&quantizationParameters=&returnCentroid=false" + + "&timeReferenceUnknownClient=false" + + "&maxRecordCountFactor=&sqlFormat=none" + + "&resultType=&featureEncoding=esriDefault" + + "&datumTransformation=&f=geojson"; + + System.out.println("Fetching Zone/Ward with URL: " + url2); + + // ✅ Use URI to avoid template parsing issues + ResponseEntity response2 = restTemplate.getForEntity(new URI(url2), String.class); + System.out.println("Response from ZONE_WARD_API: " + response2.getBody()); + + JSONObject json2 = new JSONObject(response2.getBody()); + if (!json2.has("features") || json2.getJSONArray("features").isEmpty()) { + responseMap.put("status", "error"); + responseMap.put("message", "Zone/Ward not found for this location."); + return responseMap; + } + + JSONObject properties = json2.getJSONArray("features") + .getJSONObject(0) + .getJSONObject("properties"); + + String zone = properties.optString("zone", "N/A"); + String ward = properties.optString("ward", "N/A"); + + // ✅ Success + responseMap.put("status", "success"); + responseMap.put("streetName", streetName); + responseMap.put("latitude", latitude); + responseMap.put("longitude", longitude); + responseMap.put("zone", zone); + responseMap.put("ward", ward); + + } catch (Exception e) { + e.printStackTrace(); + responseMap.put("status", "error"); + responseMap.put("message", "Failed to fetch data: Internal server error."); + } + + return responseMap; + } + + public List> getAllcharges() { + String sql = "SELECT * FROM waste_collection_charges where is_active = 1 "; + return jdbcTemplate.queryForList(sql); + } + + // public Map fetchZones() throws Exception { + // String apiUrl = appConfig.getErpUrl() + "serviceId=getZones"; + // ResponseEntity response = restTemplate.getForEntity(apiUrl, + // String.class); + // return objectMapper.readValue(response.getBody(), Map.class); + // } + + // public Map fetchWardsByZoneId(String zoneId) throws Exception + // { + // String apiUrl = appConfig.getErpUrl() + "serviceId=getWards&Zoneid=" + + // zoneId; + // ResponseEntity response = restTemplate.getForEntity(apiUrl, + // String.class); + // return objectMapper.readValue(response.getBody(), Map.class); + // } + + // get zones + public List> getZonesList() { + String sql = " SELECT id,zone_name from zones where is_active = 1 "; + return jdbcTemplate.queryForList(sql); + } + + // get wardsby zone id + public List> getWardsByZoneId(int zoneId) { + String sql = "SELECT id, ward_name FROM wards WHERE zone_id = ? AND is_active = 1 "; + return jdbcTemplate.queryForList(sql, zoneId); + } +} diff --git a/src/main/java/com/gcc/flagpoles/service/PaymentService.java b/src/main/java/com/gcc/flagpoles/service/PaymentService.java new file mode 100644 index 0000000..866ee4d --- /dev/null +++ b/src/main/java/com/gcc/flagpoles/service/PaymentService.java @@ -0,0 +1,154 @@ +package com.gcc.flagpoles.service; + +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.dao.DataAccessException; +import org.springframework.jdbc.core.JdbcTemplate; +import org.springframework.jdbc.core.PreparedStatementCreator; +import org.springframework.jdbc.support.GeneratedKeyHolder; +import org.springframework.jdbc.support.KeyHolder; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; +import org.springframework.ui.Model; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.RequestParam; + +import java.sql.Connection; +import java.sql.PreparedStatement; +import java.sql.SQLException; +import java.time.LocalDateTime; +import java.util.List; +import java.util.Map; + +@Service +public class PaymentService { + + @Autowired + private JdbcTemplate jdbcTemplate; + + @Autowired + private RequestService requestService; + + @Autowired + private WhatsappMessageService whatsappMessageService; + + @Transactional + public int saveorderLog( + + String order_id, + String order_info, + String ref_id) { + + int lastInsertId = 0; + + String sqlQuery = "INSERT INTO `order_log`(`order_id`, `order_info`, `ref_id`) " + + "VALUES (?,?,?)"; + + KeyHolder keyHolder = new GeneratedKeyHolder(); + + try { + int affectedRows = jdbcTemplate.update(new PreparedStatementCreator() { + @Override + public PreparedStatement createPreparedStatement(Connection connection) throws SQLException { + PreparedStatement ps = connection.prepareStatement(sqlQuery, new String[] { "id" }); + ps.setString(1, order_id); + ps.setString(2, order_info); + ps.setString(3, ref_id); + + return ps; + } + }, keyHolder); + + if (affectedRows > 0) { + Number generatedId = keyHolder.getKey(); + lastInsertId = (generatedId != null) ? generatedId.intValue() : 0; + return lastInsertId; + } else { + System.out.println("Error on temp save!"); + } + } catch (DataAccessException e) { + System.out.println("Data Access Exception:"); + Throwable rootCause = e.getMostSpecificCause(); + if (rootCause instanceof SQLException) { + SQLException sqlException = (SQLException) rootCause; + System.out.println("SQL State: " + sqlException.getSQLState()); + System.out.println("Error Code: " + sqlException.getErrorCode()); + System.out.println("Message: " + sqlException.getMessage()); + } else { + System.out.println("Message: " + rootCause.getMessage()); + } + } + return 0; + } + + @Transactional + public int savePayment(String totalAmount, + String payment_id, + String payment_orderid, + String payment_status, + String refId, + String mobile_no, + String paymentType) { + + int lastInsertId = 0; + + String sqlQuery = "INSERT INTO `payment`(`amount`, `mobile_no`, `order_id`, `payment_id`, `paymentstatus`, `payment_date`, `ref_id`, `payment_type`) " + + "VALUES (?,?,?,?,?,?,?,?)"; + + KeyHolder keyHolder = new GeneratedKeyHolder(); + + try { + int affectedRows = jdbcTemplate.update(new PreparedStatementCreator() { + @Override + public PreparedStatement createPreparedStatement(Connection connection) throws SQLException { + PreparedStatement ps = connection.prepareStatement(sqlQuery, new String[] { "id" }); + ps.setString(1, totalAmount); + ps.setString(2, mobile_no); + ps.setString(3, payment_orderid); + ps.setString(4, payment_id); + ps.setString(5, payment_status); + ps.setString(6, LocalDateTime.now().toString()); + ps.setString(7, refId); + ps.setString(8, paymentType); + + return ps; + } + }, keyHolder); + + if (affectedRows > 0) { + Number generatedId = keyHolder.getKey(); + lastInsertId = (generatedId != null) ? generatedId.intValue() : 0; + + String mobileNumber = mobile_no; + double actualWeight = 100; + double totalCharge = Integer.parseInt(totalAmount); + + if ("paid".equalsIgnoreCase(payment_status)) { + requestService.updatePaymentStatus(refId); + requestService.updatePaymentStatusInOrderLog(refId, payment_orderid); + // whatsappMessageService.sendrequestraisedWhatsappMessage(refId, mobileNumber); + // whatsappMessageService.sendPaymentCompleteWhatsappMessage(refId, + // actualWeight, totalCharge, mobileNumber); + + } + + return lastInsertId; + } else { + System.out.println("Error on temp save!"); + return 0; + } + } catch (DataAccessException e) { + System.out.println("Data Access Exception:"); + Throwable rootCause = e.getMostSpecificCause(); + if (rootCause instanceof SQLException) { + SQLException sqlException = (SQLException) rootCause; + System.out.println("SQL State: " + sqlException.getSQLState()); + System.out.println("Error Code: " + sqlException.getErrorCode()); + System.out.println("Message: " + sqlException.getMessage()); + } else { + System.out.println("Message: " + rootCause.getMessage()); + } + return 0; + } + } + +} diff --git a/src/main/java/com/gcc/flagpoles/service/RefundService.java b/src/main/java/com/gcc/flagpoles/service/RefundService.java new file mode 100644 index 0000000..ee4959c --- /dev/null +++ b/src/main/java/com/gcc/flagpoles/service/RefundService.java @@ -0,0 +1,323 @@ +package com.gcc.flagpoles.service; + +import java.sql.Connection; +import java.sql.PreparedStatement; +import java.sql.SQLException; +import java.time.LocalDateTime; +import java.sql.Timestamp; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +import com.gcc.flagpoles.constants.AppConstants; +import com.razorpay.RazorpayClient; +import com.razorpay.RazorpayException; +import com.razorpay.Refund; + +import org.json.JSONObject; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.dao.DataAccessException; +import org.springframework.dao.EmptyResultDataAccessException; +import org.springframework.http.ResponseEntity; +import org.springframework.jdbc.core.JdbcTemplate; +import org.springframework.jdbc.core.PreparedStatementCreator; +import org.springframework.jdbc.support.GeneratedKeyHolder; +import org.springframework.jdbc.support.KeyHolder; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; + +@Service +public class RefundService { + + @Autowired + PaymentService paymentService; + + @Autowired + BookingService bookingService; + + @Autowired + private JdbcTemplate jdbcTemplate; + + public List> refund(int refund_id) { + String refundsql = "select * from refund_info where refund_id=?"; + + return jdbcTemplate.queryForList(refundsql.toString(), refund_id); + + } + + public Map getBookingForRefund(String refId) { + + List> list = jdbcTemplate.queryForList(""" + SELECT + urd.id AS booking_id, + urd.refid, + urd.event_date, + urd.payment_status, + + p.id AS payment_db_id, + p.payment_id, + p.order_id, + p.amount, + p.paymentstatus + + FROM user_request_details urd + JOIN payment p ON p.ref_id = urd.refid + WHERE urd.refid = ? + AND p.paymentstatus IN ('paid', 'PAID', 'COMPLETED') + """, refId); + + if (list.isEmpty()) { + throw new IllegalStateException( + "No eligible payment found for refund for refId: " + refId); + } + + return list.get(0); + } + + public void validateRefundEligibility(Map booking) { + + Object eventDateObj = booking.get("event_date"); + LocalDateTime eventDate; + + if (eventDateObj instanceof LocalDateTime) { + eventDate = (LocalDateTime) eventDateObj; + } else if (eventDateObj instanceof Timestamp) { + eventDate = ((Timestamp) eventDateObj).toLocalDateTime(); + } else { + throw new IllegalStateException("Invalid event_date type: " + eventDateObj); + } + + String bookingPaymentStatus = (String) booking.get("payment_status"); + + if (!"COMPLETED".equalsIgnoreCase(bookingPaymentStatus)) { + throw new IllegalStateException("Payment not completed"); + } + + String paymentTableStatus = (String) booking.get("paymentstatus"); + + if ("refunded".equalsIgnoreCase(paymentTableStatus)) { + throw new IllegalStateException("Refund already processed"); + } + + if (LocalDateTime.now().isAfter(eventDate.minusHours(24))) { + throw new IllegalStateException("Refund not allowed within 24 hours of event"); + } + } + + public Refund initiateRazorpayRefund( + String paymentId, + double amount) throws RazorpayException { + + RazorpayClient razorpayClient = new RazorpayClient(AppConstants.key_id, AppConstants.key_secret); + + JSONObject refundRequest = new JSONObject(); + refundRequest.put("amount", (int) (amount * 100)); // paise + + return razorpayClient.payments.refund(paymentId, refundRequest); + } + + @Transactional + public void finalizeRefund( + String refId, + int bookingId, + int paymentDbId, + String orderId, + double refundAmount, + String refundId, + String refundStatus, + String reason) { + + // 1️⃣ Save refund record (USING EXISTING METHOD) + saveRefund( + bookingId, // ✅ correct + paymentDbId, // pid + refundAmount, + refundId, + refundStatus, + reason); + + // 2️⃣ Update payment table + jdbcTemplate.update(""" + UPDATE payment + SET paymentstatus = 'refunded' + WHERE order_id = ? + """, orderId); + + // 3️⃣ Update booking status + jdbcTemplate.update(""" + UPDATE user_request_details + SET booking_status = 'CANCELLED' + WHERE refid = ? + """, refId); + } + + public int saveRefund(int bookingId, int pid, double refundAmount, String refundId, String refundStatus, + String desc) { + + List> result = null; + Map response = new HashMap<>(); + int calendarId = 0; + + String sqlQuery = "INSERT INTO refund_info (bookingId, refund_amt, balance_amt, pid, refund_id, cdate, refund_status, r_desc) " + + "VALUES (?, ?, ?, ?, ?, ?, ?, ?)"; + + KeyHolder keyHolder = new GeneratedKeyHolder(); + + System.out.println("Inserting Refund Info:"); + System.out.println(" bookingId = " + bookingId); + System.out.println(" refundAmount = " + refundAmount); + System.out.println(" pid = " + pid); + System.out.println(" refundId = " + refundId); + System.out.println(" refundStatus = " + refundStatus); + System.out.println(" desc = " + desc); + + try { + int affectedRows = jdbcTemplate.update(new PreparedStatementCreator() { + @Override + public PreparedStatement createPreparedStatement(Connection connection) + throws SQLException { + PreparedStatement ps = connection.prepareStatement(sqlQuery, new String[] { "id" }); + ps.setInt(1, bookingId); // Fix: Use setInt for bookingId + ps.setDouble(2, refundAmount); // Fix: Use setDouble for refund_amt + ps.setDouble(3, 0.0); // Fix: Add balance_amt (defaulting to 0) + ps.setInt(4, pid); // Fix: Use setInt for pid + ps.setString(5, refundId); + ps.setString(6, refundStatus); + ps.setString(7, desc); + + return ps; + } + }, keyHolder); + + if (affectedRows > 0) { + Number generatedId = keyHolder.getKey(); + calendarId = (generatedId != null) ? generatedId.intValue() : 0; + return calendarId; + } else { + return 10; + } + } catch (DataAccessException e) { + System.out.println("Data Access Exception:"); + Throwable rootCause = e.getMostSpecificCause(); + if (rootCause instanceof SQLException) { + SQLException sqlException = (SQLException) rootCause; + System.out.println("SQL State: " + sqlException.getSQLState()); + System.out.println("Error Code: " + sqlException.getErrorCode()); + System.out.println("Message: " + sqlException.getMessage()); + return 0; + } else { + System.out.println("Message: " + rootCause.getMessage()); + return 0; + } + } + + } + + // public ResponseEntity refundProcessOrder(String msg, int bookingId, int + // pid) { + // try { + // Map pay = paymentService.getPaymentById(pid); + // if (pay == null || pay.isEmpty()) { + // return ResponseEntity.badRequest().body("No payment found for given id"); + // } + + // String paymentId = pay.get("payment_id").toString(); + // double amount = Double.parseDouble(pay.get("amount") + ""); + + // RazorpayClient razorpay = new RazorpayClient(AppConstants.key_id, + // AppConstants.key_secret); + + // JSONObject refundRequest = new JSONObject(); + // refundRequest.put("amount", amount * 100); + // refundRequest.put("speed", "normal"); + + // JSONObject notes = new JSONObject(); + // notes.put("notes_key_1", msg); + // refundRequest.put("notes", notes); + + // com.razorpay.Refund payment = razorpay.payments.refund(paymentId, + // refundRequest); + // JSONObject pj = payment.toJson(); + // //new update + // System.err.println("Refund Process Order:line 216"); + // System.err.println(pj); + // System.err.println("refundProcessOrder->"+pj.get("id")+"bookingId:-"+bookingId + // +"pid:-"+pid); + // if (pj.get("id") != null) { + // double amt = (pj.get("amount") != null) ? + // (Double.parseDouble(pj.get("amount") + "") / 100) : 0; + // saveRefundOrder(bookingId, pid, amt, pj.get("id").toString(), + // "REFUND_PROCESSED", pj.toString()); + // if(bookingId != 0) { + // bookingService.updateBookingStatus(bookingId, "refunded"); + // } + // } else { + // saveRefundOrder(bookingId, pid, 0, "", "REJECTED", pj.toString()); + // } + + // return ResponseEntity.ok(pj.toString()); + + // } catch (RazorpayException e) { + + // if (e.getMessage().contains("fully refunded")) { + // System.err.println("Already refunded: " + e.getMessage()); + // saveRefundOrder(bookingId, pid, 0, "", "ALREADY_REFUNDED", e.getMessage()); + // if(bookingId != 0) { + // bookingService.updateBookingStatus(bookingId, "refunded"); + // } + // return ResponseEntity.ok("Already refunded"); + // } + // return ResponseEntity.status(500).body("Refund failed: " + e.getMessage()); + // } + // } + + // public int saveRefundOrder(int bookingId, int pid, double refundAmount, + // String refundId, String refundStatus, String desc) { + // try { + // updateRefundStatusInOrderLog(pid, true); + // // Insert new refund record + // String sqlQuery = "INSERT INTO refund_info (bookingId, refund_amt, + // balance_amt, pid, refund_id, refund_status, r_desc) VALUES (?, ?, ?, ?, ?, ?, + // ?)"; + // KeyHolder keyHolder = new GeneratedKeyHolder(); + + // int affectedRows = jdbcTemplate.update(connection -> { + // PreparedStatement ps = connection.prepareStatement(sqlQuery, new + // String[]{"id"}); + // ps.setInt(1, bookingId); + // ps.setDouble(2, refundAmount); + // ps.setDouble(3, 0.0); + // ps.setInt(4, pid); + // ps.setString(5, refundId); + // ps.setString(6, refundStatus); + // ps.setString(7, desc != null ? desc : ""); + // return ps; + // }, keyHolder); + + // if (affectedRows > 0) { + // Number generatedId = keyHolder.getKey(); + // return (generatedId != null) ? generatedId.intValue() : -1; + // } else { + // return -1; // Indicate failure + // } + + // } catch (EmptyResultDataAccessException e) { + // System.err.println("No existing refund record found, proceeding with + // insert."); + // } catch (DataAccessException e) { + // System.err.println("saveRefundOrder Database error: " + e.getMessage()); + // } + + // return -1; + // } + + // public void updateRefundStatusInOrderLog(int pid, boolean + // isRefundedProcessed) { + + // String sql = "UPDATE order_log od inner join payment pay on od.order_id = + // pay.order_id SET od.sch_refund_status = ? WHERE pay.id = ?"; + + // jdbcTemplate.update(sql, isRefundedProcessed, pid); + // } + +} \ No newline at end of file diff --git a/src/main/java/com/gcc/flagpoles/service/RequestService.java b/src/main/java/com/gcc/flagpoles/service/RequestService.java new file mode 100644 index 0000000..46f4194 --- /dev/null +++ b/src/main/java/com/gcc/flagpoles/service/RequestService.java @@ -0,0 +1,1337 @@ +package com.gcc.flagpoles.service; + +import java.sql.PreparedStatement; +import java.sql.Statement; +import java.sql.Timestamp; +import java.time.LocalDate; +import java.time.LocalDateTime; +import java.time.format.DateTimeFormatter; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.LinkedHashMap; +import java.util.List; +import java.util.Map; + +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.jdbc.core.JdbcTemplate; +import org.springframework.jdbc.support.GeneratedKeyHolder; +import org.springframework.jdbc.support.KeyHolder; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; +import org.springframework.util.MultiValueMap; + +@Service +public class RequestService { + + @Autowired + private JdbcTemplate jdbcTemplate; + + @Autowired + private SMSService smsService; + + // // Helper: extract days from first street + private int getFirstStreetDays(List> streets) { + try { + return Integer.parseInt(streets.get(0).get("durationDays").toString()); + } catch (Exception e) { + return 0; + } + } + + @Transactional + public String saveFlagPoleRequest( + Map applicant, + Map event, + List> streets) { + + // Extract first street coordinates + double latitude = Double.parseDouble(streets.get(0).get("lat").toString()); + double longitude = Double.parseDouble(streets.get(0).get("long").toString()); + + String paymentstatus = "PENDING"; + // Check for nearby existing requests + // if (isRequestNearby(latitude, longitude)) { + // throw new IllegalArgumentException("A request already exists within 3 meters + // of this location."); + // } + + // SQL for inserting request + String insertRequestSql = """ + INSERT INTO user_request_details + (applicant_name, mobile_number, applicant_address, + event_id, event_date, event_desc, no_of_days, + total_poles, total_cost,payment_status) + VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?,?) + """; + + KeyHolder keyHolder = new GeneratedKeyHolder(); + // Integer deposit = 50; // Default deposit + + // Insert into user_request_details + jdbcTemplate.update(connection -> { + PreparedStatement ps = connection.prepareStatement(insertRequestSql, Statement.RETURN_GENERATED_KEYS); + + ps.setString(1, applicant.get("name").toString()); + ps.setString(2, applicant.get("mobileNumber").toString()); + ps.setString(3, applicant.get("address").toString()); + ps.setInt(4, Integer.parseInt(event.get("type").toString())); + ps.setString(5, event.get("date").toString()); + ps.setString(6, event.get("description").toString()); + ps.setInt(7, getFirstStreetDays(streets)); + ps.setInt(8, Integer.parseInt(event.get("totalPoles").toString())); + // ps.setDouble(9, deposit); + ps.setDouble(9, Double.parseDouble(event.get("totalCost").toString())); + ps.setString(10, paymentstatus); + + return ps; + }, keyHolder); + + // Get generated primary key + int userReqId = keyHolder.getKey().intValue(); + + // ================================================ + // 🔥 Generate REF ID = yyyyMMdd + userReqId + // ================================================ + String prefix = LocalDate.now().format(DateTimeFormatter.ofPattern("yyyyMMdd")); + String refId = prefix + userReqId; + + // ================================================ + // 🔥 Update user_request_details with refId + // ================================================ + String updateRefSql = "UPDATE user_request_details SET refid = ? WHERE id = ?"; + jdbcTemplate.update(updateRefSql, refId, userReqId); + + // SQL for inserting street details (refid added) + String insertStreetSql = """ + INSERT INTO street_details + (street_name, latitude, longitude, zone, ward, + no_of_poles, height, pole_material_id, flag_material_id, + pole_space, no_of_days, street_cost, user_req_id, refid) + VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?) + """; + + // Insert each street record including refid + for (Map s : streets) { + jdbcTemplate.update(insertStreetSql, + s.get("streetName"), + s.get("lat"), + s.get("long"), + s.get("zoneId"), + s.get("wardId"), + s.get("noOfPoles"), + s.get("poleHeight"), + s.get("poleMaterial"), + s.get("flagMaterial"), + s.get("spacing"), + s.get("durationDays"), + s.get("ratePerPole"), + userReqId, + refId // 🔥 Insert same REF ID into street_details + ); + } + + return refId; // or return refId if required + } + + @Transactional + public String saveTempBooking( + Map applicant, + Map event, + List> streets) { + + // 1️⃣ Insert TEMP booking (without refid) + KeyHolder keyHolder = new GeneratedKeyHolder(); + + jdbcTemplate.update(con -> { + PreparedStatement ps = con.prepareStatement(""" + INSERT INTO temp_booking + ( + applicant_name, + mobile_number, + applicant_address, + event_id, + event_date, + event_desc, + no_of_days, + total_poles, + deposit, + total_cost, + payment_status, + booking_status, + is_active, + is_delete + ) + VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, 'PENDING', 'INITIATED', 1, 0) + """, Statement.RETURN_GENERATED_KEYS); + + ps.setString(1, applicant.get("name").toString()); + ps.setString(2, applicant.get("mobileNumber").toString()); + ps.setString(3, applicant.get("address").toString()); + ps.setInt(4, Integer.parseInt(event.get("type").toString())); + ps.setString(5, event.get("date").toString()); + ps.setString(6, event.get("description").toString()); + ps.setInt(7, getFirstStreetDays(streets)); + ps.setInt(8, Integer.parseInt(event.get("totalPoles").toString())); + ps.setDouble(9, 0.0); + ps.setDouble(10, Double.parseDouble(event.get("totalCost").toString())); + return ps; + }, keyHolder); + + int tempId = keyHolder.getKey().intValue(); + + // Generate TEMP refid like FINAL + String tempRefId = LocalDate.now().format(DateTimeFormatter.ofPattern("yyyyMMdd")) + tempId; + + // Update temp_booking with refid + jdbcTemplate.update(""" + UPDATE temp_booking + SET refid = ? + WHERE id = ? + """, tempRefId, tempId); + + // Insert TEMP street details + for (Map s : streets) { + jdbcTemplate.update(""" + INSERT INTO temp_street_details + ( + temp_refid, + street_name, + latitude, + longitude, + zone, + ward, + no_of_poles, + height, + pole_material_id, + flag_material_id, + pole_space, + no_of_days, + street_cost + ) + VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?) + """, + tempRefId, + s.get("streetName"), + s.get("lat"), + s.get("long"), + s.get("zoneId"), + s.get("wardId"), + s.get("noOfPoles"), + s.get("poleHeight"), + s.get("poleMaterial"), + s.get("flagMaterial"), + s.get("spacing"), + s.get("durationDays"), + s.get("ratePerPole")); + } + + return tempRefId; + } + + @Transactional + public String moveTempToFinal(String tempRefId) { + + // Insert into FINAL booking table ONLY IF PAYMENT COMPLETED + int inserted = jdbcTemplate.update(""" + INSERT INTO user_request_details + ( + applicant_name, + mobile_number, + applicant_address, + event_id, + event_date, + event_desc, + no_of_days, + total_poles, + deposit, + total_cost, + cdate, + payment_status, + booking_status + ) + SELECT + applicant_name, + mobile_number, + applicant_address, + event_id, + event_date, + event_desc, + no_of_days, + total_poles, + deposit, + total_cost, + NOW(), + 'COMPLETED', + booking_status + FROM temp_booking + WHERE refid = ? + AND payment_status = 'COMPLETED' + AND is_active = 1 + AND is_delete = 0 + """, tempRefId); + + if (inserted == 0) { + throw new IllegalStateException( + "Payment not completed or temp record not found for refId: " + tempRefId); + } + + Integer newId = jdbcTemplate.queryForObject( + "SELECT LAST_INSERT_ID()", Integer.class); + + String finalRefId = LocalDate.now().format(DateTimeFormatter.ofPattern("yyyyMMdd")) + newId; + + jdbcTemplate.update(""" + UPDATE user_request_details + SET refid = ? + WHERE id = ? + """, finalRefId, newId); + + // Insert streets + jdbcTemplate.update(""" + INSERT INTO street_details + ( + street_name, latitude, longitude, zone, ward, + no_of_poles, height, pole_material_id, flag_material_id, + pole_space, no_of_days, street_cost, user_req_id, refid + ) + SELECT + street_name, latitude, longitude, zone, ward, + no_of_poles, height, pole_material_id, flag_material_id, + pole_space, no_of_days, street_cost, ?, ? + FROM temp_street_details + WHERE temp_refid = ? + AND is_active = 1 + AND is_delete = 0 + """, newId, finalRefId, tempRefId); + + // Mark TEMP inactive + jdbcTemplate.update(""" + UPDATE temp_booking + SET is_active = 0, + is_delete = 1 + WHERE refid = ? + """, tempRefId); + + jdbcTemplate.update(""" + UPDATE temp_street_details + SET is_active = 0, + is_delete = 1 + WHERE temp_refid = ? + """, tempRefId); + + return finalRefId; + } + + @Transactional + public void updateFinePaymentStatus(String refId) { + + jdbcTemplate.update(""" + UPDATE fine_collection + SET payment_status = 'COMPLETED' + WHERE ref_id = ? + AND isactive = 1 + AND isdelete = 0 + """, refId); + } + + @Transactional + public void updateRestorationPaymentStatus(String refId) { + + jdbcTemplate.update(""" + UPDATE restoration + SET payment_status = 'COMPLETED' + WHERE ref_id = ? + AND is_active = 1 + AND is_delete = 0 + """, refId); + } + + @Transactional + public void updateTempPaymentStatus(String tempRefId, String status) { + + jdbcTemplate.update(""" + UPDATE temp_booking + SET payment_status = ? + WHERE refid = ? + AND is_active = 1 + AND is_delete = 0 + """, status, tempRefId); + } + + public List> getFineDetails(String refid) { + String sql = "select * from fine_collection where ref_id=?"; + return jdbcTemplate.queryForList(sql, refid); + } + + // public boolean isRequestNearby(double latitude, double longitude) { + // String sql = """ + // SELECT id + // FROM street_details + // WHERE (6371008.8 * acos( + // ROUND( + // cos(radians(?)) * cos(radians(latitude)) * + // cos(radians(longitude) - radians(?)) + + // sin(radians(?)) * sin(radians(latitude)), + // 9 + // ) + // )) < 3 + // """; + + // List existingIds = jdbcTemplate.query( + // sql, + // new Object[] { latitude, longitude, latitude }, + // (rs, rowNum) -> rs.getInt("id")); + + // return !existingIds.isEmpty(); + // } + + // old + // public List> getDetailsByRequestId(String requestId) { + + // String sql = """ + // SELECT + // ud.applicant_name, + // ud.mobile_number, + // ud.applicant_address, + // et.event_name, + + // ud.total_cost, + // ud.payment_status AS booking_payment_status, + + // fc.payment_status AS fine_payment_status, + // fc.fine_amount, + // rs.payment_status AS restoration_payment_status, + // rs.amount AS restoration_amount, + + // ud.refid, + + // DATE_FORMAT(ud.event_date,'%d-%m-%Y') AS event_date, + // DATE_FORMAT(ud.cdate,'%d-%m-%Y') AS cdate, + + // ud.total_poles, + // ud.no_of_days, + + // py.payment_id, + // py.paymentstatus, + // DATE_FORMAT(py.payment_date,'%d-%m-%Y') AS payment_date, + // py.amount AS payment_amount + + // FROM temp_booking ud + // LEFT JOIN event_type et + // ON et.id = ud.event_id + + // LEFT JOIN payment py + // ON py.ref_id = ud.refid + + // LEFT JOIN fine_collection fc + // ON fc.ref_id = ud.refid + // AND fc.isactive = 1 + // AND fc.isdelete = 0 + + // LEFT JOIN restoration rs + // ON rs.ref_id = ud.refid + // AND rs.is_active = 1 + // AND rs.is_delete = 0 + + // WHERE ud.refid = ? + // """; + + // return jdbcTemplate.queryForList(sql, requestId); + // } + + // public List> getStreetDetailsByRefId(String requestId) { + // String sql = " select sd.street_name,sd.zone,sd.ward " + + // " from temp_booking ud " + + // " left join temp_street_details sd on sd.temp_refid = ud.refid " + + // " where ud.refid = ? "; + // return jdbcTemplate.queryForList(sql, requestId); + // } + + public Map getPaymentByRefIdAndType(String refId, String type) { + + String sql = """ + SELECT + p.payment_id, + p.paymentstatus, + DATE_FORMAT(p.payment_date,'%d-%m-%Y') AS payment_date, + p.amount, + p.payment_type + FROM payment p + WHERE p.ref_id = ? + AND p.payment_type = ? + ORDER BY p.payment_date DESC + LIMIT 1 + """; + + List> list = jdbcTemplate.queryForList(sql, refId, type); + + // ✅ Return null safely instead of throwing exception + return list.isEmpty() ? null : list.get(0); + } + + // public List> getDetailsByRequestIdTemp(String refId) { + + // String sql = """ + // SELECT + // ud.applicant_name, + // ud.mobile_number, + // ud.applicant_address, + // et.event_name, + // ud.total_cost, + // ud.payment_status AS booking_payment_status, + // fc.payment_status AS fine_payment_status, + // fc.fine_amount, + // rs.payment_status AS restoration_payment_status, + // rs.amount AS restoration_amount, + // ud.refid, + // DATE_FORMAT(ud.event_date,'%d-%m-%Y') AS event_date, + // DATE_FORMAT(ud.cdate,'%d-%m-%Y') AS cdate, + // ud.total_poles, + // ud.no_of_days + // FROM temp_booking ud + // LEFT JOIN event_type et ON et.id = ud.event_id + // LEFT JOIN fine_collection fc ON fc.ref_id = ud.refid + // AND fc.isactive = 1 AND fc.isdelete = 0 + // LEFT JOIN restoration rs ON rs.ref_id = ud.refid + // AND rs.is_active = 1 AND rs.is_delete = 0 + // WHERE ud.refid = ? + // AND ud.is_active = 1 + // AND ud.is_delete = 0 + // """; + + // return jdbcTemplate.queryForList(sql, refId); + // } + + public List> getDetailsByRequestIdTemp(String refId) { + + String sql = """ + SELECT + ud.applicant_name, + ud.mobile_number, + ud.applicant_address, + et.event_name, + ud.total_cost, + ud.payment_status AS booking_payment_status, + + fc.payment_status AS fine_payment_status, + fc.fine_amount, + + rs.payment_status AS restoration_payment_status, + rs.amount AS restoration_amount, + + ud.refid, + DATE_FORMAT(ud.event_date,'%d-%m-%Y') AS event_date, + DATE_FORMAT(ud.cdate,'%d-%m-%Y') AS cdate, + ud.total_poles, + ud.no_of_days + + FROM temp_booking ud + + LEFT JOIN event_type et + ON et.id = ud.event_id + + LEFT JOIN fine_collection fc + ON fc.ref_id = ud.refid + AND fc.isactive = 1 + AND fc.isdelete = 0 + + LEFT JOIN restoration rs + ON rs.ref_id = ud.refid + AND rs.is_active = 1 + AND rs.is_delete = 0 + + WHERE ud.refid = ? + AND ud.is_active = 1 + AND ud.is_delete = 0 + """; + + return jdbcTemplate.queryForList(sql, refId); + } + + // public List> getFinalDetailsByRefId(String refId) { + + // String sql = """ + // SELECT + // urd.applicant_name, + // urd.mobile_number, + // urd.applicant_address, + // et.event_name, + // urd.total_cost, + // urd.payment_status AS booking_payment_status, + // fc.payment_status AS fine_payment_status, + // fc.fine_amount, + // rs.payment_status AS restoration_payment_status, + // rs.amount AS restoration_amount, + // urd.refid, + // DATE_FORMAT(urd.event_date,'%d-%m-%Y') AS event_date, + // DATE_FORMAT(urd.cdate,'%d-%m-%Y') AS cdate, + // urd.total_poles, + // urd.no_of_days, + // p.payment_id, + // p.paymentstatus, + // DATE_FORMAT(p.payment_date,'%d-%m-%Y') AS payment_date, + // p.amount AS payment_amount + // FROM user_request_details urd + // LEFT JOIN event_type et ON et.id = urd.event_id + // LEFT JOIN payment p ON p.ref_id = urd.refid + // LEFT JOIN fine_collection fc ON fc.ref_id = urd.refid + // AND fc.isactive = 1 AND fc.isdelete = 0 + // LEFT JOIN restoration rs ON rs.ref_id = urd.refid + // AND rs.is_active = 1 AND rs.is_delete = 0 + // WHERE urd.refid = ? + // """; + + // return jdbcTemplate.queryForList(sql, refId); + // } + + public List> getFinalDetailsByRefId(String refId) { + + String sql = """ + SELECT + urd.applicant_name, + urd.mobile_number, + urd.applicant_address, + et.event_name, + urd.total_cost, + urd.payment_status AS booking_payment_status, + + fc.payment_status AS fine_payment_status, + fc.fine_amount, + + rs.payment_status AS restoration_payment_status, + rs.amount AS restoration_amount, + + urd.refid, + DATE_FORMAT(urd.event_date,'%d-%m-%Y') AS event_date, + DATE_FORMAT(urd.cdate,'%d-%m-%Y') AS cdate, + urd.total_poles, + urd.no_of_days, + + p.payment_id, + p.paymentstatus, + DATE_FORMAT(p.payment_date,'%d-%m-%Y') AS payment_date, + p.amount AS payment_amount, + p.payment_type + + FROM user_request_details urd + + LEFT JOIN event_type et + ON et.id = urd.event_id + + LEFT JOIN payment p + ON p.ref_id = urd.refid + + LEFT JOIN fine_collection fc + ON fc.ref_id = urd.refid + AND fc.isactive = 1 + AND fc.isdelete = 0 + + LEFT JOIN restoration rs + ON rs.ref_id = urd.refid + AND rs.is_active = 1 + AND rs.is_delete = 0 + + WHERE urd.refid = ? + """; + + return jdbcTemplate.queryForList(sql, refId); + } + + public List> getTempStreetDetails(String refId) { + return jdbcTemplate.queryForList(""" + SELECT street_name, zone, ward + FROM temp_street_details + WHERE temp_refid = ? + AND is_active = 1 + AND is_delete = 0 + """, refId); + } + + public List> getFinalStreetDetails(String refId) { + return jdbcTemplate.queryForList(""" + SELECT street_name, zone, ward + FROM street_details + WHERE refid = ? + AND is_active = 1 + AND is_delete = 0 + """, refId); + } + + public boolean existsInFinal(String refId) { + Integer cnt = jdbcTemplate.queryForObject( + "SELECT COUNT(*) FROM user_request_details WHERE refid = ?", + Integer.class, + refId); + return cnt != null && cnt > 0; + } + + // public List> getStreetDetailsByRefId(String requestId) { + // String sql = " select sd.street_name,sd.zone,sd.ward " + + // " from user_request_details ud " + + // " left join street_details sd on sd.refid = ud.refid " + + // " where ud.refid = ? "; + // return jdbcTemplate.queryForList(sql, requestId); + // } + + // public List> getUserDetails(String RefId) { + // String sql = "SELECT applicant_name,mobile_number,total_cost FROM + // user_request_details WHERE refid = ? "; + // return jdbcTemplate.queryForList(sql, RefId); + // } + + // public List> getUserDetailsfromTemp(String RefId) { + // String sql = "SELECT applicant_name,mobile_number,total_cost FROM + // temp_booking WHERE refid = ? "; + // return jdbcTemplate.queryForList(sql, RefId); + // } + + public List> getUserDetailsfromTemp(String refId) { + + String sql = """ + SELECT + ud.applicant_name, + ud.mobile_number, + ud.total_cost, + + ud.payment_status AS booking_payment_status, + + fc.payment_status AS fine_payment_status, + fc.fine_amount + + FROM temp_booking ud + LEFT JOIN fine_collection fc + ON fc.ref_id = ud.refid + + WHERE ud.refid = ? + """; + + return jdbcTemplate.queryForList(sql, refId); + } + + @Transactional + public int updatePaymentStatus(String RefId) { + String sql = "UPDATE user_request_details SET payment_status = 'COMPLETED' WHERE refid = ? "; + return jdbcTemplate.update(sql, RefId); + } + + @Transactional + public int updatePaymentStatusInOrderLog(String RefId, String OrderId) { + String sql = "UPDATE order_log SET order_status = 'captured' WHERE ref_id = ? and order_id= ? "; + return jdbcTemplate.update(sql, RefId, OrderId); + } + + // public List> searchRequestsByRefIdOrMobile( + // String refId, String mobileNumber) { + + // StringBuilder sql = new StringBuilder(""" + // SELECT + // urd.id, + // urd.applicant_name, + // urd.mobile_number, + // urd.applicant_address, + // urd.event_date, + // urd.ae_status, + // urd.rdo_status, + // urd.no_of_days, + // urd.rdo_remarks, + // urd.refid, + // urd.payment_status, + // urd.booking_status, + // urd.cdate, -- ✅ ADD THIS + // sd.street_name, + // sd.zone, + // sd.ward, + // sd.no_of_poles, + // sd.street_cost, + // urd.total_cost, + // et.event_name + // FROM user_request_details urd + // LEFT JOIN street_details sd + // ON urd.refid = sd.refid + // AND sd.is_active = 1 + // AND sd.is_delete = 0 + // LEFT JOIN event_type et + // ON urd.event_id = et.id + // WHERE 1=1 + // """); + + // List params = new ArrayList<>(); + + // if (refId != null && !refId.isEmpty()) { + // sql.append(" AND urd.refid = ? "); + // params.add(refId); + // } + + // if (mobileNumber != null && !mobileNumber.isEmpty()) { + // sql.append(" AND urd.mobile_number = ? "); + // params.add(mobileNumber); + // } + + // // ✅ LATEST RECORDS FIRST + // sql.append(" ORDER BY urd.cdate DESC, sd.id "); + + // List> rows = jdbcTemplate.queryForList(sql.toString(), + // params.toArray()); + + // // 🔥 GROUP BY REFID (NO CHANGE) + // Map> resultMap = new LinkedHashMap<>(); + + // for (Map row : rows) { + + // String refid = (String) row.get("refid"); + + // Map request = resultMap.computeIfAbsent(refid, k -> { + // Map map = new LinkedHashMap<>(); + // map.put("refid", row.get("refid")); + // map.put("applicant_name", row.get("applicant_name")); + // map.put("mobile_number", row.get("mobile_number")); + // map.put("applicant_address", row.get("applicant_address")); + // map.put("event_date", row.get("event_date")); + // map.put("ae_status", row.get("ae_status")); + // map.put("rdo_status", row.get("rdo_status")); + // map.put("rdo_remarks", row.get("rdo_remarks")); + // map.put("no_of_days", row.get("no_of_days")); + // map.put("event_name", row.get("event_name")); + // map.put("total_cost", row.get("total_cost")); + // map.put("payment_status", row.get("payment_status")); // ✅ + // map.put("booking_status", row.get("booking_status")); // ✅ + // map.put("cdate", row.get("cdate")); // ✅ + // map.put("streets", new ArrayList<>()); + // return map; + // }); + + // Map street = new LinkedHashMap<>(); + // street.put("street_name", row.get("street_name")); + // street.put("zone", row.get("zone")); + // street.put("ward", row.get("ward")); + // street.put("no_of_poles", row.get("no_of_poles")); + // street.put("street_cost", row.get("street_cost")); + + // ((List>) request.get("streets")).add(street); + // } + + // return new ArrayList<>(resultMap.values()); + // } + + public List> searchRequestsByRefIdOrMobile( + String refId, + String mobileNumber) { + + StringBuilder sql = new StringBuilder(""" + SELECT + urd.id, + urd.applicant_name, + urd.mobile_number, + urd.applicant_address, + urd.event_date, + urd.ae_status, + urd.rdo_status, + urd.no_of_days, + urd.rdo_remarks, + urd.refid, + urd.payment_status, + urd.booking_status, + urd.cdate, + + sd.street_name, + sd.zone, + sd.ward, + sd.no_of_poles, + sd.street_cost, + + urd.total_cost, + et.event_name, + + IFNULL(fc.fine_amount, 0) AS fine_amount, + IFNULL(rp.amount, 0) AS restoration_amount + + FROM user_request_details urd + + LEFT JOIN street_details sd + ON urd.refid = sd.refid + AND sd.is_active = 1 + AND sd.is_delete = 0 + + LEFT JOIN event_type et + ON urd.event_id = et.id + + LEFT JOIN fine_collection fc + ON urd.refid = fc.ref_id + AND fc.isactive = 1 + AND fc.isdelete = 0 + + LEFT JOIN restoration rp + ON urd.refid = rp.ref_id + AND rp.is_active = 1 + AND rp.is_delete = 0 + + WHERE 1 = 1 + """); + + List params = new ArrayList<>(); + + // 🔹 Search priority: RefId first, else Mobile + if (refId != null && !refId.trim().isEmpty()) { + sql.append(" AND urd.refid = ? "); + params.add(refId.trim()); + + } else if (mobileNumber != null && !mobileNumber.trim().isEmpty()) { + sql.append(" AND urd.mobile_number = ? "); + params.add(mobileNumber.trim()); + } + + sql.append(" ORDER BY urd.cdate DESC, sd.id "); + + List> rows = jdbcTemplate.queryForList(sql.toString(), params.toArray()); + + // 🔥 GROUP BY REFID + Map> resultMap = new LinkedHashMap<>(); + + for (Map row : rows) { + + String refid = (String) row.get("refid"); + + Map request = resultMap.computeIfAbsent(refid, k -> { + Map map = new LinkedHashMap<>(); + map.put("refid", row.get("refid")); + map.put("applicant_name", row.get("applicant_name")); + map.put("mobile_number", row.get("mobile_number")); + map.put("applicant_address", row.get("applicant_address")); + map.put("event_date", row.get("event_date")); + map.put("ae_status", row.get("ae_status")); + map.put("rdo_status", row.get("rdo_status")); + map.put("rdo_remarks", row.get("rdo_remarks")); + map.put("no_of_days", row.get("no_of_days")); + map.put("event_name", row.get("event_name")); + map.put("total_cost", row.get("total_cost")); + map.put("payment_status", row.get("payment_status")); + map.put("booking_status", row.get("booking_status")); + map.put("fine_amount", row.get("fine_amount")); + map.put("restoration_amount", row.get("restoration_amount")); + map.put("streets", new ArrayList<>()); + return map; + }); + + Map street = new LinkedHashMap<>(); + street.put("street_name", row.get("street_name")); + street.put("zone", row.get("zone")); + street.put("ward", row.get("ward")); + street.put("no_of_poles", row.get("no_of_poles")); + street.put("street_cost", row.get("street_cost")); + + ((List>) request.get("streets")).add(street); + } + + return new ArrayList<>(resultMap.values()); + } + + public List> getFineDetailsForUser(String RefId) { + String sql = "SELECT user_name,mob_no,fine_amount FROM fine_collection WHERE ref_id = ? "; + return jdbcTemplate.queryForList(sql, RefId); + } + + public List> getRestorationDetailsForUser(String RefId) { + String sql = "SELECT amount,remarks,image_path FROM restoration WHERE ref_id = ? "; + return jdbcTemplate.queryForList(sql, RefId); + } + + public List> eventPostponed(String RefId) { + String sql = "SELECT * from user_request_details WHERE refid = ? "; + return jdbcTemplate.queryForList(sql, RefId); + } + + private List getEventDateRange(LocalDate startDate, int noOfDays) { + List dates = new ArrayList<>(); + for (int i = 0; i < noOfDays; i++) { + dates.add(startDate.plusDays(i)); + } + return dates; + } + // old + // private void insertIntoHistory(String refId, String actionType) { + + // jdbcTemplate.update(""" + // INSERT INTO user_request_details_history + // ( + // applicant_name, + // mobile_number, + // applicant_address, + // event_id, + // event_date, + // event_desc, + // no_of_days, + // total_poles, + // deposit, + // total_cost, + // approved_by, + // approved_date, + // ae_status, + // rdo_status, + // rdo_remarks, + // cdate, + // refid, + // payment_status, + // refund_status, + // booking_status + // ) + // SELECT + // applicant_name, + // mobile_number, + // applicant_address, + // event_id, + // event_date, + // event_desc, + // no_of_days, + // total_poles, + // deposit, + // total_cost, + // approved_by, + // approved_date, + // ae_status, + // rdo_status, + // rdo_remarks, + // cdate, + // refid, + // payment_status, + // refund_status, + // booking_status + // FROM user_request_details + // WHERE refid = ? + // """, refId); + // } + + private void insertIntoHistoryAfterAction( + String refId, + String aeStatus, + String rdoStatus, + String rdoRemarks, + String bookingStatus, + String approvedBy) { + + jdbcTemplate.update(""" + INSERT INTO user_request_details_history + ( + refid, + applicant_name, + mobile_number, + applicant_address, + event_id, + event_date, + event_desc, + no_of_days, + total_poles, + deposit, + total_cost, + ae_status, + rdo_status, + rdo_remarks, + booking_status, + approved_by, + approved_date, + payment_status, + refund_status, + cdate + ) + SELECT + refid, + applicant_name, + mobile_number, + applicant_address, + event_id, + event_date, + event_desc, + no_of_days, + total_poles, + deposit, + total_cost, + ?, ?, ?, ?, ?, NOW(), + payment_status, + refund_status, + NOW() + FROM user_request_details + WHERE refid = ? + """, + aeStatus, + rdoStatus, + rdoRemarks, + bookingStatus, + approvedBy, + refId); + } + + @Transactional + public String cancelEvent(String refId) { + + Map record = jdbcTemplate.queryForMap(""" + SELECT event_date + FROM user_request_details + WHERE refid = ? + """, refId); + + // ✅ CORRECT CAST + LocalDateTime eventDate = (LocalDateTime) record.get("event_date"); + + if (LocalDateTime.now().isAfter(eventDate.minusHours(24))) { + return "NOT_ALLOWED"; + } + + // 🔥 INSERT HISTORY BEFORE UPDATE + // insertIntoHistory(refId, "CANCELLED"); + + insertIntoHistoryAfterAction( + refId, + null, + null, + null, + "CANCELLED", + "USER"); + + jdbcTemplate.update(""" + UPDATE user_request_details + SET booking_status = 'CANCELLED' + WHERE refid = ? + """, refId); + + return "CANCELLED"; + } + + public boolean isStreetAvailableForRangeStrict( + String streetName, + String zone, + String ward, + String lat, + String lng, + LocalDate newStartDate, + int noOfDays, + String currentRefId) { + + LocalDate newEndDate = newStartDate.plusDays(noOfDays - 1); + + String sql = """ + SELECT COUNT(*) + FROM street_details sd + JOIN user_request_details urd ON sd.refid = urd.refid + WHERE sd.street_name = ? + AND sd.zone = ? + AND sd.ward = ? + AND sd.latitude = ? + AND sd.longitude = ? + AND urd.booking_status NOT IN ('CANCELLED') + AND urd.refid <> ? + AND ( + DATE(urd.event_date) <= ? + AND DATE_ADD(DATE(urd.event_date), INTERVAL urd.no_of_days - 1 DAY) >= ? + ) + """; + + Integer count = jdbcTemplate.queryForObject( + sql, + Integer.class, + streetName, + zone, + ward, + lat, + lng, + currentRefId, + newEndDate, + newStartDate); + + return count == null || count == 0; + } + + // @Transactional + // public String postponeEvent(String refId, LocalDate newStartDate) { + + // Map record = jdbcTemplate.queryForMap(""" + // SELECT event_date, no_of_days + // FROM user_request_details + // WHERE refid = ? + // """, refId); + + // // ✅ CORRECT CAST + // LocalDateTime oldEventDate = (LocalDateTime) record.get("event_date"); + + // int noOfDays = ((Number) record.get("no_of_days")).intValue(); + + // // ⏰ 24-hour rule + // if (LocalDateTime.now().isAfter(oldEventDate.minusHours(24))) { + // return "NOT_ALLOWED"; + // } + + // // 📅 calculate full new date range + // List newDateRange = getEventDateRange(newStartDate, noOfDays); + + // // 🚧 get all streets for this request + // List streets = jdbcTemplate.queryForList(""" + // SELECT street_name + // FROM street_details + // WHERE refid = ? + // """, String.class, refId); + + // // 🚫 check availability + // for (String street : streets) { + // if (!isStreetAvailableForRange(street, newDateRange, refId)) { + // return "STREET_NOT_AVAILABLE"; + // } + // } + + // // 🔥 INSERT HISTORY BEFORE UPDATE + // insertIntoHistory(refId, "POSTPONED"); + + // // ✅ update event date + // jdbcTemplate.update(""" + // UPDATE user_request_details + // SET event_date = ?, + // booking_status = 'POSTPONED' + // WHERE refid = ? + // """, newStartDate, refId); + + // return "POSTPONED"; + // } + + // old + // @Transactional + // public String postponeEvent(String refId, LocalDate newStartDate) { + + // Map record = jdbcTemplate.queryForMap(""" + // SELECT event_date, no_of_days + // FROM user_request_details + // WHERE refid = ? + // """, refId); + + // LocalDateTime oldEventDate = (LocalDateTime) record.get("event_date"); + // int noOfDays = ((Number) record.get("no_of_days")).intValue(); + + // // ⏰ 24-hour rule + // if (LocalDateTime.now().isAfter(oldEventDate.minusHours(24))) { + // return "NOT_ALLOWED"; + // } + + // List newDateRange = getEventDateRange(newStartDate, noOfDays); + + // List streets = jdbcTemplate.queryForList(""" + // SELECT street_name + // FROM street_details + // WHERE refid = ? + // """, String.class, refId); + + // for (String street : streets) { + // if (!isStreetAvailableForRange(street, newDateRange, refId)) { + // return "STREET_NOT_AVAILABLE"; + // } + // } + + // // 🔥 Save old state into history + // // insertIntoHistory(refId, "POSTPONED"); + // insertIntoHistoryAfterAction( + // refId, + // null, + // null, + // null, + // "POSTPONED", + // "USER"); + + // // ✅ Reset approvals & update date + // jdbcTemplate.update(""" + // UPDATE user_request_details + // SET + // event_date = ?, + // booking_status = 'POSTPONED', + // ae_status = NULL, + // rdo_status = NULL, + // rdo_remarks = NULL, + // approved_date = NULL + // WHERE refid = ? + // """, newStartDate, refId); + + // return "POSTPONED"; + // } + + @Transactional + public String postponeEvent(String refId, LocalDate newStartDate) { + + if (isAlreadyPostponed(refId)) { + return "POSTPONE_ALREADY_USED"; + } + + Map record = jdbcTemplate.queryForMap(""" + SELECT event_date, no_of_days + FROM user_request_details + WHERE refid = ? + """, refId); + + LocalDateTime oldEventDate = (LocalDateTime) record.get("event_date"); + int noOfDays = ((Number) record.get("no_of_days")).intValue(); + + if (LocalDateTime.now().isAfter(oldEventDate.minusHours(24))) { + return "NOT_ALLOWED"; + } + + List> streets = jdbcTemplate.queryForList(""" + SELECT street_name, zone, ward, latitude, longitude + FROM street_details + WHERE refid = ? + AND is_active = 1 + AND is_delete = 0 + """, refId); + + for (Map street : streets) { + if (!isStreetAvailableForRangeStrict( + street.get("street_name").toString(), + street.get("zone").toString(), + street.get("ward").toString(), + street.get("latitude").toString(), + street.get("longitude").toString(), + newStartDate, + noOfDays, + refId)) { + + return "STREET_NOT_AVAILABLE"; + } + } + + insertIntoHistoryAfterAction( + refId, + null, + null, + null, + "POSTPONED", + "USER"); + + jdbcTemplate.update(""" + UPDATE user_request_details + SET + event_date = ?, + booking_status = 'POSTPONED', + ae_status = NULL, + rdo_status = NULL, + rdo_remarks = NULL, + approved_date = NULL + WHERE refid = ? + """, newStartDate, refId); + + return "POSTPONED"; + } + + public boolean isAlreadyPostponed(String refId) { + Integer count = jdbcTemplate.queryForObject(""" + SELECT COUNT(*) + FROM user_request_details_history + WHERE refid = ? + AND booking_status = 'POSTPONED' + """, Integer.class, refId); + + return count != null && count > 0; + } + + public boolean isUserExistsByMobile(String mobile) { + + Integer count = jdbcTemplate.queryForObject( + "SELECT COUNT(*) FROM user_request_details WHERE mobile_number = ?", + Integer.class, + mobile); + + return count != null && count > 0; + } + +} diff --git a/src/main/java/com/gcc/flagpoles/service/SMSService.java b/src/main/java/com/gcc/flagpoles/service/SMSService.java new file mode 100644 index 0000000..0ac9d02 --- /dev/null +++ b/src/main/java/com/gcc/flagpoles/service/SMSService.java @@ -0,0 +1,39 @@ +package com.gcc.flagpoles.service; + +import org.springframework.stereotype.Service; +import org.springframework.web.client.RestTemplate; + +import java.net.HttpURLConnection; +import java.net.URL; + +@Service +public class SMSService { + public String sendMsg(String msgUrl) { + System.out.println("Whatsapp URL :-" + msgUrl); + + String response = ""; + try { + HttpURLConnection connection = null; + + URL url = new URL(msgUrl); + connection = (HttpURLConnection) url.openConnection(); + connection.setRequestMethod("GET"); + + int responseCode = connection.getResponseCode(); + response = responseCode + ""; + System.out.println("Response Code: " + responseCode); + + } catch (Exception e) { + e.printStackTrace(); + } + + return response; + } + + public String sendSMS(String SMS_Url) { + System.out.println("SMS URL:- " + SMS_Url); + RestTemplate restTemplate = new RestTemplate(); + String response = restTemplate.getForObject(SMS_Url, String.class); + return response; + } +} diff --git a/src/main/java/com/gcc/flagpoles/service/WhatsappMessageService.java b/src/main/java/com/gcc/flagpoles/service/WhatsappMessageService.java new file mode 100644 index 0000000..362ffca --- /dev/null +++ b/src/main/java/com/gcc/flagpoles/service/WhatsappMessageService.java @@ -0,0 +1,147 @@ +package com.gcc.flagpoles.service; + +import java.net.URLEncoder; +import java.nio.charset.StandardCharsets; + +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; + +@Service +public class WhatsappMessageService { + + @Autowired + private SMSService smsService; + + // c & d waste template after user register + public void sendrequestraisedWhatsappMessage(String refId, String mobileNumber) { + try { + + String apiUrl = "https://media.smsgupshup.com/GatewayAPI/rest?userid=2000233507&password=h2YjFNcJ&send_to=" + + mobileNumber + + "&v=1.1&format=json&msg_type=TEXT&method=SENDMESSAGE&msg=Thank+you%21+Your+request+has+been+successfully+submitted.%0ARequest+Id+%3A+" + + refId + + "&isTemplate=true&header=C%26D+Waste+Collection+Request+Registered&footer=Greater+Chennai+Corporation"; + + System.out.println("WhatsApp API URL: " + apiUrl); // Optional debug + smsService.sendMsg(apiUrl); + + } catch (Exception e) { + e.printStackTrace(); + } + } + + // payment complete template + public void sendPaymentCompleteWhatsappMessage(String refId, double actualWeight, double totalCharge, + String mobileNumber) { + try { + String message = String.format( + "Your request (Request ID: *%s*) has been processed. Please proceed with the payment.\n\nActual Weight: *%.0f kg*\nAmount Payable: *%.0f*", + refId, actualWeight, totalCharge); + + String encodedMessage = URLEncoder.encode(message, StandardCharsets.UTF_8); + String encodedHeader = URLEncoder.encode("C&D Waste Collection – Payment Request", StandardCharsets.UTF_8); + String encodedFooter = URLEncoder.encode("Greater Chennai Corporation", StandardCharsets.UTF_8); + + String redirectUrlParam = URLEncoder.encode( + "http://localhost:8077/flagpolesregistration/paymentform?requestId=" + refId, + StandardCharsets.UTF_8); + + String apiUrl = "https://media.smsgupshup.com/GatewayAPI/rest?userid=2000233507" + + "&password=h2YjFNcJ" + + "&send_to=" + mobileNumber + + "&v=1.1&format=json&msg_type=TEXT&method=SENDMESSAGE" + + "&msg=" + encodedMessage + + "&isTemplate=true" + + "&header=" + encodedHeader + + "&footer=" + encodedFooter + + "&buttonUrlParam=" + redirectUrlParam; + + // Optional: log URL before hitting for debugging + System.out.println("WhatsApp API URL: " + apiUrl); + + // Make API call + // restTemplate.getForObject(apiUrl, String.class); + smsService.sendMsg(apiUrl); + } catch (Exception e) { + e.printStackTrace(); + // Optionally log or alert failure + } + } + + // for fine collection + public void sendFineCollectionWhatsappMessage(String refId, double actualWeight, double totalCharge, + String mobileNumber) { + try { + String message = String.format( + "Your request (Request ID: *%s*) has been processed. Please proceed with the payment.\n\nActual Weight: *%.0f kg*\nAmount Payable: *%.0f*", + refId, actualWeight, totalCharge); + + String encodedMessage = URLEncoder.encode(message, StandardCharsets.UTF_8); + String encodedHeader = URLEncoder.encode("C&D Waste Collection – Payment Request", StandardCharsets.UTF_8); + String encodedFooter = URLEncoder.encode("Greater Chennai Corporation", StandardCharsets.UTF_8); + + String redirectUrlParam = URLEncoder.encode( + "http://localhost:8077/flagpolesregistration/paymentform?requestId=" + refId, + StandardCharsets.UTF_8); + + String apiUrl = "https://media.smsgupshup.com/GatewayAPI/rest?userid=2000233507" + + "&password=h2YjFNcJ" + + "&send_to=" + mobileNumber + + "&v=1.1&format=json&msg_type=TEXT&method=SENDMESSAGE" + + "&msg=" + encodedMessage + + "&isTemplate=true" + + "&header=" + encodedHeader + + "&footer=" + encodedFooter + + "&buttonUrlParam=" + redirectUrlParam; + + // Optional: log URL before hitting for debugging + System.out.println("WhatsApp API URL: " + apiUrl); + + // Make API call + // restTemplate.getForObject(apiUrl, String.class); + smsService.sendMsg(apiUrl); + } catch (Exception e) { + e.printStackTrace(); + // Optionally log or alert failure + } + } + + // restoration message + public void sendRestorationWhatsappMessage(String refId, double actualWeight, double totalCharge, + String mobileNumber) { + try { + String message = String.format( + "Your request (Request ID: *%s*) has been processed. Please proceed with the payment.\n\nActual Weight: *%.0f kg*\nAmount Payable: *%.0f*", + refId, actualWeight, totalCharge); + + String encodedMessage = URLEncoder.encode(message, StandardCharsets.UTF_8); + String encodedHeader = URLEncoder.encode("C&D Waste Collection – Payment Request", StandardCharsets.UTF_8); + String encodedFooter = URLEncoder.encode("Greater Chennai Corporation", StandardCharsets.UTF_8); + + String redirectUrlParam = URLEncoder.encode( + "http://localhost:8077/flagpolesregistration/paymentform?requestId=" + refId, + StandardCharsets.UTF_8); + + String apiUrl = "https://media.smsgupshup.com/GatewayAPI/rest?userid=2000233507" + + "&password=h2YjFNcJ" + + "&send_to=" + mobileNumber + + "&v=1.1&format=json&msg_type=TEXT&method=SENDMESSAGE" + + "&msg=" + encodedMessage + + "&isTemplate=true" + + "&header=" + encodedHeader + + "&footer=" + encodedFooter + + "&buttonUrlParam=" + redirectUrlParam; + + // Optional: log URL before hitting for debugging + System.out.println("WhatsApp API URL: " + apiUrl); + + // Make API call + // restTemplate.getForObject(apiUrl, String.class); + smsService.sendMsg(apiUrl); + } catch (Exception e) { + e.printStackTrace(); + // Optionally log or alert failure + } + } + +} diff --git a/src/main/resources/application-dev.properties b/src/main/resources/application-dev.properties new file mode 100644 index 0000000..6400f51 --- /dev/null +++ b/src/main/resources/application-dev.properties @@ -0,0 +1,33 @@ +spring.application.name=flagpolesregistration + +spring.datasource.url=jdbc:mysql://localhost:3306/gcc_flag_pole +spring.datasource.username=root +spring.datasource.password=root +spring.jpa.hibernate.ddl-auto=update +spring.jpa.show-sql=true +spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver +server.port=8083 + + + + + + +spring.servlet.multipart.max-file-size=20MB + +# file.upload.directory=${user.dir}/gccoffice_uploads +# file.dump.upload.directory=${user.dir}/cd_waste_docs/cdwaste_dump + +# file.fullpath=/ +# file.dump.fullpath=/cd_waste_docs/ + +fileBaseUrl=http://localhost:8083 + +payment.razorpay.my_key_id="rzp_test_tDkHFEqWXmuEi8" + + +app.getOtpUrl=https://tmegov.onex-aura.com/api/sms? + +app.erpUrl=https://erp.chennaicorporation.gov.in/pgr/external/mobileservice? + +# dump_directory=cdwaste_dump \ No newline at end of file diff --git a/src/main/resources/application-prod.properties b/src/main/resources/application-prod.properties new file mode 100644 index 0000000..21776f7 --- /dev/null +++ b/src/main/resources/application-prod.properties @@ -0,0 +1,31 @@ +spring.application.name=flagpolesregistration +spring.datasource.url=jdbc:mysql://gcc-facial-db-instance-1.cf48eqcciziq.ap-south-1.rds.amazonaws.com:3306/gcc_flag_pole +spring.datasource.username=root +spring.datasource.password=gcc-facial-password +spring.jpa.hibernate.ddl-auto=update +spring.jpa.show-sql=true +spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver +server.port=8083 + +#production port = 8083 + + + +spring.servlet.multipart.max-file-size=20MB + +# file.upload.directory=${user.dir}/gccoffice_uploads +# file.dump.upload.directory=${user.dir}/cd_waste_docs/cdwaste_dump + +# file.fullpath=/ +# file.dump.fullpath=/cd_waste_docs/ + +fileBaseUrl=https://gccservices.in + +payment.razorpay.my_key_id="rzp_test_tDkHFEqWXmuEi8" + + +app.getOtpUrl=https://tmegov.onex-aura.com/api/sms? + +app.erpUrl=https://erp.chennaicorporation.gov.in/pgr/external/mobileservice? + +# dump_directory=cdwaste_dump \ No newline at end of file diff --git a/src/main/resources/application.properties b/src/main/resources/application.properties new file mode 100644 index 0000000..257b306 --- /dev/null +++ b/src/main/resources/application.properties @@ -0,0 +1 @@ +spring.profiles.active=dev \ No newline at end of file diff --git a/src/main/resources/templates/fragments/details.html b/src/main/resources/templates/fragments/details.html new file mode 100644 index 0000000..8c76551 --- /dev/null +++ b/src/main/resources/templates/fragments/details.html @@ -0,0 +1,188 @@ +
+
+ +
+ + +
+ GREATER CHENNAI CORPORATION +
+
+ +
+
+
+
+
+ +
+
+ +
+ + +
+ + +
+ +
+
+ User Details:
+

User Name:

+

Mobile Number:

+

Address:

+
+ + +
+
+ Payment Details:
+ + +
+ +

Transaction Id: + +

+ +

Payment Type: + +

+ +

Payment Date: + +

+ +

Payment Status: + + +

+ +

Total Amount Paid: + +

+
+ + +
+

Transaction Id: NA

+

Payment Status: NA

+

Total Amount Paid: NA

+
+
+ +
+ + + +
+
+ Event & Street Details:
+
+
+

Request Id:

+

Event Name:

+

Event Date:

+ + +
+ +
+

Request Date: +

+

Event Conducting Days: Days

+

Total No of Poles

+
+
+ + + +
+ Zone: + + | + + Ward: + + + | + Street Name: + + + + +
+ + + + + + + + + + +
+ + + +
* This is a computer-generated document. No + signature is required *
+ +

+ +
+
+ + +
+ +
+ +
+
+
+
+
\ No newline at end of file diff --git a/src/main/resources/templates/modules/flagpolesregistration/acknowledgement.html b/src/main/resources/templates/modules/flagpolesregistration/acknowledgement.html new file mode 100644 index 0000000..a6ee75f --- /dev/null +++ b/src/main/resources/templates/modules/flagpolesregistration/acknowledgement.html @@ -0,0 +1,178 @@ + + + + + + + +
+ + + + + + + + + + \ No newline at end of file diff --git a/src/main/resources/templates/modules/flagpolesregistration/index.html b/src/main/resources/templates/modules/flagpolesregistration/index.html new file mode 100644 index 0000000..4b39270 --- /dev/null +++ b/src/main/resources/templates/modules/flagpolesregistration/index.html @@ -0,0 +1,195 @@ + + + + + +GCC - FlagPoles + + + + + + + + + + + + + + + + + + + + +
+
+ + + + +
+ GREATER CHENNAI CORPORATION +
+ + + +
+ + + + +
+ + + +
+ +
+
+

FlagPoles Registration

+
+
+
+ + +
+
+ + +
+
+
+ + + + +
+ + + + + diff --git a/src/main/resources/templates/modules/flagpolesregistration/nodatafound.html b/src/main/resources/templates/modules/flagpolesregistration/nodatafound.html new file mode 100644 index 0000000..0b7c666 --- /dev/null +++ b/src/main/resources/templates/modules/flagpolesregistration/nodatafound.html @@ -0,0 +1,101 @@ + + + + + + + GCC - Flagpoles Registration + + + + + + + + + + + + + + + + + + + +
+
+ + + + +
+ GREATER CHENNAI CORPORATION +
+
+ +
+ + +
+
+
+

+
+
+
+ + + \ No newline at end of file diff --git a/src/main/resources/templates/modules/flagpolesregistration/paymentrequestform.html b/src/main/resources/templates/modules/flagpolesregistration/paymentrequestform.html new file mode 100644 index 0000000..99155a0 --- /dev/null +++ b/src/main/resources/templates/modules/flagpolesregistration/paymentrequestform.html @@ -0,0 +1,252 @@ + + + + + + + GCC - Flagpoles Registration + + + + + + + +
+ + + + +
+ +
GREATER CHENNAI CORPORATION
+
+ + +
+
+
+ +
+
+ +
+
+ +
+ + +
+ +
+ + +
+ + +
+ + + + +
+ +
+ + + + +
+ + +
+ + +
+ +
+ + + ⚠️ Important: Do not refresh or close the page after clicking the payment button until the + payment is confirmed. + + +
+ + +
+ + + +
+ + +
+
+
+ + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/src/main/resources/templates/modules/flagpolesregistration/razor-pay.html b/src/main/resources/templates/modules/flagpolesregistration/razor-pay.html new file mode 100644 index 0000000..4dca2ad --- /dev/null +++ b/src/main/resources/templates/modules/flagpolesregistration/razor-pay.html @@ -0,0 +1,135 @@ + +
+ + + + + +
+ + \ No newline at end of file diff --git a/src/main/resources/templates/modules/flagpolesregistration/requestform.html b/src/main/resources/templates/modules/flagpolesregistration/requestform.html new file mode 100644 index 0000000..2d5a322 --- /dev/null +++ b/src/main/resources/templates/modules/flagpolesregistration/requestform.html @@ -0,0 +1,2590 @@ + + + + + + + + GCC - FlagPoles + + + + + + + + + + + + + + +
+
+ + + + +
GREATER CHENNAI CORPORATION
+ + +
+ + + + +
+ + + +
+ + +
+
+
Application form for erection of temporary flag poles:-
+
+
+ +
+ +
+ + +
+
+ + +
+
+ +
+
+ + +
+ +
+ + +
+ +
+
+ + + + + + +
+
+ +
+
+ + +
+
+
Event Details :-
+
+
+ +
+ + +
+ +
+ +
+ + +
+ + + +
+ + + +
+
+
+
+ + + + +
+
+
Street details and flag pole specifications
+
+
+
+ +
+
+
+ +
+
+
+ + +
+ + +
+ +
+ +
+
Street 1 Details
+
Flag Pole Specifications
+
+ +
+ + * + + +
+ +
+ + +
+
+ + +
+ + + + + +
+ +
+
+ +
+ +
+ +
+
+ +
+ + + +
+
Duration
+
+
+ +
+ +
+ + +
+ + +
+
+ +
+ +
+ +
+
+
Cost Summary
+
+
+

Rate per pole: 0

+

Total number of poles: 0

+

No of Days: 0 day(s)

+

Total Cost: ₹0

+ +
+ Note: If poles are removed by our organization, additional removal + charges will apply. +
+ + +
+
+ +
+
+
+ +
+
+
+
+ + + + + + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/src/main/resources/templates/modules/flagpolesregistration/status.html b/src/main/resources/templates/modules/flagpolesregistration/status.html new file mode 100644 index 0000000..06c9a8d --- /dev/null +++ b/src/main/resources/templates/modules/flagpolesregistration/status.html @@ -0,0 +1,1068 @@ + + + + + + + GCC - Flagpoles + + + + + + + + + + + + + + + + + + + + + + +
+
+ + + + +
+ GREATER CHENNAI CORPORATION +
+
+ +
+ + +
+ +
+
+

Flagpole Request Status

+
+
+ +
+
+ + + + + +
+
+
+ + +
+ + +
+
+ + +
+ +
+ + + + + + + + + + + + + \ No newline at end of file diff --git a/src/test/java/com/gcc/flagpoles/FlagpolesApplicationTests.java b/src/test/java/com/gcc/flagpoles/FlagpolesApplicationTests.java new file mode 100644 index 0000000..faba12a --- /dev/null +++ b/src/test/java/com/gcc/flagpoles/FlagpolesApplicationTests.java @@ -0,0 +1,13 @@ +package com.gcc.flagpoles; + +import org.junit.jupiter.api.Test; +import org.springframework.boot.test.context.SpringBootTest; + +@SpringBootTest +class FlagpolesApplicationTests { + + @Test + void contextLoads() { + } + +}