diff --git a/mvnw b/mvnw
new file mode 100644
index 0000000..66df285
--- /dev/null
+++ b/mvnw
@@ -0,0 +1,308 @@
+#!/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
+#
+# https://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied. See the License for the
+# specific language governing permissions and limitations
+# under the License.
+# ----------------------------------------------------------------------------
+
+# ----------------------------------------------------------------------------
+# Apache Maven Wrapper startup batch script, version 3.2.0
+#
+# Required ENV vars:
+# ------------------
+# JAVA_HOME - location of a JDK home dir
+#
+# Optional ENV vars
+# -----------------
+# MAVEN_OPTS - parameters passed to the Java VM when running Maven
+# e.g. to debug Maven itself, use
+# set MAVEN_OPTS=-Xdebug -Xrunjdwp:transport=dt_socket,server=y,suspend=y,address=8000
+# MAVEN_SKIP_RC - flag to disable loading of mavenrc files
+# ----------------------------------------------------------------------------
+
+if [ -z "$MAVEN_SKIP_RC" ] ; then
+
+ if [ -f /usr/local/etc/mavenrc ] ; then
+ . /usr/local/etc/mavenrc
+ fi
+
+ if [ -f /etc/mavenrc ] ; then
+ . /etc/mavenrc
+ fi
+
+ if [ -f "$HOME/.mavenrc" ] ; then
+ . "$HOME/.mavenrc"
+ fi
+
+fi
+
+# OS specific support. $var _must_ be set to either true or false.
+cygwin=false;
+darwin=false;
+mingw=false
+case "$(uname)" in
+ CYGWIN*) cygwin=true ;;
+ MINGW*) mingw=true;;
+ Darwin*) darwin=true
+ # Use /usr/libexec/java_home if available, otherwise fall back to /Library/Java/Home
+ # See https://developer.apple.com/library/mac/qa/qa1170/_index.html
+ if [ -z "$JAVA_HOME" ]; then
+ if [ -x "/usr/libexec/java_home" ]; then
+ JAVA_HOME="$(/usr/libexec/java_home)"; export JAVA_HOME
+ else
+ JAVA_HOME="/Library/Java/Home"; export JAVA_HOME
+ fi
+ fi
+ ;;
+esac
+
+if [ -z "$JAVA_HOME" ] ; then
+ if [ -r /etc/gentoo-release ] ; then
+ JAVA_HOME=$(java-config --jre-home)
+ fi
+fi
+
+# For Cygwin, ensure paths are in UNIX format before anything is touched
+if $cygwin ; then
+ [ -n "$JAVA_HOME" ] &&
+ JAVA_HOME=$(cygpath --unix "$JAVA_HOME")
+ [ -n "$CLASSPATH" ] &&
+ CLASSPATH=$(cygpath --path --unix "$CLASSPATH")
+fi
+
+# For Mingw, ensure paths are in UNIX format before anything is touched
+if $mingw ; then
+ [ -n "$JAVA_HOME" ] && [ -d "$JAVA_HOME" ] &&
+ JAVA_HOME="$(cd "$JAVA_HOME" || (echo "cannot cd into $JAVA_HOME."; exit 1); pwd)"
+fi
+
+if [ -z "$JAVA_HOME" ]; then
+ javaExecutable="$(which javac)"
+ if [ -n "$javaExecutable" ] && ! [ "$(expr "\"$javaExecutable\"" : '\([^ ]*\)')" = "no" ]; then
+ # readlink(1) is not available as standard on Solaris 10.
+ readLink=$(which readlink)
+ if [ ! "$(expr "$readLink" : '\([^ ]*\)')" = "no" ]; then
+ if $darwin ; then
+ javaHome="$(dirname "\"$javaExecutable\"")"
+ javaExecutable="$(cd "\"$javaHome\"" && pwd -P)/javac"
+ else
+ javaExecutable="$(readlink -f "\"$javaExecutable\"")"
+ fi
+ javaHome="$(dirname "\"$javaExecutable\"")"
+ javaHome=$(expr "$javaHome" : '\(.*\)/bin')
+ JAVA_HOME="$javaHome"
+ export JAVA_HOME
+ fi
+ fi
+fi
+
+if [ -z "$JAVACMD" ] ; then
+ if [ -n "$JAVA_HOME" ] ; then
+ if [ -x "$JAVA_HOME/jre/sh/java" ] ; then
+ # IBM's JDK on AIX uses strange locations for the executables
+ JAVACMD="$JAVA_HOME/jre/sh/java"
+ else
+ JAVACMD="$JAVA_HOME/bin/java"
+ fi
+ else
+ JAVACMD="$(\unset -f command 2>/dev/null; \command -v java)"
+ fi
+fi
+
+if [ ! -x "$JAVACMD" ] ; then
+ echo "Error: JAVA_HOME is not defined correctly." >&2
+ echo " We cannot execute $JAVACMD" >&2
+ exit 1
+fi
+
+if [ -z "$JAVA_HOME" ] ; then
+ echo "Warning: JAVA_HOME environment variable is not set."
+fi
+
+# traverses directory structure from process work directory to filesystem root
+# first directory with .mvn subdirectory is considered project base directory
+find_maven_basedir() {
+ if [ -z "$1" ]
+ then
+ echo "Path not specified to find_maven_basedir"
+ return 1
+ fi
+
+ basedir="$1"
+ wdir="$1"
+ while [ "$wdir" != '/' ] ; do
+ if [ -d "$wdir"/.mvn ] ; then
+ basedir=$wdir
+ break
+ fi
+ # workaround for JBEAP-8937 (on Solaris 10/Sparc)
+ if [ -d "${wdir}" ]; then
+ wdir=$(cd "$wdir/.." || exit 1; pwd)
+ fi
+ # end of workaround
+ done
+ printf '%s' "$(cd "$basedir" || exit 1; pwd)"
+}
+
+# concatenates all lines of a file
+concat_lines() {
+ if [ -f "$1" ]; then
+ # Remove \r in case we run on Windows within Git Bash
+ # and check out the repository with auto CRLF management
+ # enabled. Otherwise, we may read lines that are delimited with
+ # \r\n and produce $'-Xarg\r' rather than -Xarg due to word
+ # splitting rules.
+ tr -s '\r\n' ' ' < "$1"
+ fi
+}
+
+log() {
+ if [ "$MVNW_VERBOSE" = true ]; then
+ printf '%s\n' "$1"
+ fi
+}
+
+BASE_DIR=$(find_maven_basedir "$(dirname "$0")")
+if [ -z "$BASE_DIR" ]; then
+ exit 1;
+fi
+
+MAVEN_PROJECTBASEDIR=${MAVEN_BASEDIR:-"$BASE_DIR"}; export MAVEN_PROJECTBASEDIR
+log "$MAVEN_PROJECTBASEDIR"
+
+##########################################################################################
+# Extension to allow automatically downloading the maven-wrapper.jar from Maven-central
+# This allows using the maven wrapper in projects that prohibit checking in binary data.
+##########################################################################################
+wrapperJarPath="$MAVEN_PROJECTBASEDIR/.mvn/wrapper/maven-wrapper.jar"
+if [ -r "$wrapperJarPath" ]; then
+ log "Found $wrapperJarPath"
+else
+ log "Couldn't find $wrapperJarPath, downloading it ..."
+
+ if [ -n "$MVNW_REPOURL" ]; then
+ wrapperUrl="$MVNW_REPOURL/org/apache/maven/wrapper/maven-wrapper/3.2.0/maven-wrapper-3.2.0.jar"
+ else
+ wrapperUrl="https://repo.maven.apache.org/maven2/org/apache/maven/wrapper/maven-wrapper/3.2.0/maven-wrapper-3.2.0.jar"
+ fi
+ while IFS="=" read -r key value; do
+ # Remove '\r' from value to allow usage on windows as IFS does not consider '\r' as a separator ( considers space, tab, new line ('\n'), and custom '=' )
+ safeValue=$(echo "$value" | tr -d '\r')
+ case "$key" in (wrapperUrl) wrapperUrl="$safeValue"; break ;;
+ esac
+ done < "$MAVEN_PROJECTBASEDIR/.mvn/wrapper/maven-wrapper.properties"
+ log "Downloading from: $wrapperUrl"
+
+ if $cygwin; then
+ wrapperJarPath=$(cygpath --path --windows "$wrapperJarPath")
+ fi
+
+ if command -v wget > /dev/null; then
+ log "Found wget ... using wget"
+ [ "$MVNW_VERBOSE" = true ] && QUIET="" || QUIET="--quiet"
+ if [ -z "$MVNW_USERNAME" ] || [ -z "$MVNW_PASSWORD" ]; then
+ wget $QUIET "$wrapperUrl" -O "$wrapperJarPath" || rm -f "$wrapperJarPath"
+ else
+ wget $QUIET --http-user="$MVNW_USERNAME" --http-password="$MVNW_PASSWORD" "$wrapperUrl" -O "$wrapperJarPath" || rm -f "$wrapperJarPath"
+ fi
+ elif command -v curl > /dev/null; then
+ log "Found curl ... using curl"
+ [ "$MVNW_VERBOSE" = true ] && QUIET="" || QUIET="--silent"
+ if [ -z "$MVNW_USERNAME" ] || [ -z "$MVNW_PASSWORD" ]; then
+ curl $QUIET -o "$wrapperJarPath" "$wrapperUrl" -f -L || rm -f "$wrapperJarPath"
+ else
+ curl $QUIET --user "$MVNW_USERNAME:$MVNW_PASSWORD" -o "$wrapperJarPath" "$wrapperUrl" -f -L || rm -f "$wrapperJarPath"
+ fi
+ else
+ log "Falling back to using Java to download"
+ javaSource="$MAVEN_PROJECTBASEDIR/.mvn/wrapper/MavenWrapperDownloader.java"
+ javaClass="$MAVEN_PROJECTBASEDIR/.mvn/wrapper/MavenWrapperDownloader.class"
+ # For Cygwin, switch paths to Windows format before running javac
+ if $cygwin; then
+ javaSource=$(cygpath --path --windows "$javaSource")
+ javaClass=$(cygpath --path --windows "$javaClass")
+ fi
+ if [ -e "$javaSource" ]; then
+ if [ ! -e "$javaClass" ]; then
+ log " - Compiling MavenWrapperDownloader.java ..."
+ ("$JAVA_HOME/bin/javac" "$javaSource")
+ fi
+ if [ -e "$javaClass" ]; then
+ log " - Running MavenWrapperDownloader.java ..."
+ ("$JAVA_HOME/bin/java" -cp .mvn/wrapper MavenWrapperDownloader "$wrapperUrl" "$wrapperJarPath") || rm -f "$wrapperJarPath"
+ fi
+ fi
+ fi
+fi
+##########################################################################################
+# End of extension
+##########################################################################################
+
+# If specified, validate the SHA-256 sum of the Maven wrapper jar file
+wrapperSha256Sum=""
+while IFS="=" read -r key value; do
+ case "$key" in (wrapperSha256Sum) wrapperSha256Sum=$value; break ;;
+ esac
+done < "$MAVEN_PROJECTBASEDIR/.mvn/wrapper/maven-wrapper.properties"
+if [ -n "$wrapperSha256Sum" ]; then
+ wrapperSha256Result=false
+ if command -v sha256sum > /dev/null; then
+ if echo "$wrapperSha256Sum $wrapperJarPath" | sha256sum -c > /dev/null 2>&1; then
+ wrapperSha256Result=true
+ fi
+ elif command -v shasum > /dev/null; then
+ if echo "$wrapperSha256Sum $wrapperJarPath" | shasum -a 256 -c > /dev/null 2>&1; then
+ wrapperSha256Result=true
+ fi
+ else
+ echo "Checksum validation was requested but neither 'sha256sum' or 'shasum' are available."
+ echo "Please install either command, or disable validation by removing 'wrapperSha256Sum' from your maven-wrapper.properties."
+ exit 1
+ fi
+ if [ $wrapperSha256Result = false ]; then
+ echo "Error: Failed to validate Maven wrapper SHA-256, your Maven wrapper might be compromised." >&2
+ echo "Investigate or delete $wrapperJarPath to attempt a clean download." >&2
+ echo "If you updated your Maven version, you need to update the specified wrapperSha256Sum property." >&2
+ exit 1
+ fi
+fi
+
+MAVEN_OPTS="$(concat_lines "$MAVEN_PROJECTBASEDIR/.mvn/jvm.config") $MAVEN_OPTS"
+
+# For Cygwin, switch paths to Windows format before running java
+if $cygwin; then
+ [ -n "$JAVA_HOME" ] &&
+ JAVA_HOME=$(cygpath --path --windows "$JAVA_HOME")
+ [ -n "$CLASSPATH" ] &&
+ CLASSPATH=$(cygpath --path --windows "$CLASSPATH")
+ [ -n "$MAVEN_PROJECTBASEDIR" ] &&
+ MAVEN_PROJECTBASEDIR=$(cygpath --path --windows "$MAVEN_PROJECTBASEDIR")
+fi
+
+# Provide a "standardized" way to retrieve the CLI args that will
+# work with both Windows and non-Windows executions.
+MAVEN_CMD_LINE_ARGS="$MAVEN_CONFIG $*"
+export MAVEN_CMD_LINE_ARGS
+
+WRAPPER_LAUNCHER=org.apache.maven.wrapper.MavenWrapperMain
+
+# shellcheck disable=SC2086 # safe args
+exec "$JAVACMD" \
+ $MAVEN_OPTS \
+ $MAVEN_DEBUG_OPTS \
+ -classpath "$MAVEN_PROJECTBASEDIR/.mvn/wrapper/maven-wrapper.jar" \
+ "-Dmaven.multiModuleProjectDirectory=${MAVEN_PROJECTBASEDIR}" \
+ ${WRAPPER_LAUNCHER} $MAVEN_CONFIG "$@"
diff --git a/mvnw.cmd b/mvnw.cmd
new file mode 100644
index 0000000..95ba6f5
--- /dev/null
+++ b/mvnw.cmd
@@ -0,0 +1,205 @@
+@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 https://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.2.0
+@REM
+@REM Required ENV vars:
+@REM JAVA_HOME - location of a JDK home dir
+@REM
+@REM Optional ENV vars
+@REM MAVEN_BATCH_ECHO - set to 'on' to enable the echoing of the batch commands
+@REM MAVEN_BATCH_PAUSE - set to 'on' to wait for a keystroke before ending
+@REM MAVEN_OPTS - parameters passed to the Java VM when running Maven
+@REM e.g. to debug Maven itself, use
+@REM set MAVEN_OPTS=-Xdebug -Xrunjdwp:transport=dt_socket,server=y,suspend=y,address=8000
+@REM MAVEN_SKIP_RC - flag to disable loading of mavenrc files
+@REM ----------------------------------------------------------------------------
+
+@REM Begin all REM lines with '@' in case MAVEN_BATCH_ECHO is 'on'
+@echo off
+@REM set title of command window
+title %0
+@REM enable echoing by setting MAVEN_BATCH_ECHO to 'on'
+@if "%MAVEN_BATCH_ECHO%" == "on" echo %MAVEN_BATCH_ECHO%
+
+@REM set %HOME% to equivalent of $HOME
+if "%HOME%" == "" (set "HOME=%HOMEDRIVE%%HOMEPATH%")
+
+@REM Execute a user defined script before this one
+if not "%MAVEN_SKIP_RC%" == "" goto skipRcPre
+@REM check for pre script, once with legacy .bat ending and once with .cmd ending
+if exist "%USERPROFILE%\mavenrc_pre.bat" call "%USERPROFILE%\mavenrc_pre.bat" %*
+if exist "%USERPROFILE%\mavenrc_pre.cmd" call "%USERPROFILE%\mavenrc_pre.cmd" %*
+:skipRcPre
+
+@setlocal
+
+set ERROR_CODE=0
+
+@REM To isolate internal variables from possible post scripts, we use another setlocal
+@setlocal
+
+@REM ==== START VALIDATION ====
+if not "%JAVA_HOME%" == "" goto OkJHome
+
+echo.
+echo Error: JAVA_HOME not found in your environment. >&2
+echo Please set the JAVA_HOME variable in your environment to match the >&2
+echo location of your Java installation. >&2
+echo.
+goto error
+
+:OkJHome
+if exist "%JAVA_HOME%\bin\java.exe" goto init
+
+echo.
+echo Error: JAVA_HOME is set to an invalid directory. >&2
+echo JAVA_HOME = "%JAVA_HOME%" >&2
+echo Please set the JAVA_HOME variable in your environment to match the >&2
+echo location of your Java installation. >&2
+echo.
+goto error
+
+@REM ==== END VALIDATION ====
+
+:init
+
+@REM Find the project base dir, i.e. the directory that contains the folder ".mvn".
+@REM Fallback to current working directory if not found.
+
+set MAVEN_PROJECTBASEDIR=%MAVEN_BASEDIR%
+IF NOT "%MAVEN_PROJECTBASEDIR%"=="" goto endDetectBaseDir
+
+set EXEC_DIR=%CD%
+set WDIR=%EXEC_DIR%
+:findBaseDir
+IF EXIST "%WDIR%"\.mvn goto baseDirFound
+cd ..
+IF "%WDIR%"=="%CD%" goto baseDirNotFound
+set WDIR=%CD%
+goto findBaseDir
+
+:baseDirFound
+set MAVEN_PROJECTBASEDIR=%WDIR%
+cd "%EXEC_DIR%"
+goto endDetectBaseDir
+
+:baseDirNotFound
+set MAVEN_PROJECTBASEDIR=%EXEC_DIR%
+cd "%EXEC_DIR%"
+
+:endDetectBaseDir
+
+IF NOT EXIST "%MAVEN_PROJECTBASEDIR%\.mvn\jvm.config" goto endReadAdditionalConfig
+
+@setlocal EnableExtensions EnableDelayedExpansion
+for /F "usebackq delims=" %%a in ("%MAVEN_PROJECTBASEDIR%\.mvn\jvm.config") do set JVM_CONFIG_MAVEN_PROPS=!JVM_CONFIG_MAVEN_PROPS! %%a
+@endlocal & set JVM_CONFIG_MAVEN_PROPS=%JVM_CONFIG_MAVEN_PROPS%
+
+:endReadAdditionalConfig
+
+SET MAVEN_JAVA_EXE="%JAVA_HOME%\bin\java.exe"
+set WRAPPER_JAR="%MAVEN_PROJECTBASEDIR%\.mvn\wrapper\maven-wrapper.jar"
+set WRAPPER_LAUNCHER=org.apache.maven.wrapper.MavenWrapperMain
+
+set WRAPPER_URL="https://repo.maven.apache.org/maven2/org/apache/maven/wrapper/maven-wrapper/3.2.0/maven-wrapper-3.2.0.jar"
+
+FOR /F "usebackq tokens=1,2 delims==" %%A IN ("%MAVEN_PROJECTBASEDIR%\.mvn\wrapper\maven-wrapper.properties") DO (
+ IF "%%A"=="wrapperUrl" SET WRAPPER_URL=%%B
+)
+
+@REM Extension to allow automatically downloading the maven-wrapper.jar from Maven-central
+@REM This allows using the maven wrapper in projects that prohibit checking in binary data.
+if exist %WRAPPER_JAR% (
+ if "%MVNW_VERBOSE%" == "true" (
+ echo Found %WRAPPER_JAR%
+ )
+) else (
+ if not "%MVNW_REPOURL%" == "" (
+ SET WRAPPER_URL="%MVNW_REPOURL%/org/apache/maven/wrapper/maven-wrapper/3.2.0/maven-wrapper-3.2.0.jar"
+ )
+ if "%MVNW_VERBOSE%" == "true" (
+ echo Couldn't find %WRAPPER_JAR%, downloading it ...
+ echo Downloading from: %WRAPPER_URL%
+ )
+
+ powershell -Command "&{"^
+ "$webclient = new-object System.Net.WebClient;"^
+ "if (-not ([string]::IsNullOrEmpty('%MVNW_USERNAME%') -and [string]::IsNullOrEmpty('%MVNW_PASSWORD%'))) {"^
+ "$webclient.Credentials = new-object System.Net.NetworkCredential('%MVNW_USERNAME%', '%MVNW_PASSWORD%');"^
+ "}"^
+ "[Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls12; $webclient.DownloadFile('%WRAPPER_URL%', '%WRAPPER_JAR%')"^
+ "}"
+ if "%MVNW_VERBOSE%" == "true" (
+ echo Finished downloading %WRAPPER_JAR%
+ )
+)
+@REM End of extension
+
+@REM If specified, validate the SHA-256 sum of the Maven wrapper jar file
+SET WRAPPER_SHA_256_SUM=""
+FOR /F "usebackq tokens=1,2 delims==" %%A IN ("%MAVEN_PROJECTBASEDIR%\.mvn\wrapper\maven-wrapper.properties") DO (
+ IF "%%A"=="wrapperSha256Sum" SET WRAPPER_SHA_256_SUM=%%B
+)
+IF NOT %WRAPPER_SHA_256_SUM%=="" (
+ powershell -Command "&{"^
+ "$hash = (Get-FileHash \"%WRAPPER_JAR%\" -Algorithm SHA256).Hash.ToLower();"^
+ "If('%WRAPPER_SHA_256_SUM%' -ne $hash){"^
+ " Write-Output 'Error: Failed to validate Maven wrapper SHA-256, your Maven wrapper might be compromised.';"^
+ " Write-Output 'Investigate or delete %WRAPPER_JAR% to attempt a clean download.';"^
+ " Write-Output 'If you updated your Maven version, you need to update the specified wrapperSha256Sum property.';"^
+ " exit 1;"^
+ "}"^
+ "}"
+ if ERRORLEVEL 1 goto error
+)
+
+@REM Provide a "standardized" way to retrieve the CLI args that will
+@REM work with both Windows and non-Windows executions.
+set MAVEN_CMD_LINE_ARGS=%*
+
+%MAVEN_JAVA_EXE% ^
+ %JVM_CONFIG_MAVEN_PROPS% ^
+ %MAVEN_OPTS% ^
+ %MAVEN_DEBUG_OPTS% ^
+ -classpath %WRAPPER_JAR% ^
+ "-Dmaven.multiModuleProjectDirectory=%MAVEN_PROJECTBASEDIR%" ^
+ %WRAPPER_LAUNCHER% %MAVEN_CONFIG% %*
+if ERRORLEVEL 1 goto error
+goto end
+
+:error
+set ERROR_CODE=1
+
+:end
+@endlocal & set ERROR_CODE=%ERROR_CODE%
+
+if not "%MAVEN_SKIP_RC%"=="" goto skipRcPost
+@REM check for post script, once with legacy .bat ending and once with .cmd ending
+if exist "%USERPROFILE%\mavenrc_post.bat" call "%USERPROFILE%\mavenrc_post.bat"
+if exist "%USERPROFILE%\mavenrc_post.cmd" call "%USERPROFILE%\mavenrc_post.cmd"
+:skipRcPost
+
+@REM pause the script if MAVEN_BATCH_PAUSE is set to 'on'
+if "%MAVEN_BATCH_PAUSE%"=="on" pause
+
+if "%MAVEN_TERMINATE_CMD%"=="on" exit %ERROR_CODE%
+
+cmd /C exit /B %ERROR_CODE%
diff --git a/pom.xml b/pom.xml
new file mode 100644
index 0000000..c7c8b2b
--- /dev/null
+++ b/pom.xml
@@ -0,0 +1,178 @@
+
+
+ 4.0.0
+
+ org.springframework.boot
+ spring-boot-starter-parent
+ 3.2.2
+
+
+ com.batch
+ SpringBatch
+ 0.0.1-SNAPSHOT
+ spring_batch
+ Batch application
+
+ 17
+
+
+
+ org.springframework.boot
+ spring-boot-starter-batch
+
+
+ org.springframework.boot
+ spring-boot-starter-web
+
+
+ org.mybatis.spring.boot
+ mybatis-spring-boot-starter
+ 3.0.3
+
+
+
+ org.postgresql
+ postgresql
+ runtime
+
+
+ com.oracle.database.jdbc
+ ojdbc11
+ runtime
+
+
+ org.projectlombok
+ lombok
+ true
+
+
+ org.springframework.boot
+ spring-boot-starter-test
+ test
+
+
+ org.mybatis.spring.boot
+ mybatis-spring-boot-starter-test
+ 3.0.3
+ test
+
+
+ org.springframework.batch
+ spring-batch-test
+ test
+
+
+ org.springframework.boot
+ spring-boot-devtools
+
+
+
+ com.github.gavlyukovskiy
+ p6spy-spring-boot-starter
+ 1.9.1
+
+
+
+ com.google.code.gson
+ gson
+ 2.10.1
+
+
+
+ org.springframework.batch
+ spring-batch-integration
+ 5.1.0
+
+
+
+
+ org.zeroturnaround
+ zt-exec
+ 1.12
+
+
+
+
+ org.springdoc
+ springdoc-openapi-starter-webmvc-ui
+ 2.3.0
+
+
+
+
+
+
+ org.springframework.boot
+ spring-boot-starter-data-jpa
+ 3.2.3
+
+
+
+ org.springframework.boot
+ spring-boot-starter-security
+ 3.2.3
+
+
+
+ org.springframework.boot
+ spring-boot-starter-validation
+ 3.2.3
+
+
+
+ io.jsonwebtoken
+ jjwt-api
+ 0.12.5
+
+
+
+ io.jsonwebtoken
+ jjwt-impl
+ 0.12.5
+ runtime
+
+
+
+ io.jsonwebtoken
+ jjwt-jackson
+ 0.12.5
+ runtime
+
+
+
+ org.springframework.security
+ spring-security-test
+ 6.2.2
+ test
+
+
+
+ org.mybatis.spring.boot
+ mybatis-spring-boot-starter-test
+ 3.0.3
+ test
+
+
+
+
+
+
+
+
+ org.springframework.boot
+ spring-boot-maven-plugin
+
+
+
+ org.projectlombok
+ lombok
+
+
+
+
+
+
+
+
+
diff --git a/src/main/java/daeucna/MatchingAiApplication.java b/src/main/java/daeucna/MatchingAiApplication.java
new file mode 100644
index 0000000..7855a92
--- /dev/null
+++ b/src/main/java/daeucna/MatchingAiApplication.java
@@ -0,0 +1,17 @@
+package daeucna;
+
+import org.springframework.boot.SpringApplication;
+import org.springframework.boot.autoconfigure.SpringBootApplication;
+import org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration;
+import org.springframework.scheduling.annotation.EnableAsync;
+
+@EnableAsync
+@SpringBootApplication(exclude = {DataSourceAutoConfiguration.class})
+public class MatchingAiApplication {
+
+ public static void main(String[] args) {
+ SpringApplication.run(MatchingAiApplication.class, args);
+
+ }
+
+}
diff --git a/src/main/java/daeucna/batch/controller/JobController.java b/src/main/java/daeucna/batch/controller/JobController.java
new file mode 100644
index 0000000..6e6899e
--- /dev/null
+++ b/src/main/java/daeucna/batch/controller/JobController.java
@@ -0,0 +1,181 @@
+package daeucna.batch.controller;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Map;
+
+import org.springframework.beans.factory.annotation.Autowired;
+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.RestController;
+
+import com.google.gson.JsonObject;
+
+import daeucna.batch.service.JobService;
+import daeucna.batch.util.FileUtil;
+import daeucna.config.batch.MatchingSetup;
+import daeucna.config.batch.MatchingSetup.Matching;
+import daeucna.mapper.primary.batch.MatchingInnerDelingMapper;
+import lombok.extern.slf4j.Slf4j;
+
+@RestController
+@RequestMapping("/api/job")
+@Slf4j
+public class JobController {
+
+ @Autowired
+ private JobService jobService;
+ @Autowired
+ private MatchingInnerDelingMapper matchingInnerDelingMapper;
+
+
+ @PostMapping("/create")
+ public String createJob( @RequestBody Map params) throws Exception {
+
+ /*
+ * {
+ * "sysSe": "LS_ALL",
+ * "accnutYm": "202306",
+ * }
+ */
+ log.debug("Start Create Job");
+ jobService.createData(params);
+ log.debug("End Create Job");
+
+
+ return "신규 작업데이타를 생성합니다. 작업이 끝난후 작업결과는 별도로 확인 바랍니다.";
+ }
+
+
+ @PostMapping("/matching")
+ public String matchingJob( @RequestBody Map params) throws Exception {
+
+ /*
+ * {
+ * "sysSe": "LS_ALL",
+ * "accnutYm": "202306",
+ * }
+ */
+ log.debug("Start Matching Job");
+ jobService.matchingJob(params);
+ log.debug("End Matching Job");
+
+
+ return "매칭작업을 시작합니다. 작업이 끝난후 작업결과는 별도로 확인 바랍니다.";
+ }
+
+ @PostMapping("/extramatching")
+ public String extraMatchingJob( @RequestBody Map params) throws Exception {
+
+ /*
+ * {
+ * "sysSe": "LS_ALL",
+ * "accnutYm": "202306",
+ * }
+ */
+ log.debug("Start Extra Matching Job");
+ List retData = matchingInnerDelingMapper.getCustomItemReadData(params);
+// List retData = new ArrayList();
+// Map m = new HashMap();
+// m.put("sys_se", "LS_ALL");
+// m.put("accnut_ym", "202311");
+// m.put("cpr_code", "A15300");
+// m.put("partn_cpr", "A01100");
+// retData.add(m);
+ for(Map curMap : retData) {
+ jobService.extraJobSub(curMap);
+ }
+ log.debug("End Extra Matching Job");
+
+
+ return "Extra 매칭작업을 시작합니다. 작업이 끝난후 작업결과는 별도로 확인 바랍니다.";
+ }
+
+
+ @PostMapping("/aimatching")
+ public String aiMatchingJob( @RequestBody Map params) throws Exception {
+
+ /*
+ * {
+ * "sysSe": "LS_ALL",
+ * "accnutYm": "202306",
+ * }
+ */
+ log.debug("Start AI Matching Job");
+ List retData = matchingInnerDelingMapper.getAiReadData(params);
+ for(Map curMap : retData) {
+ jobService.aiJobSub(curMap);
+ }
+ log.debug("End AI Matching Job");
+
+
+ return "AI 매칭작업을 시작합니다. 작업이 끝난후 작업결과는 별도로 확인 바랍니다.";
+ }
+
+ @PostMapping("/return")
+ public String returnJob( @RequestBody Map params) throws Exception {
+
+ /*
+ * {
+ * "sysSe": "LS_ALL",
+ * "accnutYm": "202306",
+ * }
+ */
+ log.debug("Start Return Job");
+ jobService.returnRwsultData(params);
+ log.debug("End Return Job");
+
+
+ return "매칭결과 반영을 시작합니다. 작업이 끝난후 작업결과는 별도로 확인 바랍니다.";
+ }
+
+
+ @GetMapping("/configJobStr")
+ public String configJobStr() throws Exception {
+
+ StringBuffer sb = FileUtil.readFileToString("matchingSetup.json");
+
+ return sb.toString();
+ }
+
+ @GetMapping("/configJobJsonObj")
+ public JsonObject configJobJsonObj() throws Exception {
+
+ StringBuffer sb = FileUtil.readFileToString("matchingSetup.json");
+ JsonObject jobj = FileUtil.strToJsonObj(sb.toString());
+
+ return jobj;
+ }
+
+ @GetMapping("/configJobObj")
+ public Object configJobObj() throws Exception {
+
+ StringBuffer sb = FileUtil.readFileToString("matchingSetup.json");
+ MatchingSetup matchingSetup = (MatchingSetup) FileUtil.strToObj(sb.toString(), MatchingSetup.class);
+
+ return matchingSetup;
+ }
+
+ @GetMapping("/config")
+ public Object config() throws Exception {
+ return configJobObj();
+ }
+
+ @GetMapping("/config/jobList")
+ public Object configJobList() throws Exception {
+
+ StringBuffer sb = FileUtil.readFileToString("matchingSetup.json");
+ MatchingSetup matchingSetup = (MatchingSetup) FileUtil.strToObj(sb.toString(), MatchingSetup.class);
+
+ List lJobList = new ArrayList();
+ for (Matching curMatching : matchingSetup.getMatchingSetup()) {
+ lJobList.add(curMatching.getType() + ':' + curMatching.getTypeName());
+ }
+
+ return lJobList;
+ }
+
+
+}
diff --git a/src/main/java/daeucna/batch/request/JobParamsRequest.java b/src/main/java/daeucna/batch/request/JobParamsRequest.java
new file mode 100644
index 0000000..a9408a3
--- /dev/null
+++ b/src/main/java/daeucna/batch/request/JobParamsRequest.java
@@ -0,0 +1,11 @@
+package daeucna.batch.request;
+
+import lombok.Getter;
+import lombok.Setter;
+
+@Setter
+@Getter
+public class JobParamsRequest {
+ private String paramKey;
+ private String paramValue;
+}
\ No newline at end of file
diff --git a/src/main/java/daeucna/batch/service/JobService.java b/src/main/java/daeucna/batch/service/JobService.java
new file mode 100644
index 0000000..5a46e67
--- /dev/null
+++ b/src/main/java/daeucna/batch/service/JobService.java
@@ -0,0 +1,327 @@
+package daeucna.batch.service;
+
+import java.text.SimpleDateFormat;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Date;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.UUID;
+
+import org.springframework.batch.core.BatchStatus;
+import org.springframework.batch.core.Job;
+import org.springframework.batch.core.JobExecution;
+import org.springframework.batch.core.JobParameters;
+import org.springframework.batch.core.JobParametersBuilder;
+import org.springframework.batch.core.JobParametersInvalidException;
+import org.springframework.batch.core.launch.JobLauncher;
+import org.springframework.batch.core.repository.JobExecutionAlreadyRunningException;
+import org.springframework.batch.core.repository.JobInstanceAlreadyCompleteException;
+import org.springframework.batch.core.repository.JobRestartException;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.beans.factory.annotation.Value;
+import org.springframework.context.ApplicationContext;
+import org.springframework.scheduling.annotation.Async;
+import org.springframework.stereotype.Service;
+import org.zeroturnaround.exec.ProcessExecutor;
+import org.zeroturnaround.exec.stream.LogOutputStream;
+
+import daeucna.batch.util.FileUtil;
+import daeucna.config.batch.MatchingExtraProcessorAuto;
+import daeucna.config.batch.MatchingSetup;
+import daeucna.config.batch.MatchingSetup.Matching;
+import daeucna.mapper.primary.batch.MatchingInnerDelingMapper;
+import daeucna.mapper.secondary.batch.OracleMapper;
+import lombok.extern.slf4j.Slf4j;
+
+@Slf4j
+@Service
+public class JobService {
+
+ @Value("${pytyon.path}")
+ String sPythonPrg;
+
+ @Value("${python.ai.target}")
+ String sPythonAiTarget;
+
+ @Autowired
+ private JobLauncher jobLauncher;
+
+ @Autowired
+ private ApplicationContext context;
+
+ @Autowired
+ private MatchingInnerDelingMapper matchingInnerDelingMapper;
+
+ @Autowired
+ private OracleMapper oracleMapper;
+
+
+ @SuppressWarnings("rawtypes")
+ @Async("commAsync")
+ public void matchingJob( Map params) throws Exception {
+
+ long startTime = System.currentTimeMillis();
+ log.info("Job Started : " + startTime);
+ log.debug("params=" + params.toString());
+
+ StringBuffer sb = FileUtil.readFileToString("matchingSetup.json");
+ MatchingSetup matchingSetup = (MatchingSetup) FileUtil.strToObj(sb.toString(), MatchingSetup.class);
+
+ String sJobTypeList = params.get("jobType").toUpperCase();
+ List lJobType = Arrays.asList(sJobTypeList != null?sJobTypeList.split(","):new String[0]);
+
+ //파라미터가 ALL일 경우 ALL 대신 등록된 모든 Type를 넣어준다.
+ if (lJobType.size() > 0 && lJobType.indexOf("ALL") != -1) {
+ lJobType = new ArrayList();
+ for (Matching matching : matchingSetup.getMatchingSetup()) {
+ if (matching.getActive()) {
+ lJobType.add(matching.getType());
+ } else {
+ log.info("JobType(" + matching.getType() + ") is Disabled");
+ }
+ }
+ }
+
+
+ for (String sJobType : lJobType) {
+ log.info("Current running job type: " + sJobType);
+ JobExecution jobExe = invokeJob("matchingInnerDelng", sJobType, params);
+ if (!jobExe.getStatus().equals(BatchStatus.COMPLETED)) {
+ throw new Exception("Job execution error : Batchstatus(" + jobExe.getStatus() + "), ExitStatus(" + jobExe.getExitStatus() + ")" );
+ }
+ }
+
+ long endTime = System.currentTimeMillis();
+ log.info("Job Type : " + lJobType.toString());
+ log.info("Job Ended: " + endTime);
+ log.info("Running Time : " + (endTime - startTime) + "ms");
+
+ }
+
+
+ @SuppressWarnings("rawtypes")
+ @Async("aiAsync")
+ public void extraJobSub(Map paramRec) throws Exception {
+
+ long startTime = System.currentTimeMillis();
+ log.info("Job Started : " + startTime);
+ log.debug("params=" + paramRec.toString());
+
+ MatchingExtraProcessorAuto matchingExtraProcessorAuto = new MatchingExtraProcessorAuto(matchingInnerDelingMapper);
+
+ //2건씩 합산 매칭일 경우 최대 20000건 까지
+ for (int i=0; i<20000;i=i+1000) {
+ matchingExtraProcessorAuto.process(paramRec, 1, 2, 0, i);
+ }
+ for (int i=0; i<20000;i=i+1000) {
+ matchingExtraProcessorAuto.process(paramRec, 2, 1, i, 0);
+ }
+ for (int i=0; i<20000;i=i+1000) {
+ matchingExtraProcessorAuto.process(paramRec, 2, 2, i, i);
+ }
+
+ //3건씩 매칭일 경우 최대 5000건 까지
+ for (int i=0; i<2000;i=i+100) {
+ matchingExtraProcessorAuto.process(paramRec, 1, 3, 0, i);
+ }
+ for (int i=0; i<2000;i=i+100) {
+ matchingExtraProcessorAuto.process(paramRec, 3, 1, i, 0);
+ }
+
+ long endTime = System.currentTimeMillis();
+ log.info("Job Ended: " + endTime);
+ log.info("Running Time : " + (endTime - startTime) + "ms");
+
+ }
+
+ @SuppressWarnings("rawtypes")
+ @Async("aiAsync")
+ public void aiJobSub(Map paramRec) throws Exception {
+
+
+ //Job Create Log
+ UUID uuid = UUID.randomUUID();
+ HashMap mt = new HashMap();
+ SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd-hh-mm-ss");
+ String sDate = dateFormat.format(new Date()) + ":" + uuid.toString();
+
+ Map paramLog = new HashMap();
+ paramLog.put("user_job_id", sDate);
+ paramLog.put("user_job_name", "AI매칭(" + paramRec.toString() + ")");
+ matchingInnerDelingMapper.createUserJob(paramLog);
+
+
+ long startTime = System.currentTimeMillis();
+ log.info("Job Started : " + startTime);
+ log.debug("params=" + paramRec.toString());
+
+ String sSysSe = (String) paramRec.get("sys_se");
+ String sAccnutYm = (String) paramRec.get("accnut_ym");
+ String sCprCode = (String) paramRec.get("cpr_code");
+ String sPartCpr = (String) paramRec.get("partn_cpr");
+ String sDelngCrncy = (String) paramRec.get("delng_crncy");
+
+ log.debug("call python");
+ new ProcessExecutor()
+ .command(sPythonPrg, sPythonAiTarget, sSysSe, sAccnutYm, sCprCode, sPartCpr, sDelngCrncy)
+ .redirectOutput(new LogOutputStream() {
+ @Override
+ protected void processLine(String line) {
+ log.info(line);
+ }
+ })
+ .execute();
+
+ long endTime = System.currentTimeMillis();
+ log.info("Job Ended: " + endTime);
+ log.info("Running Time : " + (endTime - startTime) + "ms");
+
+
+ //작업종료에 대한 로그 업데이트
+ paramLog.put("exit_code", "0");
+ paramLog.put("exit_message", "");
+ matchingInnerDelingMapper.finishUserJob(paramLog);
+
+ }
+
+
+
+ public JobExecution invokeJob(String jobName, String jobType, Map params) throws JobInstanceAlreadyCompleteException, JobExecutionAlreadyRunningException, JobParametersInvalidException, JobRestartException {
+
+ UUID uuid = UUID.randomUUID();
+ HashMap mt = new HashMap();
+ SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd-hh-mm-ss");
+ final String date = dateFormat.format(new Date()) + ":" + uuid.toString();
+ JobParameters jobParameters = new JobParametersBuilder()
+ .addString("syncDate", date)
+ .addString("jobType", jobType)
+ .addString("sysSe", params.get("sysSe"))
+ .addString("accnutYm", params.get("accnutYm"))
+ .addString("searchCond", params.get("searchCond"))
+ .toJobParameters();
+
+ var jobToStart = context.getBean(jobName, Job.class);
+ JobExecution jobExe = jobLauncher.run(jobToStart, jobParameters);
+
+ return jobExe;
+ }
+
+
+
+ @SuppressWarnings("rawtypes")
+ @Async("commAsync")
+ public void createData( Map params) throws Exception {
+
+ //Job Create Log
+ UUID uuid = UUID.randomUUID();
+ HashMap mt = new HashMap();
+ SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd-hh-mm-ss");
+ String sDate = dateFormat.format(new Date()) + ":" + uuid.toString();
+
+ Map paramLog = new HashMap();
+ paramLog.put("user_job_id", sDate);
+ paramLog.put("user_job_name", "작업데이타생성(" + params.toString() + ")");
+ matchingInnerDelingMapper.createUserJob(paramLog);
+
+
+ long startTime = System.currentTimeMillis();
+ log.info("Create Data Started : " + startTime);
+ log.debug("params=" + params.toString());
+
+ //기존데이타 삭제
+ int iDeleted = matchingInnerDelingMapper.deleteOriginalData(params);
+ log.debug("Deleted OrgData : " + iDeleted + "건");
+
+ //신규데이타 생성
+ //매칭키에 대한 정보 (sql로 조인하여 조회하기에는 너무 느리고 데이타 중복도 발생함)
+ List lMatchingInfo = oracleMapper.getMatchingInfo(params);
+ Map mMatchingInfo = new HashMap();
+ for (Map curMap : lMatchingInfo) {
+ String sKey = String.valueOf(curMap.get("SEQ"));
+ mMatchingInfo.put(sKey, curMap);
+ }
+
+ List lOrgData = oracleMapper.getOriginalData(params);
+ int iInserted = 0;
+ int limit = 1000; //1000건씩 batch
+ List lInserted = new ArrayList();
+ for (Map curRec : lOrgData) {
+ String sKey = String.valueOf(curRec.get("SEQ"));
+ Map curMatchingInfo = mMatchingInfo.get(sKey);
+ if (curMatchingInfo != null) {
+ curRec.put("MATCHING_CAUSE", curMatchingInfo.get("MATCHING_CAUSE"));
+ curRec.put("MATCH_KEY", curMatchingInfo.get("MATCH_KEY"));
+ }
+ lInserted.add(curRec);
+ if (lInserted.size() == limit) {
+ matchingInnerDelingMapper.insertOriginalData(Map.of("itemList", lInserted));
+ iInserted = iInserted + lInserted.size();
+ lInserted.clear();
+ }
+ }
+ if (lInserted.size() > 0) {
+ matchingInnerDelingMapper.insertOriginalData(Map.of("itemList", lInserted));
+ iInserted = iInserted + lInserted.size();
+ }
+ log.info("Inserted OrgData : " + iInserted + "건");
+
+ iDeleted = matchingInnerDelingMapper.deleteData(params);
+ log.debug("Deleted Work Data : " + iDeleted + "건");
+ iInserted = matchingInnerDelingMapper.insertDataFromOriginal(params);
+ log.info("Inserted Work Data : " + iInserted + "건");
+
+ iDeleted = matchingInnerDelingMapper.deleteDataAi(params);
+ log.debug("Deleted Work AI Data : " + iDeleted + "건");
+ iInserted = matchingInnerDelingMapper.insertDataAiFromOriginal(params);
+ log.info("Inserted Work AI Data : " + iInserted + "건");
+
+ long endTime = System.currentTimeMillis();
+ log.info("Create Data Ended : " + endTime);
+ log.info("Running Time : " + (endTime - startTime) + "ms");
+
+ //작업종료에 대한 로그 업데이트
+ paramLog.put("exit_code", "0");
+ paramLog.put("exit_message", "");
+ matchingInnerDelingMapper.finishUserJob(paramLog);
+
+ }
+
+
+
+ @SuppressWarnings("rawtypes")
+ @Async("commAsync")
+ public void returnRwsultData( Map params) throws Exception {
+
+ //Job Create Log
+ UUID uuid = UUID.randomUUID();
+ HashMap mt = new HashMap();
+ SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd-hh-mm-ss");
+ String sDate = dateFormat.format(new Date()) + ":" + uuid.toString();
+
+ Map paramLog = new HashMap();
+ paramLog.put("user_job_id", sDate);
+ paramLog.put("user_job_name", "결과데이타리턴(" + params.toString() + ")");
+ matchingInnerDelingMapper.createUserJob(paramLog);
+
+ long startTime = System.currentTimeMillis();
+ log.info("Update Data Started : " + startTime);
+ log.debug("params=" + params.toString());
+
+ //기존데이타 삭제
+ int iUpdated = matchingInnerDelingMapper.updateNewMatchKey(params);
+ log.debug("Updated OrgData : " + iUpdated + "건");
+
+ long endTime = System.currentTimeMillis();
+ log.info("Update Data Ended : " + endTime);
+ log.info("Running Time : " + (endTime - startTime) + "ms");
+
+
+ //작업종료에 대한 로그 업데이트
+ paramLog.put("exit_code", "0");
+ paramLog.put("exit_message", "");
+ matchingInnerDelingMapper.finishUserJob(paramLog);
+
+ }
+}
diff --git a/src/main/java/daeucna/batch/util/FileUtil.java b/src/main/java/daeucna/batch/util/FileUtil.java
new file mode 100644
index 0000000..60ff251
--- /dev/null
+++ b/src/main/java/daeucna/batch/util/FileUtil.java
@@ -0,0 +1,48 @@
+package daeucna.batch.util;
+
+import java.io.BufferedReader;
+import java.io.InputStreamReader;
+
+import org.springframework.core.io.ClassPathResource;
+
+import com.google.gson.Gson;
+import com.google.gson.JsonObject;
+import com.google.gson.JsonParser;
+
+public class FileUtil {
+
+ public static StringBuffer readFileToString(String resourceName) {
+ StringBuffer sb = new StringBuffer();
+ try {
+ ClassPathResource resource = new ClassPathResource(resourceName);
+ BufferedReader br = new BufferedReader(new InputStreamReader(resource.getInputStream()));
+
+ // br.readLine() 이 null 인지 검사할 때 한번 사용되므로 String 에 먼저 저장해둬야한다.
+ String s = "";
+ while((s = br.readLine()) != null){
+ sb.append(s);
+ }
+ } catch (Exception e) {
+ sb.append(e.getStackTrace());
+ }
+ return sb;
+ }
+
+ public static JsonObject strToJsonObj(String jsonString) {
+ JsonObject jsonObject = JsonParser.parseString(jsonString).getAsJsonObject();
+ return jsonObject;
+ }
+
+ public static Object strToObj(String jsonString, Class> anyClass) {
+ Gson gson = new Gson();
+ Object convertedObject = gson.fromJson(jsonString, anyClass);
+ return convertedObject;
+ }
+
+ public static String objToStr(Object obj) {
+ Gson gson = new Gson();
+ String stringObject = gson.toJson(obj);
+ return stringObject;
+ }
+
+}
diff --git a/src/main/java/daeucna/batch/util/StatisticsUtil.java b/src/main/java/daeucna/batch/util/StatisticsUtil.java
new file mode 100644
index 0000000..6ed3d5b
--- /dev/null
+++ b/src/main/java/daeucna/batch/util/StatisticsUtil.java
@@ -0,0 +1,58 @@
+package daeucna.batch.util;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Map;
+
+import lombok.extern.slf4j.Slf4j;
+
+@Slf4j
+public class StatisticsUtil {
+
+// public static void main(String[] args) {
+//
+// List arr = new ArrayList();
+// arr.add(Map.of("col", 100));
+// arr.add(Map.of("col", 200));
+// arr.add(Map.of("col", 300));
+// arr.add(Map.of("col", 400));
+// arr.add(Map.of("col", 500));
+//
+// List result = new ArrayList();
+// List> resultAll = new ArrayList>();
+// reculsion(arr, result, 3, arr.size(), 2, resultAll);
+//
+// log.info("resultAll=" + resultAll.toString());
+// }
+
+ /**
+ * 조합 구하기
+ *
+ * @param arr : 기준 리스트
+ * @param result : 결과를 담아줄 리스트
+ * @param index : 반복문 시작 인덱스
+ * @param n : 전체 갯수
+ * @param r : 뽑을 갯수
+ */
+ public static void reculsion(List arr, List result, int index, int n, int r, List> resultAll) {
+
+ if (r == 0) {
+
+ log.debug("Reuslt=" + result.toString());
+ List lmConfirmList = new ArrayList();
+ lmConfirmList.addAll(result);
+ resultAll.add(lmConfirmList);
+
+ return;
+ }
+
+ for (int i = index; i < n; i++) {
+
+ result.add(arr.get(i));
+ reculsion(arr, result, i + 1, n, r - 1, resultAll);
+ result.remove(result.size() - 1);
+ }
+
+ }
+
+}
diff --git a/src/main/java/daeucna/config/batch/AsyncConfig.java b/src/main/java/daeucna/config/batch/AsyncConfig.java
new file mode 100644
index 0000000..4d3b30d
--- /dev/null
+++ b/src/main/java/daeucna/config/batch/AsyncConfig.java
@@ -0,0 +1,42 @@
+package daeucna.config.batch;
+
+import java.util.concurrent.Executor;
+
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Configuration;
+import org.springframework.scheduling.annotation.EnableAsync;
+import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;
+
+@Configuration
+@EnableAsync
+public class AsyncConfig {
+
+ @Bean(name = "commAsync")
+ public Executor commAsyncExecutor() {
+ ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
+ executor.setCorePoolSize(5);
+ executor.setMaxPoolSize(50);
+ executor.setKeepAliveSeconds(30);
+ executor.setAllowCoreThreadTimeOut(true);
+ executor.setWaitForTasksToCompleteOnShutdown(true);
+ executor.setThreadNamePrefix("commAsync-processor-");
+ executor.initialize();
+
+ return executor;
+ }
+
+ @Bean(name = "aiAsync")
+ public Executor aiAsyncExecutor() {
+ ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
+ executor.setCorePoolSize(50);
+ executor.setMaxPoolSize(100);
+ executor.setQueueCapacity(1000);
+ executor.setKeepAliveSeconds(30);
+ executor.setAllowCoreThreadTimeOut(true);
+ executor.setWaitForTasksToCompleteOnShutdown(true);
+ executor.setThreadNamePrefix("aiAsync-processor-");
+ executor.initialize();
+
+ return executor;
+ }
+}
\ No newline at end of file
diff --git a/src/main/java/daeucna/config/batch/BatchMatchingConfig.java b/src/main/java/daeucna/config/batch/BatchMatchingConfig.java
new file mode 100644
index 0000000..d525d66
--- /dev/null
+++ b/src/main/java/daeucna/config/batch/BatchMatchingConfig.java
@@ -0,0 +1,109 @@
+package daeucna.config.batch;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Map;
+
+import org.springframework.batch.core.Job;
+import org.springframework.batch.core.Step;
+import org.springframework.batch.core.configuration.annotation.JobScope;
+import org.springframework.batch.core.job.builder.JobBuilder;
+import org.springframework.batch.core.launch.support.RunIdIncrementer;
+import org.springframework.batch.core.repository.JobRepository;
+import org.springframework.batch.core.step.builder.StepBuilder;
+import org.springframework.batch.item.ItemProcessor;
+import org.springframework.batch.item.ItemReader;
+import org.springframework.batch.item.ItemWriter;
+import org.springframework.batch.item.adapter.ItemWriterAdapter;
+import org.springframework.batch.item.support.CompositeItemProcessor;
+import org.springframework.batch.item.support.ListItemReader;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Configuration;
+import org.springframework.transaction.PlatformTransactionManager;
+
+import daeucna.mapper.primary.batch.MatchingInnerDelingMapper;
+import lombok.extern.slf4j.Slf4j;
+
+@Configuration
+@Slf4j
+public class BatchMatchingConfig {
+
+ final JobRepository jobRepository;
+ final PlatformTransactionManager batchTransactionManager;
+ private static final int BATCH_SIZE = 50;
+
+ @Autowired
+ MatchingInnerDelingMapper matchingInnerDelingMapper;
+ @Autowired
+ MatchingItemReader customItemReader;
+ @Autowired
+ MatchingItemWriter> matchingItemWriter;
+
+ public BatchMatchingConfig(JobRepository jobRepository, PlatformTransactionManager batchTransactionManager) {
+ this.jobRepository = jobRepository;
+ this.batchTransactionManager = batchTransactionManager;
+ }
+
+ /**
+ * Job which contains multiple steps
+ */
+ @Bean
+ public Job matchingInnerDelng() {
+ return new JobBuilder("자료매칭 job", jobRepository)
+ .incrementer(new RunIdIncrementer())
+ .start(chunkStep())
+ .build();
+ }
+
+ @SuppressWarnings({ "unchecked", "rawtypes" })
+ @Bean
+ @JobScope
+ public Step chunkStep() {
+ log.debug("chunkStep");
+ return new StepBuilder("자료매칭 step", jobRepository)
+ .chunk(BATCH_SIZE, batchTransactionManager)
+ .reader(reader())
+ .processor(compositeProcessor())
+ .writer(writer())
+ .build();
+ }
+
+ @SuppressWarnings({ "rawtypes", "unchecked" })
+ @Bean
+ public CompositeItemProcessor compositeProcessor() {
+ log.debug("CompositeItemProcessor");
+
+ List delegates = new ArrayList<>(2);
+ MatchingItemProcessorAuto customItemProcessorAuto = new MatchingItemProcessorAuto();
+ customItemProcessorAuto.setMapper(matchingInnerDelingMapper);
+ delegates.add(customItemProcessorAuto);
+
+ CompositeItemProcessor processor = new CompositeItemProcessor();
+
+ processor.setDelegates(delegates);
+
+ return processor;
+ }
+
+ @Bean
+ @JobScope
+ public ItemReader reader() {
+
+ log.debug("run ItemReader");
+
+ List lmData = customItemReader.customRead();
+ return new ListItemReader<>(lmData);
+ }
+
+ @Bean
+ public ItemWriter writer() {
+
+ ItemWriterAdapter writer = new ItemWriterAdapter<>();
+ writer.setTargetObject(matchingItemWriter); // 대상 클래스
+ writer.setTargetMethod("customWrite"); // 대상 메서드
+ return writer;
+ }
+
+
+}
\ No newline at end of file
diff --git a/src/main/java/daeucna/config/batch/MatchingExtraProcessorAuto.java b/src/main/java/daeucna/config/batch/MatchingExtraProcessorAuto.java
new file mode 100644
index 0000000..2bdfe7d
--- /dev/null
+++ b/src/main/java/daeucna/config/batch/MatchingExtraProcessorAuto.java
@@ -0,0 +1,226 @@
+package daeucna.config.batch;
+
+import java.math.BigDecimal;
+import java.text.SimpleDateFormat;
+import java.util.ArrayList;
+import java.util.Date;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.UUID;
+
+import daeucna.batch.util.StatisticsUtil;
+import daeucna.mapper.primary.batch.MatchingInnerDelingMapper;
+import lombok.RequiredArgsConstructor;
+import lombok.extern.slf4j.Slf4j;
+
+@Slf4j
+@RequiredArgsConstructor
+public class MatchingExtraProcessorAuto {
+
+ private final MatchingInnerDelingMapper matchingInnerDelingMapper;
+
+ @SuppressWarnings("unchecked")
+ public void process(Map paramRec, int iCmbnOwnCnt, int iCmbnTranCnt, int iStartOwn, int iStartTran) throws Exception {
+
+ //Job Create Log
+ UUID uuid = UUID.randomUUID();
+ HashMap mt = new HashMap();
+ SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd-hh-mm-ss");
+ String sDate = dateFormat.format(new Date()) + ":" + uuid.toString();
+
+ Map paramLog = new HashMap();
+ paramLog.put("user_job_id", sDate);
+ paramLog.put("user_job_name", "자동조합매칭(" + paramRec.toString() + ",[" + iCmbnOwnCnt + "," + iStartOwn + "],[" + iCmbnTranCnt + "," + iStartTran + "])");
+ matchingInnerDelingMapper.createUserJob(paramLog);
+
+
+ int iUpdated = 0;
+
+ String sSysSe = (String) paramRec.get("sys_se");
+ String sAccnutYm = (String) paramRec.get("accnut_ym");
+ String sCprCode = (String) paramRec.get("cpr_code");
+ String sPartCpr = (String) paramRec.get("partn_cpr");
+
+ //작업시작
+ Map mParam = new HashMap();
+ mParam.put("sysSe", sSysSe);
+ mParam.put("accnutYm", sAccnutYm);
+
+ //----------------------------------------------------------------------------
+ //자기법인 데이타 가져오기
+ mParam.put("cprCode", sCprCode);
+ mParam.put("partnCpr", sPartCpr);
+ List lMatchingDataOne = matchingInnerDelingMapper.getMatchingExtraDataOne(mParam);
+
+ //상대법인 데이타 가져오기
+ mParam.put("cprCode", sPartCpr);
+ mParam.put("partnCpr", sCprCode);
+ List lMatchingDataTwo = matchingInnerDelingMapper.getMatchingExtraDataTwo(mParam);
+
+ //Combination 데이타 만들기
+ List compResult = new ArrayList();
+ List> llMatchingDataOne = new ArrayList>();
+ List> llMatchingDataTwo = new ArrayList>();
+
+ int iEndOwn = lMatchingDataOne.size();
+ if (iCmbnOwnCnt == 2) {
+ iEndOwn = iStartOwn + 1000;
+ if (iEndOwn > lMatchingDataOne.size()) iEndOwn = lMatchingDataOne.size();
+ }
+ if (iCmbnOwnCnt > 2) {
+ iEndOwn = iStartOwn + 100;
+ if (iEndOwn > lMatchingDataOne.size()) iEndOwn = lMatchingDataOne.size();
+ }
+ int iEndTran = lMatchingDataTwo.size();
+ if (iCmbnTranCnt == 2) {
+ iEndTran = iStartTran + 1000;
+ if (iEndTran > lMatchingDataTwo.size()) iEndTran = lMatchingDataTwo.size();
+ }
+ if (iCmbnTranCnt > 2) {
+ iEndTran = iStartTran + 100;
+ if (iEndTran > lMatchingDataTwo.size()) iEndTran = lMatchingDataTwo.size();
+ }
+
+ StatisticsUtil.reculsion(lMatchingDataOne, compResult, iStartOwn, iEndOwn, iCmbnOwnCnt, llMatchingDataOne);
+ StatisticsUtil.reculsion(lMatchingDataTwo, compResult, iStartTran, iEndTran, iCmbnTranCnt, llMatchingDataTwo);
+
+ //----------------------------------------------------------------------------
+ //자기법인 데이타를 맵으로 처리한다.
+ Map>> mMatchingDataOne = new HashMap>>();
+ for (List curlMap : llMatchingDataOne) {
+ BigDecimal bdKey = BigDecimal.ZERO;
+ for(Map curMap : curlMap) {
+ bdKey = bdKey.add((BigDecimal) curMap.get("delng_amt"));
+ }
+ List> curllMap = new ArrayList>();
+ if (mMatchingDataOne.containsKey(bdKey)) curllMap = mMatchingDataOne.get(bdKey);
+ curllMap.add(curlMap);
+ mMatchingDataOne.put(bdKey, curllMap);
+ }
+
+ //상대법인 데이타를 맵으로 처리한다.
+ Map>> mMatchingDataTwo = new HashMap>>();
+ for (List curlMap : llMatchingDataTwo) {
+ BigDecimal bdKey = BigDecimal.ZERO;
+ for(Map curMap : curlMap) {
+ bdKey = bdKey.add((BigDecimal) curMap.get("delng_amt"));
+ }
+ List> curllMap = new ArrayList>();
+ if (mMatchingDataTwo.containsKey(bdKey)) curllMap = mMatchingDataTwo.get(bdKey);
+ curllMap.add(curlMap);
+ mMatchingDataTwo.put(bdKey, curllMap);
+ }
+
+ //여기서 매칭 비교
+ //비교 lMatchingDataOne vs mMatchingDataTwo
+ List lMatchingResultUpdate = new ArrayList(); //업데이트할 대상
+
+ int mtchNumber = 0;
+ String mtchSys = "AUTO";
+ String mtchType = "EX_" + iCmbnOwnCnt + "_" + iCmbnTranCnt;
+ String mtchTypeName = "자기(" + iCmbnOwnCnt + "건Sum), 상대(" + iCmbnTranCnt + "건Sum), 비교(금액)";
+ for (BigDecimal curKey : mMatchingDataOne.keySet()) {
+ if (mMatchingDataTwo.containsKey(curKey)) {
+ List> llMapOne = mMatchingDataOne.get(curKey);
+ List> llMapTwo = mMatchingDataTwo.get(curKey);
+
+ //위와 관련된 동일 레코드가 있는 리스트 삭제
+ for (int i=llMapOne.size()-1; i>=0;i--) {
+ List curlMap = llMapOne.get(i);
+ for (Map curMap : lMatchingResultUpdate) {
+ int curIdx = curlMap.indexOf(curMap);
+ if (curIdx != -1) {
+ llMapOne.remove(i);
+ break;
+ }
+ }
+ }
+ for (int i=llMapTwo.size()-1; i>=0;i--) {
+ List curlMap = llMapTwo.get(i);
+ for (Map curMap : lMatchingResultUpdate) {
+ int curIdx = curlMap.indexOf(curMap);
+ if (curIdx != -1) {
+ llMapTwo.remove(i);
+ break;
+ }
+ }
+ }
+
+
+ int iMin = Math.min(llMapOne.size(), llMapTwo.size());
+ if (iMin > 0) mtchNumber++;
+ while (iMin > 0) {
+ List curlMapOne = llMapOne.get(0);
+ for (Map curMap : curlMapOne) {
+ curMap.put("mtch_sys", mtchSys);
+ curMap.put("mtch_ty", mtchType);
+ curMap.put("mtch_ty_nm", mtchTypeName);
+ curMap.put("mtch_ky", mtchNumber);
+ lMatchingResultUpdate.add(curMap);
+ }
+ llMapOne.remove(0);
+
+ List curlMapTwo = llMapTwo.get(0);
+ for (Map curMap : curlMapTwo) {
+ curMap.put("mtch_sys", mtchSys);
+ curMap.put("mtch_ty", mtchType);
+ curMap.put("mtch_ty_nm", mtchTypeName);
+ curMap.put("mtch_ky", mtchNumber);
+ lMatchingResultUpdate.add(curMap);
+ }
+ llMapTwo.remove(0);
+
+ //위와 관련된 동일 레코드가 있는 리스트 삭제(추가 업데이트 목록)
+ for (int i=llMapOne.size()-1; i>=0;i--) {
+ List curlMap = llMapOne.get(i);
+ for (Map curMap : curlMapOne) {
+ int curIdx = curlMap.indexOf(curMap);
+ if (curIdx != -1) {
+ llMapOne.remove(i);
+ break;
+ }
+ }
+ }
+ for (int i=llMapTwo.size()-1; i>=0;i--) {
+ List curlMap = llMapTwo.get(i);
+ for (Map curMap : curlMapTwo) {
+ int curIdx = curlMap.indexOf(curMap);
+ if (curIdx != -1) {
+ llMapTwo.remove(i);
+ break;
+ }
+ }
+ }
+ iMin = Math.min(llMapOne.size(), llMapTwo.size());
+ }
+ }
+ }
+
+ //----------------------------------------------------------------------------
+ //여기서 결과 업데이트
+ iUpdated = 0;
+ int limit = 1000; //1000건씩 batch
+ List lUpdated = new ArrayList();
+ for (Map curMap : lMatchingResultUpdate) {
+ lUpdated.add(curMap);
+ if (lUpdated.size() == limit) {
+ matchingInnerDelingMapper.setExtraResult(Map.of("itemList", lUpdated));
+ iUpdated = iUpdated + lUpdated.size();
+ lUpdated.clear();
+ }
+ }
+ if (lUpdated.size() > 0) {
+ matchingInnerDelingMapper.setExtraResult(Map.of("itemList", lUpdated));
+ iUpdated = iUpdated + lUpdated.size();
+ }
+ log.debug("Updated OrgData : " + iUpdated + "건");
+
+ //작업종료에 대한 로그 업데이트
+ paramLog.put("exit_code", "0");
+ paramLog.put("exit_message", "");
+ matchingInnerDelingMapper.finishUserJob(paramLog);
+
+ }
+
+}
\ No newline at end of file
diff --git a/src/main/java/daeucna/config/batch/MatchingItemProcessorAuto.java b/src/main/java/daeucna/config/batch/MatchingItemProcessorAuto.java
new file mode 100644
index 0000000..8ec0724
--- /dev/null
+++ b/src/main/java/daeucna/config/batch/MatchingItemProcessorAuto.java
@@ -0,0 +1,214 @@
+package daeucna.config.batch;
+
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+import org.springframework.batch.core.configuration.annotation.StepScope;
+import org.springframework.batch.item.ItemProcessor;
+import org.springframework.stereotype.Component;
+
+import daeucna.config.batch.MatchingSetup.Cond;
+import daeucna.config.batch.MatchingSetup.Matching;
+import daeucna.mapper.primary.batch.MatchingInnerDelingMapper;
+import lombok.RequiredArgsConstructor;
+import lombok.extern.slf4j.Slf4j;
+
+@Slf4j
+@StepScope
+@Component
+@RequiredArgsConstructor
+public class MatchingItemProcessorAuto implements ItemProcessor {
+
+ MatchingInnerDelingMapper matchingInnerDelingMapper;
+
+ public void setMapper(MatchingInnerDelingMapper matchingInnerDelingMapper) {
+ this.matchingInnerDelingMapper = matchingInnerDelingMapper;
+ }
+
+ @SuppressWarnings("unchecked")
+ public Map process(Map item) throws Exception {
+ Map params = new HashMap((Map) item.get("jobParameters"));
+ Matching matching = (Matching) item.get("matchingType");
+ Cond condOne = matching.getCondOne();
+ Cond condTwo = matching.getCondTwo();
+ List lCompareField = matching.getCompareField();
+ String mtchType = matching.getType();
+ String mtchTypeName = matching.getTypeName();
+ int mtchNumber = 0;
+ int iUpdated = 0;
+
+ log.debug("CustomItemProcessorA.params : " + params.toString());
+ log.debug("CustomItemProcessorA.item : " + item.get("cpr_code") + "," + item.get("partn_cpr"));
+
+ //----------------------------------------------------------------------------
+ //자기법인 업데이트
+ params.put("cprCode", item.get("cpr_code"));
+ params.put("partnCpr", item.get("partn_cpr"));
+
+ params.put("cond", condOne.getCond() ); //조건리스트
+ params.put("compareKey", matching.getCompareKey() );
+ params.put("makeCompareKey", "'" + mtchType + ":' || " + condOne.getMakeCompareKey() );
+
+ iUpdated = matchingInnerDelingMapper.setDataMakeCompareKy(params);
+ log.debug("matchingInnerDelingMapper.setDataMakeCompareKy ; " + iUpdated);
+
+ //상대법인업데이트
+ params.put("cprCode", item.get("partn_cpr"));
+ params.put("partnCpr", item.get("cpr_code"));
+
+ params.put("cond", condTwo.getCond() ); //조건리스트
+ params.put("compareKey", matching.getCompareKey() );
+ params.put("makeCompareKey", "'" + mtchType + ":' || " + condTwo.getMakeCompareKey() );
+
+ iUpdated = matchingInnerDelingMapper.setDataMakeCompareKy(params);
+ log.debug("matchingInnerDelingMapper.setDataMakeCompareKy ; " + iUpdated);
+
+ //----------------------------------------------------------------------------
+ //자기법인 데이타 가져오기
+ params.put("cprCode", item.get("cpr_code"));
+ params.put("partnCpr", item.get("partn_cpr"));
+ params.put("amtField", matching.getAmtField());
+ params.put("cond", condOne.getCond() ); //조건리스트
+ List lMatchingDataOne = matchingInnerDelingMapper.getMatchingData(params);
+
+ //상대법인 데이타 가져오기
+ params.put("cprCode", item.get("partn_cpr"));
+ params.put("partnCpr", item.get("cpr_code"));
+ params.put("amtField", matching.getAmtField());
+ params.put("cond", condTwo.getCond() ); //조건리스트
+ List lMatchingDataTwo = matchingInnerDelingMapper.getMatchingData(params);
+
+ //----------------------------------------------------------------------------
+ //자기법인 데이타를 맵으로 처리한다.
+ Map> mMatchingDataOne = new HashMap>();
+ for (Map curMap : lMatchingDataOne) {
+ StringBuffer sbKey = new StringBuffer();
+ for (String curField : lCompareField) {
+ if (sbKey.length() > 0) sbKey.append(":");
+ sbKey.append(curMap.get(curField).toString());
+ }
+
+ List curlMap = new ArrayList();
+ String sKey = sbKey.toString();
+ if (mMatchingDataOne.containsKey(sKey)) curlMap = mMatchingDataOne.get(sKey);
+ curlMap.add(curMap);
+ mMatchingDataOne.put(sKey, curlMap);
+ }
+
+ //상대법인 데이타를 맵으로 처리한다.
+ Map> mMatchingDataTwo = new HashMap>();
+ for (Map curMap : lMatchingDataTwo) {
+ StringBuffer sbKey = new StringBuffer();
+ for (String curField : lCompareField) {
+ if (sbKey.length() > 0) sbKey.append(":");
+ sbKey.append(curMap.get(curField).toString());
+ }
+
+ List curlMap = new ArrayList();
+ String sKey = sbKey.toString();
+ if (mMatchingDataTwo.containsKey(sKey)) curlMap = mMatchingDataTwo.get(sKey);
+ curlMap.add(curMap);
+ mMatchingDataTwo.put(sKey, curlMap);
+ }
+
+ //여기서 매칭 비교
+ //비교 lMatchingDataOne vs mMatchingDataTwo
+ for (String curKey : mMatchingDataOne.keySet()) {
+ if (mMatchingDataTwo.containsKey(curKey)) {
+ List lMapOne = mMatchingDataOne.get(curKey);
+ List lMapTwo = mMatchingDataTwo.get(curKey);
+
+ int iMin = Math.min(lMapOne.size(), lMapTwo.size());
+ if (iMin > 0) mtchNumber++;
+ for (int i=0; i lMatchingResultUpdate = new ArrayList(); //업데이트할 대상
+ String sCompareKey = matching.getCompareKey();
+
+ //자기법인 데이타 가져오기
+ params.put("cprCode", item.get("cpr_code"));
+ params.put("partnCpr", item.get("partn_cpr"));
+ params.put("cond", condOne.getCond() ); //조건리스트
+ List lMatchingResultOne = matchingInnerDelingMapper.getMatchingResult(params);
+
+ Map mMatchingResultOne = new HashMap();
+ for (Map curMap : lMatchingDataOne) {
+ String curComapreKeyVal = (String)curMap.get(sCompareKey);
+ boolean curBlnMatching = curMap.get("mtchType")!=null && curMap.get("mtchNumber")!=null;
+ if (curBlnMatching) mMatchingResultOne.put(curComapreKeyVal, curMap);
+ }
+ for (Map curMap : lMatchingResultOne) {
+ String curComapreKeyVal = (String)curMap.get(sCompareKey);
+ if ( mMatchingResultOne.containsKey(curComapreKeyVal) ) {
+ Map mResult = mMatchingResultOne.get(curComapreKeyVal);
+ curMap.put(matching.getMatchingType() , mResult.get("mtchType"));
+ curMap.put(matching.getMatchingTypeName(), mResult.get("mtchTypeName"));
+ curMap.put(matching.getMatchingNumber(), mResult.get("mtchNumber"));
+ lMatchingResultUpdate.add(curMap);
+ }
+ }
+
+ //상대법인 데이타 가져오기
+ params.put("cprCode", item.get("partn_cpr"));
+ params.put("partnCpr", item.get("cpr_code"));
+ params.put("cond", condTwo.getCond() ); //조건리스트
+ List lMatchingResultTwo = matchingInnerDelingMapper.getMatchingResult(params);
+
+ Map mMatchingResultTwo = new HashMap();
+ for (Map curMap : lMatchingDataTwo) {
+ String curComapreKeyVal = (String)curMap.get(sCompareKey);
+ boolean curBlnMatching = curMap.get("mtchType")!=null && curMap.get("mtchNumber")!=null;
+ if (curBlnMatching) mMatchingResultTwo.put(curComapreKeyVal, curMap);
+ }
+ for (Map curMap : lMatchingResultTwo) {
+ String curComapreKeyVal = (String)curMap.get(sCompareKey);
+ if ( mMatchingResultTwo.containsKey(curComapreKeyVal) ) {
+ Map mResult = mMatchingResultTwo.get(curComapreKeyVal);
+ curMap.put(matching.getMatchingType() , mResult.get("mtchType"));
+ curMap.put(matching.getMatchingTypeName(), mResult.get("mtchTypeName"));
+ curMap.put(matching.getMatchingNumber(), mResult.get("mtchNumber"));
+ lMatchingResultUpdate.add(curMap);
+ }
+ }
+
+ iUpdated = 0;
+ int limit = 1000; //1000건씩 batch
+ List lUpdated = new ArrayList();
+ for (Map curMap : lMatchingResultUpdate) {
+ curMap.put("matchingType", matching.getMatchingType());
+ curMap.put("matchingTypeVal", curMap.get(matching.getMatchingType()));
+ curMap.put("matchingTypeName", matching.getMatchingTypeName());
+ curMap.put("matchingTypeNameVal", curMap.get(matching.getMatchingTypeName()));
+ curMap.put("matchingNumber", matching.getMatchingNumber());
+ curMap.put("matchingNumberVal", curMap.get(matching.getMatchingNumber()));
+ lUpdated.add(curMap);
+ if (lUpdated.size() == limit) {
+ matchingInnerDelingMapper.setResult(Map.of("itemList", lUpdated));
+ iUpdated = iUpdated + lUpdated.size();
+ lUpdated.clear();
+ }
+ }
+ if (lUpdated.size() > 0) {
+ matchingInnerDelingMapper.setResult(Map.of("itemList", lUpdated));
+ iUpdated = iUpdated + lUpdated.size();
+ }
+ log.debug("Updated OrgData : " + iUpdated + "건");
+
+ //작업이 정상적으로 작동 되었을 경우 현재 처리하고 있는 데이타 그대로 넘겨준다.
+ return item;
+ }
+}
\ No newline at end of file
diff --git a/src/main/java/daeucna/config/batch/MatchingItemReader.java b/src/main/java/daeucna/config/batch/MatchingItemReader.java
new file mode 100644
index 0000000..1e2aa1a
--- /dev/null
+++ b/src/main/java/daeucna/config/batch/MatchingItemReader.java
@@ -0,0 +1,52 @@
+package daeucna.config.batch;
+
+import java.util.List;
+import java.util.Map;
+
+import org.springframework.batch.core.configuration.annotation.StepScope;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.beans.factory.annotation.Value;
+import org.springframework.stereotype.Component;
+
+import daeucna.batch.util.FileUtil;
+import daeucna.config.batch.MatchingSetup.Matching;
+import daeucna.mapper.primary.batch.MatchingInnerDelingMapper;
+import lombok.RequiredArgsConstructor;
+import lombok.extern.slf4j.Slf4j;
+
+@Slf4j
+@Component
+@StepScope
+@RequiredArgsConstructor
+public class MatchingItemReader {
+
+ @Value("#{jobParameters}")
+ private final Map params;
+
+ @Autowired
+ MatchingInnerDelingMapper matchingInnerDelingMapper;
+
+ /*
+ * 자기 상대 법인단위로 작업할 단위를 읽는다.
+ */
+ public List customRead(){
+ log.debug("customRead.params : " + this.params.toString());
+ // customRead.params : {sysSe=KUMKANG, searchCond=mtch_ky is null, run.id=1, syncDate=2024-02-02-03-52-27:50deede8-ce3d-4841-ba65-f733bdd38533, jobType=F, accnutYm=202112}
+ String sMatchType = this.params.get("jobType");
+ StringBuffer sb = FileUtil.readFileToString("matchingSetup.json");
+ MatchingSetup matchingSetup = (MatchingSetup) FileUtil.strToObj(sb.toString(), MatchingSetup.class);
+ Matching matcning = matchingSetup.getMatching(sMatchType);
+
+ List retData = matchingInnerDelingMapper.getCustomItemReadData(this.params);
+
+ //레코드에 jobParameters 정보 추가
+ for (Map rec : retData) {
+ rec.put("jobParameters", this.params);
+ rec.put("matchingType", matcning);
+ }
+
+ log.debug(">> customRead >> " + FileUtil.objToStr(retData));
+ return retData;
+ }
+
+}
diff --git a/src/main/java/daeucna/config/batch/MatchingItemWriter.java b/src/main/java/daeucna/config/batch/MatchingItemWriter.java
new file mode 100644
index 0000000..0d9cd8b
--- /dev/null
+++ b/src/main/java/daeucna/config/batch/MatchingItemWriter.java
@@ -0,0 +1,35 @@
+package daeucna.config.batch;
+
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+import org.springframework.batch.core.configuration.annotation.JobScope;
+import org.springframework.batch.item.ItemProcessor;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.beans.factory.annotation.Value;
+import org.springframework.stereotype.Component;
+
+import daeucna.mapper.primary.batch.MatchingInnerDelingMapper;
+import lombok.RequiredArgsConstructor;
+import lombok.extern.slf4j.Slf4j;
+
+@Slf4j
+@Component
+@RequiredArgsConstructor
+public class MatchingItemWriter {
+
+ @Autowired
+ MatchingInnerDelingMapper matchingInnerDelingMapper;
+
+ @SuppressWarnings("unchecked")
+ public void customWrite(T item){
+ Map params = (Map) ((Map) item).get("jobParameters");
+
+ log.debug("customWrite.params : " + params.toString());
+
+// matchingInnerDelingMapper.setTest((Map) item);
+ log.debug("item test = " + item);
+ }
+
+}
diff --git a/src/main/java/daeucna/config/batch/MatchingSetup.java b/src/main/java/daeucna/config/batch/MatchingSetup.java
new file mode 100644
index 0000000..7d5b79d
--- /dev/null
+++ b/src/main/java/daeucna/config/batch/MatchingSetup.java
@@ -0,0 +1,116 @@
+package daeucna.config.batch;
+
+import java.math.BigDecimal;
+import java.util.ArrayList;
+import java.util.List;
+
+import lombok.Data;
+
+@Data
+public class MatchingSetup {
+
+ List matchingSetup;
+
+ @Data
+ public class Matching {
+ String type;
+ String typeName;
+ Cond condOne;
+ Cond condTwo;
+ List uniqueKey;
+ String compareKey;
+ List compareField;
+ String amtField;
+ String matchingType;
+ String matchingTypeName;
+ String matchingNumber;
+ Boolean active;
+
+ public Matching() {
+ this.uniqueKey = new ArrayList();
+ this.condOne = new Cond();
+ this.condTwo = new Cond();
+ this.compareField = new ArrayList();
+ }
+
+ };
+
+ @Data
+ public class Cond {
+ List cond;
+ List makeCompareKey;
+
+ public Cond() {
+ this.cond = new ArrayList();
+ this.makeCompareKey = new ArrayList();
+ }
+
+ public String getMakeCompareKey() {
+ StringBuffer sbMakeCompareKey = new StringBuffer();
+
+ for (String curStr : this.makeCompareKey) {
+ if (sbMakeCompareKey.length() > 0) sbMakeCompareKey.append(" || ':' || ");
+ sbMakeCompareKey.append(curStr);
+ }
+ String sRtnVal = sbMakeCompareKey.toString();
+ if (sRtnVal.length() < this.makeCompareKey.size()) sRtnVal = "NULL";
+ return sbMakeCompareKey.toString();
+ }
+ }
+
+ public Matching getMatching(String sName) {
+ Matching matching = null;
+
+ for (Matching curObj : this.matchingSetup) {
+ if (curObj.getType().equalsIgnoreCase(sName)) {
+ matching = curObj;
+ break;
+ }
+ }
+
+ return matching;
+ }
+
+}
+
+/*
+ * 예시 데이타
+ */
+/*
+{
+ "matchingSetup": [
+ {
+ "type": "A1",
+ "typeName": "A type",
+
+ "condOne": {
+ "cond": [
+ "dta_ty in ('11', '12')"
+ ],
+ "makeCompareKey": [
+ "cmpnsp_ky"
+ ]
+ },
+ "condTwo": {
+ "cond": [
+ "dta_ty in ('21', '22')"
+ ],
+ "makeCompareKey": [
+ "cmpnsp_ky"
+ ]
+ },
+ "uniqueKey": [
+ "sys_se",
+ "accnut_ym",
+ "sn"
+ ],
+ "compareKey": "compare_ky",
+ "amtField": "delng_amt",
+ "compareField": [
+ "accnut_ym",
+ "compare_ky"
+ ]
+ },
+ ]
+}
+*/
\ No newline at end of file
diff --git a/src/main/java/daeucna/config/datasource/MultipleDataSourceConfiguration.java b/src/main/java/daeucna/config/datasource/MultipleDataSourceConfiguration.java
new file mode 100644
index 0000000..3046eff
--- /dev/null
+++ b/src/main/java/daeucna/config/datasource/MultipleDataSourceConfiguration.java
@@ -0,0 +1,46 @@
+package daeucna.config.datasource;
+
+import javax.sql.DataSource;
+
+import org.springframework.beans.factory.annotation.Qualifier;
+import org.springframework.boot.context.properties.ConfigurationProperties;
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Configuration;
+import org.springframework.context.annotation.Primary;
+
+import com.zaxxer.hikari.HikariConfig;
+import com.zaxxer.hikari.HikariDataSource;
+
+@Configuration
+public class MultipleDataSourceConfiguration {
+
+
+ @Bean
+ @Primary
+ @Qualifier("primaryHikariConfig")
+ @ConfigurationProperties(prefix="spring.datasource.hikari.primary")
+ public HikariConfig primaryHikariConfig() {
+ return new HikariConfig();
+ }
+
+ @Bean
+ @Primary
+ @Qualifier("primaryDataSource")
+ public DataSource primaryDataSource() throws Exception {
+ return new HikariDataSource(primaryHikariConfig());
+ }
+
+ @Bean
+ @Qualifier("secondaryHikariConfig")
+ @ConfigurationProperties(prefix="spring.datasource.hikari.secondary")
+ public HikariConfig secondaryHikariConfig() {
+ return new HikariConfig();
+ }
+
+ @Bean
+ @Qualifier("secondaryDataSource")
+ public DataSource secondaryDataSource() throws Exception {
+ return new HikariDataSource(secondaryHikariConfig());
+ }
+
+}
diff --git a/src/main/java/daeucna/config/datasource/PrimaryMybatisConfiguration.java b/src/main/java/daeucna/config/datasource/PrimaryMybatisConfiguration.java
new file mode 100644
index 0000000..5024a51
--- /dev/null
+++ b/src/main/java/daeucna/config/datasource/PrimaryMybatisConfiguration.java
@@ -0,0 +1,39 @@
+package daeucna.config.datasource;
+
+import javax.sql.DataSource;
+
+import org.apache.ibatis.session.SqlSessionFactory;
+import org.mybatis.spring.SqlSessionFactoryBean;
+import org.mybatis.spring.SqlSessionTemplate;
+import org.mybatis.spring.annotation.MapperScan;
+import org.springframework.beans.factory.annotation.Qualifier;
+import org.springframework.context.ApplicationContext;
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Configuration;
+import org.springframework.context.annotation.Primary;
+import org.springframework.transaction.annotation.EnableTransactionManagement;
+
+@Configuration
+@MapperScan(value = "daeucna.mapper.primary", sqlSessionFactoryRef="primarySqlSessionFactory")
+public class PrimaryMybatisConfiguration {
+
+ @Primary
+ @Bean(name = "primarySqlSessionFactory")
+ public SqlSessionFactory sqlSessionFactory(
+ @Qualifier("primaryDataSource") DataSource dataSource, ApplicationContext applicationContext) throws Exception {
+ SqlSessionFactoryBean sqlSessionFactoryBean = new SqlSessionFactoryBean();
+ sqlSessionFactoryBean.setDataSource(dataSource);
+ sqlSessionFactoryBean.setConfigLocation(applicationContext.getResource("classpath:mybatis/mybatis-config.xml"));
+ sqlSessionFactoryBean.setMapperLocations(applicationContext.getResources("classpath:mybatis/primary/**/*.xml"));
+
+ return sqlSessionFactoryBean.getObject();
+ }
+
+ @Primary
+ @Bean(name = "primarySqlSessionTemplate")
+ public SqlSessionTemplate sqlSessionTemplate(
+ @Qualifier("primarySqlSessionFactory") SqlSessionFactory sqlSessionFactory) {
+ return new SqlSessionTemplate(sqlSessionFactory);
+ }
+
+}
diff --git a/src/main/java/daeucna/config/datasource/SecondaryMyBatisConfiguration.java b/src/main/java/daeucna/config/datasource/SecondaryMyBatisConfiguration.java
new file mode 100644
index 0000000..5e803d1
--- /dev/null
+++ b/src/main/java/daeucna/config/datasource/SecondaryMyBatisConfiguration.java
@@ -0,0 +1,36 @@
+package daeucna.config.datasource;
+
+import javax.sql.DataSource;
+
+import org.apache.ibatis.session.SqlSessionFactory;
+import org.mybatis.spring.SqlSessionFactoryBean;
+import org.mybatis.spring.SqlSessionTemplate;
+import org.mybatis.spring.annotation.MapperScan;
+import org.springframework.beans.factory.annotation.Qualifier;
+import org.springframework.context.ApplicationContext;
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Configuration;
+import org.springframework.transaction.annotation.EnableTransactionManagement;
+
+@Configuration
+@MapperScan(value = "daeucna.mapper.secondary", sqlSessionFactoryRef="secondarySqlSessionFactory")
+public class SecondaryMyBatisConfiguration {
+
+ @Bean(name = "secondarySqlSessionFactory")
+ public SqlSessionFactory sqlSessionFactory(
+ @Qualifier("secondaryDataSource") DataSource dataSource, ApplicationContext applicationContext) throws Exception {
+ SqlSessionFactoryBean sqlSessionFactoryBean = new SqlSessionFactoryBean();
+ sqlSessionFactoryBean.setDataSource(dataSource);
+ sqlSessionFactoryBean.setConfigLocation(applicationContext.getResource("classpath:mybatis/mybatis-config.xml"));
+ sqlSessionFactoryBean.setMapperLocations(applicationContext.getResources("classpath:mybatis/secondary/**/*.xml"));
+
+ return sqlSessionFactoryBean.getObject();
+ }
+
+ @Bean(name = "secondarySqlSessionTemplate")
+ public SqlSessionTemplate sqlSessionTemplate(
+ @Qualifier("secondarySqlSessionFactory") SqlSessionFactory sqlSessionFactory) {
+ return new SqlSessionTemplate(sqlSessionFactory);
+ }
+
+}
diff --git a/src/main/java/daeucna/config/handler/RootController.java b/src/main/java/daeucna/config/handler/RootController.java
new file mode 100644
index 0000000..39aa3d4
--- /dev/null
+++ b/src/main/java/daeucna/config/handler/RootController.java
@@ -0,0 +1,20 @@
+package daeucna.config.handler;
+
+import org.springframework.boot.web.servlet.error.ErrorController;
+import org.springframework.stereotype.Controller;
+import org.springframework.web.bind.annotation.GetMapping;
+
+@Controller
+public class RootController implements ErrorController {
+ // url 직접 접근할 경우 대체 경로 추가
+ private final String ERROR_PATH = "/error";
+
+ @GetMapping(ERROR_PATH)
+ public String redirectRoot(){
+ return "forward:/index.html";
+ }
+
+ public String getErrorPath(){
+ return null;
+ }
+}
\ No newline at end of file
diff --git a/src/main/java/daeucna/config/p6spy/P6SpyFomatter.java b/src/main/java/daeucna/config/p6spy/P6SpyFomatter.java
new file mode 100644
index 0000000..f0b699f
--- /dev/null
+++ b/src/main/java/daeucna/config/p6spy/P6SpyFomatter.java
@@ -0,0 +1,40 @@
+package daeucna.config.p6spy;
+
+import java.util.Locale;
+
+import org.hibernate.engine.jdbc.internal.FormatStyle;
+import org.springframework.context.annotation.Configuration;
+
+import com.p6spy.engine.logging.Category;
+import com.p6spy.engine.spy.P6SpyOptions;
+import com.p6spy.engine.spy.appender.MessageFormattingStrategy;
+
+import jakarta.annotation.PostConstruct;
+
+@Configuration
+public class P6SpyFomatter implements MessageFormattingStrategy {
+
+ @PostConstruct
+ public void setLogMessageFormat() {
+ P6SpyOptions.getActiveInstance().setLogMessageFormat(this.getClass().getName());
+ }
+
+ @Override
+ public String formatMessage(int connectionId, String now, long elapsed, String category, String prepared, String sql, String url) {
+ sql = formatSql(category, sql);
+ return String.format("[%s] | %d ms | %s", category, elapsed, formatSql(category, sql));
+ }
+
+ private String formatSql(String category, String sql) {
+ if (sql != null && !sql.trim().isEmpty() && Category.STATEMENT.getName().equals(category)) {
+ String trimmedSQL = sql.trim().toLowerCase(Locale.ROOT);
+ if (trimmedSQL.startsWith("create") || trimmedSQL.startsWith("alter") || trimmedSQL.startsWith("comment")) {
+ sql = FormatStyle.DDL.getFormatter().format(sql);
+ } else {
+ sql = FormatStyle.BASIC.getFormatter().format(sql);
+ }
+ return sql;
+ }
+ return sql;
+ }
+}
\ No newline at end of file
diff --git a/src/main/java/daeucna/config/security/JwtSecurityConfig.java b/src/main/java/daeucna/config/security/JwtSecurityConfig.java
new file mode 100644
index 0000000..182bed1
--- /dev/null
+++ b/src/main/java/daeucna/config/security/JwtSecurityConfig.java
@@ -0,0 +1,25 @@
+package daeucna.config.security;
+
+import org.springframework.security.config.annotation.SecurityConfigurerAdapter;
+import org.springframework.security.config.annotation.web.builders.HttpSecurity;
+import org.springframework.security.web.DefaultSecurityFilterChain;
+import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter;
+
+import daeucna.config.security.jwt.JwtFilter;
+import daeucna.config.security.jwt.JwtTokenProvider;
+import lombok.RequiredArgsConstructor;
+
+@RequiredArgsConstructor
+public class JwtSecurityConfig extends SecurityConfigurerAdapter {
+ private final JwtTokenProvider tokenProvider;
+
+ @Override
+ public void configure(HttpSecurity http) {
+
+ // security 로직에 JwtFilter 등록
+ http.addFilterBefore(
+ new JwtFilter(tokenProvider),
+ UsernamePasswordAuthenticationFilter.class
+ );
+ }
+}
\ No newline at end of file
diff --git a/src/main/java/daeucna/config/security/SecurityConfig.java b/src/main/java/daeucna/config/security/SecurityConfig.java
new file mode 100644
index 0000000..a413d72
--- /dev/null
+++ b/src/main/java/daeucna/config/security/SecurityConfig.java
@@ -0,0 +1,69 @@
+package daeucna.config.security;
+
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Configuration;
+import org.springframework.security.config.Customizer;
+import org.springframework.security.config.annotation.web.builders.HttpSecurity;
+import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
+import org.springframework.security.config.annotation.web.configurers.AbstractHttpConfigurer;
+import org.springframework.security.config.http.SessionCreationPolicy;
+import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
+import org.springframework.security.crypto.password.PasswordEncoder;
+import org.springframework.security.web.SecurityFilterChain;
+
+import daeucna.config.security.jwt.JwtAuthenticationEntryPoint;
+import daeucna.config.security.jwt.JwtTokenProvider;
+import lombok.RequiredArgsConstructor;
+
+@Configuration
+@EnableWebSecurity
+@RequiredArgsConstructor
+public class SecurityConfig {
+
+ private final JwtTokenProvider tokenProvider;
+ private final JwtAuthenticationEntryPoint jwtAuthenticationEntryPoint;
+
+ // PasswordEncoder는 BCryptPasswordEncoder를 사용
+ @Bean
+ public PasswordEncoder passwordEncoder() {
+ return new BCryptPasswordEncoder();
+ }
+
+ @Bean
+ public SecurityFilterChain filterChain(HttpSecurity httpSecurity) throws Exception {
+ httpSecurity
+ // token을 사용하는 방식이기 때문에 csrf를 disable합니다.
+ .csrf(AbstractHttpConfigurer::disable)
+ .securityMatcher("/api/**")
+ .authorizeHttpRequests((authorizeHttpRequests) ->
+ authorizeHttpRequests
+ .requestMatchers("/api/admin/**").hasRole("ADMIN")
+ .requestMatchers("/api/authenticate").permitAll() // 로그인 api
+ .requestMatchers("/api/refreshtoken").permitAll() // Refresh Token api
+ .requestMatchers("/api/signup").permitAll() // 회원가입 api
+ .requestMatchers("/api/exceptionDenied").permitAll() // Exception Denied
+// .anyRequest().permitAll()
+ .anyRequest().authenticated() // 그 외 인증 없이 접근X
+ )
+ .formLogin(Customizer.withDefaults())
+ .headers((headers) ->
+ headers
+ .frameOptions(frameOptions -> frameOptions
+ .sameOrigin()
+ )
+ )
+ .exceptionHandling(exceptionHandling -> exceptionHandling
+ .authenticationEntryPoint(jwtAuthenticationEntryPoint)
+ .accessDeniedPage("/api/exceptionDenied")
+ )
+ // 세션을 사용하지 않기 때문에 STATELESS로 설정
+ .sessionManagement((sessionManagement) ->
+ sessionManagement
+ .sessionCreationPolicy(SessionCreationPolicy.STATELESS)
+ )
+ .apply(new JwtSecurityConfig(tokenProvider)); // JwtFilter를 addFilterBefore로 등록했던 JwtSecurityConfig class 적용
+
+ return httpSecurity.build();
+ }
+
+}
\ No newline at end of file
diff --git a/src/main/java/daeucna/config/security/UserInitializer.java b/src/main/java/daeucna/config/security/UserInitializer.java
new file mode 100644
index 0000000..61d4efe
--- /dev/null
+++ b/src/main/java/daeucna/config/security/UserInitializer.java
@@ -0,0 +1,44 @@
+package daeucna.config.security;
+import java.util.Arrays;
+import java.util.HashSet;
+
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.boot.ApplicationArguments;
+import org.springframework.boot.ApplicationRunner;
+import org.springframework.core.env.Environment;
+import org.springframework.stereotype.Component;
+
+import daeucna.config.security.dto.AuthorityDto;
+import daeucna.config.security.dto.UserDto;
+import daeucna.config.security.service.UserService;
+
+@Component
+public class UserInitializer implements ApplicationRunner {
+
+ private final UserService userService;
+ private final Environment env;
+
+ @Autowired
+ public UserInitializer(Environment env, UserService userService) {
+ this.userService = userService;
+ this.env = env;
+ }
+
+ @Override
+ public void run(ApplicationArguments args) {
+ //초기 Admin User 넣어주기
+ AuthorityDto authorityDto = AuthorityDto.builder().authorityName("ROLE_ADMIN").build();
+ UserDto userDto = UserDto.builder()
+ .username("sangkiham")
+ .password("sangkiham")
+ .nickname("sangkiham")
+ .authorityDtoSet(new HashSet( Arrays.asList(authorityDto) ))
+ .build();
+
+ //사용자 정보가 없으면 Insert한다.
+ boolean blnAdminInit = Boolean.parseBoolean(env.getProperty("admin.init"));
+ if (blnAdminInit && userService.getUserWithAuthorities(userDto.getUsername()) == null) {
+ userService.signup(userDto);
+ }
+ }
+}
\ No newline at end of file
diff --git a/src/main/java/daeucna/config/security/controller/AuthController.java b/src/main/java/daeucna/config/security/controller/AuthController.java
new file mode 100644
index 0000000..55e1e52
--- /dev/null
+++ b/src/main/java/daeucna/config/security/controller/AuthController.java
@@ -0,0 +1,98 @@
+package daeucna.config.security.controller;
+
+import java.util.HashMap;
+
+import org.springframework.beans.factory.annotation.Value;
+import org.springframework.http.HttpHeaders;
+import org.springframework.http.HttpStatus;
+import org.springframework.http.ResponseEntity;
+import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
+import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
+import org.springframework.security.core.Authentication;
+import org.springframework.security.core.context.SecurityContextHolder;
+import org.springframework.web.bind.annotation.PostMapping;
+import org.springframework.web.bind.annotation.RequestBody;
+import org.springframework.web.bind.annotation.RequestHeader;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RestController;
+
+import daeucna.config.security.dto.LoginDto;
+import daeucna.config.security.dto.TokenDto;
+import daeucna.config.security.jwt.JwtFilter;
+import daeucna.config.security.jwt.JwtTokenProvider;
+import daeucna.config.security.utils.CommonJson;
+import io.jsonwebtoken.Claims;
+import io.jsonwebtoken.Jws;
+import jakarta.validation.Valid;
+import lombok.RequiredArgsConstructor;
+import lombok.extern.slf4j.Slf4j;
+
+@RestController
+@RequestMapping("/api")
+@RequiredArgsConstructor
+@Slf4j
+public class AuthController {
+ private final JwtTokenProvider tokenProvider;
+ private final AuthenticationManagerBuilder authenticationManagerBuilder;
+
+ @PostMapping("/authenticate")
+ public ResponseEntity authorize(
+ @Valid @RequestBody LoginDto loginDto,
+ @Value("${jwt.token-validity-in-seconds}") long tokenValidityInSeconds,
+ @Value("${jwt.refresh-token-validity-in-seconds}") long refreshTokenValidityInSeconds
+ ) {
+
+ return fnAuthorize(loginDto, tokenValidityInSeconds, refreshTokenValidityInSeconds, false);
+ }
+
+ public ResponseEntity fnAuthorize(LoginDto loginDto, long tokenValidityInSeconds, long refreshTokenValidityInSeconds, boolean blnRefresh) {
+
+ UsernamePasswordAuthenticationToken authenticationToken =
+ new UsernamePasswordAuthenticationToken(loginDto.getUsername(), loginDto.getPassword());
+
+ // authenticate 메소드가 실행이 될 때 CustomUserDetailsService class의 loadUserByUsername 메소드가 실행
+ Authentication authentication = authenticationManagerBuilder.getObject().authenticate(authenticationToken);
+ // 해당 객체를 SecurityContextHolder에 저장하고
+ SecurityContextHolder.getContext().setAuthentication(authentication);
+ // authentication 객체를 createToken 메소드를 통해서 JWT Token을 생성
+ String jwt = tokenProvider.createToken(authentication, tokenValidityInSeconds, loginDto);
+ String jwtRefresh = tokenProvider.createToken(authentication, refreshTokenValidityInSeconds, loginDto);
+ //요청이 RefreshToken 아닐 경우만 생성
+ if (blnRefresh) jwtRefresh = null;
+
+ HttpHeaders httpHeaders = new HttpHeaders();
+ // response header에 jwt token에 넣어줌
+ httpHeaders.add(JwtFilter.AUTHORIZATION_HEADER, "Bearer " + jwt);
+
+ // tokenDto를 이용해 response body에도 넣어서 리턴
+ log.debug("jwt = " + jwt);
+ log.debug("jwtRefresh = " + jwtRefresh);
+ return new ResponseEntity<>(new TokenDto(jwt, jwtRefresh), httpHeaders, HttpStatus.OK);
+ }
+ @PostMapping("/refreshtoken")
+ public ResponseEntity refreshToken(
+ @RequestHeader HttpHeaders header,
+ @Value("${jwt.token-validity-in-seconds}") long tokenValidityInSeconds,
+ @Value("${jwt.refresh-token-validity-in-seconds}") long refreshTokenValidityInSeconds
+ ) {
+
+ String sRefreshToken = header.getFirst(JwtFilter.AUTHORIZATION_REFRESH_HEADER);
+ LoginDto loginDto = null;
+ if (tokenProvider.validateToken(sRefreshToken)) {
+ Jws claims = tokenProvider.getClaims(sRefreshToken);
+
+ log.debug("parseJwt = " + CommonJson.objectToString(claims));
+ log.debug("parseJwt(getSubject) = " + claims.getBody().getSubject());
+ log.debug("parseJwt(auth) = " + (String) claims.getBody().get("auth"));
+
+ HashMap hmLoginDto = claims.getBody().get("loginDto", HashMap.class);
+ loginDto = LoginDto.builder()
+ .username(hmLoginDto.get("username"))
+ .password(hmLoginDto.get("password"))
+ .build();
+ log.debug("parseJwt(LoginDto) = " + CommonJson.objectToString(loginDto));
+ }
+
+ return fnAuthorize(loginDto, tokenValidityInSeconds, refreshTokenValidityInSeconds, true);
+ }
+}
\ No newline at end of file
diff --git a/src/main/java/daeucna/config/security/controller/ExceptionController.java b/src/main/java/daeucna/config/security/controller/ExceptionController.java
new file mode 100644
index 0000000..dfbbc92
--- /dev/null
+++ b/src/main/java/daeucna/config/security/controller/ExceptionController.java
@@ -0,0 +1,22 @@
+package daeucna.config.security.controller;
+
+import org.springframework.security.access.AccessDeniedException;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RequestMethod;
+import org.springframework.web.bind.annotation.RestController;
+
+import io.swagger.v3.oas.annotations.Operation;
+import lombok.extern.slf4j.Slf4j;
+
+@Slf4j
+@RestController
+@RequestMapping("/api")
+public class ExceptionController {
+
+ @Operation(summary = "인가 거부", description = "인가에 따른 예외가 발생했습니다.")
+ @RequestMapping(value = "/exceptionDenied", method = {RequestMethod.GET, RequestMethod.POST})
+ public void AccessDeniedException() {
+ throw new AccessDeniedException("");
+ }
+
+}
diff --git a/src/main/java/daeucna/config/security/controller/UserController.java b/src/main/java/daeucna/config/security/controller/UserController.java
new file mode 100644
index 0000000..96e8902
--- /dev/null
+++ b/src/main/java/daeucna/config/security/controller/UserController.java
@@ -0,0 +1,55 @@
+package daeucna.config.security.controller;
+
+import java.io.IOException;
+
+import org.springframework.http.ResponseEntity;
+import org.springframework.security.access.prepost.PreAuthorize;
+import org.springframework.web.bind.annotation.GetMapping;
+import org.springframework.web.bind.annotation.PathVariable;
+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.RestController;
+
+import daeucna.config.security.dto.UserDto;
+import daeucna.config.security.service.UserService;
+import jakarta.servlet.http.HttpServletRequest;
+import jakarta.servlet.http.HttpServletResponse;
+import jakarta.validation.Valid;
+import lombok.RequiredArgsConstructor;
+
+@RestController
+@RequiredArgsConstructor
+@RequestMapping("/api")
+public class UserController {
+ private final UserService userService;
+
+ @GetMapping("/hello")
+ public ResponseEntity hello() {
+ return ResponseEntity.ok("hello");
+ }
+
+ @PostMapping("/test-redirect")
+ public void testRedirect(HttpServletResponse response) throws IOException {
+ response.sendRedirect("/api/user");
+ }
+
+ @PostMapping("/signup")
+ public ResponseEntity signup(
+ @Valid @RequestBody UserDto userDto
+ ) {
+ return ResponseEntity.ok(userService.signup(userDto));
+ }
+
+ @GetMapping("/user")
+ @PreAuthorize("hasAnyRole('USER','ADMIN')")
+ public ResponseEntity getMyUserInfo(HttpServletRequest request) {
+ return ResponseEntity.ok(userService.getMyUserWithAuthorities());
+ }
+
+ @GetMapping("/user/{username}")
+ @PreAuthorize("hasAnyRole('ADMIN')")
+ public ResponseEntity getUserInfo(@PathVariable String username) {
+ return ResponseEntity.ok(userService.getUserWithAuthorities(username));
+ }
+}
\ No newline at end of file
diff --git a/src/main/java/daeucna/config/security/dto/AuthorityDto.java b/src/main/java/daeucna/config/security/dto/AuthorityDto.java
new file mode 100644
index 0000000..041a33f
--- /dev/null
+++ b/src/main/java/daeucna/config/security/dto/AuthorityDto.java
@@ -0,0 +1,28 @@
+package daeucna.config.security.dto;
+
+import daeucna.config.security.entity.Authority;
+import jakarta.validation.constraints.NotNull;
+import jakarta.validation.constraints.Size;
+import lombok.AllArgsConstructor;
+import lombok.Builder;
+import lombok.Getter;
+import lombok.NoArgsConstructor;
+import lombok.Setter;
+
+@Getter @Setter @Builder
+@AllArgsConstructor
+@NoArgsConstructor
+public class AuthorityDto {
+
+ @NotNull
+ @Size(min = 3, max = 50)
+ private String authorityName;
+
+ public static AuthorityDto from(Authority authority) {
+ if(authority == null) return null;
+
+ return AuthorityDto.builder()
+ .authorityName(authority.getAuthorityName())
+ .build();
+ }
+}
\ No newline at end of file
diff --git a/src/main/java/daeucna/config/security/dto/LoginDto.java b/src/main/java/daeucna/config/security/dto/LoginDto.java
new file mode 100644
index 0000000..6fbe89b
--- /dev/null
+++ b/src/main/java/daeucna/config/security/dto/LoginDto.java
@@ -0,0 +1,25 @@
+package daeucna.config.security.dto;
+
+import jakarta.validation.constraints.NotNull;
+import jakarta.validation.constraints.Size;
+import lombok.AllArgsConstructor;
+import lombok.Builder;
+import lombok.Getter;
+import lombok.NoArgsConstructor;
+import lombok.Setter;
+
+@Getter
+@Setter
+@Builder
+@AllArgsConstructor
+@NoArgsConstructor
+public class LoginDto {
+
+ @NotNull
+ @Size(min = 3, max = 50)
+ private String username;
+
+ @NotNull
+ @Size(min = 3, max = 100)
+ private String password;
+}
\ No newline at end of file
diff --git a/src/main/java/daeucna/config/security/dto/TokenDto.java b/src/main/java/daeucna/config/security/dto/TokenDto.java
new file mode 100644
index 0000000..0a18039
--- /dev/null
+++ b/src/main/java/daeucna/config/security/dto/TokenDto.java
@@ -0,0 +1,19 @@
+package daeucna.config.security.dto;
+
+import lombok.AllArgsConstructor;
+import lombok.Builder;
+import lombok.Getter;
+import lombok.NoArgsConstructor;
+import lombok.Setter;
+
+@Getter
+@Setter
+@Builder
+@AllArgsConstructor
+@NoArgsConstructor
+public class TokenDto {
+
+ private String token;
+ private String refreshToken;
+
+}
\ No newline at end of file
diff --git a/src/main/java/daeucna/config/security/dto/UserDto.java b/src/main/java/daeucna/config/security/dto/UserDto.java
new file mode 100644
index 0000000..a528244
--- /dev/null
+++ b/src/main/java/daeucna/config/security/dto/UserDto.java
@@ -0,0 +1,49 @@
+package daeucna.config.security.dto;
+
+import java.util.Set;
+import java.util.stream.Collectors;
+
+import com.fasterxml.jackson.annotation.JsonProperty;
+
+import daeucna.config.security.entity.User;
+import jakarta.validation.constraints.NotNull;
+import jakarta.validation.constraints.Size;
+import lombok.AllArgsConstructor;
+import lombok.Builder;
+import lombok.Getter;
+import lombok.NoArgsConstructor;
+import lombok.Setter;
+
+@Getter @Setter @Builder
+@AllArgsConstructor
+@NoArgsConstructor
+public class UserDto {
+
+ @NotNull
+ @Size(min = 3, max = 50)
+ private String username;
+
+// @JsonProperty(access = JsonProperty.Access.WRITE_ONLY)
+ @NotNull
+ @Size(min = 3, max = 100)
+ private String password;
+
+ @NotNull
+ @Size(min = 3, max = 50)
+ private String nickname;
+
+ private Set authorityDtoSet;
+
+ public static UserDto from(User user) {
+ if(user == null) return null;
+
+ return UserDto.builder()
+ .username(user.getUsername())
+ .password(user.getPassword())
+ .nickname(user.getNickname())
+ .authorityDtoSet(user.getAuthorities().stream()
+ .map(authority -> AuthorityDto.builder().authorityName(authority.getAuthorityName()).build())
+ .collect(Collectors.toSet()))
+ .build();
+ }
+}
\ No newline at end of file
diff --git a/src/main/java/daeucna/config/security/entity/Authority.java b/src/main/java/daeucna/config/security/entity/Authority.java
new file mode 100644
index 0000000..fbca813
--- /dev/null
+++ b/src/main/java/daeucna/config/security/entity/Authority.java
@@ -0,0 +1,25 @@
+package daeucna.config.security.entity;
+
+import jakarta.persistence.Column;
+import jakarta.persistence.Entity;
+import jakarta.persistence.Id;
+import jakarta.persistence.Table;
+import lombok.AllArgsConstructor;
+import lombok.Builder;
+import lombok.Getter;
+import lombok.NoArgsConstructor;
+import lombok.Setter;
+
+@Entity
+@Table(name = "authority")
+@Getter
+@Setter
+@Builder
+@AllArgsConstructor
+@NoArgsConstructor
+public class Authority {
+
+ @Id
+ @Column(name = "authority_name", length = 50)
+ private String authorityName;
+}
\ No newline at end of file
diff --git a/src/main/java/daeucna/config/security/entity/User.java b/src/main/java/daeucna/config/security/entity/User.java
new file mode 100644
index 0000000..928102b
--- /dev/null
+++ b/src/main/java/daeucna/config/security/entity/User.java
@@ -0,0 +1,58 @@
+package daeucna.config.security.entity;
+
+import java.util.Set;
+
+import com.fasterxml.jackson.annotation.JsonIgnore;
+
+import jakarta.persistence.Column;
+import jakarta.persistence.Entity;
+import jakarta.persistence.GeneratedValue;
+import jakarta.persistence.GenerationType;
+import jakarta.persistence.Id;
+import jakarta.persistence.JoinColumn;
+import jakarta.persistence.JoinTable;
+import jakarta.persistence.ManyToMany;
+import jakarta.persistence.Table;
+import lombok.AllArgsConstructor;
+import lombok.Builder;
+import lombok.Getter;
+import lombok.NoArgsConstructor;
+import lombok.Setter;
+
+@Entity // DB의 테이블과 1:1 매핑되는 객체
+@Table(name = "users")
+@Getter
+@Setter
+@Builder
+@AllArgsConstructor
+@NoArgsConstructor
+public class User {
+
+ @JsonIgnore
+ @Id // primary key
+ @Column(name = "user_id")
+ // 자동 증가 되는
+ @GeneratedValue(strategy = GenerationType.IDENTITY)
+ private Long userId;
+
+ @Column(name = "username", length = 50, unique = true)
+ private String username;
+
+ @JsonIgnore
+ @Column(name = "password", length = 100)
+ private String password;
+
+ @Column(name = "nickname", length = 50)
+ private String nickname;
+
+ @JsonIgnore
+ @Column(name = "activated")
+ private boolean activated;
+
+ @ManyToMany
+ @JoinTable(
+ name = "user_authority",
+ joinColumns = {@JoinColumn(name = "user_id", referencedColumnName = "user_id")},
+ inverseJoinColumns = {@JoinColumn(name = "authority_name", referencedColumnName = "authority_name")})
+ private Set authorities;
+}
\ No newline at end of file
diff --git a/src/main/java/daeucna/config/security/jwt/JwtAuthenticationEntryPoint.java b/src/main/java/daeucna/config/security/jwt/JwtAuthenticationEntryPoint.java
new file mode 100644
index 0000000..e6fd1c7
--- /dev/null
+++ b/src/main/java/daeucna/config/security/jwt/JwtAuthenticationEntryPoint.java
@@ -0,0 +1,23 @@
+package daeucna.config.security.jwt;
+
+import java.io.IOException;
+
+import org.springframework.security.core.AuthenticationException;
+import org.springframework.security.web.AuthenticationEntryPoint;
+import org.springframework.stereotype.Component;
+
+import jakarta.servlet.http.HttpServletRequest;
+import jakarta.servlet.http.HttpServletResponse;
+import lombok.extern.slf4j.Slf4j;
+
+@Slf4j
+@Component
+public class JwtAuthenticationEntryPoint implements AuthenticationEntryPoint {
+ @Override
+ public void commence(HttpServletRequest request,
+ HttpServletResponse response,
+ AuthenticationException authException) throws IOException {
+ // 유효한 자격증명을 제공하지 않고 접근하려 할때 401
+ response.sendError(HttpServletResponse.SC_UNAUTHORIZED);
+ }
+}
\ No newline at end of file
diff --git a/src/main/java/daeucna/config/security/jwt/JwtFilter.java b/src/main/java/daeucna/config/security/jwt/JwtFilter.java
new file mode 100644
index 0000000..1425e89
--- /dev/null
+++ b/src/main/java/daeucna/config/security/jwt/JwtFilter.java
@@ -0,0 +1,55 @@
+package daeucna.config.security.jwt;
+
+import java.io.IOException;
+
+import org.springframework.security.core.Authentication;
+import org.springframework.security.core.context.SecurityContextHolder;
+import org.springframework.util.StringUtils;
+import org.springframework.web.filter.GenericFilterBean;
+
+import jakarta.servlet.FilterChain;
+import jakarta.servlet.ServletException;
+import jakarta.servlet.ServletRequest;
+import jakarta.servlet.ServletResponse;
+import jakarta.servlet.http.HttpServletRequest;
+import lombok.RequiredArgsConstructor;
+import lombok.extern.slf4j.Slf4j;
+
+@RequiredArgsConstructor
+@Slf4j
+public class JwtFilter extends GenericFilterBean {
+
+ public static final String AUTHORIZATION_HEADER = "Authorization";
+ public static final String AUTHORIZATION_REFRESH_HEADER = "REFRESH_TOKEN";
+ private final JwtTokenProvider tokenProvider;
+
+ // 실제 필터릴 로직
+ // 토큰의 인증정보를 SecurityContext에 저장하는 역할 수행
+ @Override
+ public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
+ HttpServletRequest httpServletRequest = (HttpServletRequest) servletRequest;
+ String jwt = resolveToken(httpServletRequest);
+ String requestURI = httpServletRequest.getRequestURI();
+
+ if (StringUtils.hasText(jwt) && tokenProvider.validateToken(jwt)) {
+ Authentication authentication = tokenProvider.getAuthentication(jwt);
+ SecurityContextHolder.getContext().setAuthentication(authentication);
+ log.debug("Security Context에 '{}' 인증 정보를 저장했습니다, uri: {}", authentication.getName(), requestURI);
+ } else {
+ log.debug("유효한 JWT 토큰이 없습니다, uri: {}", requestURI);
+ }
+
+ filterChain.doFilter(servletRequest, servletResponse);
+ }
+
+ // Request Header 에서 토큰 정보를 꺼내오기 위한 메소드
+ private String resolveToken(HttpServletRequest request) {
+ String bearerToken = request.getHeader(AUTHORIZATION_HEADER);
+
+ if (StringUtils.hasText(bearerToken) && bearerToken.startsWith("Bearer ")) {
+ return bearerToken.substring(7);
+ }
+
+ return null;
+ }
+}
\ No newline at end of file
diff --git a/src/main/java/daeucna/config/security/jwt/JwtTokenProvider.java b/src/main/java/daeucna/config/security/jwt/JwtTokenProvider.java
new file mode 100644
index 0000000..d788f18
--- /dev/null
+++ b/src/main/java/daeucna/config/security/jwt/JwtTokenProvider.java
@@ -0,0 +1,129 @@
+package daeucna.config.security.jwt;
+
+import java.security.Key;
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.Date;
+import java.util.Map;
+import java.util.stream.Collectors;
+
+import javax.crypto.SecretKey;
+
+import org.springframework.beans.factory.InitializingBean;
+import org.springframework.beans.factory.annotation.Value;
+import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
+import org.springframework.security.core.Authentication;
+import org.springframework.security.core.GrantedAuthority;
+import org.springframework.security.core.authority.SimpleGrantedAuthority;
+import org.springframework.security.core.userdetails.User;
+import org.springframework.stereotype.Component;
+
+import daeucna.config.security.dto.LoginDto;
+import io.jsonwebtoken.Claims;
+import io.jsonwebtoken.ExpiredJwtException;
+import io.jsonwebtoken.Jws;
+import io.jsonwebtoken.Jwts;
+import io.jsonwebtoken.MalformedJwtException;
+import io.jsonwebtoken.SignatureAlgorithm;
+import io.jsonwebtoken.UnsupportedJwtException;
+import io.jsonwebtoken.io.Decoders;
+import io.jsonwebtoken.security.Keys;
+import lombok.extern.slf4j.Slf4j;
+
+@Component
+@Slf4j
+public class JwtTokenProvider implements InitializingBean {
+
+ private static final String AUTHORITIES_KEY = "auth";
+ private final String secret;
+ private final long tokenValidityInMilliseconds;
+ private final long freshTokenValidityInMilliseconds;
+ private SecretKey key;
+
+ public JwtTokenProvider(
+ @Value("${jwt.secret}") String secret,
+ @Value("${jwt.token-validity-in-seconds}") long tokenValidityInSeconds,
+ @Value("${jwt.refresh-token-validity-in-seconds}") long refreshTokenValidityInSeconds) {
+ this.secret = secret;
+ this.tokenValidityInMilliseconds = tokenValidityInSeconds * 1000;
+ this.freshTokenValidityInMilliseconds = refreshTokenValidityInSeconds * 1000;
+ }
+
+ // 빈이 생성되고 주입을 받은 후에 secret값을 Base64 Decode해서 key 변수에 할당하기 위해
+ @Override
+ public void afterPropertiesSet() {
+ byte[] keyBytes = Decoders.BASE64URL.decode(secret);
+ this.key = Keys.hmacShaKeyFor(keyBytes);
+ }
+
+ public SecretKey getSecretKey() {
+ return this.key;
+ }
+
+ public String createToken(Authentication authentication, long tokenValidityInMilliseconds, LoginDto loginDto) {
+ String authorities = authentication.getAuthorities().stream()
+ .map(GrantedAuthority::getAuthority)
+ .collect(Collectors.joining(","));
+
+ // 토큰의 expire 시간을 설정
+ long now = (new Date()).getTime();
+ Date validity = new Date(now + (tokenValidityInMilliseconds * 1000) ); //1000분의 1초
+
+ return Jwts.builder()
+ .subject(authentication.getName())
+ .claim(AUTHORITIES_KEY, authorities) // 정보 저장
+ .claims()
+ .add(Map.of("loginDto", loginDto))
+ .and()
+ .signWith(key, Jwts.SIG.HS512) // 사용할 암호화 알고리즘과 , signature 에 들어갈 secret값 세팅
+ .expiration(validity) // set Expire Time 해당 옵션 안넣으면 expire안함
+ .compact();
+ }
+
+ // 토큰으로 클레임을 만들고 이를 이용해 유저 객체를 만들어서 최종적으로 authentication 객체를 리턴
+ public Authentication getAuthentication(String token) {
+ Claims claims = Jwts
+ .parser()
+ .verifyWith(key)
+ .build()
+ .parseSignedClaims(token)
+ .getPayload();
+
+ Collection extends GrantedAuthority> authorities =
+ Arrays.stream(claims.get(AUTHORITIES_KEY).toString().split(","))
+ .map(SimpleGrantedAuthority::new)
+ .collect(Collectors.toList());
+
+ User principal = new User(claims.getSubject(), "", authorities);
+
+ return new UsernamePasswordAuthenticationToken(principal, token, authorities);
+ }
+
+ public Jws getClaims(String sToken) {
+ return Jwts.parser()
+ .verifyWith(this.getSecretKey())
+ .build()
+ .parseSignedClaims(sToken);
+ }
+
+ // 토큰의 유효성 검증을 수행
+ public boolean validateToken(String token) {
+ try {
+ Jwts.parser().verifyWith(key).build().parseSignedClaims(token);
+ return true;
+ } catch (io.jsonwebtoken.security.SecurityException | MalformedJwtException e) {
+
+ log.info("잘못된 JWT 서명입니다.");
+ } catch (ExpiredJwtException e) {
+
+ log.info("만료된 JWT 토큰입니다.");
+ } catch (UnsupportedJwtException e) {
+
+ log.info("지원되지 않는 JWT 토큰입니다.");
+ } catch (IllegalArgumentException e) {
+
+ log.info("JWT 토큰이 잘못되었습니다.");
+ }
+ return false;
+ }
+}
\ No newline at end of file
diff --git a/src/main/java/daeucna/config/security/repository/UserRepository.java b/src/main/java/daeucna/config/security/repository/UserRepository.java
new file mode 100644
index 0000000..d8be945
--- /dev/null
+++ b/src/main/java/daeucna/config/security/repository/UserRepository.java
@@ -0,0 +1,13 @@
+package daeucna.config.security.repository;
+
+import java.util.Optional;
+
+import org.springframework.data.jpa.repository.EntityGraph;
+import org.springframework.data.jpa.repository.JpaRepository;
+
+import daeucna.config.security.entity.User;
+
+public interface UserRepository extends JpaRepository {
+ @EntityGraph(attributePaths = "authorities")
+ Optional findOneWithAuthoritiesByUsername(String username);
+}
diff --git a/src/main/java/daeucna/config/security/service/CustomUserDetailsService.java b/src/main/java/daeucna/config/security/service/CustomUserDetailsService.java
new file mode 100644
index 0000000..44da223
--- /dev/null
+++ b/src/main/java/daeucna/config/security/service/CustomUserDetailsService.java
@@ -0,0 +1,46 @@
+package daeucna.config.security.service;
+
+import java.util.List;
+import java.util.stream.Collectors;
+
+import org.springframework.security.core.GrantedAuthority;
+import org.springframework.security.core.authority.SimpleGrantedAuthority;
+import org.springframework.security.core.userdetails.UserDetails;
+import org.springframework.security.core.userdetails.UserDetailsService;
+import org.springframework.security.core.userdetails.UsernameNotFoundException;
+import org.springframework.stereotype.Component;
+import org.springframework.transaction.annotation.Transactional;
+
+import daeucna.config.security.entity.User;
+import daeucna.config.security.repository.UserRepository;
+import lombok.RequiredArgsConstructor;
+
+@Component("userDetailsService")
+@RequiredArgsConstructor
+public class CustomUserDetailsService implements UserDetailsService {
+ private final UserRepository userRepository;
+
+ @Override
+ @Transactional
+ // 로그인시에 DB에서 유저정보와 권한정보를 가져와서 해당 정보를 기반으로 userdetails.User 객체를 생성해 리턴
+ public UserDetails loadUserByUsername(final String username) {
+
+ return userRepository.findOneWithAuthoritiesByUsername(username)
+ .map(user -> createUser(username, user))
+ .orElseThrow(() -> new UsernameNotFoundException(username + " -> 데이터베이스에서 찾을 수 없습니다."));
+ }
+
+ private org.springframework.security.core.userdetails.User createUser(String username, User user) {
+ if (!user.isActivated()) {
+ throw new RuntimeException(username + " -> 활성화되어 있지 않습니다.");
+ }
+
+ List grantedAuthorities = user.getAuthorities().stream()
+ .map(authority -> new SimpleGrantedAuthority(authority.getAuthorityName()))
+ .collect(Collectors.toList());
+
+ return new org.springframework.security.core.userdetails.User(user.getUsername(),
+ user.getPassword(),
+ grantedAuthorities);
+ }
+}
\ No newline at end of file
diff --git a/src/main/java/daeucna/config/security/service/UserService.java b/src/main/java/daeucna/config/security/service/UserService.java
new file mode 100644
index 0000000..f9587fd
--- /dev/null
+++ b/src/main/java/daeucna/config/security/service/UserService.java
@@ -0,0 +1,71 @@
+package daeucna.config.security.service;
+
+import java.util.HashSet;
+import java.util.Iterator;
+import java.util.Set;
+
+import org.springframework.security.crypto.password.PasswordEncoder;
+import org.springframework.stereotype.Service;
+import org.springframework.transaction.annotation.Transactional;
+
+import daeucna.config.security.dto.AuthorityDto;
+import daeucna.config.security.dto.UserDto;
+import daeucna.config.security.entity.Authority;
+import daeucna.config.security.entity.User;
+import daeucna.config.security.repository.UserRepository;
+import daeucna.config.security.utils.CommonJson;
+import daeucna.config.security.utils.DuplicateMemberException;
+import daeucna.config.security.utils.SecurityUtil;
+import lombok.RequiredArgsConstructor;
+import lombok.extern.slf4j.Slf4j;
+
+@Service
+@RequiredArgsConstructor
+@Slf4j
+public class UserService {
+ private final UserRepository userRepository;
+ private final PasswordEncoder passwordEncoder;
+
+ @Transactional
+ public UserDto signup(UserDto userDto) {
+ if (userRepository.findOneWithAuthoritiesByUsername(userDto.getUsername()).orElse(null) != null) {
+ throw new DuplicateMemberException("이미 가입되어 있는 유저입니다.");
+ }
+
+ Set setAuthority = new HashSet();
+ Set setAuthorityDto = userDto.getAuthorityDtoSet();
+ Iterator itAuthorityDto = setAuthorityDto.iterator();
+ while(itAuthorityDto.hasNext()) {
+ AuthorityDto curAuthorityDto = itAuthorityDto.next();
+ setAuthority.add(
+ Authority.builder()
+ .authorityName(curAuthorityDto.getAuthorityName())
+ .build()
+ );
+
+ log.debug("setAuthority = " + CommonJson.objectToString(setAuthority));
+ }
+
+
+
+ User user = User.builder()
+ .username(userDto.getUsername())
+ .password(passwordEncoder.encode(userDto.getPassword()))
+ .nickname(userDto.getNickname())
+ .authorities(setAuthority)
+ .activated(true)
+ .build();
+
+ return UserDto.from(userRepository.save(user));
+ }
+
+ @Transactional(readOnly = true)
+ public UserDto getUserWithAuthorities(String username) {
+ return UserDto.from(userRepository.findOneWithAuthoritiesByUsername(username).orElse(null));
+ }
+
+ @Transactional(readOnly = true)
+ public UserDto getMyUserWithAuthorities() {
+ return UserDto.from(SecurityUtil.getCurrentUsername().flatMap(userRepository::findOneWithAuthoritiesByUsername).orElse(null));
+ }
+}
\ No newline at end of file
diff --git a/src/main/java/daeucna/config/security/utils/CommonJson.java b/src/main/java/daeucna/config/security/utils/CommonJson.java
new file mode 100644
index 0000000..3056ea7
--- /dev/null
+++ b/src/main/java/daeucna/config/security/utils/CommonJson.java
@@ -0,0 +1,34 @@
+package daeucna.config.security.utils;
+
+import org.springframework.stereotype.Component;
+
+import com.fasterxml.jackson.databind.ObjectMapper;
+
+@Component
+public class CommonJson {
+
+ public static String objectToString(Object object) {
+ String rtnVal = "";
+ try {
+ ObjectMapper objectMapper = new ObjectMapper();
+ rtnVal = objectMapper.writeValueAsString(object);
+ } catch (Exception e) {
+ e.printStackTrace();
+ rtnVal = "Error";
+ }
+ return rtnVal;
+ }
+
+ public static Object stringToObject(String sJson, Class> objClass) {
+ Object rtnVal;
+ try {
+ ObjectMapper objectMapper = new ObjectMapper();
+ rtnVal = objectMapper.readValue(sJson, objClass);
+ } catch (Exception e) {
+ e.printStackTrace();
+ rtnVal = "Error";
+ }
+ return rtnVal;
+ }
+
+}
\ No newline at end of file
diff --git a/src/main/java/daeucna/config/security/utils/DuplicateMemberException.java b/src/main/java/daeucna/config/security/utils/DuplicateMemberException.java
new file mode 100644
index 0000000..c4df20e
--- /dev/null
+++ b/src/main/java/daeucna/config/security/utils/DuplicateMemberException.java
@@ -0,0 +1,16 @@
+package daeucna.config.security.utils;
+
+public class DuplicateMemberException extends RuntimeException {
+ public DuplicateMemberException() {
+ super();
+ }
+ public DuplicateMemberException(String message, Throwable cause) {
+ super(message, cause);
+ }
+ public DuplicateMemberException(String message) {
+ super(message);
+ }
+ public DuplicateMemberException(Throwable cause) {
+ super(cause);
+ }
+}
\ No newline at end of file
diff --git a/src/main/java/daeucna/config/security/utils/NotFoundMemberException.java b/src/main/java/daeucna/config/security/utils/NotFoundMemberException.java
new file mode 100644
index 0000000..10d40b6
--- /dev/null
+++ b/src/main/java/daeucna/config/security/utils/NotFoundMemberException.java
@@ -0,0 +1,16 @@
+package daeucna.config.security.utils;
+
+public class NotFoundMemberException extends RuntimeException {
+ public NotFoundMemberException() {
+ super();
+ }
+ public NotFoundMemberException(String message, Throwable cause) {
+ super(message, cause);
+ }
+ public NotFoundMemberException(String message) {
+ super(message);
+ }
+ public NotFoundMemberException(Throwable cause) {
+ super(cause);
+ }
+}
\ No newline at end of file
diff --git a/src/main/java/daeucna/config/security/utils/SecurityUtil.java b/src/main/java/daeucna/config/security/utils/SecurityUtil.java
new file mode 100644
index 0000000..10fba71
--- /dev/null
+++ b/src/main/java/daeucna/config/security/utils/SecurityUtil.java
@@ -0,0 +1,37 @@
+package daeucna.config.security.utils;
+
+import java.util.Optional;
+
+import org.springframework.security.core.Authentication;
+import org.springframework.security.core.context.SecurityContextHolder;
+import org.springframework.security.core.userdetails.UserDetails;
+
+import lombok.extern.slf4j.Slf4j;
+
+@Slf4j
+public class SecurityUtil {
+
+ private SecurityUtil() {}
+
+ // getCurrentUsername 메소드의 역할은 Security Cont
+ public static Optional getCurrentUsername() {
+
+ // authentication객체가 저장되는 시점은 JwtFilter의 doFilter 메소드에서
+ // Request가 들어올 때 SecurityContext에 Authentication 객체를 저장해서 사용
+ final Authentication authentication = SecurityContextHolder.getContext().getAuthentication();
+
+ if (authentication == null) {
+ log.debug("Security Context에 인증 정보가 없습니다.");
+ return Optional.empty();
+ }
+
+ String username = null;
+ if (authentication.getPrincipal() instanceof UserDetails springSecurityUser) {
+ username = springSecurityUser.getUsername();
+ } else if (authentication.getPrincipal() instanceof String) {
+ username = (String) authentication.getPrincipal();
+ }
+
+ return Optional.ofNullable(username);
+ }
+}
\ No newline at end of file
diff --git a/src/main/java/daeucna/mapper/primary/batch/MatchingInnerDelingMapper.java b/src/main/java/daeucna/mapper/primary/batch/MatchingInnerDelingMapper.java
new file mode 100644
index 0000000..784ce3c
--- /dev/null
+++ b/src/main/java/daeucna/mapper/primary/batch/MatchingInnerDelingMapper.java
@@ -0,0 +1,158 @@
+package daeucna.mapper.primary.batch;
+
+import java.util.List;
+import java.util.Map;
+
+import org.apache.ibatis.annotations.Mapper;
+
+@Mapper
+public interface MatchingInnerDelingMapper {
+
+ /*
+ * 작업리스트
+ */
+ @SuppressWarnings("rawtypes")
+ List getCustomItemReadData(Map param);
+
+
+ /**
+ * 작업키 업데이트 (파라미터 : 자기데이타/상대데이타)
+ * @param param
+ * @return
+ */
+ @SuppressWarnings("rawtypes")
+ int setDataMakeCompareKy(Map param);
+
+
+ /**
+ * 매칭작업할 데이타 가져오기(파라미터 : 자기데이타/상대데이타)
+ * @param param
+ * @return
+ */
+ @SuppressWarnings("rawtypes")
+ List getMatchingData(Map param);
+
+ /**
+ * 업데이트할 데이타 가져오기(파라미터 : 자기데이타/상대데이타)
+ * @param param
+ * @return
+ */
+ @SuppressWarnings("rawtypes")
+ List getMatchingResult(Map param);
+
+ /**
+ * 결과 업데이트
+ * @param param
+ * @return
+ */
+ @SuppressWarnings("rawtypes")
+ int setResult(Map param);
+
+
+
+
+ /**
+ * Original Data 삭제
+ * @param param
+ * @return
+ */
+ @SuppressWarnings("rawtypes")
+ int deleteOriginalData(Map param);
+
+
+ /**
+ * Original Data 생성
+ * @param param
+ * @return
+ */
+ @SuppressWarnings("rawtypes")
+ int insertOriginalData(Map param);
+
+
+ /**
+ * 작업영역 데이타 삭제
+ * @param param
+ * @return
+ */
+ @SuppressWarnings("rawtypes")
+ int deleteData(Map param);
+
+ /**
+ * 작업영역 데이타 생성(From Original Data)
+ * @param param
+ * @return
+ */
+ @SuppressWarnings("rawtypes")
+ int insertDataFromOriginal(Map param);
+
+ /**
+ * 작업영역 ai데이타 삭제
+ * @param param
+ * @return
+ */
+ @SuppressWarnings("rawtypes")
+ int deleteDataAi(Map param);
+
+ /**
+ * 작업영역 데이타 생성(From Original Data)
+ * @param param
+ * @return
+ */
+ @SuppressWarnings("rawtypes")
+ int insertDataAiFromOriginal(Map param);
+
+ /**
+ * 값을 돌려주기전 월별 새로운 일치키 생성
+ * @param param
+ * @return
+ */
+ @SuppressWarnings("rawtypes")
+ int updateNewMatchKey(Map param);
+
+ /**
+ * Extra matching을 위한 자료 조회
+ * @param param
+ * @return
+ */
+ @SuppressWarnings("rawtypes")
+ List getMatchingExtraDataOne(Map param);
+
+ /**
+ * Extra matching을 위한 자료 조회
+ * @param param
+ * @return
+ */
+ @SuppressWarnings("rawtypes")
+ List getMatchingExtraDataTwo(Map param);
+
+ /**
+ * Extra matching 데이타 적용
+ * @param param
+ * @return
+ */
+ @SuppressWarnings("rawtypes")
+ int setExtraResult(Map param);
+
+ /**
+ * User Job Start
+ * @param param
+ * @return
+ */
+ @SuppressWarnings("rawtypes")
+ int createUserJob(Map param);
+
+ /**
+ * User Job End
+ * @param param
+ * @return
+ */
+ @SuppressWarnings("rawtypes")
+ int finishUserJob(Map param);
+
+ /*
+ * ai 작업리스트
+ */
+ @SuppressWarnings("rawtypes")
+ List getAiReadData(Map param);
+
+}
\ No newline at end of file
diff --git a/src/main/java/daeucna/mapper/primary/system/CodeMapper.java b/src/main/java/daeucna/mapper/primary/system/CodeMapper.java
new file mode 100644
index 0000000..5d7ab46
--- /dev/null
+++ b/src/main/java/daeucna/mapper/primary/system/CodeMapper.java
@@ -0,0 +1,12 @@
+package daeucna.mapper.primary.system;
+
+import java.util.List;
+
+import org.apache.ibatis.annotations.Mapper;
+
+import daeucna.system.code.CodeDto;
+
+@Mapper
+public interface CodeMapper {
+ List getCmmnCode(CodeDto param);
+}
\ No newline at end of file
diff --git a/src/main/java/daeucna/mapper/secondary/batch/OracleMapper.java b/src/main/java/daeucna/mapper/secondary/batch/OracleMapper.java
new file mode 100644
index 0000000..5f292d5
--- /dev/null
+++ b/src/main/java/daeucna/mapper/secondary/batch/OracleMapper.java
@@ -0,0 +1,32 @@
+package daeucna.mapper.secondary.batch;
+
+import java.util.List;
+import java.util.Map;
+
+import org.apache.ibatis.annotations.Mapper;
+
+@Mapper
+public interface OracleMapper {
+
+ /*
+ * Original Data 조회
+ */
+ @SuppressWarnings("rawtypes")
+ List getOriginalData(Map param);
+
+ /*
+ * Original Data 조회
+ */
+ @SuppressWarnings("rawtypes")
+ List getMatchingInfo(Map param);
+
+ /**
+ * 원 테이블에 결과값 업데이트
+ * @param param
+ * @return
+ */
+ @SuppressWarnings("rawtypes")
+ int updateMatchingResult(Map param);
+
+
+}
\ No newline at end of file
diff --git a/src/main/java/daeucna/system/code/CodeController.java b/src/main/java/daeucna/system/code/CodeController.java
new file mode 100644
index 0000000..9d5f26e
--- /dev/null
+++ b/src/main/java/daeucna/system/code/CodeController.java
@@ -0,0 +1,33 @@
+package daeucna.system.code;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.http.ResponseEntity;
+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.RestController;
+
+import daeucna.system.code.CodeDto;
+import lombok.RequiredArgsConstructor;
+
+@RestController
+@RequiredArgsConstructor
+@RequestMapping("/api/code")
+public class CodeController {
+ @Autowired
+ private final CodeService codeService;
+
+ @PostMapping("/cmmncode")
+ public ResponseEntity> getCmmnCode(@RequestBody CodeDto param) {
+ List rtnVal = new ArrayList();
+
+ rtnVal = codeService.getCmmnCode(param);
+
+ return ResponseEntity.ok(rtnVal);
+ }
+
+}
\ No newline at end of file
diff --git a/src/main/java/daeucna/system/code/CodeDto.java b/src/main/java/daeucna/system/code/CodeDto.java
new file mode 100644
index 0000000..0ce98af
--- /dev/null
+++ b/src/main/java/daeucna/system/code/CodeDto.java
@@ -0,0 +1,28 @@
+package daeucna.system.code;
+
+import java.math.BigDecimal;
+
+import lombok.Data;
+
+@Data
+public class CodeDto {
+
+ private String codeTy;
+ private String cmmnCode;
+
+ private String mngIem1;
+ private String mngIem2;
+ private String mngIem3;
+ private String mngIem4;
+ private BigDecimal ordr;
+ private String useAt;
+
+ private String lcal;
+ private String cmmnCodeNm;
+
+ private String register;
+ private String inputDe;
+ private String updusr;
+ private String updtDe;
+
+}
\ No newline at end of file
diff --git a/src/main/java/daeucna/system/code/CodeService.java b/src/main/java/daeucna/system/code/CodeService.java
new file mode 100644
index 0000000..9c388f5
--- /dev/null
+++ b/src/main/java/daeucna/system/code/CodeService.java
@@ -0,0 +1,10 @@
+package daeucna.system.code;
+
+import java.util.List;
+
+public interface CodeService {
+
+ @SuppressWarnings("rawtypes")
+ public List getCmmnCode(CodeDto param);
+
+}
\ No newline at end of file
diff --git a/src/main/java/daeucna/system/code/CodeServiceImpl.java b/src/main/java/daeucna/system/code/CodeServiceImpl.java
new file mode 100644
index 0000000..df615cf
--- /dev/null
+++ b/src/main/java/daeucna/system/code/CodeServiceImpl.java
@@ -0,0 +1,36 @@
+package daeucna.system.code;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Repository;
+import org.springframework.stereotype.Service;
+import org.springframework.transaction.annotation.Propagation;
+import org.springframework.transaction.annotation.Transactional;
+
+import daeucna.mapper.primary.system.CodeMapper;
+import lombok.RequiredArgsConstructor;
+import lombok.extern.slf4j.Slf4j;
+
+@Service
+@RequiredArgsConstructor
+@Slf4j
+@Repository
+@Transactional(propagation = Propagation.REQUIRED, rollbackFor={Exception.class})
+public class CodeServiceImpl implements CodeService {
+ @Autowired
+ private CodeMapper codeMapper;
+
+
+ @Override
+ public List getCmmnCode(CodeDto param) {
+ List lCodeDto = new ArrayList();
+
+ lCodeDto = codeMapper.getCmmnCode(param);
+
+ log.info("CodeServiceImpl");
+ return lCodeDto;
+ }
+
+}
\ 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..598f3a6
--- /dev/null
+++ b/src/main/resources/application.properties
@@ -0,0 +1,62 @@
+server.port=8080
+
+spring.mvc.converters.preferred-json-mapper=gson
+
+spring.mvc.view.prefix=/
+spring.mvc.view.suffix: .html
+spring.mvc.hiddenmethod.filter.enabled=true
+
+spring.main.allow-bean-definition-overriding=true
+
+## JPA
+spring.jpa.database-platform=org.hibernate.dialect.PostgreSQLDialect
+spring.jpa.generate-ddl=true
+spring.jpa.hibernate.ddl-auto=update
+spring.jpa.defer-datasource-initialization=true
+
+## Datasource
+# primary
+spring.datasource.hikari.primary.driver-class-name=org.postgresql.Driver
+spring.datasource.hikari.primary.jdbc-url=jdbc:postgresql://daeuserver.iptime.org:20430/account
+spring.datasource.hikari.primary.username=account
+spring.datasource.hikari.primary.password=daeucna10!
+
+# secondary
+#spring.datasource.hikari.secondary.driver-class-name=oracle.jdbc.driver.OracleDriver
+#spring.datasource.hikari.secondary.jdbc-url=jdbc:oracle:thin:@vanguardlab.kr:63522/CONFINAS19C
+#spring.datasource.hikari.secondary.username=ai
+#spring.datasource.hikari.secondary.password=ai
+spring.datasource.hikari.secondary.driver-class-name=oracle.jdbc.driver.OracleDriver
+spring.datasource.hikari.secondary.jdbc-url=jdbc:oracle:thin:@daeuserver2.iptime.org:1521/orcl
+spring.datasource.hikari.secondary.username=CONFINAS3
+spring.datasource.hikari.secondary.password=CONFINAS3
+
+
+spring.sql.encoding=UTF-8
+spring.sql.init.mode=always
+
+spring.batch.jdbc.initialize-schema=always
+#스프링잡 자동시작 옵션
+spring.batch.job.enabled=false
+
+spring.devtools.livereload.enabled=true
+spring.devtools.restart.enabled=true
+
+#p6spy query logging
+decorator.datasource.p6spy.enable-logging=true
+
+logging.level.root=info
+logging.level.daeucna=debug
+logging.level.p6spy=debug
+
+## Python 프로퍼티 설정
+pytyon.path=D:\\Programs\\devp\\python-3.12.2\\python.exe
+python.ai.target=D:\\Working\\Python\\Test1.py
+
+## JWT
+jwt.header=Authorization
+# HS512 알고리즘을 사용할 것이기 때문에 512bit, 즉 64byte 이상의 secret key를 사용
+# echo 'jsh-springboot-and-jwt-tutorial-this-is-for-generating-jwt-secretkey-base64'|base64
+jwt.secret=4oCYc2lsdmVybmluZS10ZWNoLXNwcmluZy1ib290LWp3dC10dXRvcmlhbC1zZWNyZXQtc2lsdmVybmluZS10ZWNoLXNwcmluZy1ib290LWp3dC10dXRvcmlhbC1zZWNyZXTigJkK
+jwt.token-validity-in-seconds=60
+jwt.refresh-token-validity-in-seconds=86400
diff --git a/src/main/resources/data.sql b/src/main/resources/data.sql
new file mode 100644
index 0000000..3451d94
--- /dev/null
+++ b/src/main/resources/data.sql
@@ -0,0 +1,45 @@
+MERGE INTO authority m
+USING (
+ SELECT
+ 'ROLE_ADMIN' as authority_name
+ ) s
+ON
+ m.authority_name = s.authority_name
+WHEN NOT MATCHED THEN
+ INSERT (authority_name) VALUES (s.authority_name);
+
+MERGE INTO authority m
+USING (
+ SELECT
+ 'ROLE_USER' as authority_name
+ ) s
+ON
+ m.authority_name = s.authority_name
+WHEN NOT MATCHED THEN
+ INSERT (authority_name) VALUES (s.authority_name);
+
+MERGE INTO users m
+USING (
+ SELECT
+ 1 as user_id,
+ true as activated,
+ 'sangkiham' as nickname,
+ '$2a$10$nyHQj.Nj2tID4UzIkd1/SuMeYwlKaaHT8Gi3Wgg2x/h9K9qLQciLO' as password,
+ 'sangkiham' as username
+ ) s
+ON
+ m.user_id = s.user_id
+WHEN NOT MATCHED THEN
+ INSERT (user_id, activated, nickname, password, username) VALUES (s.user_id, s.activated, s.nickname, s.password, s.username);
+
+MERGE INTO user_authority m
+USING (
+ SELECT
+ 1 as user_id,
+ 'ROLE_ADMIN' as authority_name
+ ) s
+ON
+ m.user_id = s.user_id
+ and m.authority_name = s.authority_name
+WHEN NOT MATCHED THEN
+ INSERT (user_id, authority_name) VALUES (s.user_id, s.authority_name);
diff --git a/src/main/resources/matchingSetup.json b/src/main/resources/matchingSetup.json
new file mode 100644
index 0000000..40c292c
--- /dev/null
+++ b/src/main/resources/matchingSetup.json
@@ -0,0 +1,3573 @@
+{
+ "matchingSetup": [
+ {
+ "active": true,
+ "type": "A-A",
+ "typeName": "자기수익(대사키),상대비용(대사키),비교(년월,비교키,거래금액)",
+
+ "condOne": {
+ "cond": [
+ "dta_ty in ('11','21')",
+ "mtch_ty is null",
+ "cmpnsp_ky is not null",
+ "cmpnsp_ky != ''"
+ ],
+ "makeCompareKey": [
+ "cmpnsp_ky"
+ ]
+ },
+ "condTwo": {
+ "cond": [
+ "dta_ty in ('12','22')",
+ "mtch_ty is null",
+ "cmpnsp_ky is not null",
+ "cmpnsp_ky != ''"
+ ],
+ "makeCompareKey": [
+ "cmpnsp_ky"
+ ]
+ },
+ "uniqueKey": [
+ "sys_se",
+ "accnut_ym",
+ "sn"
+ ],
+ "compareKey": "compare_ky",
+ "amtField": "sum(delng_amt) as delng_amt",
+ "compareField": [
+ "accnut_ym",
+ "compare_ky",
+ "delng_amt"
+ ],
+ "matchingType": "mtch_ty",
+ "matchingTypeName": "mtch_ty_nm",
+ "matchingNumber": "mtch_ky"
+ },
+ {
+ "active": true,
+ "type": "A-B",
+ "typeName": "자기채권(대사키),상대채무(대사키),비교(년월,비교키,거래금액)",
+
+ "condOne": {
+ "cond": [
+ "dta_ty in ('31','33','35','37','41')",
+ "mtch_ty is null",
+ "cmpnsp_ky is not null",
+ "cmpnsp_ky != ''"
+ ],
+ "makeCompareKey": [
+ "cmpnsp_ky"
+ ]
+ },
+ "condTwo": {
+ "cond": [
+ "dta_ty in ('32','34','36','38','42')",
+ "mtch_ty is null",
+ "cmpnsp_ky is not null",
+ "cmpnsp_ky != ''"
+ ],
+ "makeCompareKey": [
+ "cmpnsp_ky"
+ ]
+ },
+ "uniqueKey": [
+ "sys_se",
+ "accnut_ym",
+ "sn"
+ ],
+ "compareKey": "compare_ky",
+ "amtField": "sum(delng_amt) as delng_amt",
+ "compareField": [
+ "accnut_ym",
+ "compare_ky",
+ "delng_amt"
+ ],
+ "matchingType": "mtch_ty",
+ "matchingTypeName": "mtch_ty_nm",
+ "matchingNumber": "mtch_ky"
+ },
+
+
+
+
+ {
+ "active": true,
+ "type": "B-A",
+ "typeName": "자기수익(합산키),상대비용(합산키),비교(년월,거래금액)",
+
+ "condOne": {
+ "cond": [
+ "dta_ty in ('11','21')",
+ "mtch_ty is null",
+ "ext_key1 is not null",
+ "ext_key1 != ''"
+ ],
+ "makeCompareKey": [
+ "ext_key1"
+ ]
+ },
+ "condTwo": {
+ "cond": [
+ "dta_ty in ('12','22')",
+ "mtch_ty is null",
+ "ext_key1 is not null",
+ "ext_key1 != ''"
+ ],
+ "makeCompareKey": [
+ "ext_key1"
+ ]
+ },
+ "uniqueKey": [
+ "sys_se",
+ "accnut_ym",
+ "sn"
+ ],
+ "compareKey": "compare_ky",
+ "amtField": "sum(delng_amt) as delng_amt",
+ "compareField": [
+ "accnut_ym",
+ "delng_amt"
+ ],
+ "matchingType": "mtch_ty",
+ "matchingTypeName": "mtch_ty_nm",
+ "matchingNumber": "mtch_ky"
+ },
+ {
+ "active": true,
+ "type": "B-B",
+ "typeName": "자기채권(합산키),상대채무(합산키),비교(년월,거래금액)",
+
+ "condOne": {
+ "cond": [
+ "dta_ty in ('31','33','35','37','41')",
+ "mtch_ty is null",
+ "ext_key1 is not null",
+ "ext_key1 != ''"
+ ],
+ "makeCompareKey": [
+ "ext_key1"
+ ]
+ },
+ "condTwo": {
+ "cond": [
+ "dta_ty in ('32','34','36','38','42')",
+ "mtch_ty is null",
+ "ext_key1 is not null",
+ "ext_key1 != ''"
+ ],
+ "makeCompareKey": [
+ "ext_key1"
+ ]
+ },
+ "uniqueKey": [
+ "sys_se",
+ "accnut_ym",
+ "sn"
+ ],
+ "compareKey": "compare_ky",
+ "amtField": "sum(delng_amt) as delng_amt",
+ "compareField": [
+ "accnut_ym",
+ "delng_amt"
+ ],
+ "matchingType": "mtch_ty",
+ "matchingTypeName": "mtch_ty_nm",
+ "matchingNumber": "mtch_ky"
+ },
+
+
+
+
+
+
+ {
+ "active": true,
+ "type": "C-A",
+ "typeName": "자기수익(전표번호),상대비용(전표번호),비교(년월,거래금액)",
+
+ "condOne": {
+ "cond": [
+ "dta_ty in ('11','21')",
+ "mtch_ty is null",
+ "chit_no is not null",
+ "chit_no != ''"
+ ],
+ "makeCompareKey": [
+ "chit_no"
+ ]
+ },
+ "condTwo": {
+ "cond": [
+ "dta_ty in ('12','22')",
+ "mtch_ty is null",
+ "chit_no is not null",
+ "chit_no != ''"
+ ],
+ "makeCompareKey": [
+ "chit_no"
+ ]
+ },
+ "uniqueKey": [
+ "sys_se",
+ "accnut_ym",
+ "sn"
+ ],
+ "compareKey": "compare_ky",
+ "amtField": "sum(delng_amt) as delng_amt",
+ "compareField": [
+ "accnut_ym",
+ "delng_amt"
+ ],
+ "matchingType": "mtch_ty",
+ "matchingTypeName": "mtch_ty_nm",
+ "matchingNumber": "mtch_ky"
+ },
+ {
+ "active": true,
+ "type": "C-B",
+ "typeName": "자기채권(전표번호),상대채무(전표번호),비교(년월,거래금액)",
+
+ "condOne": {
+ "cond": [
+ "dta_ty in ('31','33','35','37','41')",
+ "mtch_ty is null",
+ "chit_no is not null",
+ "chit_no != ''"
+ ],
+ "makeCompareKey": [
+ "chit_no"
+ ]
+ },
+ "condTwo": {
+ "cond": [
+ "dta_ty in ('32','34','36','38','42')",
+ "mtch_ty is null",
+ "chit_no is not null"
+ ],
+ "makeCompareKey": [
+ "chit_no"
+ ]
+ },
+ "uniqueKey": [
+ "sys_se",
+ "accnut_ym",
+ "sn"
+ ],
+ "compareKey": "compare_ky",
+ "amtField": "sum(delng_amt) as delng_amt",
+ "compareField": [
+ "accnut_ym",
+ "delng_amt"
+ ],
+ "matchingType": "mtch_ty",
+ "matchingTypeName": "mtch_ty_nm",
+ "matchingNumber": "mtch_ky"
+ },
+
+
+
+
+
+
+ {
+ "active": true,
+ "type": "D-A",
+ "typeName": "자기수익(거래일자),상대비용(거래일자),비교(년월,거래금액)",
+
+ "condOne": {
+ "cond": [
+ "dta_ty in ('11','21')",
+ "mtch_ty is null"
+ ],
+ "makeCompareKey": [
+ "delng_de"
+ ]
+ },
+ "condTwo": {
+ "cond": [
+ "dta_ty in ('12','22')",
+ "mtch_ty is null"
+ ],
+ "makeCompareKey": [
+ "delng_de"
+ ]
+ },
+ "uniqueKey": [
+ "sys_se",
+ "accnut_ym",
+ "sn"
+ ],
+ "compareKey": "compare_ky",
+ "amtField": "sum(delng_amt) as delng_amt",
+ "compareField": [
+ "accnut_ym",
+ "delng_amt"
+ ],
+ "matchingType": "mtch_ty",
+ "matchingTypeName": "mtch_ty_nm",
+ "matchingNumber": "mtch_ky"
+ },
+ {
+ "active": true,
+ "type": "D-B",
+ "typeName": "자기채권(거래일자),상대채무(거래일자),비교(년월,거래금액)",
+
+ "condOne": {
+ "cond": [
+ "dta_ty in ('31','33','35','37','41')",
+ "mtch_ty is null"
+ ],
+ "makeCompareKey": [
+ "delng_de"
+ ]
+ },
+ "condTwo": {
+ "cond": [
+ "dta_ty in ('32','34','36','38','42')",
+ "mtch_ty is null"
+ ],
+ "makeCompareKey": [
+ "delng_de"
+ ]
+ },
+ "uniqueKey": [
+ "sys_se",
+ "accnut_ym",
+ "sn"
+ ],
+ "compareKey": "compare_ky",
+ "amtField": "sum(delng_amt) as delng_amt",
+ "compareField": [
+ "accnut_ym",
+ "delng_amt"
+ ],
+ "matchingType": "mtch_ty",
+ "matchingTypeName": "mtch_ty_nm",
+ "matchingNumber": "mtch_ky"
+ },
+
+
+
+
+
+ {
+ "active": true,
+ "type": "E-A",
+ "typeName": "자기수익(거래월),상대비용(거래월),비교(년월,거래금액)",
+
+ "condOne": {
+ "cond": [
+ "dta_ty in ('11','21')",
+ "mtch_ty is null"
+ ],
+ "makeCompareKey": [
+ "substring(delng_de,1,6)"
+ ]
+ },
+ "condTwo": {
+ "cond": [
+ "dta_ty in ('12','22')",
+ "mtch_ty is null"
+ ],
+ "makeCompareKey": [
+ "substring(delng_de,1,6)"
+ ]
+ },
+ "uniqueKey": [
+ "sys_se",
+ "accnut_ym",
+ "sn"
+ ],
+ "compareKey": "compare_ky",
+ "amtField": "sum(delng_amt) as delng_amt",
+ "compareField": [
+ "accnut_ym",
+ "delng_amt"
+ ],
+ "matchingType": "mtch_ty",
+ "matchingTypeName": "mtch_ty_nm",
+ "matchingNumber": "mtch_ky"
+ },
+ {
+ "active": true,
+ "type": "E-B",
+ "typeName": "자기채권(거래월),상대채무(거래월),비교(년월,거래금액)",
+
+ "condOne": {
+ "cond": [
+ "dta_ty in ('31','33','35','37','41')",
+ "mtch_ty is null"
+ ],
+ "makeCompareKey": [
+ "substring(delng_de,1,6)"
+ ]
+ },
+ "condTwo": {
+ "cond": [
+ "dta_ty in ('32','34','36','38','42')",
+ "mtch_ty is null"
+ ],
+ "makeCompareKey": [
+ "substring(delng_de,1,6)"
+ ]
+ },
+ "uniqueKey": [
+ "sys_se",
+ "accnut_ym",
+ "sn"
+ ],
+ "compareKey": "compare_ky",
+ "amtField": "sum(delng_amt) as delng_amt",
+ "compareField": [
+ "accnut_ym",
+ "delng_amt"
+ ],
+ "matchingType": "mtch_ty",
+ "matchingTypeName": "mtch_ty_nm",
+ "matchingNumber": "mtch_ky"
+ },
+
+
+
+
+
+
+
+
+ {
+ "active": true,
+ "type": "F-A",
+ "typeName": "자기수익(전체),상대비용(전체),비교(년월,거래금액)",
+
+ "condOne": {
+ "cond": [
+ "dta_ty in ('11','21')",
+ "mtch_ty is null"
+ ],
+ "makeCompareKey": [
+ "sys_se",
+ "accnut_ym"
+ ]
+ },
+ "condTwo": {
+ "cond": [
+ "dta_ty in ('12','22')",
+ "mtch_ty is null"
+ ],
+ "makeCompareKey": [
+ "sys_se",
+ "accnut_ym"
+ ]
+ },
+ "uniqueKey": [
+ "sys_se",
+ "accnut_ym",
+ "sn"
+ ],
+ "compareKey": "compare_ky",
+ "amtField": "sum(delng_amt) as delng_amt",
+ "compareField": [
+ "accnut_ym",
+ "delng_amt"
+ ],
+ "matchingType": "mtch_ty",
+ "matchingTypeName": "mtch_ty_nm",
+ "matchingNumber": "mtch_ky"
+ },
+ {
+ "active": true,
+ "type": "F-B",
+ "typeName": "자기채권(전체),상대채무(전체),비교(년월,거래금액)",
+
+ "condOne": {
+ "cond": [
+ "dta_ty in ('31','33','35','37','41')",
+ "mtch_ty is null"
+ ],
+ "makeCompareKey": [
+ "sys_se",
+ "accnut_ym"
+ ]
+ },
+ "condTwo": {
+ "cond": [
+ "dta_ty in ('32','34','36','38','42')",
+ "mtch_ty is null"
+ ],
+ "makeCompareKey": [
+ "sys_se",
+ "accnut_ym"
+ ]
+ },
+ "uniqueKey": [
+ "sys_se",
+ "accnut_ym",
+ "sn"
+ ],
+ "compareKey": "compare_ky",
+ "amtField": "sum(delng_amt) as delng_amt",
+ "compareField": [
+ "accnut_ym",
+ "delng_amt"
+ ],
+ "matchingType": "mtch_ty",
+ "matchingTypeName": "mtch_ty_nm",
+ "matchingNumber": "mtch_ky"
+ },
+
+
+
+
+
+ {
+ "active": true,
+ "type": "G-A",
+ "typeName": "개별자기수익,상대개별비용,비교(년월,거래금액)",
+
+ "condOne": {
+ "cond": [
+ "dta_ty in ('11','21')",
+ "mtch_ty is null"
+ ],
+ "makeCompareKey": [
+ "sys_se",
+ "accnut_ym",
+ "cast(sn as text)"
+ ]
+ },
+ "condTwo": {
+ "cond": [
+ "dta_ty in ('12','22')",
+ "mtch_ty is null"
+ ],
+ "makeCompareKey": [
+ "sys_se",
+ "accnut_ym",
+ "cast(sn as text)"
+ ]
+ },
+ "uniqueKey": [
+ "sys_se",
+ "accnut_ym",
+ "sn"
+ ],
+ "compareKey": "compare_ky",
+ "amtField": "sum(delng_amt) as delng_amt",
+ "compareField": [
+ "accnut_ym",
+ "delng_amt"
+ ],
+ "matchingType": "mtch_ty",
+ "matchingTypeName": "mtch_ty_nm",
+ "matchingNumber": "mtch_ky"
+ },
+ {
+ "active": true,
+ "type": "G-B",
+ "typeName": "개별자기채권,상대개별채무,비교(년월,거래금액)",
+
+ "condOne": {
+ "cond": [
+ "dta_ty in ('31','33','35','37','41')",
+ "mtch_ty is null"
+ ],
+ "makeCompareKey": [
+ "sys_se",
+ "accnut_ym",
+ "cast(sn as text)"
+ ]
+ },
+ "condTwo": {
+ "cond": [
+ "dta_ty in ('32','34','36','38','42')",
+ "mtch_ty is null"
+ ],
+ "makeCompareKey": [
+ "sys_se",
+ "accnut_ym",
+ "cast(sn as text)"
+ ]
+ },
+ "uniqueKey": [
+ "sys_se",
+ "accnut_ym",
+ "sn"
+ ],
+ "compareKey": "compare_ky",
+ "amtField": "sum(delng_amt) as delng_amt",
+ "compareField": [
+ "accnut_ym",
+ "delng_amt"
+ ],
+ "matchingType": "mtch_ty",
+ "matchingTypeName": "mtch_ty_nm",
+ "matchingNumber": "mtch_ky"
+ },
+
+
+
+
+
+
+
+
+ {
+ "active": true,
+ "type": "H-AA",
+ "typeName": "자기수익(거래일자),개별상대비용,비교(년월,거래금액)",
+
+ "condOne": {
+ "cond": [
+ "dta_ty in ('11','21')",
+ "mtch_ty is null"
+ ],
+ "makeCompareKey": [
+ "sys_se",
+ "accnut_ym",
+ "delng_de"
+ ]
+ },
+ "condTwo": {
+ "cond": [
+ "dta_ty in ('12','22')",
+ "mtch_ty is null"
+ ],
+ "makeCompareKey": [
+ "sys_se",
+ "accnut_ym",
+ "cast(sn as text)"
+ ]
+ },
+ "uniqueKey": [
+ "sys_se",
+ "accnut_ym",
+ "sn"
+ ],
+ "compareKey": "compare_ky",
+ "amtField": "sum(delng_amt) as delng_amt",
+ "compareField": [
+ "accnut_ym",
+ "delng_amt"
+ ],
+ "matchingType": "mtch_ty",
+ "matchingTypeName": "mtch_ty_nm",
+ "matchingNumber": "mtch_ky"
+ },
+ {
+ "active": true,
+ "type": "H-AB",
+ "typeName": "자기수익(거래월),개별상대비용,비교(년월,거래금액)",
+
+ "condOne": {
+ "cond": [
+ "dta_ty in ('11','21')",
+ "mtch_ty is null"
+ ],
+ "makeCompareKey": [
+ "sys_se",
+ "accnut_ym",
+ "substring(delng_de,1,6)" ]
+ },
+ "condTwo": {
+ "cond": [
+ "dta_ty in ('12','22')",
+ "mtch_ty is null"
+ ],
+ "makeCompareKey": [
+ "sys_se",
+ "accnut_ym",
+ "cast(sn as text)"
+ ]
+ },
+ "uniqueKey": [
+ "sys_se",
+ "accnut_ym",
+ "sn"
+ ],
+ "compareKey": "compare_ky",
+ "amtField": "sum(delng_amt) as delng_amt",
+ "compareField": [
+ "accnut_ym",
+ "delng_amt"
+ ],
+ "matchingType": "mtch_ty",
+ "matchingTypeName": "mtch_ty_nm",
+ "matchingNumber": "mtch_ky"
+ },
+ {
+ "active": true,
+ "type": "H-AC",
+ "typeName": "자기수익(전표번호),개별상대비용,비교(년월,거래금액)",
+
+ "condOne": {
+ "cond": [
+ "dta_ty in ('11','21')",
+ "mtch_ty is null",
+ "chit_no is not null",
+ "chit_no != ''"
+ ],
+ "makeCompareKey": [
+ "sys_se",
+ "accnut_ym",
+ "chit_no" ]
+ },
+ "condTwo": {
+ "cond": [
+ "dta_ty in ('12','22')",
+ "mtch_ty is null"
+ ],
+ "makeCompareKey": [
+ "sys_se",
+ "accnut_ym",
+ "cast(sn as text)"
+ ]
+ },
+ "uniqueKey": [
+ "sys_se",
+ "accnut_ym",
+ "sn"
+ ],
+ "compareKey": "compare_ky",
+ "amtField": "sum(delng_amt) as delng_amt",
+ "compareField": [
+ "accnut_ym",
+ "delng_amt"
+ ],
+ "matchingType": "mtch_ty",
+ "matchingTypeName": "mtch_ty_nm",
+ "matchingNumber": "mtch_ky"
+ },
+ {
+ "active": true,
+ "type": "H-AD",
+ "typeName": "자기수익(합산키),개별상대비용,비교(년월,거래금액)",
+
+ "condOne": {
+ "cond": [
+ "dta_ty in ('11','21')",
+ "mtch_ty is null",
+ "ext_key1 is not null",
+ "ext_key1 != ''"
+ ],
+ "makeCompareKey": [
+ "sys_se",
+ "accnut_ym",
+ "ext_key1" ]
+ },
+ "condTwo": {
+ "cond": [
+ "dta_ty in ('12','22')",
+ "mtch_ty is null"
+ ],
+ "makeCompareKey": [
+ "sys_se",
+ "accnut_ym",
+ "cast(sn as text)"
+ ]
+ },
+ "uniqueKey": [
+ "sys_se",
+ "accnut_ym",
+ "sn"
+ ],
+ "compareKey": "compare_ky",
+ "amtField": "sum(delng_amt) as delng_amt",
+ "compareField": [
+ "accnut_ym",
+ "delng_amt"
+ ],
+ "matchingType": "mtch_ty",
+ "matchingTypeName": "mtch_ty_nm",
+ "matchingNumber": "mtch_ky"
+ },
+ {
+ "active": true,
+ "type": "H-AE",
+ "typeName": "자기비용(거래일자),개별상대수익,비교(년월,거래금액)",
+
+ "condOne": {
+ "cond": [
+ "dta_ty in ('12','22')",
+ "mtch_ty is null"
+ ],
+ "makeCompareKey": [
+ "sys_se",
+ "accnut_ym",
+ "delng_de"
+ ]
+ },
+ "condTwo": {
+ "cond": [
+ "dta_ty in ('11','21')",
+ "mtch_ty is null"
+ ],
+ "makeCompareKey": [
+ "sys_se",
+ "accnut_ym",
+ "cast(sn as text)"
+ ]
+ },
+ "uniqueKey": [
+ "sys_se",
+ "accnut_ym",
+ "sn"
+ ],
+ "compareKey": "compare_ky",
+ "amtField": "sum(delng_amt) as delng_amt",
+ "compareField": [
+ "accnut_ym",
+ "delng_amt"
+ ],
+ "matchingType": "mtch_ty",
+ "matchingTypeName": "mtch_ty_nm",
+ "matchingNumber": "mtch_ky"
+ },
+ {
+ "active": true,
+ "type": "H-AF",
+ "typeName": "자기비용(거래월),개별상대수익,비교(년월,거래금액)",
+
+ "condOne": {
+ "cond": [
+ "dta_ty in ('12','22')",
+ "mtch_ty is null"
+ ],
+ "makeCompareKey": [
+ "sys_se",
+ "accnut_ym",
+ "substring(delng_de,1,6)" ]
+ },
+ "condTwo": {
+ "cond": [
+ "dta_ty in ('11','21')",
+ "mtch_ty is null"
+ ],
+ "makeCompareKey": [
+ "sys_se",
+ "accnut_ym",
+ "cast(sn as text)"
+ ]
+ },
+ "uniqueKey": [
+ "sys_se",
+ "accnut_ym",
+ "sn"
+ ],
+ "compareKey": "compare_ky",
+ "amtField": "sum(delng_amt) as delng_amt",
+ "compareField": [
+ "accnut_ym",
+ "delng_amt"
+ ],
+ "matchingType": "mtch_ty",
+ "matchingTypeName": "mtch_ty_nm",
+ "matchingNumber": "mtch_ky"
+ },
+ {
+ "active": true,
+ "type": "H-AG",
+ "typeName": "자기비용(전표번호),개별상대수익,비교(년월,거래금액)",
+
+ "condOne": {
+ "cond": [
+ "dta_ty in ('12','22')",
+ "mtch_ty is null",
+ "chit_no is not null",
+ "chit_no != ''"
+ ],
+ "makeCompareKey": [
+ "sys_se",
+ "accnut_ym",
+ "chit_no" ]
+ },
+ "condTwo": {
+ "cond": [
+ "dta_ty in ('11','21')",
+ "mtch_ty is null"
+ ],
+ "makeCompareKey": [
+ "sys_se",
+ "accnut_ym",
+ "cast(sn as text)"
+ ]
+ },
+ "uniqueKey": [
+ "sys_se",
+ "accnut_ym",
+ "sn"
+ ],
+ "compareKey": "compare_ky",
+ "amtField": "sum(delng_amt) as delng_amt",
+ "compareField": [
+ "accnut_ym",
+ "delng_amt"
+ ],
+ "matchingType": "mtch_ty",
+ "matchingTypeName": "mtch_ty_nm",
+ "matchingNumber": "mtch_ky"
+ },
+ {
+ "active": true,
+ "type": "H-AH",
+ "typeName": "자기비용(합산키),개별상대수익,비교(년월,거래금액)",
+
+ "condOne": {
+ "cond": [
+ "dta_ty in ('12','22')",
+ "mtch_ty is null",
+ "ext_key1 is not null",
+ "ext_key1 != ''"
+ ],
+ "makeCompareKey": [
+ "sys_se",
+ "accnut_ym",
+ "ext_key1" ]
+ },
+ "condTwo": {
+ "cond": [
+ "dta_ty in ('11','21')",
+ "mtch_ty is null"
+ ],
+ "makeCompareKey": [
+ "sys_se",
+ "accnut_ym",
+ "cast(sn as text)"
+ ]
+ },
+ "uniqueKey": [
+ "sys_se",
+ "accnut_ym",
+ "sn"
+ ],
+ "compareKey": "compare_ky",
+ "amtField": "sum(delng_amt) as delng_amt",
+ "compareField": [
+ "accnut_ym",
+ "delng_amt"
+ ],
+ "matchingType": "mtch_ty",
+ "matchingTypeName": "mtch_ty_nm",
+ "matchingNumber": "mtch_ky"
+ },
+
+
+
+ {
+ "active": true,
+ "type": "H-BA",
+ "typeName": "자기채권(거래일자),개별상대채무,비교(년월,거래금액)",
+
+ "condOne": {
+ "cond": [
+ "dta_ty in ('31','33','35','37','41')",
+ "mtch_ty is null"
+ ],
+ "makeCompareKey": [
+ "sys_se",
+ "accnut_ym",
+ "delng_de"
+ ]
+ },
+ "condTwo": {
+ "cond": [
+ "dta_ty in ('32','34','36','38','42')",
+ "mtch_ty is null"
+ ],
+ "makeCompareKey": [
+ "sys_se",
+ "accnut_ym",
+ "cast(sn as text)"
+ ]
+ },
+ "uniqueKey": [
+ "sys_se",
+ "accnut_ym",
+ "sn"
+ ],
+ "compareKey": "compare_ky",
+ "amtField": "sum(delng_amt) as delng_amt",
+ "compareField": [
+ "accnut_ym",
+ "delng_amt"
+ ],
+ "matchingType": "mtch_ty",
+ "matchingTypeName": "mtch_ty_nm",
+ "matchingNumber": "mtch_ky"
+ },
+ {
+ "active": true,
+ "type": "H-BB",
+ "typeName": "자기채권(거래월),개별상대채무,비교(년월,거래금액)",
+
+ "condOne": {
+ "cond": [
+ "dta_ty in ('31','33','35','37','41')",
+ "mtch_ty is null"
+ ],
+ "makeCompareKey": [
+ "sys_se",
+ "accnut_ym",
+ "substring(delng_de,1,6)" ]
+ },
+ "condTwo": {
+ "cond": [
+ "dta_ty in ('32','34','36','38','42')",
+ "mtch_ty is null"
+ ],
+ "makeCompareKey": [
+ "sys_se",
+ "accnut_ym",
+ "cast(sn as text)"
+ ]
+ },
+ "uniqueKey": [
+ "sys_se",
+ "accnut_ym",
+ "sn"
+ ],
+ "compareKey": "compare_ky",
+ "amtField": "sum(delng_amt) as delng_amt",
+ "compareField": [
+ "accnut_ym",
+ "delng_amt"
+ ],
+ "matchingType": "mtch_ty",
+ "matchingTypeName": "mtch_ty_nm",
+ "matchingNumber": "mtch_ky"
+ },
+ {
+ "active": true,
+ "type": "H-BC",
+ "typeName": "자기채권(전표번호),개별상대채무,비교(년월,거래금액)",
+
+ "condOne": {
+ "cond": [
+ "dta_ty in ('31','33','35','37','41')",
+ "mtch_ty is null",
+ "chit_no is not null",
+ "chit_no != ''"
+ ],
+ "makeCompareKey": [
+ "sys_se",
+ "accnut_ym",
+ "chit_no" ]
+ },
+ "condTwo": {
+ "cond": [
+ "dta_ty in ('32','34','36','38','42')",
+ "mtch_ty is null"
+ ],
+ "makeCompareKey": [
+ "sys_se",
+ "accnut_ym",
+ "cast(sn as text)"
+ ]
+ },
+ "uniqueKey": [
+ "sys_se",
+ "accnut_ym",
+ "sn"
+ ],
+ "compareKey": "compare_ky",
+ "amtField": "sum(delng_amt) as delng_amt",
+ "compareField": [
+ "accnut_ym",
+ "delng_amt"
+ ],
+ "matchingType": "mtch_ty",
+ "matchingTypeName": "mtch_ty_nm",
+ "matchingNumber": "mtch_ky"
+ },
+ {
+ "active": true,
+ "type": "H-BD",
+ "typeName": "자기채권(합산키),개별상대채무,비교(년월,거래금액)",
+
+ "condOne": {
+ "cond": [
+ "dta_ty in ('31','33','35','37','41')",
+ "mtch_ty is null"
+ ],
+ "makeCompareKey": [
+ "sys_se",
+ "accnut_ym",
+ "ext_key1" ]
+ },
+ "condTwo": {
+ "cond": [
+ "dta_ty in ('32','34','36','38','42')",
+ "mtch_ty is null"
+ ],
+ "makeCompareKey": [
+ "sys_se",
+ "accnut_ym",
+ "cast(sn as text)"
+ ]
+ },
+ "uniqueKey": [
+ "sys_se",
+ "accnut_ym",
+ "sn"
+ ],
+ "compareKey": "compare_ky",
+ "amtField": "sum(delng_amt) as delng_amt",
+ "compareField": [
+ "accnut_ym",
+ "delng_amt"
+ ],
+ "matchingType": "mtch_ty",
+ "matchingTypeName": "mtch_ty_nm",
+ "matchingNumber": "mtch_ky"
+ },
+ {
+ "active": true,
+ "type": "H-BE",
+ "typeName": "자기채무(거래일자),개별상대채권,비교(년월,거래금액)",
+
+ "condOne": {
+ "cond": [
+ "dta_ty in ('32','34','36','38','42')",
+ "mtch_ty is null"
+ ],
+ "makeCompareKey": [
+ "sys_se",
+ "accnut_ym",
+ "delng_de"
+ ]
+ },
+ "condTwo": {
+ "cond": [
+ "dta_ty in ('31','33','35','37','41')",
+ "mtch_ty is null"
+ ],
+ "makeCompareKey": [
+ "sys_se",
+ "accnut_ym",
+ "cast(sn as text)"
+ ]
+ },
+ "uniqueKey": [
+ "sys_se",
+ "accnut_ym",
+ "sn"
+ ],
+ "compareKey": "compare_ky",
+ "amtField": "sum(delng_amt) as delng_amt",
+ "compareField": [
+ "accnut_ym",
+ "delng_amt"
+ ],
+ "matchingType": "mtch_ty",
+ "matchingTypeName": "mtch_ty_nm",
+ "matchingNumber": "mtch_ky"
+ },
+ {
+ "active": true,
+ "type": "H-BF",
+ "typeName": "자기채무(거래월),개별상대채권,비교(년월,거래금액)",
+
+ "condOne": {
+ "cond": [
+ "dta_ty in ('32','34','36','38','42')",
+ "mtch_ty is null"
+ ],
+ "makeCompareKey": [
+ "sys_se",
+ "accnut_ym",
+ "substring(delng_de,1,6)" ]
+ },
+ "condTwo": {
+ "cond": [
+ "dta_ty in ('31','33','35','37','41')",
+ "mtch_ty is null"
+ ],
+ "makeCompareKey": [
+ "sys_se",
+ "accnut_ym",
+ "cast(sn as text)"
+ ]
+ },
+ "uniqueKey": [
+ "sys_se",
+ "accnut_ym",
+ "sn"
+ ],
+ "compareKey": "compare_ky",
+ "amtField": "sum(delng_amt) as delng_amt",
+ "compareField": [
+ "accnut_ym",
+ "delng_amt"
+ ],
+ "matchingType": "mtch_ty",
+ "matchingTypeName": "mtch_ty_nm",
+ "matchingNumber": "mtch_ky"
+ },
+ {
+ "active": true,
+ "type": "H-BG",
+ "typeName": "자기채무(전표번호),개별상대채권,비교(년월,거래금액)",
+
+ "condOne": {
+ "cond": [
+ "dta_ty in ('32','34','36','38','42')",
+ "mtch_ty is null",
+ "chit_no is not null",
+ "chit_no != ''"
+ ],
+ "makeCompareKey": [
+ "sys_se",
+ "accnut_ym",
+ "chit_no" ]
+ },
+ "condTwo": {
+ "cond": [
+ "dta_ty in ('31','33','35','37','41')",
+ "mtch_ty is null"
+ ],
+ "makeCompareKey": [
+ "sys_se",
+ "accnut_ym",
+ "cast(sn as text)"
+ ]
+ },
+ "uniqueKey": [
+ "sys_se",
+ "accnut_ym",
+ "sn"
+ ],
+ "compareKey": "compare_ky",
+ "amtField": "sum(delng_amt) as delng_amt",
+ "compareField": [
+ "accnut_ym",
+ "delng_amt"
+ ],
+ "matchingType": "mtch_ty",
+ "matchingTypeName": "mtch_ty_nm",
+ "matchingNumber": "mtch_ky"
+ },
+ {
+ "active": true,
+ "type": "H-BH",
+ "typeName": "자기채무(합산키),개별상대채권,비교(년월,거래금액)",
+
+ "condOne": {
+ "cond": [
+ "dta_ty in ('32','34','36','38','42')",
+ "mtch_ty is null"
+ ],
+ "makeCompareKey": [
+ "sys_se",
+ "accnut_ym",
+ "ext_key1" ]
+ },
+ "condTwo": {
+ "cond": [
+ "dta_ty in ('31','33','35','37','41')",
+ "mtch_ty is null"
+ ],
+ "makeCompareKey": [
+ "sys_se",
+ "accnut_ym",
+ "cast(sn as text)"
+ ]
+ },
+ "uniqueKey": [
+ "sys_se",
+ "accnut_ym",
+ "sn"
+ ],
+ "compareKey": "compare_ky",
+ "amtField": "sum(delng_amt) as delng_amt",
+ "compareField": [
+ "accnut_ym",
+ "delng_amt"
+ ],
+ "matchingType": "mtch_ty",
+ "matchingTypeName": "mtch_ty_nm",
+ "matchingNumber": "mtch_ky"
+ },
+
+
+
+
+ {
+ "active": true,
+ "type": "I-AA",
+ "typeName": "자기수익(전체),상대비용(겨래월),비교(년월,거래금액)",
+
+ "condOne": {
+ "cond": [
+ "dta_ty in ('11','21')",
+ "mtch_ty is null"
+ ],
+ "makeCompareKey": [
+ "sys_se",
+ "accnut_ym"
+ ]
+ },
+ "condTwo": {
+ "cond": [
+ "dta_ty in ('12','22')",
+ "mtch_ty is null"
+ ],
+ "makeCompareKey": [
+ "sys_se",
+ "accnut_ym",
+ "substring(delng_de,1,6)"
+ ]
+ },
+ "uniqueKey": [
+ "sys_se",
+ "accnut_ym",
+ "sn"
+ ],
+ "compareKey": "compare_ky",
+ "amtField": "sum(delng_amt) as delng_amt",
+ "compareField": [
+ "accnut_ym",
+ "delng_amt"
+ ],
+ "matchingType": "mtch_ty",
+ "matchingTypeName": "mtch_ty_nm",
+ "matchingNumber": "mtch_ky"
+ },
+ {
+ "active": true,
+ "type": "I-AB",
+ "typeName": "자기수익(전체),상대비용(겨래일자),비교(년월,거래금액)",
+
+ "condOne": {
+ "cond": [
+ "dta_ty in ('11','21')",
+ "mtch_ty is null"
+ ],
+ "makeCompareKey": [
+ "sys_se",
+ "accnut_ym"
+ ]
+ },
+ "condTwo": {
+ "cond": [
+ "dta_ty in ('12','22')",
+ "mtch_ty is null"
+ ],
+ "makeCompareKey": [
+ "sys_se",
+ "accnut_ym",
+ "delng_de"
+ ]
+ },
+ "uniqueKey": [
+ "sys_se",
+ "accnut_ym",
+ "sn"
+ ],
+ "compareKey": "compare_ky",
+ "amtField": "sum(delng_amt) as delng_amt",
+ "compareField": [
+ "accnut_ym",
+ "delng_amt"
+ ],
+ "matchingType": "mtch_ty",
+ "matchingTypeName": "mtch_ty_nm",
+ "matchingNumber": "mtch_ky"
+ },
+ {
+ "active": true,
+ "type": "I-AC",
+ "typeName": "자기비용(전체),상대수익(겨래월),비교(년월,거래금액)",
+
+ "condOne": {
+ "cond": [
+ "dta_ty in ('12','22')",
+ "mtch_ty is null"
+ ],
+ "makeCompareKey": [
+ "sys_se",
+ "accnut_ym"
+ ]
+ },
+ "condTwo": {
+ "cond": [
+ "dta_ty in ('11','21')",
+ "mtch_ty is null"
+ ],
+ "makeCompareKey": [
+ "sys_se",
+ "accnut_ym",
+ "substring(delng_de,1,6)"
+ ]
+ },
+ "uniqueKey": [
+ "sys_se",
+ "accnut_ym",
+ "sn"
+ ],
+ "compareKey": "compare_ky",
+ "amtField": "sum(delng_amt) as delng_amt",
+ "compareField": [
+ "accnut_ym",
+ "delng_amt"
+ ],
+ "matchingType": "mtch_ty",
+ "matchingTypeName": "mtch_ty_nm",
+ "matchingNumber": "mtch_ky"
+ },
+ {
+ "active": true,
+ "type": "I-AD",
+ "typeName": "자기비용(전체),상대수익(겨래일자),비교(년월,거래금액)",
+
+ "condOne": {
+ "cond": [
+ "dta_ty in ('12','22')",
+ "mtch_ty is null"
+ ],
+ "makeCompareKey": [
+ "sys_se",
+ "accnut_ym"
+ ]
+ },
+ "condTwo": {
+ "cond": [
+ "dta_ty in ('11','21')",
+ "mtch_ty is null"
+ ],
+ "makeCompareKey": [
+ "sys_se",
+ "accnut_ym",
+ "delng_de"
+ ]
+ },
+ "uniqueKey": [
+ "sys_se",
+ "accnut_ym",
+ "sn"
+ ],
+ "compareKey": "compare_ky",
+ "amtField": "sum(delng_amt) as delng_amt",
+ "compareField": [
+ "accnut_ym",
+ "delng_amt"
+ ],
+ "matchingType": "mtch_ty",
+ "matchingTypeName": "mtch_ty_nm",
+ "matchingNumber": "mtch_ky"
+ },
+ {
+ "active": true,
+ "type": "I-AE",
+ "typeName": "자기수익(전체),상대비용(법인계정코드),비교(년월,거래금액)",
+
+ "condOne": {
+ "cond": [
+ "dta_ty in ('11','21')",
+ "mtch_ty is null"
+ ],
+ "makeCompareKey": [
+ "sys_se",
+ "accnut_ym"
+ ]
+ },
+ "condTwo": {
+ "cond": [
+ "dta_ty in ('12','22')",
+ "mtch_ty is null"
+ ],
+ "makeCompareKey": [
+ "sys_se",
+ "accnut_ym",
+ "cpr_acnt_code"
+ ]
+ },
+ "uniqueKey": [
+ "sys_se",
+ "accnut_ym",
+ "sn"
+ ],
+ "compareKey": "compare_ky",
+ "amtField": "sum(delng_amt) as delng_amt",
+ "compareField": [
+ "accnut_ym",
+ "delng_amt"
+ ],
+ "matchingType": "mtch_ty",
+ "matchingTypeName": "mtch_ty_nm",
+ "matchingNumber": "mtch_ky"
+ },
+ {
+ "active": true,
+ "type": "I-AF",
+ "typeName": "자기비용(전체),상대수익(법인계정코드),비교(년월,거래금액)",
+
+ "condOne": {
+ "cond": [
+ "dta_ty in ('12','22')",
+ "mtch_ty is null"
+ ],
+ "makeCompareKey": [
+ "sys_se",
+ "accnut_ym"
+ ]
+ },
+ "condTwo": {
+ "cond": [
+ "dta_ty in ('11','21')",
+ "mtch_ty is null"
+ ],
+ "makeCompareKey": [
+ "sys_se",
+ "accnut_ym",
+ "cpr_acnt_code"
+ ]
+ },
+ "uniqueKey": [
+ "sys_se",
+ "accnut_ym",
+ "sn"
+ ],
+ "compareKey": "compare_ky",
+ "amtField": "sum(delng_amt) as delng_amt",
+ "compareField": [
+ "accnut_ym",
+ "delng_amt"
+ ],
+ "matchingType": "mtch_ty",
+ "matchingTypeName": "mtch_ty_nm",
+ "matchingNumber": "mtch_ky"
+ },
+
+
+
+ {
+ "active": true,
+ "type": "I-BA",
+ "typeName": "자기채권(전체),상대채무(겨래월),비교(년월,거래금액)",
+
+ "condOne": {
+ "cond": [
+ "dta_ty in ('31','33','35','37','41')",
+ "mtch_ty is null"
+ ],
+ "makeCompareKey": [
+ "sys_se",
+ "accnut_ym"
+ ]
+ },
+ "condTwo": {
+ "cond": [
+ "dta_ty in ('32','34','36','38','42')",
+ "mtch_ty is null"
+ ],
+ "makeCompareKey": [
+ "sys_se",
+ "accnut_ym",
+ "substring(delng_de,1,6)"
+ ]
+ },
+ "uniqueKey": [
+ "sys_se",
+ "accnut_ym",
+ "sn"
+ ],
+ "compareKey": "compare_ky",
+ "amtField": "sum(delng_amt) as delng_amt",
+ "compareField": [
+ "accnut_ym",
+ "delng_amt"
+ ],
+ "matchingType": "mtch_ty",
+ "matchingTypeName": "mtch_ty_nm",
+ "matchingNumber": "mtch_ky"
+ },
+ {
+ "active": true,
+ "type": "I-BB",
+ "typeName": "자기채권(전체),상대채무(겨래일자),비교(년월,거래금액)",
+
+ "condOne": {
+ "cond": [
+ "dta_ty in ('31','33','35','37','41')",
+ "mtch_ty is null"
+ ],
+ "makeCompareKey": [
+ "sys_se",
+ "accnut_ym"
+ ]
+ },
+ "condTwo": {
+ "cond": [
+ "dta_ty in ('32','34','36','38','42')",
+ "mtch_ty is null"
+ ],
+ "makeCompareKey": [
+ "sys_se",
+ "accnut_ym",
+ "delng_de"
+ ]
+ },
+ "uniqueKey": [
+ "sys_se",
+ "accnut_ym",
+ "sn"
+ ],
+ "compareKey": "compare_ky",
+ "amtField": "sum(delng_amt) as delng_amt",
+ "compareField": [
+ "accnut_ym",
+ "delng_amt"
+ ],
+ "matchingType": "mtch_ty",
+ "matchingTypeName": "mtch_ty_nm",
+ "matchingNumber": "mtch_ky"
+ },
+ {
+ "active": true,
+ "type": "I-BC",
+ "typeName": "자기채무(전체),상대채권(겨래월),비교(년월,거래금액)",
+
+ "condOne": {
+ "cond": [
+ "dta_ty in ('32','34','36','38','42')",
+ "mtch_ty is null"
+ ],
+ "makeCompareKey": [
+ "sys_se",
+ "accnut_ym"
+ ]
+ },
+ "condTwo": {
+ "cond": [
+ "dta_ty in ('31','33','35','37','41')",
+ "mtch_ty is null"
+ ],
+ "makeCompareKey": [
+ "sys_se",
+ "accnut_ym",
+ "substring(delng_de,1,6)"
+ ]
+ },
+ "uniqueKey": [
+ "sys_se",
+ "accnut_ym",
+ "sn"
+ ],
+ "compareKey": "compare_ky",
+ "amtField": "sum(delng_amt) as delng_amt",
+ "compareField": [
+ "accnut_ym",
+ "delng_amt"
+ ],
+ "matchingType": "mtch_ty",
+ "matchingTypeName": "mtch_ty_nm",
+ "matchingNumber": "mtch_ky"
+ },
+ {
+ "active": true,
+ "type": "I-BD",
+ "typeName": "자기채무(전체),상대채권(겨래일자),비교(년월,거래금액)",
+
+ "condOne": {
+ "cond": [
+ "dta_ty in ('32','34','36','38','42')",
+ "mtch_ty is null"
+ ],
+ "makeCompareKey": [
+ "sys_se",
+ "accnut_ym"
+ ]
+ },
+ "condTwo": {
+ "cond": [
+ "dta_ty in ('31','33','35','37','41')",
+ "mtch_ty is null"
+ ],
+ "makeCompareKey": [
+ "sys_se",
+ "accnut_ym",
+ "delng_de"
+ ]
+ },
+ "uniqueKey": [
+ "sys_se",
+ "accnut_ym",
+ "sn"
+ ],
+ "compareKey": "compare_ky",
+ "amtField": "sum(delng_amt) as delng_amt",
+ "compareField": [
+ "accnut_ym",
+ "delng_amt"
+ ],
+ "matchingType": "mtch_ty",
+ "matchingTypeName": "mtch_ty_nm",
+ "matchingNumber": "mtch_ky"
+ },
+ {
+ "active": true,
+ "type": "I-BE",
+ "typeName": "자기채권(전체),상대채무(계정코드),비교(년월,거래금액)",
+
+ "condOne": {
+ "cond": [
+ "dta_ty in ('31','33','35','37','41')",
+ "mtch_ty is null"
+ ],
+ "makeCompareKey": [
+ "sys_se",
+ "cpr_acnt_code"
+ ]
+ },
+ "condTwo": {
+ "cond": [
+ "dta_ty in ('32','34','36','38','42')",
+ "mtch_ty is null"
+ ],
+ "makeCompareKey": [
+ "sys_se",
+ "accnut_ym",
+ "delng_de"
+ ]
+ },
+ "uniqueKey": [
+ "sys_se",
+ "accnut_ym",
+ "sn"
+ ],
+ "compareKey": "compare_ky",
+ "amtField": "sum(delng_amt) as delng_amt",
+ "compareField": [
+ "accnut_ym",
+ "delng_amt"
+ ],
+ "matchingType": "mtch_ty",
+ "matchingTypeName": "mtch_ty_nm",
+ "matchingNumber": "mtch_ky"
+ },
+ {
+ "active": true,
+ "type": "I-BF",
+ "typeName": "자기채무(전체),상대채권(계정코드),비교(년월,거래금액)",
+
+ "condOne": {
+ "cond": [
+ "dta_ty in ('32','34','36','38','42')",
+ "mtch_ty is null"
+ ],
+ "makeCompareKey": [
+ "sys_se",
+ "cpr_acnt_code"
+ ]
+ },
+ "condTwo": {
+ "cond": [
+ "dta_ty in ('31','33','35','37','41')",
+ "mtch_ty is null"
+ ],
+ "makeCompareKey": [
+ "sys_se",
+ "accnut_ym",
+ "delng_de"
+ ]
+ },
+ "uniqueKey": [
+ "sys_se",
+ "accnut_ym",
+ "sn"
+ ],
+ "compareKey": "compare_ky",
+ "amtField": "sum(delng_amt) as delng_amt",
+ "compareField": [
+ "accnut_ym",
+ "delng_amt"
+ ],
+ "matchingType": "mtch_ty",
+ "matchingTypeName": "mtch_ty_nm",
+ "matchingNumber": "mtch_ky"
+ },
+
+
+
+
+ {
+ "active": true,
+ "type": "J-AA",
+ "typeName": "자기수익(거래월),상대비용(겨래일자),비교(년월,거래금액)",
+
+ "condOne": {
+ "cond": [
+ "dta_ty in ('11','21')",
+ "mtch_ty is null"
+ ],
+ "makeCompareKey": [
+ "sys_se",
+ "accnut_ym",
+ "substring(delng_de,1,6)"
+ ]
+ },
+ "condTwo": {
+ "cond": [
+ "dta_ty in ('12','22')",
+ "mtch_ty is null"
+ ],
+ "makeCompareKey": [
+ "sys_se",
+ "accnut_ym",
+ "delng_de"
+ ]
+ },
+ "uniqueKey": [
+ "sys_se",
+ "accnut_ym",
+ "sn"
+ ],
+ "compareKey": "compare_ky",
+ "amtField": "sum(delng_amt) as delng_amt",
+ "compareField": [
+ "accnut_ym",
+ "delng_amt"
+ ],
+ "matchingType": "mtch_ty",
+ "matchingTypeName": "mtch_ty_nm",
+ "matchingNumber": "mtch_ky"
+ },
+ {
+ "active": true,
+ "type": "J-AB",
+ "typeName": "자기비용(거래월),상대수익(겨래일자),비교(년월,거래금액)",
+
+ "condOne": {
+ "cond": [
+ "dta_ty in ('12','22')",
+ "mtch_ty is null"
+ ],
+ "makeCompareKey": [
+ "sys_se",
+ "accnut_ym",
+ "substring(delng_de,1,6)"
+ ]
+ },
+ "condTwo": {
+ "cond": [
+ "dta_ty in ('11','21')",
+ "mtch_ty is null"
+ ],
+ "makeCompareKey": [
+ "sys_se",
+ "accnut_ym",
+ "delng_de"
+ ]
+ },
+ "uniqueKey": [
+ "sys_se",
+ "accnut_ym",
+ "sn"
+ ],
+ "compareKey": "compare_ky",
+ "amtField": "sum(delng_amt) as delng_amt",
+ "compareField": [
+ "accnut_ym",
+ "delng_amt"
+ ],
+ "matchingType": "mtch_ty",
+ "matchingTypeName": "mtch_ty_nm",
+ "matchingNumber": "mtch_ky"
+ },
+ {
+ "active": true,
+ "type": "J-AC",
+ "typeName": "자기수익(거래월),상대비용(계정코드),비교(년월,거래금액)",
+
+ "condOne": {
+ "cond": [
+ "dta_ty in ('11','21')",
+ "mtch_ty is null"
+ ],
+ "makeCompareKey": [
+ "sys_se",
+ "accnut_ym",
+ "substring(delng_de,1,6)"
+ ]
+ },
+ "condTwo": {
+ "cond": [
+ "dta_ty in ('12','22')",
+ "mtch_ty is null"
+ ],
+ "makeCompareKey": [
+ "sys_se",
+ "accnut_ym",
+ "cpr_acnt_code"
+ ]
+ },
+ "uniqueKey": [
+ "sys_se",
+ "accnut_ym",
+ "sn"
+ ],
+ "compareKey": "compare_ky",
+ "amtField": "sum(delng_amt) as delng_amt",
+ "compareField": [
+ "accnut_ym",
+ "delng_amt"
+ ],
+ "matchingType": "mtch_ty",
+ "matchingTypeName": "mtch_ty_nm",
+ "matchingNumber": "mtch_ky"
+ },
+ {
+ "active": true,
+ "type": "J-AD",
+ "typeName": "자기비용(거래월),상대수익(계정코드),비교(년월,거래금액)",
+
+ "condOne": {
+ "cond": [
+ "dta_ty in ('12','22')",
+ "mtch_ty is null"
+ ],
+ "makeCompareKey": [
+ "sys_se",
+ "accnut_ym",
+ "substring(delng_de,1,6)"
+ ]
+ },
+ "condTwo": {
+ "cond": [
+ "dta_ty in ('11','21')",
+ "mtch_ty is null"
+ ],
+ "makeCompareKey": [
+ "sys_se",
+ "accnut_ym",
+ "cpr_acnt_code"
+ ]
+ },
+ "uniqueKey": [
+ "sys_se",
+ "accnut_ym",
+ "sn"
+ ],
+ "compareKey": "compare_ky",
+ "amtField": "sum(delng_amt) as delng_amt",
+ "compareField": [
+ "accnut_ym",
+ "delng_amt"
+ ],
+ "matchingType": "mtch_ty",
+ "matchingTypeName": "mtch_ty_nm",
+ "matchingNumber": "mtch_ky"
+ },
+
+ {
+ "active": true,
+ "type": "J-BA",
+ "typeName": "자기채권(거래월),상대채무(겨래일자),비교(년월,거래금액)",
+
+ "condOne": {
+ "cond": [
+ "dta_ty in ('31','33','35','37','41')",
+ "mtch_ty is null"
+ ],
+ "makeCompareKey": [
+ "sys_se",
+ "accnut_ym",
+ "substring(delng_de,1,6)"
+ ]
+ },
+ "condTwo": {
+ "cond": [
+ "dta_ty in ('32','34','36','38','42')",
+ "mtch_ty is null"
+ ],
+ "makeCompareKey": [
+ "sys_se",
+ "accnut_ym",
+ "delng_de"
+ ]
+ },
+ "uniqueKey": [
+ "sys_se",
+ "accnut_ym",
+ "sn"
+ ],
+ "compareKey": "compare_ky",
+ "amtField": "sum(delng_amt) as delng_amt",
+ "compareField": [
+ "accnut_ym",
+ "delng_amt"
+ ],
+ "matchingType": "mtch_ty",
+ "matchingTypeName": "mtch_ty_nm",
+ "matchingNumber": "mtch_ky"
+ },
+ {
+ "active": true,
+ "type": "J-BB",
+ "typeName": "자기채무(거래월),상대채권(겨래일자),비교(년월,거래금액)",
+
+ "condOne": {
+ "cond": [
+ "dta_ty in ('32','34','36','38','42')",
+ "mtch_ty is null"
+ ],
+ "makeCompareKey": [
+ "sys_se",
+ "accnut_ym",
+ "substring(delng_de,1,6)"
+ ]
+ },
+ "condTwo": {
+ "cond": [
+ "dta_ty in ('31','33','35','37','41')",
+ "mtch_ty is null"
+ ],
+ "makeCompareKey": [
+ "sys_se",
+ "accnut_ym",
+ "delng_de"
+ ]
+ },
+ "uniqueKey": [
+ "sys_se",
+ "accnut_ym",
+ "sn"
+ ],
+ "compareKey": "compare_ky",
+ "amtField": "sum(delng_amt) as delng_amt",
+ "compareField": [
+ "accnut_ym",
+ "delng_amt"
+ ],
+ "matchingType": "mtch_ty",
+ "matchingTypeName": "mtch_ty_nm",
+ "matchingNumber": "mtch_ky"
+ },
+ {
+ "active": true,
+ "type": "J-BC",
+ "typeName": "자기채권(거래월),상대채무(계정코드),비교(년월,거래금액)",
+
+ "condOne": {
+ "cond": [
+ "dta_ty in ('31','33','35','37','41')",
+ "mtch_ty is null"
+ ],
+ "makeCompareKey": [
+ "sys_se",
+ "accnut_ym",
+ "substring(delng_de,1,6)"
+ ]
+ },
+ "condTwo": {
+ "cond": [
+ "dta_ty in ('32','34','36','38','42')",
+ "mtch_ty is null"
+ ],
+ "makeCompareKey": [
+ "sys_se",
+ "accnut_ym",
+ "cpr_acnt_code"
+ ]
+ },
+ "uniqueKey": [
+ "sys_se",
+ "accnut_ym",
+ "sn"
+ ],
+ "compareKey": "compare_ky",
+ "amtField": "sum(delng_amt) as delng_amt",
+ "compareField": [
+ "accnut_ym",
+ "delng_amt"
+ ],
+ "matchingType": "mtch_ty",
+ "matchingTypeName": "mtch_ty_nm",
+ "matchingNumber": "mtch_ky"
+ },
+ {
+ "active": true,
+ "type": "J-BD",
+ "typeName": "자기채무(거래월),상대채권(계정코드),비교(년월,거래금액)",
+
+ "condOne": {
+ "cond": [
+ "dta_ty in ('32','34','36','38','42')",
+ "mtch_ty is null"
+ ],
+ "makeCompareKey": [
+ "sys_se",
+ "accnut_ym",
+ "substring(delng_de,1,6)"
+ ]
+ },
+ "condTwo": {
+ "cond": [
+ "dta_ty in ('31','33','35','37','41')",
+ "mtch_ty is null"
+ ],
+ "makeCompareKey": [
+ "sys_se",
+ "accnut_ym",
+ "cpr_acnt_code"
+ ]
+ },
+ "uniqueKey": [
+ "sys_se",
+ "accnut_ym",
+ "sn"
+ ],
+ "compareKey": "compare_ky",
+ "amtField": "sum(delng_amt) as delng_amt",
+ "compareField": [
+ "accnut_ym",
+ "delng_amt"
+ ],
+ "matchingType": "mtch_ty",
+ "matchingTypeName": "mtch_ty_nm",
+ "matchingNumber": "mtch_ky"
+ },
+
+
+
+
+
+
+
+
+
+
+
+
+
+ {
+ "active": true,
+ "type": "K-AA",
+ "typeName": "자기수익(적요),상대비용(적요),비교(년월,거래금액)",
+
+ "condOne": {
+ "cond": [
+ "dta_ty in ('11','21')",
+ "mtch_ty is null"
+ ],
+ "makeCompareKey": [
+ "sys_se",
+ "accnut_ym",
+ "substring(sumry, 1, 80)"
+ ]
+ },
+ "condTwo": {
+ "cond": [
+ "dta_ty in ('12','22')",
+ "mtch_ty is null"
+ ],
+ "makeCompareKey": [
+ "sys_se",
+ "accnut_ym",
+ "substring(sumry, 1, 80)"
+ ]
+ },
+ "uniqueKey": [
+ "sys_se",
+ "accnut_ym",
+ "sn"
+ ],
+ "compareKey": "compare_ky",
+ "amtField": "sum(delng_amt) as delng_amt",
+ "compareField": [
+ "accnut_ym",
+ "delng_amt"
+ ],
+ "matchingType": "mtch_ty",
+ "matchingTypeName": "mtch_ty_nm",
+ "matchingNumber": "mtch_ky"
+ },
+ {
+ "active": true,
+ "type": "K-AB",
+ "typeName": "자기비용(적요),상대수익(겨래일자),비교(년월,거래금액)",
+
+ "condOne": {
+ "cond": [
+ "dta_ty in ('12','22')",
+ "mtch_ty is null"
+ ],
+ "makeCompareKey": [
+ "sys_se",
+ "accnut_ym",
+ "substring(sumry, 1, 80)"
+ ]
+ },
+ "condTwo": {
+ "cond": [
+ "dta_ty in ('11','21')",
+ "mtch_ty is null"
+ ],
+ "makeCompareKey": [
+ "sys_se",
+ "accnut_ym",
+ "delng_de"
+ ]
+ },
+ "uniqueKey": [
+ "sys_se",
+ "accnut_ym",
+ "sn"
+ ],
+ "compareKey": "compare_ky",
+ "amtField": "sum(delng_amt) as delng_amt",
+ "compareField": [
+ "accnut_ym",
+ "delng_amt"
+ ],
+ "matchingType": "mtch_ty",
+ "matchingTypeName": "mtch_ty_nm",
+ "matchingNumber": "mtch_ky"
+ },
+ {
+ "active": true,
+ "type": "K-AC",
+ "typeName": "자기수익(적요),개별상대비용,비교(년월,거래금액)",
+
+ "condOne": {
+ "cond": [
+ "dta_ty in ('11','21')",
+ "mtch_ty is null"
+ ],
+ "makeCompareKey": [
+ "sys_se",
+ "accnut_ym",
+ "substring(sumry, 1, 80)"
+ ]
+ },
+ "condTwo": {
+ "cond": [
+ "dta_ty in ('12','22')",
+ "mtch_ty is null"
+ ],
+ "makeCompareKey": [
+ "sys_se",
+ "accnut_ym",
+ "cast(sn as text)"
+ ]
+ },
+ "uniqueKey": [
+ "sys_se",
+ "accnut_ym",
+ "sn"
+ ],
+ "compareKey": "compare_ky",
+ "amtField": "sum(delng_amt) as delng_amt",
+ "compareField": [
+ "accnut_ym",
+ "delng_amt"
+ ],
+ "matchingType": "mtch_ty",
+ "matchingTypeName": "mtch_ty_nm",
+ "matchingNumber": "mtch_ky"
+ },
+ {
+ "active": true,
+ "type": "K-AD",
+ "typeName": "자기비용(적요),개별상대수익,비교(년월,거래금액)",
+
+ "condOne": {
+ "cond": [
+ "dta_ty in ('12','22')",
+ "mtch_ty is null"
+ ],
+ "makeCompareKey": [
+ "sys_se",
+ "accnut_ym",
+ "substring(sumry, 1, 80)"
+ ]
+ },
+ "condTwo": {
+ "cond": [
+ "dta_ty in ('11','21')",
+ "mtch_ty is null"
+ ],
+ "makeCompareKey": [
+ "sys_se",
+ "accnut_ym",
+ "cast(sn as text)"
+ ]
+ },
+ "uniqueKey": [
+ "sys_se",
+ "accnut_ym",
+ "sn"
+ ],
+ "compareKey": "compare_ky",
+ "amtField": "sum(delng_amt) as delng_amt",
+ "compareField": [
+ "accnut_ym",
+ "delng_amt"
+ ],
+ "matchingType": "mtch_ty",
+ "matchingTypeName": "mtch_ty_nm",
+ "matchingNumber": "mtch_ky"
+ },
+ {
+ "active": true,
+ "type": "K-BA",
+ "typeName": "자기채권(적요),상대채무(겨래일자),비교(년월,거래금액)",
+
+ "condOne": {
+ "cond": [
+ "dta_ty in ('31','33','35','37','41')",
+ "mtch_ty is null"
+ ],
+ "makeCompareKey": [
+ "sys_se",
+ "accnut_ym",
+ "substring(sumry, 1, 80)"
+ ]
+ },
+ "condTwo": {
+ "cond": [
+ "dta_ty in ('32','34','36','38','42')",
+ "mtch_ty is null"
+ ],
+ "makeCompareKey": [
+ "sys_se",
+ "accnut_ym",
+ "delng_de"
+ ]
+ },
+ "uniqueKey": [
+ "sys_se",
+ "accnut_ym",
+ "sn"
+ ],
+ "compareKey": "compare_ky",
+ "amtField": "sum(delng_amt) as delng_amt",
+ "compareField": [
+ "accnut_ym",
+ "delng_amt"
+ ],
+ "matchingType": "mtch_ty",
+ "matchingTypeName": "mtch_ty_nm",
+ "matchingNumber": "mtch_ky"
+ },
+ {
+ "active": true,
+ "type": "K-BB",
+ "typeName": "자기채무(적요),상대채권(겨래일자),비교(년월,거래금액)",
+
+ "condOne": {
+ "cond": [
+ "dta_ty in ('32','34','36','38','42')",
+ "mtch_ty is null"
+ ],
+ "makeCompareKey": [
+ "sys_se",
+ "accnut_ym",
+ "substring(sumry, 1, 80)"
+ ]
+ },
+ "condTwo": {
+ "cond": [
+ "dta_ty in ('31','33','35','37','41')",
+ "mtch_ty is null"
+ ],
+ "makeCompareKey": [
+ "sys_se",
+ "accnut_ym",
+ "delng_de"
+ ]
+ },
+ "uniqueKey": [
+ "sys_se",
+ "accnut_ym",
+ "sn"
+ ],
+ "compareKey": "compare_ky",
+ "amtField": "sum(delng_amt) as delng_amt",
+ "compareField": [
+ "accnut_ym",
+ "delng_amt"
+ ],
+ "matchingType": "mtch_ty",
+ "matchingTypeName": "mtch_ty_nm",
+ "matchingNumber": "mtch_ky"
+ },
+ {
+ "active": true,
+ "type": "K-BC",
+ "typeName": "자기채권(적요),개별상대채무,비교(년월,거래금액)",
+
+ "condOne": {
+ "cond": [
+ "dta_ty in ('31','33','35','37','41')",
+ "mtch_ty is null"
+ ],
+ "makeCompareKey": [
+ "sys_se",
+ "accnut_ym",
+ "substring(sumry, 1, 80)"
+ ]
+ },
+ "condTwo": {
+ "cond": [
+ "dta_ty in ('32','34','36','38','42')",
+ "mtch_ty is null"
+ ],
+ "makeCompareKey": [
+ "sys_se",
+ "accnut_ym",
+ "cast(sn as text)"
+ ]
+ },
+ "uniqueKey": [
+ "sys_se",
+ "accnut_ym",
+ "sn"
+ ],
+ "compareKey": "compare_ky",
+ "amtField": "sum(delng_amt) as delng_amt",
+ "compareField": [
+ "accnut_ym",
+ "delng_amt"
+ ],
+ "matchingType": "mtch_ty",
+ "matchingTypeName": "mtch_ty_nm",
+ "matchingNumber": "mtch_ky"
+ },
+ {
+ "active": true,
+ "type": "K-BD",
+ "typeName": "자기채무(적요),개별상대채권,비교(년월,거래금액)",
+
+ "condOne": {
+ "cond": [
+ "dta_ty in ('32','34','36','38','42')",
+ "mtch_ty is null"
+ ],
+ "makeCompareKey": [
+ "sys_se",
+ "accnut_ym",
+ "substring(sumry, 1, 80)"
+ ]
+ },
+ "condTwo": {
+ "cond": [
+ "dta_ty in ('31','33','35','37','41')",
+ "mtch_ty is null"
+ ],
+ "makeCompareKey": [
+ "sys_se",
+ "accnut_ym",
+ "cast(sn as text)"
+ ]
+ },
+ "uniqueKey": [
+ "sys_se",
+ "accnut_ym",
+ "sn"
+ ],
+ "compareKey": "compare_ky",
+ "amtField": "sum(delng_amt) as delng_amt",
+ "compareField": [
+ "accnut_ym",
+ "delng_amt"
+ ],
+ "matchingType": "mtch_ty",
+ "matchingTypeName": "mtch_ty_nm",
+ "matchingNumber": "mtch_ky"
+ },
+
+
+
+
+ {
+ "active": true,
+ "type": "L-A",
+ "typeName": "자기수익(회계일자),상대비용(회계일자),비교(년월,거래금액)",
+
+ "condOne": {
+ "cond": [
+ "dta_ty in ('11','21')",
+ "mtch_ty is null",
+ "elcty_de is not null",
+ "elcty_de != ''"
+ ],
+ "makeCompareKey": [
+ "elcty_de"
+ ]
+ },
+ "condTwo": {
+ "cond": [
+ "dta_ty in ('12','22')",
+ "mtch_ty is null",
+ "elcty_de is not null",
+ "elcty_de != ''"
+ ],
+ "makeCompareKey": [
+ "elcty_de"
+ ]
+ },
+ "uniqueKey": [
+ "sys_se",
+ "accnut_ym",
+ "sn"
+ ],
+ "compareKey": "compare_ky",
+ "amtField": "sum(delng_amt) as delng_amt",
+ "compareField": [
+ "accnut_ym",
+ "delng_amt"
+ ],
+ "matchingType": "mtch_ty",
+ "matchingTypeName": "mtch_ty_nm",
+ "matchingNumber": "mtch_ky"
+ },
+ {
+ "active": true,
+ "type": "L-AA",
+ "typeName": "자기수익(회계일자),개별상대비용,비교(년월,거래금액)",
+
+ "condOne": {
+ "cond": [
+ "dta_ty in ('11','21')",
+ "mtch_ty is null",
+ "elcty_de is not null",
+ "elcty_de != ''"
+ ],
+ "makeCompareKey": [
+ "elcty_de"
+ ]
+ },
+ "condTwo": {
+ "cond": [
+ "dta_ty in ('12','22')",
+ "mtch_ty is null"
+ ],
+ "makeCompareKey": [
+ "sys_se",
+ "accnut_ym",
+ "cast(sn as text)"
+ ]
+ },
+ "uniqueKey": [
+ "sys_se",
+ "accnut_ym",
+ "sn"
+ ],
+ "compareKey": "compare_ky",
+ "amtField": "sum(delng_amt) as delng_amt",
+ "compareField": [
+ "accnut_ym",
+ "delng_amt"
+ ],
+ "matchingType": "mtch_ty",
+ "matchingTypeName": "mtch_ty_nm",
+ "matchingNumber": "mtch_ky"
+ },
+ {
+ "active": true,
+ "type": "L-AB",
+ "typeName": "자기비용(회계일자),개별상대수익,비교(년월,거래금액)",
+
+ "condOne": {
+ "cond": [
+ "dta_ty in ('12','22')",
+ "mtch_ty is null",
+ "elcty_de is not null",
+ "elcty_de != ''"
+ ],
+ "makeCompareKey": [
+ "elcty_de"
+ ]
+ },
+ "condTwo": {
+ "cond": [
+ "dta_ty in ('11','21')",
+ "mtch_ty is null"
+ ],
+ "makeCompareKey": [
+ "sys_se",
+ "accnut_ym",
+ "cast(sn as text)"
+ ]
+ },
+ "uniqueKey": [
+ "sys_se",
+ "accnut_ym",
+ "sn"
+ ],
+ "compareKey": "compare_ky",
+ "amtField": "sum(delng_amt) as delng_amt",
+ "compareField": [
+ "accnut_ym",
+ "delng_amt"
+ ],
+ "matchingType": "mtch_ty",
+ "matchingTypeName": "mtch_ty_nm",
+ "matchingNumber": "mtch_ky"
+ },
+
+
+
+
+
+ {
+ "active": true,
+ "type": "M-A",
+ "typeName": "자기수익(법인계정코드),상대비용(법인계정코드),비교(년월,거래금액)",
+
+ "condOne": {
+ "cond": [
+ "dta_ty in ('11','21')",
+ "mtch_ty is null"
+ ],
+ "makeCompareKey": [
+ "cpr_acnt_code"
+ ]
+ },
+ "condTwo": {
+ "cond": [
+ "dta_ty in ('12','22')",
+ "mtch_ty is null"
+ ],
+ "makeCompareKey": [
+ "cpr_acnt_code"
+ ]
+ },
+ "uniqueKey": [
+ "sys_se",
+ "accnut_ym",
+ "sn"
+ ],
+ "compareKey": "compare_ky",
+ "amtField": "sum(delng_amt) as delng_amt",
+ "compareField": [
+ "accnut_ym",
+ "delng_amt"
+ ],
+ "matchingType": "mtch_ty",
+ "matchingTypeName": "mtch_ty_nm",
+ "matchingNumber": "mtch_ky"
+ },
+ {
+ "active": true,
+ "type": "M-AA",
+ "typeName": "자기수익(법인계정코드),개별상대비용,비교(년월,거래금액)",
+
+ "condOne": {
+ "cond": [
+ "dta_ty in ('11','21')",
+ "mtch_ty is null"
+ ],
+ "makeCompareKey": [
+ "cpr_acnt_code"
+ ]
+ },
+ "condTwo": {
+ "cond": [
+ "dta_ty in ('12','22')",
+ "mtch_ty is null"
+ ],
+ "makeCompareKey": [
+ "sys_se",
+ "accnut_ym",
+ "cast(sn as text)"
+ ]
+ },
+ "uniqueKey": [
+ "sys_se",
+ "accnut_ym",
+ "sn"
+ ],
+ "compareKey": "compare_ky",
+ "amtField": "sum(delng_amt) as delng_amt",
+ "compareField": [
+ "accnut_ym",
+ "delng_amt"
+ ],
+ "matchingType": "mtch_ty",
+ "matchingTypeName": "mtch_ty_nm",
+ "matchingNumber": "mtch_ky"
+ },
+ {
+ "active": true,
+ "type": "M-AB",
+ "typeName": "자기비용(법인계정코드),개별상대수익,비교(년월,거래금액)",
+
+ "condOne": {
+ "cond": [
+ "dta_ty in ('12','22')",
+ "mtch_ty is null"
+ ],
+ "makeCompareKey": [
+ "cpr_acnt_code"
+ ]
+ },
+ "condTwo": {
+ "cond": [
+ "dta_ty in ('11','21')",
+ "mtch_ty is null"
+ ],
+ "makeCompareKey": [
+ "sys_se",
+ "accnut_ym",
+ "cast(sn as text)"
+ ]
+ },
+ "uniqueKey": [
+ "sys_se",
+ "accnut_ym",
+ "sn"
+ ],
+ "compareKey": "compare_ky",
+ "amtField": "sum(delng_amt) as delng_amt",
+ "compareField": [
+ "accnut_ym",
+ "delng_amt"
+ ],
+ "matchingType": "mtch_ty",
+ "matchingTypeName": "mtch_ty_nm",
+ "matchingNumber": "mtch_ky"
+ },
+
+
+
+
+ {
+ "active": true,
+ "type": "N-A",
+ "typeName": "자기수익(계정코드),상대비용(계정코드),비교(년월,거래금액)",
+
+ "condOne": {
+ "cond": [
+ "dta_ty in ('11','21')",
+ "mtch_ty is null"
+ ],
+ "makeCompareKey": [
+ "cnnc_acnt_code"
+ ]
+ },
+ "condTwo": {
+ "cond": [
+ "dta_ty in ('12','22')",
+ "mtch_ty is null"
+ ],
+ "makeCompareKey": [
+ "cnnc_acnt_code"
+ ]
+ },
+ "uniqueKey": [
+ "sys_se",
+ "accnut_ym",
+ "sn"
+ ],
+ "compareKey": "compare_ky",
+ "amtField": "sum(delng_amt) as delng_amt",
+ "compareField": [
+ "accnut_ym",
+ "delng_amt"
+ ],
+ "matchingType": "mtch_ty",
+ "matchingTypeName": "mtch_ty_nm",
+ "matchingNumber": "mtch_ky"
+ },
+ {
+ "active": true,
+ "type": "N-AA",
+ "typeName": "자기수익(계정코드),개별상대비용,비교(년월,거래금액)",
+
+ "condOne": {
+ "cond": [
+ "dta_ty in ('11','21')",
+ "mtch_ty is null"
+ ],
+ "makeCompareKey": [
+ "cnnc_acnt_code"
+ ]
+ },
+ "condTwo": {
+ "cond": [
+ "dta_ty in ('12','22')",
+ "mtch_ty is null"
+ ],
+ "makeCompareKey": [
+ "sys_se",
+ "accnut_ym",
+ "cast(sn as text)"
+ ]
+ },
+ "uniqueKey": [
+ "sys_se",
+ "accnut_ym",
+ "sn"
+ ],
+ "compareKey": "compare_ky",
+ "amtField": "sum(delng_amt) as delng_amt",
+ "compareField": [
+ "accnut_ym",
+ "delng_amt"
+ ],
+ "matchingType": "mtch_ty",
+ "matchingTypeName": "mtch_ty_nm",
+ "matchingNumber": "mtch_ky"
+ },
+ {
+ "active": true,
+ "type": "N-AB",
+ "typeName": "자기비용(계정코드),개별상대수익,비교(년월,비교키,거래금액)",
+
+ "condOne": {
+ "cond": [
+ "dta_ty in ('12','22')",
+ "mtch_ty is null"
+ ],
+ "makeCompareKey": [
+ "cnnc_acnt_code"
+ ]
+ },
+ "condTwo": {
+ "cond": [
+ "dta_ty in ('11','21')",
+ "mtch_ty is null"
+ ],
+ "makeCompareKey": [
+ "sys_se",
+ "accnut_ym",
+ "cast(sn as text)"
+ ]
+ },
+ "uniqueKey": [
+ "sys_se",
+ "accnut_ym",
+ "sn"
+ ],
+ "compareKey": "compare_ky",
+ "amtField": "sum(delng_amt) as delng_amt",
+ "compareField": [
+ "accnut_ym",
+ "delng_amt"
+ ],
+ "matchingType": "mtch_ty",
+ "matchingTypeName": "mtch_ty_nm",
+ "matchingNumber": "mtch_ky"
+ },
+ {
+ "active": true,
+ "type": "N-AC",
+ "typeName": "자기수익(계정코드),상대비용(법인계정코드),비교(년월,거래금액)",
+
+ "condOne": {
+ "cond": [
+ "dta_ty in ('11','21')",
+ "mtch_ty is null"
+ ],
+ "makeCompareKey": [
+ "cnnc_acnt_code"
+ ]
+ },
+ "condTwo": {
+ "cond": [
+ "dta_ty in ('12','22')",
+ "mtch_ty is null"
+ ],
+ "makeCompareKey": [
+ "cpr_acnt_code"
+ ]
+ },
+ "uniqueKey": [
+ "sys_se",
+ "accnut_ym",
+ "sn"
+ ],
+ "compareKey": "compare_ky",
+ "amtField": "sum(delng_amt) as delng_amt",
+ "compareField": [
+ "accnut_ym",
+ "delng_amt"
+ ],
+ "matchingType": "mtch_ty",
+ "matchingTypeName": "mtch_ty_nm",
+ "matchingNumber": "mtch_ky"
+ },
+ {
+ "active": true,
+ "type": "N-AD",
+ "typeName": "자기비용(계정코드),상대수익(법인계정코드),비교(년월,거래금액)",
+
+ "condOne": {
+ "cond": [
+ "dta_ty in ('12','22')",
+ "mtch_ty is null"
+ ],
+ "makeCompareKey": [
+ "cnnc_acnt_code"
+ ]
+ },
+ "condTwo": {
+ "cond": [
+ "dta_ty in ('11','21')",
+ "mtch_ty is null"
+ ],
+ "makeCompareKey": [
+ "cpr_acnt_code"
+ ]
+ },
+ "uniqueKey": [
+ "sys_se",
+ "accnut_ym",
+ "sn"
+ ],
+ "compareKey": "compare_ky",
+ "amtField": "sum(delng_amt) as delng_amt",
+ "compareField": [
+ "accnut_ym",
+ "delng_amt"
+ ],
+ "matchingType": "mtch_ty",
+ "matchingTypeName": "mtch_ty_nm",
+ "matchingNumber": "mtch_ky"
+ },
+
+
+
+
+ {
+ "active": true,
+ "type": "O-A",
+ "typeName": "자기수익(INVOICE),상대비용(INVOICE),비교(년월,거래금액)",
+
+ "condOne": {
+ "cond": [
+ "dta_ty in ('11','21')",
+ "mtch_ty is null",
+ "ext_key2 is not null",
+ "ext_key2 != ''"
+ ],
+ "makeCompareKey": [
+ "ext_key2"
+ ]
+ },
+ "condTwo": {
+ "cond": [
+ "dta_ty in ('12','22')",
+ "mtch_ty is null",
+ "ext_key2 is not null",
+ "ext_key2 != ''"
+ ],
+ "makeCompareKey": [
+ "ext_key2"
+ ]
+ },
+ "uniqueKey": [
+ "sys_se",
+ "accnut_ym",
+ "sn"
+ ],
+ "compareKey": "compare_ky",
+ "amtField": "sum(delng_amt) as delng_amt",
+ "compareField": [
+ "accnut_ym",
+ "delng_amt"
+ ],
+ "matchingType": "mtch_ty",
+ "matchingTypeName": "mtch_ty_nm",
+ "matchingNumber": "mtch_ky"
+ },
+ {
+ "active": true,
+ "type": "O-AA",
+ "typeName": "자기수익(INVOICE),개별상대비용,비교(년월,거래금액)",
+
+ "condOne": {
+ "cond": [
+ "dta_ty in ('11','21')",
+ "mtch_ty is null",
+ "ext_key2 is not null",
+ "ext_key2 != ''"
+ ],
+ "makeCompareKey": [
+ "ext_key2"
+ ]
+ },
+ "condTwo": {
+ "cond": [
+ "dta_ty in ('12','22')",
+ "mtch_ty is null"
+ ],
+ "makeCompareKey": [
+ "sys_se",
+ "accnut_ym",
+ "cast(sn as text)"
+ ]
+ },
+ "uniqueKey": [
+ "sys_se",
+ "accnut_ym",
+ "sn"
+ ],
+ "compareKey": "compare_ky",
+ "amtField": "sum(delng_amt) as delng_amt",
+ "compareField": [
+ "accnut_ym",
+ "delng_amt"
+ ],
+ "matchingType": "mtch_ty",
+ "matchingTypeName": "mtch_ty_nm",
+ "matchingNumber": "mtch_ky"
+ },
+ {
+ "active": true,
+ "type": "O-AB",
+ "typeName": "자기비용(INVOICE),개별상대수익,비교(년월,거래금액)",
+
+ "condOne": {
+ "cond": [
+ "dta_ty in ('12','22')",
+ "mtch_ty is null",
+ "ext_key2 is not null",
+ "ext_key2 != ''"
+ ],
+ "makeCompareKey": [
+ "ext_key2"
+ ]
+ },
+ "condTwo": {
+ "cond": [
+ "dta_ty in ('11','21')",
+ "mtch_ty is null"
+ ],
+ "makeCompareKey": [
+ "sys_se",
+ "accnut_ym",
+ "cast(sn as text)"
+ ]
+ },
+ "uniqueKey": [
+ "sys_se",
+ "accnut_ym",
+ "sn"
+ ],
+ "compareKey": "compare_ky",
+ "amtField": "sum(delng_amt) as delng_amt",
+ "compareField": [
+ "accnut_ym",
+ "delng_amt"
+ ],
+ "matchingType": "mtch_ty",
+ "matchingTypeName": "mtch_ty_nm",
+ "matchingNumber": "mtch_ky"
+ },
+
+
+
+ {
+ "active": true,
+ "type": "P-A",
+ "typeName": "자기수익(BL),상대비용(BL),비교(년월,거래금액)",
+
+ "condOne": {
+ "cond": [
+ "dta_ty in ('11','21')",
+ "mtch_ty is null",
+ "ext_key3 is not null",
+ "ext_key3 != ''"
+ ],
+ "makeCompareKey": [
+ "ext_key3"
+ ]
+ },
+ "condTwo": {
+ "cond": [
+ "dta_ty in ('12','22')",
+ "mtch_ty is null",
+ "ext_key3 is not null",
+ "ext_key3 != ''"
+ ],
+ "makeCompareKey": [
+ "ext_key3"
+ ]
+ },
+ "uniqueKey": [
+ "sys_se",
+ "accnut_ym",
+ "sn"
+ ],
+ "compareKey": "compare_ky",
+ "amtField": "sum(delng_amt) as delng_amt",
+ "compareField": [
+ "accnut_ym",
+ "delng_amt"
+ ],
+ "matchingType": "mtch_ty",
+ "matchingTypeName": "mtch_ty_nm",
+ "matchingNumber": "mtch_ky"
+ },
+ {
+ "active": true,
+ "type": "P-AA",
+ "typeName": "자기수익(BL),개별상대비용,비교(년월,거래금액)",
+
+ "condOne": {
+ "cond": [
+ "dta_ty in ('11','21')",
+ "mtch_ty is null",
+ "ext_key3 is not null",
+ "ext_key3 != ''"
+ ],
+ "makeCompareKey": [
+ "ext_key3"
+ ]
+ },
+ "condTwo": {
+ "cond": [
+ "dta_ty in ('12','22')",
+ "mtch_ty is null"
+ ],
+ "makeCompareKey": [
+ "sys_se",
+ "accnut_ym",
+ "cast(sn as text)"
+ ]
+ },
+ "uniqueKey": [
+ "sys_se",
+ "accnut_ym",
+ "sn"
+ ],
+ "compareKey": "compare_ky",
+ "amtField": "sum(delng_amt) as delng_amt",
+ "compareField": [
+ "accnut_ym",
+ "delng_amt"
+ ],
+ "matchingType": "mtch_ty",
+ "matchingTypeName": "mtch_ty_nm",
+ "matchingNumber": "mtch_ky"
+ },
+ {
+ "active": true,
+ "type": "P-AB",
+ "typeName": "자기비용(BL),개별상대수익,비교(년월,거래금액)",
+
+ "condOne": {
+ "cond": [
+ "dta_ty in ('12','22')",
+ "mtch_ty is null",
+ "ext_key3 is not null",
+ "ext_key3 != ''"
+ ],
+ "makeCompareKey": [
+ "ext_key3"
+ ]
+ },
+ "condTwo": {
+ "cond": [
+ "dta_ty in ('11','21')",
+ "mtch_ty is null"
+ ],
+ "makeCompareKey": [
+ "sys_se",
+ "accnut_ym",
+ "cast(sn as text)"
+ ]
+ },
+ "uniqueKey": [
+ "sys_se",
+ "accnut_ym",
+ "sn"
+ ],
+ "compareKey": "compare_ky",
+ "amtField": "sum(delng_amt) as delng_amt",
+ "compareField": [
+ "accnut_ym",
+ "delng_amt"
+ ],
+ "matchingType": "mtch_ty",
+ "matchingTypeName": "mtch_ty_nm",
+ "matchingNumber": "mtch_ky"
+ },
+
+
+
+ {
+ "active": true,
+ "type": "Q-A",
+ "typeName": "자기수익(LC),상대비용(LC),비교(년월,거래금액)",
+
+ "condOne": {
+ "cond": [
+ "dta_ty in ('11','21')",
+ "mtch_ty is null",
+ "ext_key4 is not null",
+ "ext_key4 != ''"
+ ],
+ "makeCompareKey": [
+ "ext_key4"
+ ]
+ },
+ "condTwo": {
+ "cond": [
+ "dta_ty in ('12','22')",
+ "mtch_ty is null",
+ "ext_key4 is not null",
+ "ext_key4 != ''"
+ ],
+ "makeCompareKey": [
+ "ext_key4"
+ ]
+ },
+ "uniqueKey": [
+ "sys_se",
+ "accnut_ym",
+ "sn"
+ ],
+ "compareKey": "compare_ky",
+ "amtField": "sum(delng_amt) as delng_amt",
+ "compareField": [
+ "accnut_ym",
+ "delng_amt"
+ ],
+ "matchingType": "mtch_ty",
+ "matchingTypeName": "mtch_ty_nm",
+ "matchingNumber": "mtch_ky"
+ },
+ {
+ "active": true,
+ "type": "Q-AA",
+ "typeName": "자기수익(LC),개별상대비용,비교(년월,거래금액)",
+
+ "condOne": {
+ "cond": [
+ "dta_ty in ('11','21')",
+ "mtch_ty is null",
+ "ext_key4 is not null",
+ "ext_key4 != ''"
+ ],
+ "makeCompareKey": [
+ "ext_key4"
+ ]
+ },
+ "condTwo": {
+ "cond": [
+ "dta_ty in ('12','22')",
+ "mtch_ty is null"
+ ],
+ "makeCompareKey": [
+ "sys_se",
+ "accnut_ym",
+ "cast(sn as text)"
+ ]
+ },
+ "uniqueKey": [
+ "sys_se",
+ "accnut_ym",
+ "sn"
+ ],
+ "compareKey": "compare_ky",
+ "amtField": "sum(delng_amt) as delng_amt",
+ "compareField": [
+ "accnut_ym",
+ "delng_amt"
+ ],
+ "matchingType": "mtch_ty",
+ "matchingTypeName": "mtch_ty_nm",
+ "matchingNumber": "mtch_ky"
+ },
+ {
+ "active": true,
+ "type": "Q-AB",
+ "typeName": "자기비용(LC),개별상대수익,비교(년월,거래금액)",
+
+ "condOne": {
+ "cond": [
+ "dta_ty in ('12','22')",
+ "mtch_ty is null",
+ "ext_key4 is not null",
+ "ext_key4 != ''"
+ ],
+ "makeCompareKey": [
+ "ext_key4"
+ ]
+ },
+ "condTwo": {
+ "cond": [
+ "dta_ty in ('11','21')",
+ "mtch_ty is null"
+ ],
+ "makeCompareKey": [
+ "sys_se",
+ "accnut_ym",
+ "cast(sn as text)"
+ ]
+ },
+ "uniqueKey": [
+ "sys_se",
+ "accnut_ym",
+ "sn"
+ ],
+ "compareKey": "compare_ky",
+ "amtField": "sum(delng_amt) as delng_amt",
+ "compareField": [
+ "accnut_ym",
+ "delng_amt"
+ ],
+ "matchingType": "mtch_ty",
+ "matchingTypeName": "mtch_ty_nm",
+ "matchingNumber": "mtch_ky"
+ },
+
+
+
+
+
+ {
+ "active": true,
+ "type": "Z-AA",
+ "typeName": "[재실행]자기수익(거래일자),상대비용(거래일자),비교(년월,거래금액)",
+
+ "condOne": {
+ "cond": [
+ "dta_ty in ('11','21')",
+ "mtch_ty is null"
+ ],
+ "makeCompareKey": [
+ "sys_se",
+ "accnut_ym",
+ "delng_de"
+ ]
+ },
+ "condTwo": {
+ "cond": [
+ "dta_ty in ('12','22')",
+ "mtch_ty is null"
+ ],
+ "makeCompareKey": [
+ "sys_se",
+ "accnut_ym",
+ "delng_de"
+ ]
+ },
+ "uniqueKey": [
+ "sys_se",
+ "accnut_ym",
+ "sn"
+ ],
+ "compareKey": "compare_ky",
+ "amtField": "sum(delng_amt) as delng_amt",
+ "compareField": [
+ "accnut_ym",
+ "delng_amt"
+ ],
+ "matchingType": "mtch_ty",
+ "matchingTypeName": "mtch_ty_nm",
+ "matchingNumber": "mtch_ky"
+ },
+ {
+ "active": true,
+ "type": "Z-AB",
+ "typeName": "[재실행]자기수익(거래월),상대비용(거래월),비교(년월,거래금액)",
+
+ "condOne": {
+ "cond": [
+ "dta_ty in ('11','21')",
+ "mtch_ty is null"
+ ],
+ "makeCompareKey": [
+ "sys_se",
+ "accnut_ym",
+ "substring(delng_de,1,6)"
+ ]
+ },
+ "condTwo": {
+ "cond": [
+ "dta_ty in ('12','22')",
+ "mtch_ty is null"
+ ],
+ "makeCompareKey": [
+ "sys_se",
+ "accnut_ym",
+ "substring(delng_de,1,6)"
+ ]
+ },
+ "uniqueKey": [
+ "sys_se",
+ "accnut_ym",
+ "sn"
+ ],
+ "compareKey": "compare_ky",
+ "amtField": "sum(delng_amt) as delng_amt",
+ "compareField": [
+ "accnut_ym",
+ "delng_amt"
+ ],
+ "matchingType": "mtch_ty",
+ "matchingTypeName": "mtch_ty_nm",
+ "matchingNumber": "mtch_ky"
+ },
+ {
+ "active": true,
+ "type": "Z-AC",
+ "typeName": "[재실행]자기수익(전체),상대비용(전체),비교(년월,거래금액)",
+
+ "condOne": {
+ "cond": [
+ "dta_ty in ('11','21')",
+ "mtch_ty is null"
+ ],
+ "makeCompareKey": [
+ "sys_se",
+ "accnut_ym"
+ ]
+ },
+ "condTwo": {
+ "cond": [
+ "dta_ty in ('12','22')",
+ "mtch_ty is null"
+ ],
+ "makeCompareKey": [
+ "sys_se",
+ "accnut_ym"
+ ]
+ },
+ "uniqueKey": [
+ "sys_se",
+ "accnut_ym",
+ "sn"
+ ],
+ "compareKey": "compare_ky",
+ "amtField": "sum(delng_amt) as delng_amt",
+ "compareField": [
+ "accnut_ym",
+ "delng_amt"
+ ],
+ "matchingType": "mtch_ty",
+ "matchingTypeName": "mtch_ty_nm",
+ "matchingNumber": "mtch_ky"
+ },
+ {
+ "active": true,
+ "type": "Z-BA",
+ "typeName": "[재실행]자기채권(거래일자),상대채무(거래일자),비교(년월,거래금액)",
+
+ "condOne": {
+ "cond": [
+ "dta_ty in ('31','33','35','37','41')",
+ "mtch_ty is null"
+ ],
+ "makeCompareKey": [
+ "sys_se",
+ "accnut_ym",
+ "delng_de"
+ ]
+ },
+ "condTwo": {
+ "cond": [
+ "dta_ty in ('32','34','36','38','42')",
+ "mtch_ty is null"
+ ],
+ "makeCompareKey": [
+ "sys_se",
+ "accnut_ym",
+ "delng_de"
+ ]
+ },
+ "uniqueKey": [
+ "sys_se",
+ "accnut_ym",
+ "sn"
+ ],
+ "compareKey": "compare_ky",
+ "amtField": "sum(delng_amt) as delng_amt",
+ "compareField": [
+ "accnut_ym",
+ "delng_amt"
+ ],
+ "matchingType": "mtch_ty",
+ "matchingTypeName": "mtch_ty_nm",
+ "matchingNumber": "mtch_ky"
+ },
+ {
+ "active": true,
+ "type": "Z-BB",
+ "typeName": "[재실행]자기채권(거래월),상대채무(거래월),비교(년월,거래금액)",
+
+ "condOne": {
+ "cond": [
+ "dta_ty in ('31','33','35','37','41')",
+ "mtch_ty is null"
+ ],
+ "makeCompareKey": [
+ "sys_se",
+ "accnut_ym",
+ "substring(delng_de,1,6)"
+ ]
+ },
+ "condTwo": {
+ "cond": [
+ "dta_ty in ('32','34','36','38','42')",
+ "mtch_ty is null"
+ ],
+ "makeCompareKey": [
+ "sys_se",
+ "accnut_ym",
+ "substring(delng_de,1,6)"
+ ]
+ },
+ "uniqueKey": [
+ "sys_se",
+ "accnut_ym",
+ "sn"
+ ],
+ "compareKey": "compare_ky",
+ "amtField": "sum(delng_amt) as delng_amt",
+ "compareField": [
+ "accnut_ym",
+ "delng_amt"
+ ],
+ "matchingType": "mtch_ty",
+ "matchingTypeName": "mtch_ty_nm",
+ "matchingNumber": "mtch_ky"
+ },
+ {
+ "active": true,
+ "type": "Z-BC",
+ "typeName": "[재실행]자기채권(전체),상대채무(전체),비교(년월,거래금액)",
+
+ "condOne": {
+ "cond": [
+ "dta_ty in ('31','33','35','37','41')",
+ "mtch_ty is null"
+ ],
+ "makeCompareKey": [
+ "sys_se",
+ "accnut_ym"
+ ]
+ },
+ "condTwo": {
+ "cond": [
+ "dta_ty in ('32','34','36','38','42')",
+ "mtch_ty is null"
+ ],
+ "makeCompareKey": [
+ "sys_se",
+ "accnut_ym"
+ ]
+ },
+ "uniqueKey": [
+ "sys_se",
+ "accnut_ym",
+ "sn"
+ ],
+ "compareKey": "compare_ky",
+ "amtField": "sum(delng_amt) as delng_amt",
+ "compareField": [
+ "accnut_ym",
+ "delng_amt"
+ ],
+ "matchingType": "mtch_ty",
+ "matchingTypeName": "mtch_ty_nm",
+ "matchingNumber": "mtch_ky"
+ }
+
+
+ ]
+}
\ No newline at end of file
diff --git a/src/main/resources/mybatis/mybatis-config.xml b/src/main/resources/mybatis/mybatis-config.xml
new file mode 100644
index 0000000..31f7889
--- /dev/null
+++ b/src/main/resources/mybatis/mybatis-config.xml
@@ -0,0 +1,27 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/src/main/resources/mybatis/primary/batch/MatchingInnerDelingMapper.xml b/src/main/resources/mybatis/primary/batch/MatchingInnerDelingMapper.xml
new file mode 100644
index 0000000..e0e4b4b
--- /dev/null
+++ b/src/main/resources/mybatis/primary/batch/MatchingInnerDelingMapper.xml
@@ -0,0 +1,542 @@
+
+
+
+
+
+
+ SELECT
+ sys_se
+ , accnut_ym
+ , cpr_code
+ , partn_cpr
+ FROM
+ (
+ SELECT
+ sys_se
+ , accnut_ym
+ , cpr_code
+ , partn_cpr
+ , case when count(*) > 0 then 1 else 0 end as cnt
+ FROM
+ public.batch_tbcr_inner_delng
+ WHERE
+ sys_se = #{sysSe}
+ and accnut_ym = #{accnutYm}
+ and mtch_ty is null
+ and dta_ty in ('11','21','31','33','35','37','41')
+ GROUP BY
+ sys_se
+ , accnut_ym
+ , cpr_code
+ , partn_cpr
+ union all
+ SELECT
+ sys_se
+ , accnut_ym
+ , partn_cpr as cpr_code
+ , cpr_code as partn_cpr
+ , case when count(*) > 0 then 1 else 0 end as cnt
+ FROM
+ public.batch_tbcr_inner_delng
+ WHERE
+ sys_se = #{sysSe}
+ and accnut_ym = #{accnutYm}
+ and mtch_ty is null
+ and dta_ty in ('12','22','32','34','36','38','42')
+ GROUP BY
+ sys_se
+ , accnut_ym
+ , cpr_code
+ , partn_cpr
+ ) m
+ GROUP BY
+ sys_se
+ , accnut_ym
+ , cpr_code
+ , partn_cpr
+ HAVING sum(cnt) > 1
+
+
+
+
+ UPDATE public.batch_tbcr_inner_delng
+ SET
+ ${compareKey} = ${makeCompareKey}
+ WHERE
+ sys_se = #{sysSe}
+ and accnut_ym = #{accnutYm}
+ and cpr_code = #{cprCode}
+ and partn_cpr = #{partnCpr}
+
+ and ${item}
+
+
+
+
+
+ SELECT
+ accnut_ym
+ , compare_ky
+ , ${amtField}
+ FROM
+ public.batch_tbcr_inner_delng
+ WHERE
+ sys_se = #{sysSe}
+ and accnut_ym = #{accnutYm}
+ and compare_ky is not null
+ and cpr_code = #{cprCode}
+ and partn_cpr = #{partnCpr}
+
+ and ${item}
+
+ group by
+ accnut_ym,
+ compare_ky
+
+
+
+
+ SELECT
+ sys_se
+ , accnut_ym
+ , sn
+ , compare_ky
+ FROM
+ public.batch_tbcr_inner_delng
+ WHERE
+ sys_se = #{sysSe}
+ and accnut_ym = #{accnutYm}
+ and compare_ky is not null
+ and cpr_code = #{cprCode}
+ and partn_cpr = #{partnCpr}
+
+ and ${item}
+
+
+
+
+
+
+ UPDATE public.batch_tbcr_inner_delng
+ SET
+ mtch_sys = 'AUTO',
+ ${item.matchingType} = #{item.matchingTypeVal},
+ ${item.matchingTypeName} = #{item.matchingTypeNameVal},
+ ${item.matchingNumber} = #{item.matchingNumberVal}
+ WHERE
+ sys_se = #{item.sys_se}
+ and accnut_ym = #{item.accnut_ym}
+ and sn = #{item.sn}
+
+
+
+
+
+
+
+
+
+ DELETE FROM tbcr_transaction_history
+ WHERE
+ cons_group = #{sysSe}
+ and account_period = #{accnutYm}
+
+
+
+
+
+ INSERT INTO tbcr_transaction_history (
+ session_id,
+ cons_group,
+ ledger,
+ account_period,
+ seq,
+ tran_type,
+ own_comp,
+ tran_comp,
+ comp_acct_code,
+ comp_prod_code,
+ recon_key,
+ tran_date,
+ tran_currency,
+ tran_amt,
+ book_amt,
+ group_amt,
+ book_cost,
+ document_no,
+ remark,
+ cons_acct_code,
+ cons_acct_name,
+ prod_code,
+ adjust_type,
+ adjust_remark,
+ if_account_period,
+ if_comp_code,
+ if_file_id,
+ if_source,
+ equal_check,
+ cons_own_comp,
+ cons_tran_comp,
+ invoice_no,
+ lc_no,
+ bl_no,
+ own_biz_no,
+ partner_biz_no,
+ acct_date,
+ matching_cause,
+ match_key
+ ) values
+
+ (
+ #{item.SESSION_ID},
+ #{item.CONS_GROUP},
+ #{item.LEDGER},
+ #{item.ACCOUNT_PERIOD},
+ #{item.SEQ},
+ #{item.TRAN_TYPE},
+ #{item.OWN_COMP},
+ #{item.TRAN_COMP},
+ #{item.COMP_ACCT_CODE},
+ #{item.COMP_PROD_CODE},
+ #{item.RECON_KEY},
+ #{item.TRAN_DATE},
+ #{item.TRAN_CURRENCY},
+ #{item.TRAN_AMT},
+ #{item.BOOK_AMT},
+ #{item.GROUP_AMT},
+ #{item.BOOK_COST},
+ #{item.DOCUMENT_NO},
+ #{item.REMARK},
+ #{item.CONS_ACCT_CODE},
+ #{item.CONS_ACCT_NAME},
+ #{item.PROD_CODE},
+ #{item.ADJUST_TYPE},
+ #{item.ADJUST_REMARK},
+ #{item.IF_ACCOUNT_PERIOD},
+ #{item.IF_COMP_CODE},
+ #{item.IF_FILE_ID},
+ #{item.IF_SOURCE},
+ #{item.EQUAL_CHECK},
+ #{item.CONS_OWN_COMP},
+ #{item.CONS_TRAN_COMP},
+ #{item.INVOICE_NO},
+ #{item.LC_NO},
+ #{item.BL_NO},
+ #{item.OWN_BIZ_NO},
+ #{item.PARTNER_BIZ_NO},
+ #{item.ACCT_DATE},
+ #{item.MATCHING_CAUSE},
+ #{item.MATCH_KEY}
+ )
+
+
+
+
+ DELETE FROM batch_tbcr_inner_delng
+ WHERE
+ sys_se = #{sysSe}
+ and accnut_ym = #{accnutYm}
+
+
+
+ INSERT INTO
+ batch_tbcr_inner_delng
+ (
+ sys_se
+ , accnut_ym
+ , sn
+ , dta_ty
+ , cpr_code
+ , partn_cpr
+ , cpr_acnt_code
+ , cnnc_acnt_code
+ , cnnc_acnt_nm
+ , delng_de
+ , elcty_de
+ , chit_no
+ , cmpnsp_ky
+ , ext_key1
+ , ext_key2
+ , ext_key3
+ , ext_key4
+ , ext_key5
+ , delng_crncy
+ , delng_amt
+ , acntbk_amt
+ , group_amt
+ , suply_amount
+ , sumry
+ , org_mtch_ty
+ , org_mtch_ky
+ , new_mtch_ty
+ , new_mtch_ky
+ , compare_ky
+ , mtch_ty
+ , mtch_ty_nm
+ , mtch_ky
+ )
+ SELECT
+ cons_group
+ , account_period
+ , seq
+ , tran_type
+ , own_comp
+ , tran_comp
+ , comp_acct_code
+ , cons_acct_code
+ , cons_acct_name
+ , tran_date
+ , acct_date
+ , document_no
+ , recon_key
+ , null
+ , invoice_no
+ , lc_no
+ , bl_no
+ , null
+ , tran_currency
+ , tran_amt
+ , book_amt
+ , group_amt
+ , book_cost
+ , remark
+ , matching_cause
+ , match_key
+ , null
+ , null
+ , null
+ , null
+ , null
+ , null
+ FROM
+ tbcr_transaction_history
+ WHERE
+ cons_group = #{sysSe}
+ and account_period = #{accnutYm}
+
+
+
+ DELETE FROM batch_tbcr_inner_delng_ai
+ WHERE
+ sys_se = #{sysSe}
+ and accnut_ym = #{accnutYm}
+
+
+
+
+ INSERT INTO
+ batch_tbcr_inner_delng_ai
+ (
+ sys_se
+ , accnut_ym
+ , sn
+ , ai_key1
+ , ai_key2
+ , ai_key3
+ , ai_key4
+ , ai_key5
+ , ai_key6
+ , ai_key7
+ , ai_key8
+ , ai_key9
+ , ai_key10
+ )
+ SELECT
+ cons_group
+ , account_period
+ , seq
+ , regexp_replace(document_no, '[^0-9a-zA-Z]', '',1,0) as ai_key1
+ , regexp_replace(recon_key, '[^0-9a-zA-Z]', '',1,0) as ai_key2
+ , '' as ai_key3
+ , '' as ai_key4
+ , '' as ai_key5
+ , '' as ai_key6
+ , '' as ai_key7
+ , '' as ai_key8
+ , '' as ai_key9
+ , '' as ai_key10
+ FROM
+ tbcr_transaction_history
+ WHERE
+ cons_group = #{sysSe}
+ and account_period = #{accnutYm}
+
+
+
+ merge into batch_tbcr_inner_delng m
+ using
+ (
+ select
+ sys_se,
+ accnut_ym,
+ sn,
+ org_mtch_ty,
+ org_mtch_ky,
+ mtch_ty as new_mtch_ty,
+ mtch_ky,
+ DENSE_RANK() over (order by mtch_ty, mtch_ky) AS new_mtch_ky
+ from batch_tbcr_inner_delng
+ where
+ sys_se = #{sysSe}
+ AND accnut_ym = #{accnutYm}
+ AND mtch_ty is not null
+ ) t
+ on
+ m.sys_se = t.sys_se
+ and m.accnut_ym = t.accnut_ym
+ and m.sn = t.sn
+ when matched then
+ update set
+ new_mtch_ty = t.new_mtch_ty,
+ new_mtch_ky = t.new_mtch_ky
+
+
+
+
+
+
+
+
+
+
+
+
+
+ INSERT INTO public.batch_user_job_status (
+ user_job_id,
+ user_job_name,
+ start_time,
+ status
+ ) VALUES (
+ #{user_job_id},
+ #{user_job_name},
+ now(),
+ 'Started'
+ )
+
+
+
+ UPDATE public.batch_user_job_status
+ SET
+ end_time = now(),
+ status = 'Finished',
+ exit_code = #{exit_code},
+ exit_message = #{exit_message}
+ WHERE
+ user_job_id = #{user_job_id}
+
+
+
+
+ SELECT
+ sys_se
+ , accnut_ym
+ , cpr_code
+ , partn_cpr
+ , delng_crncy
+ FROM
+ (
+ SELECT
+ sys_se
+ , accnut_ym
+ , cpr_code
+ , partn_cpr
+ , delng_crncy
+ , case when count(*) > 0 then 1 else 0 end as cnt
+ FROM
+ public.batch_tbcr_inner_delng
+ WHERE
+ sys_se = #{sysSe}
+ and accnut_ym = #{accnutYm}
+ and mtch_ty is null
+ and dta_ty in ('11','21','31','33','35','37','41')
+ GROUP BY
+ sys_se
+ , accnut_ym
+ , cpr_code
+ , partn_cpr
+ , delng_crncy
+ union all
+ SELECT
+ sys_se
+ , accnut_ym
+ , partn_cpr as cpr_code
+ , cpr_code as partn_cpr
+ , delng_crncy
+ , case when count(*) > 0 then 1 else 0 end as cnt
+ FROM
+ public.batch_tbcr_inner_delng
+ WHERE
+ sys_se = #{sysSe}
+ and accnut_ym = #{accnutYm}
+ and mtch_ty is null
+ and dta_ty in ('12','22','32','34','36','38','42')
+ GROUP BY
+ sys_se
+ , accnut_ym
+ , cpr_code
+ , partn_cpr
+ , delng_crncy
+ ) m
+ GROUP BY
+ sys_se
+ , accnut_ym
+ , cpr_code
+ , partn_cpr
+ , delng_crncy
+ HAVING sum(cnt) > 1
+
+
\ No newline at end of file
diff --git a/src/main/resources/mybatis/primary/system/CodeMapper.xml b/src/main/resources/mybatis/primary/system/CodeMapper.xml
new file mode 100644
index 0000000..dcef363
--- /dev/null
+++ b/src/main/resources/mybatis/primary/system/CodeMapper.xml
@@ -0,0 +1,32 @@
+
+
+
+
+
+ SELECT
+ m.code_ty
+ , m.cmmn_code
+ , m.mng_iem_1
+ , m.mng_iem_2
+ , m.mng_iem_3
+ , m.mng_iem_4
+ , m.ordr
+ , m.use_at
+ , m.register
+ , m.input_de
+ , m.updusr
+ , m.updt_de
+ , s.lcal
+ , s.cmmn_code_nm
+ FROM
+ public.sy_cmmn_code_mng m
+ LEFT OUTER JOIN public.sy_cmmn_code_mng_nls s
+ ON
+ m.code_ty = s.code_ty
+ and m.cmmn_code = s.cmmn_code
+ and lcal = #{lcal};
+
+
+
\ No newline at end of file
diff --git a/src/main/resources/mybatis/secondary/OracleMapper.HN b/src/main/resources/mybatis/secondary/OracleMapper.HN
new file mode 100644
index 0000000..3f0045f
--- /dev/null
+++ b/src/main/resources/mybatis/secondary/OracleMapper.HN
@@ -0,0 +1,77 @@
+
+
+
+
+
+
+ SELECT
+ A.SESSION_ID,
+ A.CONS_GROUP,
+ A.LEDGER,
+ A.ACCOUNT_PERIOD,
+ A.SEQ,
+ A.TRAN_TYPE,
+ A.OWN_COMP,
+ A.TRAN_COMP,
+ A.COMP_ACCT_CODE,
+ A.COMP_PROD_CODE,
+ A.RECON_KEY,
+ A.TRAN_DATE,
+ A.TRAN_CURRENCY,
+ A.TRAN_AMT,
+ A.BOOK_AMT,
+ A.GROUP_AMT,
+ A.BOOK_COST,
+ A.DOCUMENT_NO,
+ A.REMARK,
+ A.CONS_ACCT_CODE,
+ B.CONS_ACCT_KR_SNAME AS CONS_ACCT_NAME,
+ A.PROD_CODE,
+ A.ADJUST_TYPE,
+ A.ADJUST_REMARK,
+ A.IF_ACCOUNT_PERIOD,
+ A.IF_COMP_CODE,
+ A.IF_FILE_ID,
+ A.IF_SOURCE,
+ A.EQUAL_CHECK,
+ A.CONS_OWN_COMP,
+ A.CONS_TRAN_COMP,
+ A.INVOICE_NO,
+ A.LC_NO,
+ A.BL_NO,
+ A.OWN_BIZ_NO,
+ A.PARTNER_BIZ_NO,
+ A.ACCT_DATE
+ FROM
+ TBCR_TRANSACTION_HISTORY A
+ LEFT OUTER JOIN TBBC_ACCT_CODE B
+ ON
+ B.CONS_ACCT_CODE = A.CONS_ACCT_CODE
+ AND B.SESSION_ID = 'XNER'
+ AND B.CONS_COA = 'GOV_I_COA'
+ AND B.FS_TYPE = '1'
+ AND TO_CHAR(SYSDATE, 'YYYYMM') BETWEEN B.START_YYMM AND B.END_YYMM
+ WHERE
+ A.CONS_GROUP = #{sysSe}
+ AND A.ACCOUNT_PERIOD = #{accnutYm}
+
+
+
+ SELECT
+ A.MATCH_KEY,
+ A.MATCHING_CAUSE,
+ B.SEQ
+ FROM TBCR_MATCHING A,
+ TBCR_MATCHING_DETAIL B
+ WHERE
+ A.MATCH_KEY = B.MATCH_KEY
+ AND A.ACCOUNT_PERIOD = B.ACCOUNT_PERIOD
+ AND A.CONS_GROUP = #{sysSe}
+ AND A.ACCOUNT_PERIOD = #{accnutYm}
+
+
+
+ --결과 업데이트
+
+
+
\ No newline at end of file
diff --git a/src/main/resources/mybatis/secondary/OracleMapper.LS b/src/main/resources/mybatis/secondary/OracleMapper.LS
new file mode 100644
index 0000000..ba6ce9f
--- /dev/null
+++ b/src/main/resources/mybatis/secondary/OracleMapper.LS
@@ -0,0 +1,79 @@
+
+
+
+
+
+
+ SELECT
+ A.SESSION_ID,
+ A.CONS_GROUP,
+ A.LEDGER,
+ A.ACCOUNT_PERIOD,
+ A.SEQ,
+ A.TRAN_TYPE,
+ A.OWN_COMP,
+ A.TRAN_COMP,
+ A.COMP_ACCT_CODE,
+ A.COMP_PROD_CODE,
+ A.RECON_KEY,
+ A.TRAN_DATE,
+ A.TRAN_CURRENCY,
+ A.TRAN_AMT,
+ A.BOOK_AMT,
+ A.GROUP_AMT,
+ A.BOOK_COST,
+ A.DOCUMENT_NO,
+ A.REMARK,
+ A.CONS_ACCT_CODE,
+ B.CONS_ACCT_NAME_0 AS CONS_ACCT_NAME,
+ A.PROD_CODE,
+ A.ADJUST_TYPE,
+ A.ADJUST_REMARK,
+ A.IF_ACCOUNT_PERIOD,
+ A.IF_COMP_CODE,
+ A.IF_FILE_ID,
+ A.IF_SOURCE,
+ A.EQUAL_CHECK,
+ A.CONS_OWN_COMP,
+ A.CONS_TRAN_COMP,
+ A.INVOICE_NO,
+ A.LC_NO,
+ A.BL_NO,
+ A.OWN_BIZ_NO,
+ A.PARTNER_BIZ_NO,
+ A.ACCT_DATE
+ FROM
+ TBCR_TRANSACTION_HISTORY A
+ LEFT OUTER JOIN TBBC_ACCT_CODE_NLS B
+ ON
+ B.CONS_ACCT_CODE = A.CONS_ACCT_CODE
+ AND B.CONS_COA = 'LS_COA'
+ AND B.FS_TYPE = '1'
+ AND TO_CHAR(SYSDATE, 'YYYYMM') BETWEEN B.START_YYMM AND B.END_YYMM
+ WHERE
+ A.CONS_GROUP = #{sysSe}
+ AND A.ACCOUNT_PERIOD = #{accnutYm}
+
+
+
+ SELECT
+ A.MATCH_KEY,
+ A.MATCHING_CAUSE,
+ B.SEQ
+ FROM TBCR_MATCHING A,
+ TBCR_MATCHING_DETAIL B
+ WHERE
+ A.SESSION_ID = B.SESSION_ID
+ AND A.CONS_GROUP = B.CONS_GROUP
+ AND A.LEDGER = B.LEDGER
+ AND A.MATCH_KEY = B.MATCH_KEY
+ AND A.ACCOUNT_PERIOD = B.ACCOUNT_PERIOD
+ AND A.CONS_GROUP = #{sysSe}
+ AND A.ACCOUNT_PERIOD = #{accnutYm}
+
+
+
+ --결과 업데이트
+
+
+
\ No newline at end of file
diff --git a/src/main/resources/mybatis/secondary/OracleMapper.xml b/src/main/resources/mybatis/secondary/OracleMapper.xml
new file mode 100644
index 0000000..ba6ce9f
--- /dev/null
+++ b/src/main/resources/mybatis/secondary/OracleMapper.xml
@@ -0,0 +1,79 @@
+
+
+
+
+
+
+ SELECT
+ A.SESSION_ID,
+ A.CONS_GROUP,
+ A.LEDGER,
+ A.ACCOUNT_PERIOD,
+ A.SEQ,
+ A.TRAN_TYPE,
+ A.OWN_COMP,
+ A.TRAN_COMP,
+ A.COMP_ACCT_CODE,
+ A.COMP_PROD_CODE,
+ A.RECON_KEY,
+ A.TRAN_DATE,
+ A.TRAN_CURRENCY,
+ A.TRAN_AMT,
+ A.BOOK_AMT,
+ A.GROUP_AMT,
+ A.BOOK_COST,
+ A.DOCUMENT_NO,
+ A.REMARK,
+ A.CONS_ACCT_CODE,
+ B.CONS_ACCT_NAME_0 AS CONS_ACCT_NAME,
+ A.PROD_CODE,
+ A.ADJUST_TYPE,
+ A.ADJUST_REMARK,
+ A.IF_ACCOUNT_PERIOD,
+ A.IF_COMP_CODE,
+ A.IF_FILE_ID,
+ A.IF_SOURCE,
+ A.EQUAL_CHECK,
+ A.CONS_OWN_COMP,
+ A.CONS_TRAN_COMP,
+ A.INVOICE_NO,
+ A.LC_NO,
+ A.BL_NO,
+ A.OWN_BIZ_NO,
+ A.PARTNER_BIZ_NO,
+ A.ACCT_DATE
+ FROM
+ TBCR_TRANSACTION_HISTORY A
+ LEFT OUTER JOIN TBBC_ACCT_CODE_NLS B
+ ON
+ B.CONS_ACCT_CODE = A.CONS_ACCT_CODE
+ AND B.CONS_COA = 'LS_COA'
+ AND B.FS_TYPE = '1'
+ AND TO_CHAR(SYSDATE, 'YYYYMM') BETWEEN B.START_YYMM AND B.END_YYMM
+ WHERE
+ A.CONS_GROUP = #{sysSe}
+ AND A.ACCOUNT_PERIOD = #{accnutYm}
+
+
+
+ SELECT
+ A.MATCH_KEY,
+ A.MATCHING_CAUSE,
+ B.SEQ
+ FROM TBCR_MATCHING A,
+ TBCR_MATCHING_DETAIL B
+ WHERE
+ A.SESSION_ID = B.SESSION_ID
+ AND A.CONS_GROUP = B.CONS_GROUP
+ AND A.LEDGER = B.LEDGER
+ AND A.MATCH_KEY = B.MATCH_KEY
+ AND A.ACCOUNT_PERIOD = B.ACCOUNT_PERIOD
+ AND A.CONS_GROUP = #{sysSe}
+ AND A.ACCOUNT_PERIOD = #{accnutYm}
+
+
+
+ --결과 업데이트
+
+
+
\ No newline at end of file
diff --git a/src/main/resources/schema.sql b/src/main/resources/schema.sql
new file mode 100644
index 0000000..48cecfc
--- /dev/null
+++ b/src/main/resources/schema.sql
@@ -0,0 +1,385 @@
+CREATE TABLE IF NOT EXISTS batch_tbcr_inner_delng
+(
+ sys_se character varying(10) NOT NULL,
+ accnut_ym character varying(6) NOT NULL,
+ sn bigint NOT NULL DEFAULT 0,
+ dta_ty character varying(3),
+ cpr_code character varying(10),
+ partn_cpr character varying(10),
+ cpr_acnt_code character varying(20),
+ cnnc_acnt_code character varying(20),
+ cnnc_acnt_nm character varying(100),
+ delng_de character varying(8),
+ elcty_de character varying(8),
+ chit_no character varying(100),
+ cmpnsp_ky character varying(100),
+ ext_key1 character varying(100),
+ ext_key2 character varying(100),
+ ext_key3 character varying(100),
+ ext_key4 character varying(100),
+ ext_key5 character varying(100),
+ delng_crncy character varying(3),
+ delng_amt numeric(19,2) DEFAULT 0,
+ acntbk_amt numeric(19,2) DEFAULT 0,
+ group_amt numeric(19,2) DEFAULT 0,
+ suply_amount numeric(19,2) DEFAULT 0,
+ sumry character varying(500),
+ org_mtch_ty character varying(10),
+ org_mtch_ky numeric(10,0),
+ new_mtch_ty character varying(10),
+ new_mtch_ky numeric(10,0),
+ compare_ky character varying(100),
+ mtch_sys character varying(10),
+ mtch_ty character varying(10),
+ mtch_ty_nm character varying(100),
+ mtch_ky bigint DEFAULT 0,
+ CONSTRAINT batch_tbcr_inner_delng_pkey PRIMARY KEY (sys_se, accnut_ym, sn)
+);
+
+COMMENT ON TABLE batch_tbcr_inner_delng
+ IS '내부거래대사자료';
+
+COMMENT ON COLUMN batch_tbcr_inner_delng.sys_se
+ IS '시스템구분';
+
+COMMENT ON COLUMN batch_tbcr_inner_delng.accnut_ym
+ IS '회계연월';
+
+COMMENT ON COLUMN batch_tbcr_inner_delng.sn
+ IS '순번';
+
+COMMENT ON COLUMN batch_tbcr_inner_delng.dta_ty
+ IS '거래유형';
+
+COMMENT ON COLUMN batch_tbcr_inner_delng.cpr_code
+ IS '자기법인';
+
+COMMENT ON COLUMN batch_tbcr_inner_delng.partn_cpr
+ IS '상대법인';
+
+COMMENT ON COLUMN batch_tbcr_inner_delng.cpr_acnt_code
+ IS '법인계정코드';
+
+COMMENT ON COLUMN batch_tbcr_inner_delng.cnnc_acnt_code
+ IS '연결계정코드';
+
+COMMENT ON COLUMN batch_tbcr_inner_delng.cnnc_acnt_nm
+ IS '연결계정명';
+
+COMMENT ON COLUMN batch_tbcr_inner_delng.delng_de
+ IS '거래일자';
+
+COMMENT ON COLUMN batch_tbcr_inner_delng.elcty_de
+ IS '전기일자';
+
+COMMENT ON COLUMN batch_tbcr_inner_delng.chit_no
+ IS '법인전표번호';
+
+COMMENT ON COLUMN batch_tbcr_inner_delng.cmpnsp_ky
+ IS '대사 Key';
+
+COMMENT ON COLUMN batch_tbcr_inner_delng.ext_key1
+ IS '합산Key';
+
+COMMENT ON COLUMN batch_tbcr_inner_delng.ext_key2
+ IS 'INVOICE번호';
+
+COMMENT ON COLUMN batch_tbcr_inner_delng.ext_key3
+ IS 'LC번호';
+
+COMMENT ON COLUMN batch_tbcr_inner_delng.ext_key4
+ IS 'BL번호';
+
+COMMENT ON COLUMN batch_tbcr_inner_delng.ext_key5
+ IS '기타Key5';
+
+COMMENT ON COLUMN batch_tbcr_inner_delng.delng_crncy
+ IS '거래통화';
+
+COMMENT ON COLUMN batch_tbcr_inner_delng.delng_amt
+ IS '거래통화금액';
+
+COMMENT ON COLUMN batch_tbcr_inner_delng.acntbk_amt
+ IS '장부통화금액';
+
+COMMENT ON COLUMN batch_tbcr_inner_delng.group_amt
+ IS '그룹통화금액';
+
+COMMENT ON COLUMN batch_tbcr_inner_delng.suply_amount
+ IS '공급가액';
+
+COMMENT ON COLUMN batch_tbcr_inner_delng.sumry
+ IS '적요';
+
+COMMENT ON COLUMN batch_tbcr_inner_delng.org_mtch_ty
+ IS 'Org.일치유형';
+
+COMMENT ON COLUMN batch_tbcr_inner_delng.org_mtch_ky
+ IS 'Org.일치KEY';
+
+COMMENT ON COLUMN batch_tbcr_inner_delng.new_mtch_ty
+ IS 'New.일치유형';
+
+COMMENT ON COLUMN batch_tbcr_inner_delng.new_mtch_ky
+ IS 'New.일치KEY';
+
+COMMENT ON COLUMN batch_tbcr_inner_delng.compare_ky
+ IS '비교키(시스템)';
+
+COMMENT ON COLUMN batch_tbcr_inner_delng.mtch_sys
+ IS '일치시스템';
+
+COMMENT ON COLUMN batch_tbcr_inner_delng.mtch_ty
+ IS '일치유형';
+
+COMMENT ON COLUMN batch_tbcr_inner_delng.mtch_ty_nm
+ IS '일치유형명칭';
+
+COMMENT ON COLUMN batch_tbcr_inner_delng.mtch_ky
+ IS '일치KEY';
+
+CREATE INDEX IF NOT EXISTS batch_tbcr_inner_delng_idx1
+ ON batch_tbcr_inner_delng USING btree
+ (sys_se ASC NULLS LAST, accnut_ym ASC NULLS LAST, cpr_code ASC NULLS LAST, dta_ty ASC NULLS LAST, partn_cpr ASC NULLS LAST);
+
+CREATE INDEX IF NOT EXISTS batch_tbcr_inner_delng_idx2
+ ON batch_tbcr_inner_delng USING btree
+ (sys_se ASC NULLS LAST, accnut_ym ASC NULLS LAST, cpr_code ASC NULLS LAST, partn_cpr ASC NULLS LAST, compare_ky ASC NULLS LAST);
+
+
+
+
+CREATE TABLE IF NOT EXISTS tbcr_transaction_history
+(
+ session_id character varying(5) NOT NULL,
+ cons_group character varying(10) NOT NULL,
+ ledger character varying(3) NOT NULL,
+ account_period character varying(6) NOT NULL,
+ seq numeric NOT NULL,
+ tran_type character varying(3),
+ own_comp character varying(10),
+ tran_comp character varying(10),
+ comp_acct_code character varying(20),
+ comp_prod_code character varying(20),
+ recon_key character varying(100),
+ tran_date character varying(8),
+ tran_currency character varying(3),
+ tran_amt numeric(17,2) DEFAULT 0,
+ book_amt numeric(17,2) DEFAULT 0,
+ group_amt numeric(17,2) DEFAULT 0,
+ book_cost numeric(17,2) DEFAULT 0,
+ document_no character varying(50),
+ remark character varying(500),
+ cons_acct_code character varying(10),
+ cons_acct_name character varying(100),
+ prod_code character varying(10),
+ adjust_type character varying(3),
+ adjust_remark character varying(255),
+ if_account_period character varying(6),
+ if_comp_code character varying(10),
+ if_file_id character varying(3),
+ if_source character varying(3),
+ equal_check character varying(3),
+ cons_own_comp character varying(10),
+ cons_tran_comp character varying(10),
+ invoice_no character varying(80),
+ lc_no character varying(80),
+ bl_no character varying(80),
+ own_biz_no character varying(20),
+ partner_biz_no character varying(20),
+ acct_date character varying(8),
+ matching_cause character varying(10),
+ match_key numeric(10,0),
+ CONSTRAINT tbcr_transaction_history_ky PRIMARY KEY (session_id, cons_group, ledger, account_period, seq)
+);
+
+
+CREATE TABLE IF NOT EXISTS batch_tbcr_inner_delng_ai
+(
+ sys_se character varying(10) NOT NULL,
+ accnut_ym character varying(6) NOT NULL,
+ sn bigint NOT NULL DEFAULT 0,
+ ai_key1 character varying(100) ,
+ ai_key2 character varying(100) ,
+ ai_key3 character varying(100) ,
+ ai_key4 character varying(100) ,
+ ai_key5 character varying(100) ,
+ ai_key6 character varying(100) ,
+ ai_key7 character varying(100) ,
+ ai_key8 character varying(100) ,
+ ai_key9 character varying(100) ,
+ ai_key10 character varying(100) ,
+ CONSTRAINT batch_tbcr_inner_delng_aikey PRIMARY KEY (sys_se, accnut_ym, sn)
+);
+
+
+CREATE TABLE IF NOT EXISTS batch_user_job_status
+(
+ user_job_id character varying(128) COLLATE pg_catalog."default" NOT NULL,
+ user_job_name character varying(200) COLLATE pg_catalog."default",
+ start_time timestamp with time zone,
+ end_time timestamp with time zone,
+ status character varying(50) COLLATE pg_catalog."default",
+ exit_code character varying(10) COLLATE pg_catalog."default",
+ exit_message character varying(2000) COLLATE pg_catalog."default",
+ CONSTRAINT batch_user_job_status_pkey PRIMARY KEY (user_job_id)
+ USING INDEX TABLESPACE account
+);
+
+COMMENT ON TABLE batch_user_job_status
+ IS 'User Job Status';
+
+
+
+-- Table: users
+
+-- DROP TABLE IF EXISTS users;
+
+CREATE TABLE IF NOT EXISTS users
+(
+ user_id bigint NOT NULL DEFAULT nextval('users_user_id_seq'::regclass),
+ activated boolean,
+ nickname character varying(50) COLLATE pg_catalog."default",
+ password character varying(100) COLLATE pg_catalog."default",
+ username character varying(50) COLLATE pg_catalog."default",
+ CONSTRAINT users_pkey PRIMARY KEY (user_id),
+ CONSTRAINT uk_r43af9ap4edm43mmtq01oddj6 UNIQUE (username)
+);
+
+-- Table: authority
+
+-- DROP TABLE IF EXISTS authority;
+
+CREATE TABLE IF NOT EXISTS authority
+(
+ authority_name character varying(50) COLLATE pg_catalog."default" NOT NULL,
+ CONSTRAINT authority_pkey PRIMARY KEY (authority_name)
+);
+
+-- Table: user_authority
+
+-- DROP TABLE IF EXISTS user_authority;
+
+CREATE TABLE IF NOT EXISTS user_authority
+(
+ user_id bigint NOT NULL,
+ authority_name character varying(50) COLLATE pg_catalog."default" NOT NULL,
+ CONSTRAINT user_authority_pkey PRIMARY KEY (user_id, authority_name),
+ CONSTRAINT fk6ktglpl5mjosa283rvken2py5 FOREIGN KEY (authority_name)
+ REFERENCES authority (authority_name) MATCH SIMPLE
+ ON UPDATE NO ACTION
+ ON DELETE NO ACTION,
+ CONSTRAINT fkhi46vu7680y1hwvmnnuh4cybx FOREIGN KEY (user_id)
+ REFERENCES users (user_id) MATCH SIMPLE
+ ON UPDATE NO ACTION
+ ON DELETE NO ACTION
+);
+
+-- Table: sy_cmmn_code_mng
+
+-- DROP TABLE IF EXISTS sy_cmmn_code_mng;
+
+CREATE TABLE IF NOT EXISTS sy_cmmn_code_mng
+(
+ code_ty character varying(20) COLLATE pg_catalog."default" NOT NULL,
+ cmmn_code character varying(20) COLLATE pg_catalog."default" NOT NULL,
+ mng_iem_1 character varying(50) COLLATE pg_catalog."default",
+ mng_iem_2 character varying(50) COLLATE pg_catalog."default",
+ mng_iem_3 character varying(50) COLLATE pg_catalog."default",
+ mng_iem_4 character varying(50) COLLATE pg_catalog."default",
+ ordr bigint DEFAULT 0,
+ use_at character varying(1) COLLATE pg_catalog."default",
+ register character varying(20) COLLATE pg_catalog."default",
+ input_de timestamp without time zone,
+ updusr character varying(20) COLLATE pg_catalog."default",
+ updt_de timestamp without time zone,
+ CONSTRAINT sy_cmmn_code_mng_pkey PRIMARY KEY (code_ty, cmmn_code)
+);
+
+COMMENT ON TABLE sy_cmmn_code_mng
+ IS 'SY_공통코드관리';
+
+COMMENT ON COLUMN sy_cmmn_code_mng.code_ty
+ IS '코드타입';
+
+COMMENT ON COLUMN sy_cmmn_code_mng.cmmn_code
+ IS '공통코드';
+
+COMMENT ON COLUMN sy_cmmn_code_mng.mng_iem_1
+ IS '관리항목1';
+
+COMMENT ON COLUMN sy_cmmn_code_mng.mng_iem_2
+ IS '관리항목2';
+
+COMMENT ON COLUMN sy_cmmn_code_mng.mng_iem_3
+ IS '관리항목3';
+
+COMMENT ON COLUMN sy_cmmn_code_mng.mng_iem_4
+ IS '관리항목4';
+
+COMMENT ON COLUMN sy_cmmn_code_mng.ordr
+ IS '순서';
+
+COMMENT ON COLUMN sy_cmmn_code_mng.use_at
+ IS '사용여부';
+
+COMMENT ON COLUMN sy_cmmn_code_mng.register
+ IS '입력자';
+
+COMMENT ON COLUMN sy_cmmn_code_mng.input_de
+ IS '입력일자';
+
+COMMENT ON COLUMN sy_cmmn_code_mng.updusr
+ IS '수정자';
+
+COMMENT ON COLUMN sy_cmmn_code_mng.updt_de
+ IS '수정일자';
+
+
+-- Table: sy_cmmn_code_mng_nls
+
+-- DROP TABLE IF EXISTS sy_cmmn_code_mng_nls;
+
+CREATE TABLE IF NOT EXISTS sy_cmmn_code_mng_nls
+(
+ code_ty character varying(20) COLLATE pg_catalog."default" NOT NULL,
+ cmmn_code character varying(20) COLLATE pg_catalog."default" NOT NULL,
+ lcal character varying(5) COLLATE pg_catalog."default" NOT NULL,
+ cmmn_code_nm character varying(100) COLLATE pg_catalog."default",
+ register character varying(20) COLLATE pg_catalog."default",
+ input_de timestamp without time zone,
+ updusr character varying(20) COLLATE pg_catalog."default",
+ updt_de timestamp without time zone,
+ CONSTRAINT sy_cmmn_code_mng_nls_pkey PRIMARY KEY (code_ty, cmmn_code, lcal),
+ CONSTRAINT fk_s_mng_to_s_mng_nls FOREIGN KEY (code_ty, cmmn_code)
+ REFERENCES sy_cmmn_code_mng (code_ty, cmmn_code) MATCH SIMPLE
+ ON UPDATE NO ACTION
+ ON DELETE CASCADE
+);
+
+COMMENT ON TABLE sy_cmmn_code_mng_nls
+ IS 'SY_공통코드관리_NLS';
+
+COMMENT ON COLUMN sy_cmmn_code_mng_nls.code_ty
+ IS '코드타입';
+
+COMMENT ON COLUMN sy_cmmn_code_mng_nls.cmmn_code
+ IS '공통코드';
+
+COMMENT ON COLUMN sy_cmmn_code_mng_nls.lcal
+ IS '로케일';
+
+COMMENT ON COLUMN sy_cmmn_code_mng_nls.cmmn_code_nm
+ IS '공통코드명';
+
+COMMENT ON COLUMN sy_cmmn_code_mng_nls.register
+ IS '입력자';
+
+COMMENT ON COLUMN sy_cmmn_code_mng_nls.input_de
+ IS '입력일자';
+
+COMMENT ON COLUMN sy_cmmn_code_mng_nls.updusr
+ IS '수정자';
+
+COMMENT ON COLUMN sy_cmmn_code_mng_nls.updt_de
+ IS '수정일자';
\ No newline at end of file
diff --git a/src/test/java/daeucna/MatchingAiApplicationTests.java b/src/test/java/daeucna/MatchingAiApplicationTests.java
new file mode 100644
index 0000000..7cd7224
--- /dev/null
+++ b/src/test/java/daeucna/MatchingAiApplicationTests.java
@@ -0,0 +1,213 @@
+package daeucna;
+
+import static org.hamcrest.CoreMatchers.containsString;
+import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get;
+import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.post;
+import static org.springframework.test.web.servlet.result.MockMvcResultHandlers.print;
+import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.content;
+import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;
+
+import java.util.Arrays;
+import java.util.HashMap;
+import java.util.HashSet;
+
+import javax.crypto.SecretKey;
+
+import org.junit.jupiter.api.Test;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.beans.factory.annotation.Value;
+import org.springframework.boot.test.autoconfigure.web.servlet.AutoConfigureMockMvc;
+import org.springframework.boot.test.context.SpringBootTest;
+import org.springframework.http.MediaType;
+import org.springframework.test.context.ContextConfiguration;
+import org.springframework.test.web.servlet.MockMvc;
+import org.springframework.test.web.servlet.MvcResult;
+
+import daeucna.config.security.dto.AuthorityDto;
+import daeucna.config.security.dto.LoginDto;
+import daeucna.config.security.dto.UserDto;
+import daeucna.config.security.jwt.JwtFilter;
+import daeucna.config.security.utils.CommonJson;
+import io.jsonwebtoken.Claims;
+import io.jsonwebtoken.Jws;
+import io.jsonwebtoken.Jwts;
+import io.jsonwebtoken.io.Decoders;
+import io.jsonwebtoken.security.Keys;
+import lombok.extern.slf4j.Slf4j;
+
+@SpringBootTest
+@ContextConfiguration(classes = MatchingAiApplication.class)
+@AutoConfigureMockMvc
+@Slf4j
+class MatchingAiApplicationTests {
+
+ @Autowired
+ private MockMvc mockMvc;
+
+ @Test
+ void userSignup() throws Exception {
+ AuthorityDto authorityDto = AuthorityDto.builder().authorityName("ROLE_ADMIN").build();
+ UserDto userDto = UserDto.builder()
+ .username("sangkiTest")
+ .password("sangkiTest")
+ .nickname("sangkiTest")
+ .authorityDtoSet(new HashSet( Arrays.asList(authorityDto) ))
+ .build();
+
+ String body = CommonJson.objectToString(userDto);
+ this.mockMvc.perform(
+ post("/api/signup")
+ .contentType(MediaType.APPLICATION_JSON)
+ .content(body)
+ )
+ .andDo(print())
+ .andExpect(status().isOk())
+ .andExpect(content().string(containsString("sangkiTest")));
+ }
+
+ @Test
+ void authenticate() throws Exception {
+ fnAuthenticate();
+ }
+
+ MvcResult fnAuthenticate() throws Exception {
+ LoginDto loginDto = LoginDto.builder()
+ .username("sangkiTest")
+ .password("sangkiTest")
+ .build();
+
+ String body = CommonJson.objectToString(loginDto);
+ MvcResult mvcResult = this.mockMvc.perform(
+ post("/api/authenticate")
+ .contentType(MediaType.APPLICATION_JSON)
+ .content(body)
+ )
+ .andDo(print())
+ .andExpect(status().isOk())
+ .andExpect(content().string(containsString("token")))
+ .andReturn();
+
+ return mvcResult;
+ }
+
+ @SuppressWarnings("unchecked")
+ @Test
+ void user() throws Exception {
+ MvcResult mvcResult = fnAuthenticate();
+ String sReturn = mvcResult.getResponse().getContentAsString();
+ log.debug("sReturn = " + sReturn);
+
+ HashMap mapVal = (HashMap) CommonJson.stringToObject(sReturn, HashMap.class);
+ log.debug("token = " + mapVal.get("token") );
+
+ this.mockMvc.perform(
+ get("/api/user")
+ .header("Authorization", "Bearer " + mapVal.get("token"))
+ )
+ .andDo(print())
+ .andExpect(status().isOk());
+
+ }
+
+ @SuppressWarnings("unchecked")
+ @Test
+ void testRedirect() throws Exception {
+ MvcResult mvcResult = fnAuthenticate();
+ String sReturn = mvcResult.getResponse().getContentAsString();
+ log.debug("sReturn = " + sReturn);
+
+ HashMap mapVal = (HashMap) CommonJson.stringToObject(sReturn, HashMap.class);
+ log.debug("token = " + mapVal.get("token") );
+
+ this.mockMvc.perform(
+ post("/api/test-redirect")
+ .header("Authorization", "Bearer " + mapVal.get("token"))
+ )
+ .andDo(print())
+ .andExpect(status().isOk());
+
+ }
+
+ @SuppressWarnings("unchecked")
+ @Test
+ void userSangki() throws Exception {
+ MvcResult mvcResult = fnAuthenticate();
+ String sReturn = mvcResult.getResponse().getContentAsString();
+ log.debug("sReturn = " + sReturn);
+
+ HashMap mapVal = (HashMap) CommonJson.stringToObject(sReturn, HashMap.class);
+ log.debug("token = " + mapVal.get("token") );
+
+ this.mockMvc.perform(
+ get("/api/user/sangki")
+ .header("Authorization", "Bearer " + mapVal.get("token"))
+ )
+ .andDo(print())
+ .andExpect(status().isOk())
+ .andExpect(content().string(containsString("sangki")));
+
+ }
+
+ @SuppressWarnings("unchecked")
+ @Test
+ void hello() throws Exception {
+ MvcResult mvcResult = fnAuthenticate();
+ String sReturn = mvcResult.getResponse().getContentAsString();
+ log.debug("sReturn = " + sReturn);
+
+ HashMap mapVal = (HashMap) CommonJson.stringToObject(sReturn, HashMap.class);
+ log.debug("token = " + mapVal.get("token") );
+
+ this.mockMvc.perform(
+ get("/api/hello")
+ .header("Authorization", "Bearer " + mapVal.get("token"))
+ )
+ .andDo(print())
+ .andExpect(status().isOk())
+ .andExpect(content().string(containsString("hello")));
+
+ }
+
+ @Test
+ void parseJwt(@Value("${jwt.secret}") String secret) throws Exception {
+ MvcResult mvcResult = fnAuthenticate();
+ String sReturn = mvcResult.getResponse().getContentAsString();
+
+ HashMap mapVal = (HashMap) CommonJson.stringToObject(sReturn, HashMap.class);
+ String accessToken = (String) mapVal.get("token");
+ byte[] keyBytes = Decoders.BASE64URL.decode(secret);
+ SecretKey key = Keys.hmacShaKeyFor(keyBytes);
+ Jws claims;
+ try{
+ claims = Jwts.parser()
+ .verifyWith(key)
+ .build()
+ .parseSignedClaims(accessToken);
+ log.debug("parseJwt = " + CommonJson.objectToString(claims));
+ log.debug("parseJwt(getSubject) = " + claims.getBody().getSubject());
+ log.debug("parseJwt(claims) = " + CommonJson.objectToString(claims.getBody()));
+ } catch (Exception ignored) {
+ log.debug("parseJwt = " + ignored.getLocalizedMessage());
+ }
+ }
+
+ @Test
+ void refreshToken() throws Exception {
+
+ MvcResult mvcResult = fnAuthenticate();
+ String sReturn = mvcResult.getResponse().getContentAsString();
+
+ HashMap mapVal = (HashMap) CommonJson.stringToObject(sReturn, HashMap.class);
+ String refreshToken = (String) mapVal.get("refreshToken");
+
+ this.mockMvc.perform(
+ post("/api/refreshtoken")
+ .header(JwtFilter.AUTHORIZATION_REFRESH_HEADER, refreshToken)
+ )
+ .andDo(print())
+ .andExpect(status().isOk())
+ .andExpect(content().string(containsString("token")))
+ .andReturn();
+ }
+
+}
--
libgit2 0.21.4