initial commit
This commit is contained in:
parent
7e8fb52862
commit
1a54ae9661
|
@ -1,190 +1,33 @@
|
|||
# ---> Java
|
||||
# Compiled class file
|
||||
*.class
|
||||
|
||||
# Log file
|
||||
*.log
|
||||
|
||||
# BlueJ files
|
||||
*.ctxt
|
||||
|
||||
# Mobile Tools for Java (J2ME)
|
||||
.mtj.tmp/
|
||||
|
||||
# Package Files #
|
||||
*.jar
|
||||
*.war
|
||||
*.nar
|
||||
*.ear
|
||||
*.zip
|
||||
*.tar.gz
|
||||
*.rar
|
||||
|
||||
# virtual machine crash logs, see http://www.java.com/en/download/help/error_hotspot.xml
|
||||
hs_err_pid*
|
||||
replay_pid*
|
||||
|
||||
# ---> JetBrains
|
||||
# Covers JetBrains IDEs: IntelliJ, RubyMine, PhpStorm, AppCode, PyCharm, CLion, Android Studio, WebStorm and Rider
|
||||
# Reference: https://intellij-support.jetbrains.com/hc/en-us/articles/206544839
|
||||
|
||||
# User-specific stuff
|
||||
.idea/**/workspace.xml
|
||||
.idea/**/tasks.xml
|
||||
.idea/**/usage.statistics.xml
|
||||
.idea/**/dictionaries
|
||||
.idea/**/shelf
|
||||
|
||||
# AWS User-specific
|
||||
.idea/**/aws.xml
|
||||
|
||||
# Generated files
|
||||
.idea/**/contentModel.xml
|
||||
|
||||
# Sensitive or high-churn files
|
||||
.idea/**/dataSources/
|
||||
.idea/**/dataSources.ids
|
||||
.idea/**/dataSources.local.xml
|
||||
.idea/**/sqlDataSources.xml
|
||||
.idea/**/dynamic.xml
|
||||
.idea/**/uiDesigner.xml
|
||||
.idea/**/dbnavigator.xml
|
||||
|
||||
# Gradle
|
||||
.idea/**/gradle.xml
|
||||
.idea/**/libraries
|
||||
|
||||
# Gradle and Maven with auto-import
|
||||
# When using Gradle or Maven with auto-import, you should exclude module files,
|
||||
# since they will be recreated, and may cause churn. Uncomment if using
|
||||
# auto-import.
|
||||
# .idea/artifacts
|
||||
# .idea/compiler.xml
|
||||
# .idea/jarRepositories.xml
|
||||
# .idea/modules.xml
|
||||
# .idea/*.iml
|
||||
# .idea/modules
|
||||
# *.iml
|
||||
# *.ipr
|
||||
|
||||
# CMake
|
||||
cmake-build-*/
|
||||
|
||||
# Mongo Explorer plugin
|
||||
.idea/**/mongoSettings.xml
|
||||
|
||||
# File-based project format
|
||||
*.iws
|
||||
|
||||
# IntelliJ
|
||||
out/
|
||||
|
||||
# mpeltonen/sbt-idea plugin
|
||||
.idea_modules/
|
||||
|
||||
# JIRA plugin
|
||||
atlassian-ide-plugin.xml
|
||||
|
||||
# Cursive Clojure plugin
|
||||
.idea/replstate.xml
|
||||
|
||||
# SonarLint plugin
|
||||
.idea/sonarlint/
|
||||
|
||||
# Crashlytics plugin (for Android Studio and IntelliJ)
|
||||
com_crashlytics_export_strings.xml
|
||||
crashlytics.properties
|
||||
crashlytics-build.properties
|
||||
fabric.properties
|
||||
|
||||
# Editor-based Rest Client
|
||||
.idea/httpRequests
|
||||
|
||||
# Android studio 3.1+ serialized cache file
|
||||
.idea/caches/build_file_checksums.ser
|
||||
|
||||
# ---> Linux
|
||||
*~
|
||||
|
||||
# temporary files which can be created if a process still has a handle open of a deleted file
|
||||
.fuse_hidden*
|
||||
|
||||
# KDE directory preferences
|
||||
.directory
|
||||
|
||||
# Linux trash folder which might appear on any partition or disk
|
||||
.Trash-*
|
||||
|
||||
# .nfs files are created when an open file is removed but is still being accessed
|
||||
.nfs*
|
||||
|
||||
# ---> macOS
|
||||
# General
|
||||
.DS_Store
|
||||
.AppleDouble
|
||||
.LSOverride
|
||||
|
||||
# Icon must end with two \r
|
||||
Icon
|
||||
|
||||
# Thumbnails
|
||||
._*
|
||||
|
||||
# Files that might appear in the root of a volume
|
||||
.DocumentRevisions-V100
|
||||
.fseventsd
|
||||
.Spotlight-V100
|
||||
.TemporaryItems
|
||||
.Trashes
|
||||
.VolumeIcon.icns
|
||||
.com.apple.timemachine.donotpresent
|
||||
|
||||
# Directories potentially created on remote AFP share
|
||||
.AppleDB
|
||||
.AppleDesktop
|
||||
Network Trash Folder
|
||||
Temporary Items
|
||||
.apdisk
|
||||
|
||||
# ---> Gradle
|
||||
.gradle
|
||||
**/build/
|
||||
!src/**/build/
|
||||
|
||||
# Ignore Gradle GUI config
|
||||
gradle-app.setting
|
||||
|
||||
# Avoid ignoring Gradle wrapper jar file (.jar files are usually ignored)
|
||||
!gradle-wrapper.jar
|
||||
|
||||
# Avoid ignore Gradle wrappper properties
|
||||
!gradle-wrapper.properties
|
||||
|
||||
# Cache of project
|
||||
.gradletasknamecache
|
||||
|
||||
# Eclipse Gradle plugin generated files
|
||||
# Eclipse Core
|
||||
.project
|
||||
# JDT-specific (Eclipse Java Development Tools)
|
||||
.classpath
|
||||
|
||||
# ---> Maven
|
||||
HELP.md
|
||||
target/
|
||||
pom.xml.tag
|
||||
pom.xml.releaseBackup
|
||||
pom.xml.versionsBackup
|
||||
pom.xml.next
|
||||
release.properties
|
||||
dependency-reduced-pom.xml
|
||||
buildNumber.properties
|
||||
.mvn/timing.properties
|
||||
# https://github.com/takari/maven-wrapper#usage-without-binary-jar
|
||||
.mvn/wrapper/maven-wrapper.jar
|
||||
!.mvn/wrapper/maven-wrapper.jar
|
||||
!**/src/main/**/target/
|
||||
!**/src/test/**/target/
|
||||
|
||||
# Eclipse m2e generated files
|
||||
# Eclipse Core
|
||||
.project
|
||||
# JDT-specific (Eclipse Java Development Tools)
|
||||
### STS ###
|
||||
.apt_generated
|
||||
.classpath
|
||||
.factorypath
|
||||
.project
|
||||
.settings
|
||||
.springBeans
|
||||
.sts4-cache
|
||||
|
||||
### IntelliJ IDEA ###
|
||||
.idea
|
||||
*.iws
|
||||
*.iml
|
||||
*.ipr
|
||||
|
||||
### NetBeans ###
|
||||
/nbproject/private/
|
||||
/nbbuild/
|
||||
/dist/
|
||||
/nbdist/
|
||||
/.nb-gradle/
|
||||
build/
|
||||
!**/src/main/**/build/
|
||||
!**/src/test/**/build/
|
||||
|
||||
### VS Code ###
|
||||
.vscode/
|
||||
|
|
Binary file not shown.
|
@ -0,0 +1,18 @@
|
|||
# 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.
|
||||
distributionUrl=https://repo.maven.apache.org/maven2/org/apache/maven/apache-maven/3.8.7/apache-maven-3.8.7-bin.zip
|
||||
wrapperUrl=https://repo.maven.apache.org/maven2/org/apache/maven/wrapper/maven-wrapper/3.1.1/maven-wrapper-3.1.1.jar
|
|
@ -0,0 +1,316 @@
|
|||
#!/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.
|
||||
# ----------------------------------------------------------------------------
|
||||
|
||||
# ----------------------------------------------------------------------------
|
||||
# Maven Start Up Batch script
|
||||
#
|
||||
# Required ENV vars:
|
||||
# ------------------
|
||||
# JAVA_HOME - location of a JDK home dir
|
||||
#
|
||||
# Optional ENV vars
|
||||
# -----------------
|
||||
# M2_HOME - location of maven2's installed home dir
|
||||
# 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
|
||||
export JAVA_HOME="`/usr/libexec/java_home`"
|
||||
else
|
||||
export JAVA_HOME="/Library/Java/Home"
|
||||
fi
|
||||
fi
|
||||
;;
|
||||
esac
|
||||
|
||||
if [ -z "$JAVA_HOME" ] ; then
|
||||
if [ -r /etc/gentoo-release ] ; then
|
||||
JAVA_HOME=`java-config --jre-home`
|
||||
fi
|
||||
fi
|
||||
|
||||
if [ -z "$M2_HOME" ] ; then
|
||||
## resolve links - $0 may be a link to maven's home
|
||||
PRG="$0"
|
||||
|
||||
# need this for relative symlinks
|
||||
while [ -h "$PRG" ] ; do
|
||||
ls=`ls -ld "$PRG"`
|
||||
link=`expr "$ls" : '.*-> \(.*\)$'`
|
||||
if expr "$link" : '/.*' > /dev/null; then
|
||||
PRG="$link"
|
||||
else
|
||||
PRG="`dirname "$PRG"`/$link"
|
||||
fi
|
||||
done
|
||||
|
||||
saveddir=`pwd`
|
||||
|
||||
M2_HOME=`dirname "$PRG"`/..
|
||||
|
||||
# make it fully qualified
|
||||
M2_HOME=`cd "$M2_HOME" && pwd`
|
||||
|
||||
cd "$saveddir"
|
||||
# echo Using m2 at $M2_HOME
|
||||
fi
|
||||
|
||||
# For Cygwin, ensure paths are in UNIX format before anything is touched
|
||||
if $cygwin ; then
|
||||
[ -n "$M2_HOME" ] &&
|
||||
M2_HOME=`cygpath --unix "$M2_HOME"`
|
||||
[ -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 "$M2_HOME" ] &&
|
||||
M2_HOME="`(cd "$M2_HOME"; pwd)`"
|
||||
[ -n "$JAVA_HOME" ] &&
|
||||
JAVA_HOME="`(cd "$JAVA_HOME"; 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; \\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
|
||||
|
||||
CLASSWORLDS_LAUNCHER=org.codehaus.plexus.classworlds.launcher.Launcher
|
||||
|
||||
# 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/.."; pwd`
|
||||
fi
|
||||
# end of workaround
|
||||
done
|
||||
echo "${basedir}"
|
||||
}
|
||||
|
||||
# concatenates all lines of a file
|
||||
concat_lines() {
|
||||
if [ -f "$1" ]; then
|
||||
echo "$(tr -s '\n' ' ' < "$1")"
|
||||
fi
|
||||
}
|
||||
|
||||
BASE_DIR=`find_maven_basedir "$(pwd)"`
|
||||
if [ -z "$BASE_DIR" ]; then
|
||||
exit 1;
|
||||
fi
|
||||
|
||||
##########################################################################################
|
||||
# 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.
|
||||
##########################################################################################
|
||||
if [ -r "$BASE_DIR/.mvn/wrapper/maven-wrapper.jar" ]; then
|
||||
if [ "$MVNW_VERBOSE" = true ]; then
|
||||
echo "Found .mvn/wrapper/maven-wrapper.jar"
|
||||
fi
|
||||
else
|
||||
if [ "$MVNW_VERBOSE" = true ]; then
|
||||
echo "Couldn't find .mvn/wrapper/maven-wrapper.jar, downloading it ..."
|
||||
fi
|
||||
if [ -n "$MVNW_REPOURL" ]; then
|
||||
jarUrl="$MVNW_REPOURL/org/apache/maven/wrapper/maven-wrapper/3.1.0/maven-wrapper-3.1.0.jar"
|
||||
else
|
||||
jarUrl="https://repo.maven.apache.org/maven2/org/apache/maven/wrapper/maven-wrapper/3.1.0/maven-wrapper-3.1.0.jar"
|
||||
fi
|
||||
while IFS="=" read key value; do
|
||||
case "$key" in (wrapperUrl) jarUrl="$value"; break ;;
|
||||
esac
|
||||
done < "$BASE_DIR/.mvn/wrapper/maven-wrapper.properties"
|
||||
if [ "$MVNW_VERBOSE" = true ]; then
|
||||
echo "Downloading from: $jarUrl"
|
||||
fi
|
||||
wrapperJarPath="$BASE_DIR/.mvn/wrapper/maven-wrapper.jar"
|
||||
if $cygwin; then
|
||||
wrapperJarPath=`cygpath --path --windows "$wrapperJarPath"`
|
||||
fi
|
||||
|
||||
if command -v wget > /dev/null; then
|
||||
if [ "$MVNW_VERBOSE" = true ]; then
|
||||
echo "Found wget ... using wget"
|
||||
fi
|
||||
if [ -z "$MVNW_USERNAME" ] || [ -z "$MVNW_PASSWORD" ]; then
|
||||
wget "$jarUrl" -O "$wrapperJarPath" || rm -f "$wrapperJarPath"
|
||||
else
|
||||
wget --http-user=$MVNW_USERNAME --http-password=$MVNW_PASSWORD "$jarUrl" -O "$wrapperJarPath" || rm -f "$wrapperJarPath"
|
||||
fi
|
||||
elif command -v curl > /dev/null; then
|
||||
if [ "$MVNW_VERBOSE" = true ]; then
|
||||
echo "Found curl ... using curl"
|
||||
fi
|
||||
if [ -z "$MVNW_USERNAME" ] || [ -z "$MVNW_PASSWORD" ]; then
|
||||
curl -o "$wrapperJarPath" "$jarUrl" -f
|
||||
else
|
||||
curl --user $MVNW_USERNAME:$MVNW_PASSWORD -o "$wrapperJarPath" "$jarUrl" -f
|
||||
fi
|
||||
|
||||
else
|
||||
if [ "$MVNW_VERBOSE" = true ]; then
|
||||
echo "Falling back to using Java to download"
|
||||
fi
|
||||
javaClass="$BASE_DIR/.mvn/wrapper/MavenWrapperDownloader.java"
|
||||
# For Cygwin, switch paths to Windows format before running javac
|
||||
if $cygwin; then
|
||||
javaClass=`cygpath --path --windows "$javaClass"`
|
||||
fi
|
||||
if [ -e "$javaClass" ]; then
|
||||
if [ ! -e "$BASE_DIR/.mvn/wrapper/MavenWrapperDownloader.class" ]; then
|
||||
if [ "$MVNW_VERBOSE" = true ]; then
|
||||
echo " - Compiling MavenWrapperDownloader.java ..."
|
||||
fi
|
||||
# Compiling the Java class
|
||||
("$JAVA_HOME/bin/javac" "$javaClass")
|
||||
fi
|
||||
if [ -e "$BASE_DIR/.mvn/wrapper/MavenWrapperDownloader.class" ]; then
|
||||
# Running the downloader
|
||||
if [ "$MVNW_VERBOSE" = true ]; then
|
||||
echo " - Running MavenWrapperDownloader.java ..."
|
||||
fi
|
||||
("$JAVA_HOME/bin/java" -cp .mvn/wrapper MavenWrapperDownloader "$MAVEN_PROJECTBASEDIR")
|
||||
fi
|
||||
fi
|
||||
fi
|
||||
fi
|
||||
##########################################################################################
|
||||
# End of extension
|
||||
##########################################################################################
|
||||
|
||||
export MAVEN_PROJECTBASEDIR=${MAVEN_BASEDIR:-"$BASE_DIR"}
|
||||
if [ "$MVNW_VERBOSE" = true ]; then
|
||||
echo $MAVEN_PROJECTBASEDIR
|
||||
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 "$M2_HOME" ] &&
|
||||
M2_HOME=`cygpath --path --windows "$M2_HOME"`
|
||||
[ -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
|
||||
|
||||
exec "$JAVACMD" \
|
||||
$MAVEN_OPTS \
|
||||
$MAVEN_DEBUG_OPTS \
|
||||
-classpath "$MAVEN_PROJECTBASEDIR/.mvn/wrapper/maven-wrapper.jar" \
|
||||
"-Dmaven.home=${M2_HOME}" \
|
||||
"-Dmaven.multiModuleProjectDirectory=${MAVEN_PROJECTBASEDIR}" \
|
||||
${WRAPPER_LAUNCHER} $MAVEN_CONFIG "$@"
|
|
@ -0,0 +1,188 @@
|
|||
@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 Maven Start Up Batch script
|
||||
@REM
|
||||
@REM Required ENV vars:
|
||||
@REM JAVA_HOME - location of a JDK home dir
|
||||
@REM
|
||||
@REM Optional ENV vars
|
||||
@REM M2_HOME - location of maven2's installed home dir
|
||||
@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 DOWNLOAD_URL="https://repo.maven.apache.org/maven2/org/apache/maven/wrapper/maven-wrapper/3.1.0/maven-wrapper-3.1.0.jar"
|
||||
|
||||
FOR /F "usebackq tokens=1,2 delims==" %%A IN ("%MAVEN_PROJECTBASEDIR%\.mvn\wrapper\maven-wrapper.properties") DO (
|
||||
IF "%%A"=="wrapperUrl" SET DOWNLOAD_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 DOWNLOAD_URL="%MVNW_REPOURL%/org/apache/maven/wrapper/maven-wrapper/3.1.0/maven-wrapper-3.1.0.jar"
|
||||
)
|
||||
if "%MVNW_VERBOSE%" == "true" (
|
||||
echo Couldn't find %WRAPPER_JAR%, downloading it ...
|
||||
echo Downloading from: %DOWNLOAD_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('%DOWNLOAD_URL%', '%WRAPPER_JAR%')"^
|
||||
"}"
|
||||
if "%MVNW_VERBOSE%" == "true" (
|
||||
echo Finished downloading %WRAPPER_JAR%
|
||||
)
|
||||
)
|
||||
@REM End of extension
|
||||
|
||||
@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%
|
|
@ -0,0 +1,120 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
<parent>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter-parent</artifactId>
|
||||
<version>3.1.0-SNAPSHOT</version>
|
||||
<relativePath/> <!-- lookup parent from repository -->
|
||||
</parent>
|
||||
<groupId>de.arminwolf</groupId>
|
||||
<artifactId>finance-analyzer</artifactId>
|
||||
<version>0.0.1-SNAPSHOT</version>
|
||||
<name>finance-analyzer</name>
|
||||
<description>App to Analyze Excel Exports from Finanzguru</description>
|
||||
<properties>
|
||||
<java.version>17</java.version>
|
||||
</properties>
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter-web</artifactId>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter-thymeleaf</artifactId>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter-test</artifactId>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>nz.net.ultraq.thymeleaf</groupId>
|
||||
<artifactId>thymeleaf-layout-dialect</artifactId>
|
||||
<version>3.2.0</version>
|
||||
</dependency>
|
||||
|
||||
|
||||
<dependency>
|
||||
<groupId>org.apache.poi</groupId>
|
||||
<artifactId>poi</artifactId>
|
||||
<version>5.1.0</version>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>org.apache.poi</groupId>
|
||||
<artifactId>poi-ooxml</artifactId>
|
||||
<version>5.1.0</version>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>com.fasterxml.jackson.core</groupId>
|
||||
<artifactId>jackson-core</artifactId>
|
||||
<version>2.13.1</version>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>com.fasterxml.jackson.core</groupId>
|
||||
<artifactId>jackson-databind</artifactId>
|
||||
<version>2.16.1</version>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>com.fasterxml.jackson.dataformat</groupId>
|
||||
<artifactId>jackson-dataformat-csv</artifactId>
|
||||
<version>2.13.1</version>
|
||||
</dependency>
|
||||
|
||||
</dependencies>
|
||||
|
||||
<build>
|
||||
<plugins>
|
||||
<plugin>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-maven-plugin</artifactId>
|
||||
</plugin>
|
||||
</plugins>
|
||||
</build>
|
||||
<repositories>
|
||||
<repository>
|
||||
<id>spring-milestones</id>
|
||||
<name>Spring Milestones</name>
|
||||
<url>https://repo.spring.io/milestone</url>
|
||||
<snapshots>
|
||||
<enabled>false</enabled>
|
||||
</snapshots>
|
||||
</repository>
|
||||
<repository>
|
||||
<id>spring-snapshots</id>
|
||||
<name>Spring Snapshots</name>
|
||||
<url>https://repo.spring.io/snapshot</url>
|
||||
<releases>
|
||||
<enabled>false</enabled>
|
||||
</releases>
|
||||
</repository>
|
||||
</repositories>
|
||||
<pluginRepositories>
|
||||
<pluginRepository>
|
||||
<id>spring-milestones</id>
|
||||
<name>Spring Milestones</name>
|
||||
<url>https://repo.spring.io/milestone</url>
|
||||
<snapshots>
|
||||
<enabled>false</enabled>
|
||||
</snapshots>
|
||||
</pluginRepository>
|
||||
<pluginRepository>
|
||||
<id>spring-snapshots</id>
|
||||
<name>Spring Snapshots</name>
|
||||
<url>https://repo.spring.io/snapshot</url>
|
||||
<releases>
|
||||
<enabled>false</enabled>
|
||||
</releases>
|
||||
</pluginRepository>
|
||||
</pluginRepositories>
|
||||
|
||||
</project>
|
|
@ -0,0 +1,14 @@
|
|||
package de.arminwolf.financeanalyzer;
|
||||
|
||||
import org.springframework.boot.SpringApplication;
|
||||
import org.springframework.boot.autoconfigure.SpringBootApplication;
|
||||
|
||||
@SpringBootApplication
|
||||
public class FinanceAnalyzerApplication {
|
||||
|
||||
|
||||
public static void main(String[] args) {
|
||||
SpringApplication.run(FinanceAnalyzerApplication.class, args);
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,61 @@
|
|||
package de.arminwolf.financeanalyzer.conf;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.util.Objects;
|
||||
|
||||
public class BankAccount implements Serializable, Comparable<BankAccount> {
|
||||
|
||||
private String iban;
|
||||
private String bankAccountName;
|
||||
|
||||
|
||||
public BankAccount() {
|
||||
}
|
||||
|
||||
|
||||
public BankAccount(final String iban, final String bankAccountName) {
|
||||
this.iban = iban;
|
||||
this.bankAccountName = bankAccountName;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public int compareTo(final BankAccount o) {
|
||||
return bankAccountName.compareTo(o.bankAccountName);
|
||||
}
|
||||
|
||||
|
||||
public String getIban() {
|
||||
return iban;
|
||||
}
|
||||
|
||||
|
||||
public void setIban(final String iban) {
|
||||
this.iban = iban;
|
||||
}
|
||||
|
||||
|
||||
public String getBankAccountName() {
|
||||
return bankAccountName;
|
||||
}
|
||||
|
||||
|
||||
public void setBankAccountName(final String bankAccountName) {
|
||||
this.bankAccountName = bankAccountName;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public boolean equals(final Object o) {
|
||||
if (this == o) return true;
|
||||
if (o == null || getClass() != o.getClass()) return false;
|
||||
final BankAccount that = (BankAccount) o;
|
||||
return Objects.equals(iban, that.iban) && Objects.equals(bankAccountName, that.bankAccountName);
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return Objects.hash(iban, bankAccountName);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,36 @@
|
|||
package de.arminwolf.financeanalyzer.conf;
|
||||
|
||||
import java.util.HashSet;
|
||||
import java.util.Set;
|
||||
|
||||
public class Configuration {
|
||||
|
||||
private Set<BankAccount> bankAccounts;
|
||||
private int numberOfMonths;
|
||||
|
||||
|
||||
public Configuration() {
|
||||
this.numberOfMonths = 1;
|
||||
this.bankAccounts = new HashSet<>();
|
||||
}
|
||||
|
||||
|
||||
public Set<BankAccount> getBankAccounts() {
|
||||
return bankAccounts;
|
||||
}
|
||||
|
||||
|
||||
public void setBankAccounts(final Set<BankAccount> bankAccounts) {
|
||||
this.bankAccounts = bankAccounts;
|
||||
}
|
||||
|
||||
|
||||
public int getNumberOfMonths() {
|
||||
return numberOfMonths;
|
||||
}
|
||||
|
||||
|
||||
public void setNumberOfMonths(final int numberOfMonths) {
|
||||
this.numberOfMonths = numberOfMonths;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,15 @@
|
|||
package de.arminwolf.financeanalyzer.conf;
|
||||
|
||||
import nz.net.ultraq.thymeleaf.layoutdialect.LayoutDialect;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
|
||||
@Configuration
|
||||
public class SpringConfiguration {
|
||||
|
||||
@Bean
|
||||
public LayoutDialect layoutDialect() {
|
||||
return new LayoutDialect();
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,111 @@
|
|||
package de.arminwolf.financeanalyzer.controller;
|
||||
|
||||
import de.arminwolf.financeanalyzer.conf.BankAccount;
|
||||
import de.arminwolf.financeanalyzer.conf.Configuration;
|
||||
import de.arminwolf.financeanalyzer.service.CacheService;
|
||||
import de.arminwolf.financeanalyzer.service.ConverterService;
|
||||
import de.arminwolf.financeanalyzer.service.FileService;
|
||||
import de.arminwolf.financeanalyzer.util.Constants;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.stereotype.Controller;
|
||||
import org.springframework.ui.Model;
|
||||
import org.springframework.web.bind.annotation.GetMapping;
|
||||
import org.springframework.web.bind.annotation.ModelAttribute;
|
||||
import org.springframework.web.bind.annotation.PostMapping;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
import org.springframework.web.bind.annotation.RequestParam;
|
||||
import org.springframework.web.multipart.MultipartFile;
|
||||
import org.springframework.web.servlet.mvc.support.RedirectAttributes;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.Path;
|
||||
import java.nio.file.Paths;
|
||||
import java.util.Arrays;
|
||||
import java.util.Optional;
|
||||
import java.util.Set;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
@Controller
|
||||
@RequestMapping("/data")
|
||||
public class ConverterController {
|
||||
|
||||
@Autowired
|
||||
ConverterService service;
|
||||
|
||||
@Autowired
|
||||
CacheService cacheService;
|
||||
|
||||
@Autowired
|
||||
FileService fileService;
|
||||
|
||||
|
||||
@PostMapping("/convert")
|
||||
public String convert(RedirectAttributes redirectAttributes, @RequestParam("file") MultipartFile file) {
|
||||
try (InputStream in = file.getInputStream()) {
|
||||
Optional<String> json = service.convert(in);
|
||||
if (json.isPresent()) {
|
||||
File workingDirectory = fileService.getOrCreateWorkingDirectory();
|
||||
Path tempFile = Files.createFile(Paths.get(workingDirectory.getPath(), "finance-analyzer.json"));
|
||||
Path path = Files.writeString(tempFile, json.get(), StandardCharsets.UTF_8);
|
||||
|
||||
cacheService.put("currentJsonFile", path.toAbsolutePath().toFile().toString());
|
||||
Configuration configuration = new Configuration();
|
||||
Set<BankAccount> bankAccounts =
|
||||
Arrays.stream(fileService.getJsonFile())
|
||||
.map(t -> new BankAccount(t.getReferenzkonto(), t.getNameReferenzkonto()))
|
||||
.collect(Collectors.toSet());
|
||||
|
||||
configuration.setBankAccounts(bankAccounts);
|
||||
fileService.saveConfiguration(configuration);
|
||||
redirectAttributes.addFlashAttribute("result", "Converted successfully!");
|
||||
return "redirect:/data/success";
|
||||
} else {
|
||||
redirectAttributes.addFlashAttribute("result", "Error while converting");
|
||||
return "redirect:/data/error";
|
||||
}
|
||||
|
||||
} catch (IOException e) {
|
||||
redirectAttributes.addFlashAttribute("result", "Error while converting");
|
||||
return "redirect:/data/error";
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@PostMapping("/load")
|
||||
public String convert(RedirectAttributes redirectAttributes,
|
||||
@RequestParam("account") String account,
|
||||
@RequestParam("month") String month) {
|
||||
redirectAttributes.addFlashAttribute("result", "Converted successfully!");
|
||||
redirectAttributes.addFlashAttribute("account", account);
|
||||
redirectAttributes.addFlashAttribute("month", month);
|
||||
System.out.println("[ Load Method ] Account: " + account);
|
||||
System.out.println("[ Load Method ] Month: " + month);
|
||||
return "redirect:/data/success";
|
||||
}
|
||||
|
||||
|
||||
@GetMapping("/templates/error")
|
||||
public String handleError(@ModelAttribute("result") String result, Model model) {
|
||||
model.addAttribute("result", result);
|
||||
return Constants.ERROR;
|
||||
}
|
||||
|
||||
|
||||
@GetMapping("/success")
|
||||
public String handleSuccess(RedirectAttributes redirectAttributes,
|
||||
@ModelAttribute("result") String result,
|
||||
@ModelAttribute("account") String account,
|
||||
@ModelAttribute("month") String month,
|
||||
Model model) {
|
||||
redirectAttributes.addFlashAttribute("result", "Converted successfully!");
|
||||
redirectAttributes.addFlashAttribute("account", account);
|
||||
redirectAttributes.addFlashAttribute("month", month);
|
||||
redirectAttributes.addFlashAttribute("result", result);
|
||||
return "redirect:/".concat(Constants.REPORTS).concat("/");
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,31 @@
|
|||
package de.arminwolf.financeanalyzer.controller;
|
||||
|
||||
import jakarta.servlet.RequestDispatcher;
|
||||
import jakarta.servlet.http.HttpServletRequest;
|
||||
import org.springframework.boot.web.servlet.error.ErrorController;
|
||||
import org.springframework.http.HttpStatus;
|
||||
import org.springframework.stereotype.Controller;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
|
||||
@Controller
|
||||
public class CustomErrorController implements ErrorController {
|
||||
|
||||
@RequestMapping("/error")
|
||||
public String handleError(HttpServletRequest request) {
|
||||
Object status = request.getAttribute(RequestDispatcher.ERROR_STATUS_CODE);
|
||||
|
||||
if (status != null) {
|
||||
int statusCode = Integer.parseInt(status.toString());
|
||||
|
||||
if(statusCode == HttpStatus.NOT_FOUND.value()) {
|
||||
System.out.println(request.getRequestURL());
|
||||
return "/error/404";
|
||||
}
|
||||
else if(statusCode == HttpStatus.INTERNAL_SERVER_ERROR.value()) {
|
||||
return "/error/500";
|
||||
}
|
||||
}
|
||||
|
||||
return "/error";
|
||||
}
|
||||
}
|
|
@ -0,0 +1,38 @@
|
|||
package de.arminwolf.financeanalyzer.controller;
|
||||
|
||||
import de.arminwolf.financeanalyzer.service.CacheService;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.http.HttpStatus;
|
||||
import org.springframework.http.ResponseEntity;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
import org.springframework.web.bind.annotation.RequestMethod;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.Paths;
|
||||
import java.util.Objects;
|
||||
|
||||
@RestController
|
||||
@RequestMapping("/file")
|
||||
public class FileController {
|
||||
|
||||
|
||||
@Autowired
|
||||
CacheService cacheService;
|
||||
|
||||
|
||||
@RequestMapping(value = "/current", method = RequestMethod.GET, produces = "application/json")
|
||||
public ResponseEntity<String> get() throws IOException {
|
||||
|
||||
if (Objects.nonNull(cacheService.get("currentJsonFile"))) {
|
||||
String jsonFile = Files.readString(Paths.get(cacheService.get("currentJsonFile").toString()));
|
||||
if (Objects.nonNull(jsonFile) && !jsonFile.isEmpty()) {
|
||||
return ResponseEntity.ok(jsonFile);
|
||||
}
|
||||
}
|
||||
|
||||
return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).body("No persistent JSON found. Upload a new one.");
|
||||
|
||||
}
|
||||
}
|
|
@ -0,0 +1,55 @@
|
|||
package de.arminwolf.financeanalyzer.controller;
|
||||
|
||||
import de.arminwolf.financeanalyzer.dao.TransactionDAO;
|
||||
import de.arminwolf.financeanalyzer.util.UrlUtil;
|
||||
import jakarta.servlet.http.HttpServletRequest;
|
||||
import org.springframework.stereotype.Controller;
|
||||
import org.springframework.ui.Model;
|
||||
import org.springframework.web.bind.annotation.GetMapping;
|
||||
import org.springframework.web.client.RestClientException;
|
||||
import org.springframework.web.client.RestTemplate;
|
||||
|
||||
import java.util.Objects;
|
||||
import java.util.Optional;
|
||||
|
||||
import static de.arminwolf.financeanalyzer.util.Constants.INDEX;
|
||||
|
||||
@Controller
|
||||
public class MainController {
|
||||
|
||||
|
||||
@GetMapping("/")
|
||||
public String get(Model model, HttpServletRequest request) {
|
||||
RestTemplate restTemplate = new RestTemplate();
|
||||
|
||||
try {
|
||||
final Optional<TransactionDAO[]> response = getTransactions(request, restTemplate);
|
||||
if (response.isEmpty()) {
|
||||
return "redirect:/upload/";
|
||||
} else {
|
||||
// Verarbeiten Sie hier die Antwort
|
||||
model.addAttribute("data", response.get());
|
||||
return INDEX;
|
||||
}
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace(System.err);
|
||||
return "redirect:/upload";
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private static Optional<TransactionDAO[]> getTransactions(final HttpServletRequest request, final RestTemplate restTemplate) {
|
||||
try {
|
||||
TransactionDAO[] forObject = restTemplate.getForObject(UrlUtil.getRelativeUrl(request, "/file/current"), TransactionDAO[].class);
|
||||
if (Objects.isNull(forObject)) {
|
||||
return Optional.empty();
|
||||
} else {
|
||||
return Optional.of(forObject);
|
||||
}
|
||||
} catch (RestClientException e) {
|
||||
return Optional.empty();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,57 @@
|
|||
package de.arminwolf.financeanalyzer.controller;
|
||||
|
||||
import de.arminwolf.financeanalyzer.conf.Configuration;
|
||||
import de.arminwolf.financeanalyzer.dao.TransactionDAO;
|
||||
import de.arminwolf.financeanalyzer.dao.ReportDAO;
|
||||
import de.arminwolf.financeanalyzer.dao.TableDataDAO;
|
||||
import de.arminwolf.financeanalyzer.service.CacheService;
|
||||
import de.arminwolf.financeanalyzer.service.ReportService;
|
||||
import de.arminwolf.financeanalyzer.util.Constants;
|
||||
import de.arminwolf.financeanalyzer.util.DateUtil;
|
||||
import de.arminwolf.financeanalyzer.util.UrlUtil;
|
||||
import jakarta.servlet.http.HttpServletRequest;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.stereotype.Controller;
|
||||
import org.springframework.ui.Model;
|
||||
import org.springframework.web.bind.annotation.GetMapping;
|
||||
import org.springframework.web.bind.annotation.ModelAttribute;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
import org.springframework.web.client.RestTemplate;
|
||||
|
||||
import java.time.LocalDate;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
import java.util.Objects;
|
||||
|
||||
@Controller
|
||||
@RequestMapping("/reports")
|
||||
public class ReportController {
|
||||
|
||||
@Autowired
|
||||
private ReportService reportService;
|
||||
|
||||
@GetMapping("/")
|
||||
public String reports(@ModelAttribute("account") String iban,
|
||||
@ModelAttribute("month") String month,
|
||||
Model model, HttpServletRequest request) {
|
||||
RestTemplate restTemplate = new RestTemplate();
|
||||
if (Objects.isNull(iban) || iban.isEmpty()) {
|
||||
return "redirect:/upload/";
|
||||
}
|
||||
|
||||
try {
|
||||
final String fileURL = UrlUtil.getRelativeUrl(request, "/file/current");
|
||||
final TransactionDAO[] response = restTemplate.getForObject(fileURL, TransactionDAO[].class);
|
||||
if (Objects.isNull(response)) {
|
||||
return "redirect:/upload";
|
||||
} else {
|
||||
reportService.createReport(response, month, iban, model);
|
||||
return Constants.REPORTS;
|
||||
}
|
||||
} catch (Exception e) {
|
||||
System.err.println("Error: " + e.getMessage());
|
||||
return "redirect:/upload/";
|
||||
}
|
||||
|
||||
}
|
||||
}
|
|
@ -0,0 +1,38 @@
|
|||
package de.arminwolf.financeanalyzer.controller;
|
||||
|
||||
import de.arminwolf.financeanalyzer.conf.Configuration;
|
||||
import de.arminwolf.financeanalyzer.service.CacheService;
|
||||
import de.arminwolf.financeanalyzer.service.FileService;
|
||||
import de.arminwolf.financeanalyzer.service.ReportService;
|
||||
import de.arminwolf.financeanalyzer.util.Constants;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.stereotype.Controller;
|
||||
import org.springframework.ui.Model;
|
||||
import org.springframework.web.bind.annotation.GetMapping;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
import org.springframework.web.servlet.mvc.support.RedirectAttributes;
|
||||
import org.springframework.web.servlet.mvc.support.RedirectAttributesModelMap;
|
||||
|
||||
@Controller
|
||||
@RequestMapping("/upload")
|
||||
public class UploadController {
|
||||
@Autowired
|
||||
FileService fileService;
|
||||
|
||||
@Autowired
|
||||
CacheService cacheService;
|
||||
|
||||
|
||||
@GetMapping("/")
|
||||
public String upload(Model model) {
|
||||
final RedirectAttributes redirectAttributes = new RedirectAttributesModelMap();
|
||||
fileService.getJsonFileName().ifPresent(jsonFileName -> {
|
||||
cacheService.put("currentJsonFile", jsonFileName);
|
||||
cacheService.put("configuration", fileService.getConfiguration());
|
||||
model.addAttribute("foundJsonFile", jsonFileName);
|
||||
model.addAttribute("accounts", ((Configuration) cacheService.get("configuration")).getBankAccounts());
|
||||
});
|
||||
|
||||
return Constants.INDEX;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,151 @@
|
|||
package de.arminwolf.financeanalyzer.dao;
|
||||
|
||||
import de.arminwolf.financeanalyzer.dao.charts.model.HighChartDAO;
|
||||
import de.arminwolf.financeanalyzer.dao.charts.model.Series;
|
||||
import de.arminwolf.financeanalyzer.dao.charts.factories.BubbleChartFactory;
|
||||
import de.arminwolf.financeanalyzer.dao.charts.factories.ColumnChartFactory;
|
||||
import de.arminwolf.financeanalyzer.dao.charts.factories.LineChartFactory;
|
||||
import de.arminwolf.financeanalyzer.dao.model.OutputData;
|
||||
import de.arminwolf.financeanalyzer.util.NumberUtil;
|
||||
import de.arminwolf.financeanalyzer.util.OrderDateStringComparator;
|
||||
import org.apache.commons.math3.util.Pair;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
public class ReportDAO {
|
||||
|
||||
|
||||
private HighChartDAO cashFlowChart;
|
||||
private HighChartDAO accountBalanceLineChart;
|
||||
private HighChartDAO transactionCategoriesBubbleChart;
|
||||
|
||||
private Set<OutputData> standingOutputData;
|
||||
private Set<OutputData> notStandingOutputData;
|
||||
private List<OutputData> incomeList;
|
||||
|
||||
|
||||
public ReportDAO() {
|
||||
this.standingOutputData = new HashSet<>();
|
||||
this.notStandingOutputData = new HashSet<>();
|
||||
this.incomeList = new ArrayList<>();
|
||||
}
|
||||
|
||||
|
||||
public Set<OutputData> getStandingOrders() {
|
||||
return this.standingOutputData;
|
||||
}
|
||||
|
||||
|
||||
public List<OutputData> getSortedStandingOrders() {
|
||||
return this.standingOutputData.stream().sorted(new OrderDateStringComparator()).collect(Collectors.toList());
|
||||
}
|
||||
|
||||
|
||||
public Float getStandingOrdersAmount() {
|
||||
return NumberUtil.round(getStandingOrders().stream().map(OutputData::getAmountAsFloat).reduce(0f, Float::sum));
|
||||
}
|
||||
|
||||
|
||||
public Float getNotStandingOrdersAmount() {
|
||||
return NumberUtil.round(getNotStandingOrders().stream().map(OutputData::getAmountAsFloat).reduce(0f, Float::sum));
|
||||
}
|
||||
|
||||
|
||||
public HighChartDAO getTransactionCategoriesBubbleChart() {
|
||||
return transactionCategoriesBubbleChart;
|
||||
}
|
||||
|
||||
|
||||
public void setIncomeList(final List<TransactionDAO> incomes) {
|
||||
this.incomeList = incomes.stream()
|
||||
.map(t -> new OutputData(t.getVerwendungszweck(), t))
|
||||
.sorted(new OrderDateStringComparator())
|
||||
.collect(Collectors.toList());
|
||||
}
|
||||
|
||||
|
||||
public List<OutputData> getIncomeList() {
|
||||
return incomeList;
|
||||
}
|
||||
|
||||
|
||||
public void setNotStandingOrders(final List<TransactionDAO> notStandingOrders) {
|
||||
Set<OutputData> list = new HashSet<>();
|
||||
notStandingOrders.forEach(order -> list.add(new OutputData(order)));
|
||||
this.notStandingOutputData = list;
|
||||
}
|
||||
|
||||
|
||||
public final Set<OutputData> getNotStandingOrders() {
|
||||
return notStandingOutputData;
|
||||
}
|
||||
|
||||
|
||||
public final List<OutputData> getSortedNotStandingOrders() {
|
||||
return notStandingOutputData.stream().sorted(new OrderDateStringComparator()).collect(Collectors.toList());
|
||||
}
|
||||
|
||||
|
||||
public Float getTotalExpense() {
|
||||
return getStandingOrdersAmount() + getNotStandingOrdersAmount();
|
||||
}
|
||||
|
||||
|
||||
public void setTransactionCategoriesBubbleChart(final List<TransactionDAO> transactions) {
|
||||
this.transactionCategoriesBubbleChart = BubbleChartFactory.createBubbleChart("Kateogrien der Transaktionen", transactions);
|
||||
}
|
||||
|
||||
|
||||
public void setAccountBalanceLineChart(final List<Pair<String, String>> pairList) {
|
||||
String title = "Verlauf des Kontostandes";
|
||||
String chartTitle = "Kontostand in EUR";
|
||||
List<Series> series = new ArrayList<>();
|
||||
Series data = new Series();
|
||||
data.setData(pairList.stream().map(e -> Float.parseFloat(e.getValue())).collect(Collectors.toList()));
|
||||
series.add(data);
|
||||
|
||||
this.accountBalanceLineChart = LineChartFactory.createLineChart(title, chartTitle, pairList.stream().map(Pair::getKey).collect(Collectors.toList()), series);
|
||||
}
|
||||
|
||||
|
||||
public HighChartDAO getAccountBalanceLineChart() {
|
||||
return accountBalanceLineChart;
|
||||
}
|
||||
|
||||
|
||||
public void setCashFlowChart(final Map<String, List<Float>> ausgaben, final Map<String, List<Float>> einnahmen) {
|
||||
this.cashFlowChart =
|
||||
ColumnChartFactory.createColumnChart("Cashflow",
|
||||
"Einnahmen und Ausgaben",
|
||||
ausgaben, "Ausgaben",
|
||||
einnahmen, "Einnahmen");
|
||||
}
|
||||
|
||||
|
||||
public HighChartDAO getCashFlowChart() {
|
||||
return cashFlowChart;
|
||||
}
|
||||
|
||||
|
||||
public Float getIncome() {
|
||||
return this.incomeList.stream().map(OutputData::getAmountAsFloat).reduce(0f, Float::sum);
|
||||
}
|
||||
|
||||
|
||||
public Float getDiff() {
|
||||
return NumberUtil.round(Math.abs(getIncome()) - Math.abs(getTotalExpense()));
|
||||
}
|
||||
|
||||
|
||||
public void setStandingOrders(final Collection<TransactionDAO> orders) {
|
||||
Set<OutputData> list = new HashSet<>();
|
||||
orders.forEach(order -> list.add(new OutputData(order)));
|
||||
this.standingOutputData = list;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,37 @@
|
|||
package de.arminwolf.financeanalyzer.dao;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
public class TableDataDAO {
|
||||
|
||||
private List<String> headers;
|
||||
private List<List<String>> rows;
|
||||
|
||||
|
||||
public List<String> getHeaders() {
|
||||
return headers;
|
||||
}
|
||||
|
||||
|
||||
public void setHeaders(final List<String> headers) {
|
||||
this.headers = headers;
|
||||
}
|
||||
|
||||
|
||||
public List<List<String>> getRows() {
|
||||
return rows;
|
||||
}
|
||||
|
||||
|
||||
public void setRows(final List<List<String>> rows) {
|
||||
this.rows = rows;
|
||||
}
|
||||
|
||||
|
||||
|
||||
public static class TableDataFactory {
|
||||
public static TableDataDAO createTableDataDTO() {
|
||||
return new TableDataDAO();
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,555 @@
|
|||
package de.arminwolf.financeanalyzer.dao;
|
||||
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonAnyGetter;
|
||||
import com.fasterxml.jackson.annotation.JsonAnySetter;
|
||||
import com.fasterxml.jackson.annotation.JsonIgnore;
|
||||
import com.fasterxml.jackson.annotation.JsonInclude;
|
||||
import com.fasterxml.jackson.annotation.JsonProperty;
|
||||
import com.fasterxml.jackson.annotation.JsonPropertyOrder;
|
||||
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.Map;
|
||||
import java.util.Objects;
|
||||
|
||||
@JsonInclude(JsonInclude.Include.NON_NULL)
|
||||
@JsonPropertyOrder({
|
||||
"mandatsreferenz",
|
||||
"analyse-vom-frei-verfuegbaren-einkommen-ausgeschlossen",
|
||||
"analyse-vertrag",
|
||||
"e-ref",
|
||||
"analyse-hauptkategorie",
|
||||
"analyse-umsatzart",
|
||||
"analyse-woche",
|
||||
"analyse-monat",
|
||||
"analyse-quartal",
|
||||
"kontostand",
|
||||
"analyse-vertrags-id",
|
||||
"waehrung",
|
||||
"verwendungszweck",
|
||||
"buchungstag",
|
||||
"analyse-vertragsturnus",
|
||||
"analyse-betrag",
|
||||
"betrag",
|
||||
"name-referenzkonto",
|
||||
"beguenstigter/auftraggeber",
|
||||
"analyse-umbuchung",
|
||||
"iban-beguenstigter/auftraggeber",
|
||||
"referenzkonto",
|
||||
"analyse-unterkategorie",
|
||||
"analyse-jahr",
|
||||
"glaeubiger-id"
|
||||
})
|
||||
public class TransactionDAO {
|
||||
|
||||
@JsonProperty("mandatsreferenz")
|
||||
private String mandatsreferenz;
|
||||
@JsonProperty("analyse-vom-frei-verfuegbaren-einkommen-ausgeschlossen")
|
||||
private String analyseVomFreiVerfuegbarenEinkommenAusgeschlossen;
|
||||
@JsonProperty("analyse-vertrag")
|
||||
private String analyseVertrag;
|
||||
@JsonProperty("e-ref")
|
||||
private String eRef;
|
||||
@JsonProperty("analyse-hauptkategorie")
|
||||
private String analyseHauptkategorie;
|
||||
@JsonProperty("analyse-umsatzart")
|
||||
private String analyseUmsatzart;
|
||||
@JsonProperty("analyse-woche")
|
||||
private String analyseWoche;
|
||||
@JsonProperty("analyse-monat")
|
||||
private String analyseMonat;
|
||||
@JsonProperty("analyse-quartal")
|
||||
private String analyseQuartal;
|
||||
@JsonProperty("kontostand")
|
||||
private String kontostand;
|
||||
@JsonProperty("analyse-vertrags-id")
|
||||
private String analyseVertragsId;
|
||||
@JsonProperty("waehrung")
|
||||
private String waehrung;
|
||||
@JsonProperty("verwendungszweck")
|
||||
private String verwendungszweck;
|
||||
@JsonProperty("buchungstag")
|
||||
private String buchungstag;
|
||||
@JsonProperty("analyse-vertragsturnus")
|
||||
private String analyseVertragsturnus;
|
||||
@JsonProperty("analyse-betrag")
|
||||
private String analyseBetrag;
|
||||
@JsonProperty("betrag")
|
||||
private String betrag;
|
||||
@JsonProperty("name-referenzkonto")
|
||||
private String nameReferenzkonto;
|
||||
@JsonProperty("beguenstigter/auftraggeber")
|
||||
private String beguenstigterAuftraggeber;
|
||||
@JsonProperty("analyse-umbuchung")
|
||||
private String analyseUmbuchung;
|
||||
@JsonProperty("iban-beguenstigter/auftraggeber")
|
||||
private String ibanBeguenstigterAuftraggeber;
|
||||
@JsonProperty("referenzkonto")
|
||||
private String referenzkonto;
|
||||
@JsonProperty("analyse-unterkategorie")
|
||||
private String analyseUnterkategorie;
|
||||
@JsonProperty("analyse-jahr")
|
||||
private String analyseJahr;
|
||||
@JsonProperty("glaeubiger-id")
|
||||
private String glaeubigerId;
|
||||
@JsonIgnore
|
||||
private final Map<String, Object> additionalProperties = new LinkedHashMap<String, Object>();
|
||||
|
||||
|
||||
@JsonAnyGetter
|
||||
public Map<String, Object> getAdditionalProperties() {
|
||||
return this.additionalProperties;
|
||||
}
|
||||
|
||||
|
||||
@JsonProperty("analyse-betrag")
|
||||
public String getAnalyseBetrag() {
|
||||
return analyseBetrag;
|
||||
}
|
||||
|
||||
|
||||
@JsonProperty("analyse-hauptkategorie")
|
||||
public String getAnalyseHauptkategorie() {
|
||||
return analyseHauptkategorie;
|
||||
}
|
||||
|
||||
|
||||
@JsonProperty("analyse-jahr")
|
||||
public String getAnalyseJahr() {
|
||||
return analyseJahr;
|
||||
}
|
||||
|
||||
|
||||
@JsonProperty("analyse-monat")
|
||||
public String getAnalyseMonat() {
|
||||
return analyseMonat;
|
||||
}
|
||||
|
||||
|
||||
@JsonProperty("analyse-quartal")
|
||||
public String getAnalyseQuartal() {
|
||||
return analyseQuartal;
|
||||
}
|
||||
|
||||
|
||||
@JsonProperty("analyse-umbuchung")
|
||||
public String getAnalyseUmbuchung() {
|
||||
return analyseUmbuchung;
|
||||
}
|
||||
|
||||
|
||||
@JsonProperty("analyse-umsatzart")
|
||||
public String getAnalyseUmsatzart() {
|
||||
return analyseUmsatzart;
|
||||
}
|
||||
|
||||
|
||||
@JsonProperty("analyse-unterkategorie")
|
||||
public String getAnalyseUnterkategorie() {
|
||||
return analyseUnterkategorie;
|
||||
}
|
||||
|
||||
|
||||
@JsonProperty("analyse-vertrag")
|
||||
public String getAnalyseVertrag() {
|
||||
return analyseVertrag;
|
||||
}
|
||||
|
||||
|
||||
@JsonProperty("analyse-vertrags-id")
|
||||
public String getAnalyseVertragsId() {
|
||||
return analyseVertragsId;
|
||||
}
|
||||
|
||||
|
||||
@JsonProperty("analyse-vertragsturnus")
|
||||
public String getAnalyseVertragsturnus() {
|
||||
return analyseVertragsturnus;
|
||||
}
|
||||
|
||||
|
||||
@JsonProperty("analyse-vom-frei-verfuegbaren-einkommen-ausgeschlossen")
|
||||
public String getAnalyseVomFreiVerfuegbarenEinkommenAusgeschlossen() {
|
||||
return analyseVomFreiVerfuegbarenEinkommenAusgeschlossen;
|
||||
}
|
||||
|
||||
|
||||
@JsonProperty("analyse-woche")
|
||||
public String getAnalyseWoche() {
|
||||
return analyseWoche;
|
||||
}
|
||||
|
||||
|
||||
@JsonProperty("beguenstigter/auftraggeber")
|
||||
public String getBeguenstigterAuftraggeber() {
|
||||
return beguenstigterAuftraggeber;
|
||||
}
|
||||
|
||||
|
||||
@JsonProperty("betrag")
|
||||
public String getBetrag() {
|
||||
return betrag;
|
||||
}
|
||||
|
||||
|
||||
public float getBetragAsFloat() {
|
||||
return Float.parseFloat(betrag);
|
||||
}
|
||||
|
||||
|
||||
@JsonProperty("buchungstag")
|
||||
public String getBuchungstag() {
|
||||
return buchungstag;
|
||||
}
|
||||
|
||||
|
||||
@JsonProperty("glaeubiger-id")
|
||||
public String getGlaeubigerId() {
|
||||
return glaeubigerId;
|
||||
}
|
||||
|
||||
|
||||
@JsonProperty("iban-beguenstigter/auftraggeber")
|
||||
public String getIbanBeguenstigterAuftraggeber() {
|
||||
return ibanBeguenstigterAuftraggeber;
|
||||
}
|
||||
|
||||
|
||||
@JsonProperty("kontostand")
|
||||
public String getKontostand() {
|
||||
return kontostand;
|
||||
}
|
||||
|
||||
|
||||
@JsonProperty("mandatsreferenz")
|
||||
public String getMandatsreferenz() {
|
||||
return mandatsreferenz;
|
||||
}
|
||||
|
||||
|
||||
@JsonProperty("name-referenzkonto")
|
||||
public String getNameReferenzkonto() {
|
||||
return nameReferenzkonto;
|
||||
}
|
||||
|
||||
|
||||
@JsonProperty("referenzkonto")
|
||||
public String getReferenzkonto() {
|
||||
return referenzkonto;
|
||||
}
|
||||
|
||||
|
||||
@JsonProperty("verwendungszweck")
|
||||
public String getVerwendungszweck() {
|
||||
return verwendungszweck;
|
||||
}
|
||||
|
||||
|
||||
@JsonProperty("waehrung")
|
||||
public String getWaehrung() {
|
||||
return waehrung;
|
||||
}
|
||||
|
||||
|
||||
@JsonProperty("e-ref")
|
||||
public String geteRef() {
|
||||
return eRef;
|
||||
}
|
||||
|
||||
|
||||
@JsonAnySetter
|
||||
public void setAdditionalProperty(String name, Object value) {
|
||||
this.additionalProperties.put(name, value);
|
||||
}
|
||||
|
||||
|
||||
@JsonProperty("analyse-betrag")
|
||||
public void setAnalyseBetrag(String analyseBetrag) {
|
||||
this.analyseBetrag = analyseBetrag;
|
||||
}
|
||||
|
||||
|
||||
@JsonProperty("analyse-hauptkategorie")
|
||||
public void setAnalyseHauptkategorie(String analyseHauptkategorie) {
|
||||
this.analyseHauptkategorie = analyseHauptkategorie;
|
||||
}
|
||||
|
||||
|
||||
@JsonProperty("analyse-jahr")
|
||||
public void setAnalyseJahr(String analyseJahr) {
|
||||
this.analyseJahr = analyseJahr;
|
||||
}
|
||||
|
||||
|
||||
@JsonProperty("analyse-monat")
|
||||
public void setAnalyseMonat(String analyseMonat) {
|
||||
this.analyseMonat = analyseMonat;
|
||||
}
|
||||
|
||||
|
||||
@JsonProperty("analyse-quartal")
|
||||
public void setAnalyseQuartal(String analyseQuartal) {
|
||||
this.analyseQuartal = analyseQuartal;
|
||||
}
|
||||
|
||||
|
||||
@JsonProperty("analyse-umbuchung")
|
||||
public void setAnalyseUmbuchung(String analyseUmbuchung) {
|
||||
this.analyseUmbuchung = analyseUmbuchung;
|
||||
}
|
||||
|
||||
|
||||
@JsonProperty("analyse-umsatzart")
|
||||
public void setAnalyseUmsatzart(String analyseUmsatzart) {
|
||||
this.analyseUmsatzart = analyseUmsatzart;
|
||||
}
|
||||
|
||||
|
||||
@JsonProperty("analyse-unterkategorie")
|
||||
public void setAnalyseUnterkategorie(String analyseUnterkategorie) {
|
||||
this.analyseUnterkategorie = analyseUnterkategorie;
|
||||
}
|
||||
|
||||
|
||||
@JsonProperty("analyse-vertrag")
|
||||
public void setAnalyseVertrag(String analyseVertrag) {
|
||||
this.analyseVertrag = analyseVertrag;
|
||||
}
|
||||
|
||||
|
||||
@JsonProperty("analyse-vertrags-id")
|
||||
public void setAnalyseVertragsId(String analyseVertragsId) {
|
||||
this.analyseVertragsId = analyseVertragsId;
|
||||
}
|
||||
|
||||
|
||||
@JsonProperty("analyse-vertragsturnus")
|
||||
public void setAnalyseVertragsturnus(String analyseVertragsturnus) {
|
||||
this.analyseVertragsturnus = analyseVertragsturnus;
|
||||
}
|
||||
|
||||
|
||||
@JsonProperty("analyse-vom-frei-verfuegbaren-einkommen-ausgeschlossen")
|
||||
public void setAnalyseVomFreiVerfuegbarenEinkommenAusgeschlossen(String analyseVomFreiVerfuegbarenEinkommenAusgeschlossen) {
|
||||
this.analyseVomFreiVerfuegbarenEinkommenAusgeschlossen = analyseVomFreiVerfuegbarenEinkommenAusgeschlossen;
|
||||
}
|
||||
|
||||
|
||||
@JsonProperty("analyse-woche")
|
||||
public void setAnalyseWoche(String analyseWoche) {
|
||||
this.analyseWoche = analyseWoche;
|
||||
}
|
||||
|
||||
|
||||
@JsonProperty("beguenstigter/auftraggeber")
|
||||
public void setBeguenstigterAuftraggeber(String beguenstigterAuftraggeber) {
|
||||
if (beguenstigterAuftraggeber.contains("Abbuchung")) {
|
||||
this.beguenstigterAuftraggeber = "Sparkasse Münsterland Ost";
|
||||
} else {
|
||||
this.beguenstigterAuftraggeber = beguenstigterAuftraggeber;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
@JsonProperty("betrag")
|
||||
public void setBetrag(String betrag) {
|
||||
this.betrag = betrag;
|
||||
}
|
||||
|
||||
|
||||
@JsonProperty("buchungstag")
|
||||
public void setBuchungstag(String buchungstag) {
|
||||
this.buchungstag = buchungstag;
|
||||
}
|
||||
|
||||
|
||||
@JsonProperty("glaeubiger-id")
|
||||
public void setGlaeubigerId(String glaeubigerId) {
|
||||
this.glaeubigerId = glaeubigerId;
|
||||
}
|
||||
|
||||
|
||||
@JsonProperty("iban-beguenstigter/auftraggeber")
|
||||
public void setIbanBeguenstigterAuftraggeber(String ibanBeguenstigterAuftraggeber) {
|
||||
this.ibanBeguenstigterAuftraggeber = ibanBeguenstigterAuftraggeber;
|
||||
}
|
||||
|
||||
|
||||
@JsonProperty("kontostand")
|
||||
public void setKontostand(String kontostand) {
|
||||
this.kontostand = kontostand;
|
||||
}
|
||||
|
||||
|
||||
@JsonProperty("mandatsreferenz")
|
||||
public void setMandatsreferenz(String mandatsreferenz) {
|
||||
this.mandatsreferenz = mandatsreferenz;
|
||||
}
|
||||
|
||||
|
||||
@JsonProperty("name-referenzkonto")
|
||||
public void setNameReferenzkonto(String nameReferenzkonto) {
|
||||
this.nameReferenzkonto = nameReferenzkonto;
|
||||
}
|
||||
|
||||
|
||||
@JsonProperty("referenzkonto")
|
||||
public void setReferenzkonto(String referenzkonto) {
|
||||
this.referenzkonto = referenzkonto;
|
||||
}
|
||||
|
||||
|
||||
@JsonProperty("verwendungszweck")
|
||||
public void setVerwendungszweck(String verwendungszweck) {
|
||||
this.verwendungszweck = verwendungszweck;
|
||||
}
|
||||
|
||||
|
||||
@JsonProperty("waehrung")
|
||||
public void setWaehrung(String waehrung) {
|
||||
this.waehrung = waehrung;
|
||||
}
|
||||
|
||||
|
||||
@JsonProperty("e-ref")
|
||||
public void seteRef(String eRef) {
|
||||
this.eRef = eRef;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
StringBuilder sb = new StringBuilder();
|
||||
sb.append(TransactionDAO.class.getName()).append('@').append(Integer.toHexString(System.identityHashCode(this))).append('[');
|
||||
sb.append("mandatsreferenz");
|
||||
sb.append('=');
|
||||
sb.append(((this.mandatsreferenz == null) ? "<null>" : this.mandatsreferenz));
|
||||
sb.append(',');
|
||||
sb.append("analyseVomFreiVerfuegbarenEinkommenAusgeschlossen");
|
||||
sb.append('=');
|
||||
sb.append(((this.analyseVomFreiVerfuegbarenEinkommenAusgeschlossen == null) ? "<null>" : this.analyseVomFreiVerfuegbarenEinkommenAusgeschlossen));
|
||||
sb.append(',');
|
||||
sb.append("analyseVertrag");
|
||||
sb.append('=');
|
||||
sb.append(((this.analyseVertrag == null) ? "<null>" : this.analyseVertrag));
|
||||
sb.append(',');
|
||||
sb.append("eRef");
|
||||
sb.append('=');
|
||||
sb.append(((this.eRef == null) ? "<null>" : this.eRef));
|
||||
sb.append(',');
|
||||
sb.append("analyseHauptkategorie");
|
||||
sb.append('=');
|
||||
sb.append(((this.analyseHauptkategorie == null) ? "<null>" : this.analyseHauptkategorie));
|
||||
sb.append(',');
|
||||
sb.append("analyseUmsatzart");
|
||||
sb.append('=');
|
||||
sb.append(((this.analyseUmsatzart == null) ? "<null>" : this.analyseUmsatzart));
|
||||
sb.append(',');
|
||||
sb.append("analyseWoche");
|
||||
sb.append('=');
|
||||
sb.append(((this.analyseWoche == null) ? "<null>" : this.analyseWoche));
|
||||
sb.append(',');
|
||||
sb.append("analyseMonat");
|
||||
sb.append('=');
|
||||
sb.append(((this.analyseMonat == null) ? "<null>" : this.analyseMonat));
|
||||
sb.append(',');
|
||||
sb.append("analyseQuartal");
|
||||
sb.append('=');
|
||||
sb.append(((this.analyseQuartal == null) ? "<null>" : this.analyseQuartal));
|
||||
sb.append(',');
|
||||
sb.append("kontostand");
|
||||
sb.append('=');
|
||||
sb.append(((this.kontostand == null) ? "<null>" : this.kontostand));
|
||||
sb.append(',');
|
||||
sb.append("analyseVertragsId");
|
||||
sb.append('=');
|
||||
sb.append(((this.analyseVertragsId == null) ? "<null>" : this.analyseVertragsId));
|
||||
sb.append(',');
|
||||
sb.append("waehrung");
|
||||
sb.append('=');
|
||||
sb.append(((this.waehrung == null) ? "<null>" : this.waehrung));
|
||||
sb.append(',');
|
||||
sb.append("verwendungszweck");
|
||||
sb.append('=');
|
||||
sb.append(((this.verwendungszweck == null) ? "<null>" : this.verwendungszweck));
|
||||
sb.append(',');
|
||||
sb.append("buchungstag");
|
||||
sb.append('=');
|
||||
sb.append(((this.buchungstag == null) ? "<null>" : this.buchungstag));
|
||||
sb.append(',');
|
||||
sb.append("analyseVertragsturnus");
|
||||
sb.append('=');
|
||||
sb.append(((this.analyseVertragsturnus == null) ? "<null>" : this.analyseVertragsturnus));
|
||||
sb.append(',');
|
||||
sb.append("analyseBetrag");
|
||||
sb.append('=');
|
||||
sb.append(((this.analyseBetrag == null) ? "<null>" : this.analyseBetrag));
|
||||
sb.append(',');
|
||||
sb.append("betrag");
|
||||
sb.append('=');
|
||||
sb.append(((this.betrag == null) ? "<null>" : this.betrag));
|
||||
sb.append(',');
|
||||
sb.append("nameReferenzkonto");
|
||||
sb.append('=');
|
||||
sb.append(((this.nameReferenzkonto == null) ? "<null>" : this.nameReferenzkonto));
|
||||
sb.append(',');
|
||||
sb.append("beguenstigterAuftraggeber");
|
||||
sb.append('=');
|
||||
sb.append(((this.beguenstigterAuftraggeber == null) ? "<null>" : this.beguenstigterAuftraggeber));
|
||||
sb.append(',');
|
||||
sb.append("analyseUmbuchung");
|
||||
sb.append('=');
|
||||
sb.append(((this.analyseUmbuchung == null) ? "<null>" : this.analyseUmbuchung));
|
||||
sb.append(',');
|
||||
sb.append("ibanBeguenstigterAuftraggeber");
|
||||
sb.append('=');
|
||||
sb.append(((this.ibanBeguenstigterAuftraggeber == null) ? "<null>" : this.ibanBeguenstigterAuftraggeber));
|
||||
sb.append(',');
|
||||
sb.append("referenzkonto");
|
||||
sb.append('=');
|
||||
sb.append(((this.referenzkonto == null) ? "<null>" : this.referenzkonto));
|
||||
sb.append(',');
|
||||
sb.append("analyseUnterkategorie");
|
||||
sb.append('=');
|
||||
sb.append(((this.analyseUnterkategorie == null) ? "<null>" : this.analyseUnterkategorie));
|
||||
sb.append(',');
|
||||
sb.append("analyseJahr");
|
||||
sb.append('=');
|
||||
sb.append(((this.analyseJahr == null) ? "<null>" : this.analyseJahr));
|
||||
sb.append(',');
|
||||
sb.append("glaeubigerId");
|
||||
sb.append('=');
|
||||
sb.append(((this.glaeubigerId == null) ? "<null>" : this.glaeubigerId));
|
||||
sb.append(',');
|
||||
sb.append("additionalProperties");
|
||||
sb.append('=');
|
||||
sb.append(((this.additionalProperties == null) ? "<null>" : this.additionalProperties));
|
||||
sb.append(',');
|
||||
if (sb.charAt((sb.length() - 1)) == ',') {
|
||||
sb.setCharAt((sb.length() - 1), ']');
|
||||
} else {
|
||||
sb.append(']');
|
||||
}
|
||||
return sb.toString();
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public boolean equals(final Object o) {
|
||||
if (this == o) return true;
|
||||
if (o == null || getClass() != o.getClass()) return false;
|
||||
final TransactionDAO that = (TransactionDAO) o;
|
||||
return Objects.equals(referenzkonto, that.referenzkonto)
|
||||
&& Objects.equals(analyseBetrag, that.analyseBetrag)
|
||||
&& Objects.equals(verwendungszweck, that.verwendungszweck)
|
||||
&& Objects.equals(betrag, that.betrag)
|
||||
&& Objects.equals(ibanBeguenstigterAuftraggeber, that.ibanBeguenstigterAuftraggeber);
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return Objects.hash(referenzkonto, verwendungszweck, analyseBetrag, betrag, ibanBeguenstigterAuftraggeber);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,60 @@
|
|||
package de.arminwolf.financeanalyzer.dao.charts.factories;
|
||||
|
||||
import de.arminwolf.financeanalyzer.dao.TransactionDAO;
|
||||
import de.arminwolf.financeanalyzer.dao.charts.model.Chart;
|
||||
import de.arminwolf.financeanalyzer.dao.charts.model.HighChartDAO;
|
||||
import de.arminwolf.financeanalyzer.dao.charts.model.Packedbubble;
|
||||
import de.arminwolf.financeanalyzer.dao.charts.model.PlotOptions;
|
||||
import de.arminwolf.financeanalyzer.dao.charts.model.Series;
|
||||
import de.arminwolf.financeanalyzer.dao.charts.model.SeriesElement;
|
||||
import de.arminwolf.financeanalyzer.dao.charts.model.Title;
|
||||
import de.arminwolf.financeanalyzer.dao.charts.model.ToolTip;
|
||||
import de.arminwolf.financeanalyzer.util.RandomColorUtil;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.concurrent.atomic.AtomicInteger;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
public class BubbleChartFactory {
|
||||
|
||||
public static HighChartDAO createBubbleChart(
|
||||
final String pTitle,
|
||||
final List<TransactionDAO> transactions) {
|
||||
HighChartDAO highChartDAO = new HighChartDAO();
|
||||
highChartDAO.setTitle(new Title(pTitle));
|
||||
|
||||
highChartDAO.setChart(new Chart("packedbubble", "75%"));
|
||||
|
||||
List<Series> series = new ArrayList<>();
|
||||
List<String> colors = new ArrayList<>();
|
||||
|
||||
AtomicInteger min = new AtomicInteger(0);
|
||||
AtomicInteger max = new AtomicInteger(0);
|
||||
|
||||
transactions.stream()
|
||||
.collect(Collectors.groupingBy(TransactionDAO::getAnalyseHauptkategorie))
|
||||
.forEach((key, value) -> {
|
||||
Series data = new Series();
|
||||
data.setName(key);
|
||||
Float reduce = value.stream().reduce(0f, (a, b) -> a + (-1.0f * b.getBetragAsFloat()), Float::sum);
|
||||
min.set(Math.min(min.get(), reduce.intValue()));
|
||||
max.set(Math.max(max.get(), reduce.intValue()));
|
||||
data.setComplexData(value.stream().map(b -> new SeriesElement(b.getBeguenstigterAuftraggeber(), -1.0f * b.getBetragAsFloat())).collect(Collectors.toList()));
|
||||
series.add(data);
|
||||
colors.add(RandomColorUtil.getRandomColor());
|
||||
});
|
||||
|
||||
PlotOptions plotOptions = new PlotOptions();
|
||||
plotOptions.setPackedbubble(new Packedbubble());
|
||||
plotOptions.getPackedbubble().setzMax(max.get());
|
||||
plotOptions.getPackedbubble().setzMin(min.get());
|
||||
plotOptions.getPackedbubble().getDataLabels().getFilter().setValue(Double.valueOf(0.2 * max.get()).intValue());
|
||||
highChartDAO.setPlotOptions(plotOptions);
|
||||
|
||||
highChartDAO.setTooltip(new ToolTip("<b>{point.name}:</b> <u>{point.value} €</u>", true));
|
||||
highChartDAO.setColors(colors);
|
||||
highChartDAO.setSeries(series);
|
||||
return highChartDAO;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,74 @@
|
|||
package de.arminwolf.financeanalyzer.dao.charts.factories;
|
||||
|
||||
import de.arminwolf.financeanalyzer.dao.charts.model.Chart;
|
||||
import de.arminwolf.financeanalyzer.dao.charts.model.Column;
|
||||
import de.arminwolf.financeanalyzer.dao.charts.model.HighChartDAO;
|
||||
import de.arminwolf.financeanalyzer.dao.charts.model.PlotOptions;
|
||||
import de.arminwolf.financeanalyzer.dao.charts.model.Series;
|
||||
import de.arminwolf.financeanalyzer.dao.charts.model.Title;
|
||||
import de.arminwolf.financeanalyzer.dao.charts.model.XAxis;
|
||||
import de.arminwolf.financeanalyzer.dao.charts.model.YAxis;
|
||||
import de.arminwolf.financeanalyzer.util.RandomColorUtil;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
public class ColumnChartFactory {
|
||||
|
||||
public static HighChartDAO createColumnChart(
|
||||
final String pTitle,
|
||||
final String pChartTitle,
|
||||
final Map<String, List<Float>> ausgaben,
|
||||
final String pAusgabenTitle,
|
||||
final Map<String, List<Float>> einnahmen,
|
||||
final String pEinnahmenTitle) {
|
||||
|
||||
HighChartDAO chart = new HighChartDAO();
|
||||
|
||||
PlotOptions plotOptions = new PlotOptions();
|
||||
Column column = new Column();
|
||||
//column.setStacking("normal");
|
||||
plotOptions.setColumn(column);
|
||||
chart.setPlotOptions(plotOptions);
|
||||
|
||||
chart.setTitle(new Title(pTitle));
|
||||
|
||||
XAxis xAxis = new XAxis();
|
||||
xAxis.setCategories(List.of("Einname", "Ausgabe"));
|
||||
chart.setXAxis(xAxis);
|
||||
|
||||
YAxis yAxis = new YAxis();
|
||||
yAxis.setMin(0);
|
||||
yAxis.setTitle(new Title(pChartTitle));
|
||||
chart.setYAxis(yAxis);
|
||||
|
||||
chart.setChart(new Chart("column"));
|
||||
|
||||
Series einnahmenSeries = new Series();
|
||||
einnahmenSeries.setStack(1);
|
||||
einnahmenSeries.setName(pEinnahmenTitle);
|
||||
einnahmenSeries.setData(einnahmen.values()
|
||||
.stream()
|
||||
.map(floats -> floats.stream().reduce(0.0f, Float::sum))
|
||||
.collect(Collectors.toList()));
|
||||
|
||||
|
||||
Series ausgabenSeries = new Series();
|
||||
ausgabenSeries.setStack(0);
|
||||
ausgabenSeries.setName(pAusgabenTitle);
|
||||
ausgabenSeries.setData(ausgaben.values()
|
||||
.stream()
|
||||
.map(floats -> floats.stream().map(Math::abs).reduce(0.0f, Float::sum))
|
||||
.collect(Collectors.toList()));
|
||||
|
||||
chart.setColors(List.of(RandomColorUtil.getRandomColor(), RandomColorUtil.getRandomColor()));
|
||||
|
||||
List<Series> series = new ArrayList<>();
|
||||
series.add(einnahmenSeries);
|
||||
series.add(ausgabenSeries);
|
||||
chart.setSeries(series);
|
||||
return chart;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,42 @@
|
|||
package de.arminwolf.financeanalyzer.dao.charts.factories;
|
||||
|
||||
import de.arminwolf.financeanalyzer.dao.charts.model.Chart;
|
||||
import de.arminwolf.financeanalyzer.dao.charts.model.HighChartDAO;
|
||||
import de.arminwolf.financeanalyzer.dao.charts.model.Series;
|
||||
import de.arminwolf.financeanalyzer.dao.charts.model.Title;
|
||||
import de.arminwolf.financeanalyzer.dao.charts.model.XAxis;
|
||||
import de.arminwolf.financeanalyzer.dao.charts.model.YAxis;
|
||||
import de.arminwolf.financeanalyzer.util.RandomColorUtil;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
public class LineChartFactory {
|
||||
|
||||
|
||||
public static HighChartDAO createLineChart(final String pTitle, final String pChartTitle, final List<String> categories, final List<Series> pData) {
|
||||
HighChartDAO lineChart = new HighChartDAO();
|
||||
Title title = new Title();
|
||||
title.setText(pTitle);
|
||||
lineChart.setTitle(title);
|
||||
|
||||
XAxis xAxis = new XAxis();
|
||||
xAxis.setCategories(categories);
|
||||
|
||||
YAxis yAxis = new YAxis();
|
||||
Title chartTitle = new Title();
|
||||
chartTitle.setText(pChartTitle);
|
||||
yAxis.setTitle(chartTitle);
|
||||
|
||||
lineChart.setXAxis(xAxis);
|
||||
lineChart.setYAxis(yAxis);
|
||||
|
||||
|
||||
Chart chart = new Chart();
|
||||
chart.setType("line");
|
||||
|
||||
lineChart.setChart(chart);
|
||||
lineChart.setColors(List.of(RandomColorUtil.getRandomColor()));
|
||||
lineChart.setSeries(pData);
|
||||
return lineChart;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,46 @@
|
|||
package de.arminwolf.financeanalyzer.dao.charts.model;
|
||||
|
||||
import java.io.Serializable;
|
||||
|
||||
public class Chart implements Serializable {
|
||||
|
||||
private String type;
|
||||
private String height;
|
||||
|
||||
|
||||
public Chart() {
|
||||
this.type = "";
|
||||
}
|
||||
|
||||
|
||||
public Chart(final String type) {
|
||||
this.type = type;
|
||||
}
|
||||
|
||||
|
||||
public Chart(final String type, final String height) {
|
||||
this.type = type;
|
||||
this.height = height;
|
||||
}
|
||||
|
||||
|
||||
public String getHeight() {
|
||||
return height;
|
||||
}
|
||||
|
||||
|
||||
public void setHeight(final String height) {
|
||||
this.height = height;
|
||||
}
|
||||
|
||||
|
||||
public String getType() {
|
||||
return this.type;
|
||||
}
|
||||
|
||||
|
||||
public void setType(String type) {
|
||||
this.type = type;
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,20 @@
|
|||
package de.arminwolf.financeanalyzer.dao.charts.model;
|
||||
|
||||
import java.io.Serializable;
|
||||
|
||||
public class Column implements Serializable {
|
||||
|
||||
private String stacking;
|
||||
|
||||
|
||||
public String getStacking() {
|
||||
return this.stacking;
|
||||
}
|
||||
|
||||
|
||||
public void setStacking(String stacking) {
|
||||
this.stacking = stacking;
|
||||
}
|
||||
|
||||
|
||||
}
|
|
@ -0,0 +1,59 @@
|
|||
package de.arminwolf.financeanalyzer.dao.charts.model;
|
||||
|
||||
|
||||
|
||||
public class DataLabels {
|
||||
|
||||
private boolean enabled;
|
||||
private String format;
|
||||
private Filter filter;
|
||||
private Style style;
|
||||
|
||||
|
||||
public DataLabels(boolean enabled, String format, Filter filter, Style style) {
|
||||
this.enabled = enabled;
|
||||
this.format = format;
|
||||
this.filter = filter;
|
||||
this.style = style;
|
||||
}
|
||||
|
||||
|
||||
public boolean isEnabled() {
|
||||
return enabled;
|
||||
}
|
||||
|
||||
|
||||
public void setEnabled(final boolean enabled) {
|
||||
this.enabled = enabled;
|
||||
}
|
||||
|
||||
|
||||
public String getFormat() {
|
||||
return format;
|
||||
}
|
||||
|
||||
|
||||
public void setFormat(final String format) {
|
||||
this.format = format;
|
||||
}
|
||||
|
||||
|
||||
public Filter getFilter() {
|
||||
return filter;
|
||||
}
|
||||
|
||||
|
||||
public void setFilter(final Filter filter) {
|
||||
this.filter = filter;
|
||||
}
|
||||
|
||||
|
||||
public Style getStyle() {
|
||||
return style;
|
||||
}
|
||||
|
||||
|
||||
public void setStyle(final Style style) {
|
||||
this.style = style;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,45 @@
|
|||
package de.arminwolf.financeanalyzer.dao.charts.model;
|
||||
|
||||
public class Filter {
|
||||
|
||||
private String property;
|
||||
private String operator;
|
||||
private int value;
|
||||
|
||||
|
||||
public Filter(String property, String operator, int value) {
|
||||
this.property = property;
|
||||
this.operator = operator;
|
||||
this.value = value;
|
||||
}
|
||||
|
||||
|
||||
public String getProperty() {
|
||||
return property;
|
||||
}
|
||||
|
||||
|
||||
public void setProperty(final String property) {
|
||||
this.property = property;
|
||||
}
|
||||
|
||||
|
||||
public String getOperator() {
|
||||
return operator;
|
||||
}
|
||||
|
||||
|
||||
public void setOperator(final String operator) {
|
||||
this.operator = operator;
|
||||
}
|
||||
|
||||
|
||||
public int getValue() {
|
||||
return value;
|
||||
}
|
||||
|
||||
|
||||
public void setValue(final int value) {
|
||||
this.value = value;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,125 @@
|
|||
package de.arminwolf.financeanalyzer.dao.charts.model;
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonInclude;
|
||||
import com.fasterxml.jackson.annotation.JsonProperty;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.util.List;
|
||||
|
||||
@JsonInclude(JsonInclude.Include.NON_NULL)
|
||||
public class HighChartDAO implements Serializable {
|
||||
|
||||
private PlotOptions plotOptions;
|
||||
private ToolTip tooltip;
|
||||
private YAxis yAxis;
|
||||
private XAxis xAxis;
|
||||
private List<? extends Series> series;
|
||||
private Title title;
|
||||
private Chart chart;
|
||||
private List<String> colors;
|
||||
|
||||
|
||||
@JsonProperty("tooltip")
|
||||
public ToolTip getTooltip() {
|
||||
return tooltip;
|
||||
}
|
||||
|
||||
|
||||
public void setTooltip(final ToolTip tooltip) {
|
||||
this.tooltip = tooltip;
|
||||
}
|
||||
|
||||
|
||||
public YAxis getyAxis() {
|
||||
return yAxis;
|
||||
}
|
||||
|
||||
|
||||
public void setyAxis(final YAxis yAxis) {
|
||||
this.yAxis = yAxis;
|
||||
}
|
||||
|
||||
|
||||
public XAxis getxAxis() {
|
||||
return xAxis;
|
||||
}
|
||||
|
||||
|
||||
public void setxAxis(final XAxis xAxis) {
|
||||
this.xAxis = xAxis;
|
||||
}
|
||||
|
||||
|
||||
public List<String> getColors() {
|
||||
return colors;
|
||||
}
|
||||
|
||||
|
||||
public void setColors(final List<String> colors) {
|
||||
this.colors = colors;
|
||||
}
|
||||
|
||||
|
||||
public PlotOptions getPlotOptions() {
|
||||
return this.plotOptions;
|
||||
}
|
||||
|
||||
|
||||
public void setPlotOptions(PlotOptions plotOptions) {
|
||||
this.plotOptions = plotOptions;
|
||||
}
|
||||
|
||||
|
||||
@JsonProperty("yAxis")
|
||||
public YAxis getYAxis() {
|
||||
return this.yAxis;
|
||||
}
|
||||
|
||||
|
||||
public void setYAxis(YAxis yAxis) {
|
||||
this.yAxis = yAxis;
|
||||
}
|
||||
|
||||
|
||||
@JsonProperty("xAxis")
|
||||
public XAxis getXAxis() {
|
||||
return this.xAxis;
|
||||
}
|
||||
|
||||
|
||||
public void setXAxis(XAxis xAxis) {
|
||||
this.xAxis = xAxis;
|
||||
}
|
||||
|
||||
|
||||
public List<? extends Series> getSeries() {
|
||||
return this.series;
|
||||
}
|
||||
|
||||
|
||||
public void setSeries(List<? extends Series> series) {
|
||||
this.series = series;
|
||||
}
|
||||
|
||||
|
||||
public Title getTitle() {
|
||||
return this.title;
|
||||
}
|
||||
|
||||
|
||||
public void setTitle(Title title) {
|
||||
this.title = title;
|
||||
}
|
||||
|
||||
|
||||
public Chart getChart() {
|
||||
return this.chart;
|
||||
}
|
||||
|
||||
|
||||
public void setChart(Chart chart) {
|
||||
this.chart = chart;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,76 @@
|
|||
package de.arminwolf.financeanalyzer.dao.charts.model;
|
||||
|
||||
public class LayoutAlgorithm {
|
||||
|
||||
private double gravitationalConstant;
|
||||
private boolean splitSeries;
|
||||
private boolean seriesInteraction;
|
||||
private boolean dragBetweenSeries;
|
||||
private boolean parentNodeLimit;
|
||||
|
||||
|
||||
public LayoutAlgorithm(
|
||||
final double gravitationalConstant,
|
||||
final boolean splitSeries,
|
||||
final boolean seriesInteraction,
|
||||
final boolean dragBetweenSeries,
|
||||
final boolean parentNodeLimit
|
||||
) {
|
||||
|
||||
this.gravitationalConstant = gravitationalConstant;
|
||||
this.splitSeries = splitSeries;
|
||||
this.seriesInteraction = seriesInteraction;
|
||||
this.dragBetweenSeries = dragBetweenSeries;
|
||||
this.parentNodeLimit = parentNodeLimit;
|
||||
}
|
||||
|
||||
|
||||
public double getGravitationalConstant() {
|
||||
return gravitationalConstant;
|
||||
}
|
||||
|
||||
|
||||
public void setGravitationalConstant(final double gravitationalConstant) {
|
||||
this.gravitationalConstant = gravitationalConstant;
|
||||
}
|
||||
|
||||
|
||||
public boolean isSplitSeries() {
|
||||
return splitSeries;
|
||||
}
|
||||
|
||||
|
||||
public void setSplitSeries(final boolean splitSeries) {
|
||||
this.splitSeries = splitSeries;
|
||||
}
|
||||
|
||||
|
||||
public boolean isSeriesInteraction() {
|
||||
return seriesInteraction;
|
||||
}
|
||||
|
||||
|
||||
public void setSeriesInteraction(final boolean seriesInteraction) {
|
||||
this.seriesInteraction = seriesInteraction;
|
||||
}
|
||||
|
||||
|
||||
public boolean isDragBetweenSeries() {
|
||||
return dragBetweenSeries;
|
||||
}
|
||||
|
||||
|
||||
public void setDragBetweenSeries(final boolean dragBetweenSeries) {
|
||||
this.dragBetweenSeries = dragBetweenSeries;
|
||||
}
|
||||
|
||||
|
||||
public boolean isParentNodeLimit() {
|
||||
return parentNodeLimit;
|
||||
}
|
||||
|
||||
|
||||
public void setParentNodeLimit(final boolean parentNodeLimit) {
|
||||
this.parentNodeLimit = parentNodeLimit;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,95 @@
|
|||
package de.arminwolf.financeanalyzer.dao.charts.model;
|
||||
|
||||
public class Packedbubble {
|
||||
|
||||
private String minSize;
|
||||
private String maxSize;
|
||||
private int zMin;
|
||||
private int zMax;
|
||||
private LayoutAlgorithm layoutAlgorithm;
|
||||
private DataLabels dataLabels;
|
||||
|
||||
|
||||
public Packedbubble(String minSize, String maxSize, int zMin, int zMax, LayoutAlgorithm layoutAlgorithm, DataLabels dataLabels) {
|
||||
this.minSize = minSize;
|
||||
this.maxSize = maxSize;
|
||||
this.zMin = zMin;
|
||||
this.zMax = zMax;
|
||||
this.layoutAlgorithm = layoutAlgorithm;
|
||||
this.dataLabels = dataLabels;
|
||||
}
|
||||
|
||||
|
||||
public Packedbubble() {
|
||||
this.minSize = "20%";
|
||||
this.maxSize = "100%";
|
||||
this.zMin = 0;
|
||||
this.zMax = 1000;
|
||||
this.layoutAlgorithm = new LayoutAlgorithm(0.02, true, false, true, true);
|
||||
this.dataLabels = new DataLabels(
|
||||
true, "{point.name}",
|
||||
new Filter("y", ">", 0),
|
||||
new Style("black", "none", "normal")
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
public String getMinSize() {
|
||||
return minSize;
|
||||
}
|
||||
|
||||
|
||||
public void setMinSize(final String minSize) {
|
||||
this.minSize = minSize;
|
||||
}
|
||||
|
||||
|
||||
public String getMaxSize() {
|
||||
return maxSize;
|
||||
}
|
||||
|
||||
|
||||
public void setMaxSize(final String maxSize) {
|
||||
this.maxSize = maxSize;
|
||||
}
|
||||
|
||||
|
||||
public int getzMin() {
|
||||
return zMin;
|
||||
}
|
||||
|
||||
|
||||
public void setzMin(final int zMin) {
|
||||
this.zMin = zMin;
|
||||
}
|
||||
|
||||
|
||||
public int getzMax() {
|
||||
return zMax;
|
||||
}
|
||||
|
||||
|
||||
public void setzMax(final int zMax) {
|
||||
this.zMax = zMax;
|
||||
}
|
||||
|
||||
|
||||
public LayoutAlgorithm getLayoutAlgorithm() {
|
||||
return layoutAlgorithm;
|
||||
}
|
||||
|
||||
|
||||
public void setLayoutAlgorithm(final LayoutAlgorithm layoutAlgorithm) {
|
||||
this.layoutAlgorithm = layoutAlgorithm;
|
||||
}
|
||||
|
||||
|
||||
public DataLabels getDataLabels() {
|
||||
return dataLabels;
|
||||
}
|
||||
|
||||
|
||||
public void setDataLabels(final DataLabels dataLabels) {
|
||||
this.dataLabels = dataLabels;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,28 @@
|
|||
package de.arminwolf.financeanalyzer.dao.charts.model;
|
||||
|
||||
public class PlotOptions {
|
||||
|
||||
private Packedbubble packedbubble;
|
||||
|
||||
private Column column;
|
||||
|
||||
|
||||
public Column getColumn() {
|
||||
return this.column;
|
||||
}
|
||||
|
||||
|
||||
public void setColumn(Column column) {
|
||||
this.column = column;
|
||||
}
|
||||
|
||||
|
||||
public Packedbubble getPackedbubble() {
|
||||
return packedbubble;
|
||||
}
|
||||
|
||||
|
||||
public void setPackedbubble(final Packedbubble packedbubble) {
|
||||
this.packedbubble = packedbubble;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,62 @@
|
|||
package de.arminwolf.financeanalyzer.dao.charts.model;
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonProperty;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.util.Collection;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Objects;
|
||||
import java.util.Set;
|
||||
|
||||
public class Series implements Serializable {
|
||||
|
||||
private Set<? extends SeriesElement> complexData;
|
||||
private List<Float> data;
|
||||
|
||||
private int stack = 0;
|
||||
|
||||
private String name;
|
||||
|
||||
|
||||
|
||||
public void setComplexData(Collection<? extends SeriesElement> data) {
|
||||
this.complexData = new HashSet<>(data);
|
||||
}
|
||||
|
||||
|
||||
public String getName() {
|
||||
return this.name;
|
||||
}
|
||||
|
||||
|
||||
public int getStack() {
|
||||
return stack;
|
||||
}
|
||||
|
||||
|
||||
public void setName(String name) {
|
||||
this.name = name;
|
||||
}
|
||||
|
||||
|
||||
public void setData(final List<Float> data) {
|
||||
this.data = data;
|
||||
}
|
||||
|
||||
|
||||
@JsonProperty("data")
|
||||
public List<?> getData() {
|
||||
|
||||
if (Objects.isNull(data)) {
|
||||
return this.complexData.stream().toList();
|
||||
} else {
|
||||
return this.data;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public void setStack(final int i) {
|
||||
this.stack = i;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,50 @@
|
|||
package de.arminwolf.financeanalyzer.dao.charts.model;
|
||||
|
||||
import java.util.Objects;
|
||||
|
||||
public class SeriesElement {
|
||||
|
||||
private String name;
|
||||
private Float value;
|
||||
|
||||
|
||||
public SeriesElement(final String name, final Float value) {
|
||||
this.name = name;
|
||||
this.value = value;
|
||||
}
|
||||
|
||||
|
||||
public String getName() {
|
||||
return name;
|
||||
}
|
||||
|
||||
|
||||
public void setName(final String name) {
|
||||
this.name = name;
|
||||
}
|
||||
|
||||
|
||||
public Float getValue() {
|
||||
return value;
|
||||
}
|
||||
|
||||
|
||||
public void setValue(final Float value) {
|
||||
this.value = value;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public boolean equals(final Object o) {
|
||||
if (this == o) return true;
|
||||
if (o == null || getClass() != o.getClass()) return false;
|
||||
final SeriesElement that = (SeriesElement) o;
|
||||
return Objects.equals(name, that.name) && Objects.equals(value, that.value);
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return Objects.hash(name, value);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,46 @@
|
|||
package de.arminwolf.financeanalyzer.dao.charts.model;
|
||||
|
||||
public class Style {
|
||||
|
||||
private String color;
|
||||
private String textOutline;
|
||||
private String fontWeight;
|
||||
|
||||
|
||||
public Style(String color, String textOutline, String fontWeight) {
|
||||
this.color = color;
|
||||
this.textOutline = textOutline;
|
||||
this.fontWeight = fontWeight;
|
||||
}
|
||||
|
||||
|
||||
public String getColor() {
|
||||
return color;
|
||||
}
|
||||
|
||||
|
||||
public void setColor(final String color) {
|
||||
this.color = color;
|
||||
}
|
||||
|
||||
|
||||
public String getTextOutline() {
|
||||
return textOutline;
|
||||
}
|
||||
|
||||
|
||||
public void setTextOutline(final String textOutline) {
|
||||
this.textOutline = textOutline;
|
||||
}
|
||||
|
||||
|
||||
public String getFontWeight() {
|
||||
return fontWeight;
|
||||
}
|
||||
|
||||
|
||||
public void setFontWeight(final String fontWeight) {
|
||||
this.fontWeight = fontWeight;
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,28 @@
|
|||
package de.arminwolf.financeanalyzer.dao.charts.model;
|
||||
|
||||
import java.io.Serializable;
|
||||
|
||||
public class Title implements Serializable {
|
||||
|
||||
private String text;
|
||||
|
||||
|
||||
public Title() {
|
||||
this.text = "";
|
||||
}
|
||||
|
||||
|
||||
public Title(final String text) {
|
||||
this.text = text;
|
||||
}
|
||||
|
||||
|
||||
public String getText() {
|
||||
return this.text;
|
||||
}
|
||||
|
||||
|
||||
public void setText(String text) {
|
||||
this.text = text;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,39 @@
|
|||
package de.arminwolf.financeanalyzer.dao.charts.model;
|
||||
|
||||
public class ToolTip {
|
||||
|
||||
private String pointFormat;
|
||||
private boolean useHTML;
|
||||
|
||||
|
||||
public ToolTip(String pointFormat, boolean useHTML) {
|
||||
this.pointFormat = pointFormat;
|
||||
this.useHTML = useHTML;
|
||||
}
|
||||
|
||||
|
||||
public ToolTip() {
|
||||
this.pointFormat = "<b>{point.name}:</b> {point.value}";
|
||||
this.useHTML = true;
|
||||
}
|
||||
|
||||
|
||||
public String getPointFormat() {
|
||||
return pointFormat;
|
||||
}
|
||||
|
||||
|
||||
public void setPointFormat(final String pointFormat) {
|
||||
this.pointFormat = pointFormat;
|
||||
}
|
||||
|
||||
|
||||
public boolean isUseHTML() {
|
||||
return useHTML;
|
||||
}
|
||||
|
||||
|
||||
public void setUseHTML(final boolean useHTML) {
|
||||
this.useHTML = useHTML;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,20 @@
|
|||
package de.arminwolf.financeanalyzer.dao.charts.model;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.util.Collection;
|
||||
|
||||
public class XAxis implements Serializable {
|
||||
|
||||
private Collection<? extends String> categories;
|
||||
|
||||
|
||||
public Collection<? extends String> getCategories() {
|
||||
return this.categories;
|
||||
}
|
||||
|
||||
|
||||
public void setCategories(Collection<? extends String> categories) {
|
||||
this.categories = categories;
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,32 @@
|
|||
package de.arminwolf.financeanalyzer.dao.charts.model;
|
||||
|
||||
import java.io.Serializable;
|
||||
|
||||
public class YAxis implements Serializable {
|
||||
|
||||
private Title title;
|
||||
private int min;
|
||||
|
||||
|
||||
public Title getTitle() {
|
||||
return this.title;
|
||||
}
|
||||
|
||||
|
||||
public void setMin(final int i) {
|
||||
this.min=i;
|
||||
}
|
||||
|
||||
|
||||
public int getMin() {
|
||||
return min;
|
||||
}
|
||||
|
||||
|
||||
public void setTitle(Title title) {
|
||||
this.title = title;
|
||||
}
|
||||
|
||||
|
||||
|
||||
}
|
|
@ -0,0 +1,147 @@
|
|||
package de.arminwolf.financeanalyzer.dao.model;
|
||||
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonProperty;
|
||||
import de.arminwolf.financeanalyzer.dao.TransactionDAO;
|
||||
import de.arminwolf.financeanalyzer.util.DateUtil;
|
||||
import de.arminwolf.financeanalyzer.util.NumberUtil;
|
||||
|
||||
import java.time.LocalDate;
|
||||
import java.util.Date;
|
||||
import java.util.Map;
|
||||
import java.util.Objects;
|
||||
|
||||
public class OutputData implements Comparable<OutputData> {
|
||||
|
||||
@JsonProperty("id")
|
||||
public String id;
|
||||
@JsonProperty("amount")
|
||||
public String amount;
|
||||
@JsonProperty("amountAsFloat")
|
||||
public Float amountAsFloat;
|
||||
@JsonProperty("contractTurnaround")
|
||||
public String contractTurnaround;
|
||||
|
||||
@JsonProperty("contractTurnaround")
|
||||
public String date;
|
||||
@JsonProperty("recipient")
|
||||
public String recipient;
|
||||
@JsonProperty("purpose")
|
||||
public String purpose;
|
||||
|
||||
|
||||
|
||||
public OutputData(final Map.Entry<String, TransactionDAO> order) {
|
||||
this(order.getKey(), order.getValue());
|
||||
}
|
||||
|
||||
|
||||
public OutputData(final String id, final TransactionDAO transaction) {
|
||||
this.id = id;
|
||||
this.amount = transaction.getBetrag().concat(" ").concat(transaction.getWaehrung());
|
||||
this.contractTurnaround = transaction.getAnalyseVertragsturnus().isBlank() ? "monatlich" : transaction.getAnalyseVertragsturnus();
|
||||
this.amountAsFloat = Float.parseFloat(transaction.getBetrag());
|
||||
this.date = DateUtil.prettyPrint(DateUtil.parse(transaction.getBuchungstag()));
|
||||
this.purpose = transaction.getVerwendungszweck().trim().isEmpty() ?
|
||||
"Überweisung an " + transaction.getBeguenstigterAuftraggeber() :
|
||||
transaction.getVerwendungszweck();
|
||||
this.recipient = transaction.getBeguenstigterAuftraggeber();
|
||||
}
|
||||
|
||||
|
||||
public OutputData(final TransactionDAO t) {
|
||||
this(LocalDate.now().toString(), t);
|
||||
}
|
||||
|
||||
|
||||
public String getDate() {
|
||||
return date;
|
||||
}
|
||||
|
||||
|
||||
public void setDate(final String date) {
|
||||
this.date = date;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public int compareTo(final OutputData o) {
|
||||
return getAmountAsFloat().compareTo(o.getAmountAsFloat());
|
||||
}
|
||||
|
||||
|
||||
public Float getAmountAsFloat() {
|
||||
return NumberUtil.round(amountAsFloat);
|
||||
}
|
||||
|
||||
|
||||
public void setAmountAsFloat(final Float amountAsFloat) {
|
||||
this.amountAsFloat = amountAsFloat;
|
||||
}
|
||||
|
||||
|
||||
public String getId() {
|
||||
return id;
|
||||
}
|
||||
|
||||
|
||||
public void setId(final String id) {
|
||||
this.id = id;
|
||||
}
|
||||
|
||||
|
||||
public String getAmount() {
|
||||
return amount;
|
||||
}
|
||||
|
||||
|
||||
public void setAmount(final String amount) {
|
||||
this.amount = amount;
|
||||
}
|
||||
|
||||
|
||||
|
||||
public String getContractTurnaround() {
|
||||
return contractTurnaround;
|
||||
}
|
||||
|
||||
|
||||
public void setContractTurnaround(final String contractTurnaround) {
|
||||
this.contractTurnaround = contractTurnaround;
|
||||
}
|
||||
|
||||
|
||||
public String getPurpose() {
|
||||
return purpose;
|
||||
}
|
||||
|
||||
|
||||
public void setPurpose(final String purpose) {
|
||||
this.purpose = purpose;
|
||||
}
|
||||
|
||||
|
||||
public String getRecipient() {
|
||||
return recipient;
|
||||
}
|
||||
|
||||
|
||||
public void setRecipient(final String recipient) {
|
||||
this.recipient = recipient;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public boolean equals(final Object o) {
|
||||
if (this == o) return true;
|
||||
if (o == null || getClass() != o.getClass()) return false;
|
||||
final OutputData outputData = (OutputData) o;
|
||||
return Objects.equals(amount, outputData.amount) && Objects.equals(contractTurnaround, outputData.contractTurnaround) && Objects.equals(date, outputData.date) && Objects.equals(recipient, outputData.recipient) && Objects.equals(purpose, outputData.purpose);
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return Objects.hash(amount, contractTurnaround, date, recipient, purpose);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,24 @@
|
|||
package de.arminwolf.financeanalyzer.service;
|
||||
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
@Service
|
||||
public class CacheService {
|
||||
|
||||
private final Map<String, Object> cache = new HashMap<>();
|
||||
|
||||
|
||||
public void put(final String key, final Object value) {
|
||||
System.out.printf("Added to Cache. Key: [%s], Value: [%s]\n", key, value);
|
||||
cache.put(key, value);
|
||||
}
|
||||
|
||||
|
||||
public Object get(final String key) {
|
||||
return cache.get(key);
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,16 @@
|
|||
package de.arminwolf.financeanalyzer.service;
|
||||
|
||||
import de.arminwolf.financeanalyzer.util.XlsxToJsonConverter;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
import java.io.InputStream;
|
||||
import java.util.Optional;
|
||||
|
||||
@Service
|
||||
public class ConverterService {
|
||||
|
||||
public Optional<String> convert(InputStream in) {
|
||||
return XlsxToJsonConverter.writeJson(XlsxToJsonConverter.readXlsx(in));
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,134 @@
|
|||
package de.arminwolf.financeanalyzer.service;
|
||||
|
||||
import com.fasterxml.jackson.core.type.TypeReference;
|
||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||
import de.arminwolf.financeanalyzer.conf.Configuration;
|
||||
import de.arminwolf.financeanalyzer.dao.TransactionDAO;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.Path;
|
||||
import java.nio.file.Paths;
|
||||
import java.util.Arrays;
|
||||
import java.util.Objects;
|
||||
import java.util.Optional;
|
||||
import java.util.stream.Stream;
|
||||
|
||||
@Service
|
||||
public class FileService {
|
||||
|
||||
|
||||
public static final String CONFIGURATION_JSON = "configuration.json";
|
||||
@Autowired
|
||||
private CacheService cacheService;
|
||||
|
||||
|
||||
public Configuration getConfiguration() {
|
||||
File workingDirectory = getOrCreateWorkingDirectory();
|
||||
Path configurationFilePath = Paths.get(workingDirectory.toPath().toString(), CONFIGURATION_JSON);
|
||||
|
||||
System.out.printf("Loading '%s'\n", configurationFilePath);
|
||||
ObjectMapper objectMapper = new ObjectMapper();
|
||||
try {
|
||||
return objectMapper.readValue(configurationFilePath.toFile(), Configuration.class);
|
||||
} catch (IOException e) {
|
||||
System.out.printf("Error while accesing '%s'\n", configurationFilePath);
|
||||
}
|
||||
|
||||
return new Configuration();
|
||||
}
|
||||
|
||||
|
||||
public Optional<String> getJsonFileName() {
|
||||
File workingDirectory = getOrCreateWorkingDirectory();
|
||||
final Path jsonFilePath = Paths.get(workingDirectory.toPath().toString(), "finance-analyzer.json");
|
||||
if (!jsonFilePath.toFile().exists()) {
|
||||
return Optional.empty();
|
||||
} else {
|
||||
String absolutePath = jsonFilePath.toAbsolutePath().toString();
|
||||
System.out.println("Absolute Path of json file: " + absolutePath);
|
||||
return Optional.of(absolutePath);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public boolean isJsonPresent() {
|
||||
File orCreateWorkingDirectory = getOrCreateWorkingDirectory();
|
||||
return getJsonFiles(orCreateWorkingDirectory).findFirst().isPresent();
|
||||
}
|
||||
|
||||
|
||||
private Stream<String> getJsonFiles(final File orCreateWorkingDirectory) {
|
||||
return Arrays.stream(Objects.requireNonNull(orCreateWorkingDirectory.list((dir, name) -> name.endsWith(".json"))));
|
||||
}
|
||||
|
||||
|
||||
public TransactionDAO[] getJsonFile() {
|
||||
File workingDirectory = getOrCreateWorkingDirectory();
|
||||
final Path jsonFilePath = Paths.get(workingDirectory.toPath().toString(), "finance-analyzer.json");
|
||||
if (!jsonFilePath.toFile().exists()) {
|
||||
throw new IllegalStateException("Could not load json file.");
|
||||
} else {
|
||||
|
||||
System.out.printf("Loading '%s'\n", jsonFilePath);
|
||||
ObjectMapper objectMapper = new ObjectMapper();
|
||||
try {
|
||||
return objectMapper.readValue(jsonFilePath.toFile(), new TypeReference<TransactionDAO[]>() {
|
||||
});
|
||||
} catch (IOException e) {
|
||||
System.out.printf("Error while accesing '%s'\n", jsonFilePath);
|
||||
}
|
||||
}
|
||||
|
||||
return new TransactionDAO[0];
|
||||
}
|
||||
|
||||
|
||||
public File getOrCreateWorkingDirectory() {
|
||||
if (Objects.isNull(cacheService.get("workingDirectory"))) {
|
||||
final String userHomeAsString = System.getProperty("user.home");
|
||||
System.out.printf("Looking for working Directory '.finance-analyser' in user home (%s).\n", userHomeAsString);
|
||||
Path path = Paths.get(userHomeAsString.concat(File.separator).concat(".finance-analyser"));
|
||||
boolean exists = Files.exists(path);
|
||||
if (exists) {
|
||||
return path.toFile();
|
||||
} else {
|
||||
Path directory = null;
|
||||
try {
|
||||
directory = Files.createDirectory(path);
|
||||
cacheService.put("workingDirectory", directory.toFile());
|
||||
return directory.toFile();
|
||||
} catch (IOException e) {
|
||||
System.err.println("Could not create directory in user home.. Permission issue?" + e.getMessage());
|
||||
}
|
||||
throw new IllegalStateException("Could not create working directory. Please fix the permissions.");
|
||||
}
|
||||
} else {
|
||||
return (File) cacheService.get("workingDirectory");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public void saveConfiguration(final Configuration configuration) {
|
||||
File workingDirectory = getOrCreateWorkingDirectory();
|
||||
Path path = Paths.get(workingDirectory.getPath(), CONFIGURATION_JSON);
|
||||
if (path.toFile().exists()) {
|
||||
System.out.println("Configuration file already exists. Overwriting it.");
|
||||
try {
|
||||
Files.delete(path);
|
||||
} catch (IOException e) {
|
||||
System.out.println("Could not delete existing configuration file." + e.getMessage());
|
||||
}
|
||||
}
|
||||
ObjectMapper objectMapper = new ObjectMapper();
|
||||
try {
|
||||
objectMapper.writeValue(path.toFile(), configuration);
|
||||
} catch (IOException e) {
|
||||
System.err.println("Could not save configuration file." + e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,181 @@
|
|||
package de.arminwolf.financeanalyzer.service;
|
||||
|
||||
import de.arminwolf.financeanalyzer.conf.Configuration;
|
||||
import de.arminwolf.financeanalyzer.dao.ReportDAO;
|
||||
import de.arminwolf.financeanalyzer.dao.TableDataDAO;
|
||||
import de.arminwolf.financeanalyzer.dao.TransactionDAO;
|
||||
import de.arminwolf.financeanalyzer.service.usecases.CashFlowService;
|
||||
import de.arminwolf.financeanalyzer.service.usecases.IncomeService;
|
||||
import de.arminwolf.financeanalyzer.service.usecases.OtherTransactionService;
|
||||
import de.arminwolf.financeanalyzer.service.usecases.StandingOrderService;
|
||||
import de.arminwolf.financeanalyzer.util.DateUtil;
|
||||
import de.arminwolf.financeanalyzer.util.TransactionDateStringComparator;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.stereotype.Service;
|
||||
import org.springframework.ui.Model;
|
||||
|
||||
import java.time.LocalDate;
|
||||
import java.time.YearMonth;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import static de.arminwolf.financeanalyzer.util.Constants.AUSGABEN;
|
||||
import static de.arminwolf.financeanalyzer.util.Constants.BEGUENSTIGTER;
|
||||
import static de.arminwolf.financeanalyzer.util.Constants.BETRAG;
|
||||
import static de.arminwolf.financeanalyzer.util.Constants.DATUM;
|
||||
import static de.arminwolf.financeanalyzer.util.Constants.EINNAHMEN;
|
||||
import static de.arminwolf.financeanalyzer.util.Constants.TURNUS;
|
||||
import static de.arminwolf.financeanalyzer.util.Constants.VERWENDUNGSZWECK;
|
||||
|
||||
@Service
|
||||
public class ReportService {
|
||||
|
||||
|
||||
public static final String EUR = " EUR";
|
||||
@Autowired
|
||||
private IncomeService incomeService;
|
||||
@Autowired
|
||||
private CashFlowService cashFlowService;
|
||||
|
||||
@Autowired
|
||||
private StandingOrderService standingOrderService;
|
||||
|
||||
@Autowired
|
||||
private OtherTransactionService otherTransactionService;
|
||||
|
||||
@Autowired
|
||||
private CacheService cacheService;
|
||||
|
||||
private ReportDAO report;
|
||||
|
||||
|
||||
public ReportDAO createReport(final TransactionDAO[] response, String month, String iban, final Model model) {
|
||||
this.report = new ReportDAO();
|
||||
System.out.println("LocalDate : " + DateUtil.parseMonth(month));
|
||||
int numberOfMonths = DateUtil.monthsBetween(DateUtil.parseMonth(month), LocalDate.now());
|
||||
final List<TransactionDAO> filteredIncomeTransactions = getFilteredIncomeTransactions(response, numberOfMonths, iban);
|
||||
final List<TransactionDAO> filteredExpenseTransactions = getFilteredExpenseTransactions(response, numberOfMonths, iban);
|
||||
|
||||
// Verarbeiten Sie hier die Antwort
|
||||
((Configuration) cacheService.get("configuration")).getBankAccounts().stream()
|
||||
.filter(bankAccount -> bankAccount.getIban().equals(iban)).findFirst()
|
||||
.ifPresent(bankAccount -> {
|
||||
model.addAttribute("accountName", bankAccount.getBankAccountName());
|
||||
model.addAttribute("iban", iban);
|
||||
});
|
||||
|
||||
// Daueraufträge
|
||||
standingOrderService.setStandingOrder(report, filteredExpenseTransactions);
|
||||
|
||||
// Sonstige Transaktionen
|
||||
otherTransactionService.setOtherTransaction(report, filteredExpenseTransactions);
|
||||
|
||||
// Cashflow
|
||||
cashFlowService.setCashFlowChart(report, filteredIncomeTransactions, filteredExpenseTransactions);
|
||||
|
||||
// Einkommen
|
||||
incomeService.setIncome(report, filteredIncomeTransactions);
|
||||
|
||||
|
||||
LocalDate localDate = LocalDate.now().minusMonths(numberOfMonths);
|
||||
final LocalDate start = DateUtil.getFirstDayOfMonth(localDate);
|
||||
final LocalDate end = DateUtil.getLastDayOfMonth(localDate);
|
||||
|
||||
model.addAttribute("date", String.format("%s - %s", DateUtil.format(start), DateUtil.format(end)));
|
||||
model.addAttribute("numberOfMonths", numberOfMonths);
|
||||
|
||||
|
||||
model.addAttribute("cashFlow", getCashFlowData());
|
||||
model.addAttribute("income", getIncomeData());
|
||||
model.addAttribute("standingOrders", getStandingOrdersData());
|
||||
model.addAttribute("notStandingOrders", getNotStandingOrdersData());
|
||||
|
||||
model.addAttribute("incomeExpenseColumnReport", report.getCashFlowChart());
|
||||
model.addAttribute("accountBalanceLineChart", report.getAccountBalanceLineChart());
|
||||
model.addAttribute("transactionCategories", report.getTransactionCategoriesBubbleChart());
|
||||
|
||||
return report;
|
||||
}
|
||||
|
||||
|
||||
private TableDataDAO getCashFlowData() {
|
||||
TableDataDAO cashFlowData = TableDataDAO.TableDataFactory.createTableDataDTO();
|
||||
cashFlowData.setHeaders(Arrays.asList("Einnahmen", "Verträge", "Ausgaben (ohne Veträge)", "Ausgaben insgesammt", "Differenz"));
|
||||
cashFlowData.setRows(List.of(
|
||||
Arrays.asList(
|
||||
String.valueOf(report.getIncome()).concat(EUR),
|
||||
String.valueOf(report.getStandingOrdersAmount()).concat(EUR),
|
||||
String.valueOf(report.getNotStandingOrdersAmount()).concat(EUR),
|
||||
String.valueOf(report.getTotalExpense()).concat(EUR),
|
||||
String.valueOf(report.getDiff()).concat(EUR)))
|
||||
);
|
||||
return cashFlowData;
|
||||
}
|
||||
|
||||
|
||||
private List<TransactionDAO> getFilteredIncomeTransactions(final TransactionDAO[] response, final int numberOfMonths, final String iban) {
|
||||
return getFilteredTransactions(response, EINNAHMEN, numberOfMonths, iban);
|
||||
}
|
||||
|
||||
|
||||
private List<TransactionDAO> getFilteredExpenseTransactions(final TransactionDAO[] response, final int numberOfMonths, final String iban) {
|
||||
return getFilteredTransactions(response, AUSGABEN, numberOfMonths, iban);
|
||||
}
|
||||
|
||||
|
||||
private List<TransactionDAO> getFilteredTransactions(final TransactionDAO[] response, final String type, int numberOfMonths, String iban) {
|
||||
final LocalDate localDate = LocalDate.now().minusMonths(numberOfMonths);
|
||||
final LocalDate start = LocalDate.of(localDate.getYear(), localDate.getMonth(), 1);
|
||||
final LocalDate end = YearMonth.of(localDate.getYear(), localDate.getMonth()).atEndOfMonth();
|
||||
|
||||
return Arrays.stream(response)
|
||||
.filter(t -> DateUtil.isBetween(t.getBuchungstag(), start, end))
|
||||
.filter(t -> t.getReferenzkonto().equals(iban))
|
||||
.filter(e -> e.getAnalyseBetrag().equals(type))
|
||||
.sorted(new TransactionDateStringComparator())
|
||||
.collect(Collectors.toList());
|
||||
}
|
||||
|
||||
|
||||
|
||||
private TableDataDAO getIncomeData() {
|
||||
TableDataDAO incomeData = TableDataDAO.TableDataFactory.createTableDataDTO();
|
||||
incomeData.setHeaders(Arrays.asList(BETRAG, DATUM, BEGUENSTIGTER, VERWENDUNGSZWECK));
|
||||
incomeData.setRows(report.getIncomeList().stream()
|
||||
.map(income -> Arrays.asList(
|
||||
income.getAmount(),
|
||||
income.getDate(),
|
||||
income.getRecipient(),
|
||||
income.getPurpose())).toList());
|
||||
return incomeData;
|
||||
}
|
||||
|
||||
|
||||
private TableDataDAO getNotStandingOrdersData() {
|
||||
TableDataDAO notStandingOrders = TableDataDAO.TableDataFactory.createTableDataDTO();
|
||||
notStandingOrders.setHeaders(Arrays.asList(BETRAG, DATUM, TURNUS, BEGUENSTIGTER, VERWENDUNGSZWECK));
|
||||
notStandingOrders.setRows(report.getSortedNotStandingOrders().stream()
|
||||
.map(income -> Arrays.asList(
|
||||
income.getAmount(),
|
||||
income.getDate(),
|
||||
income.getContractTurnaround(),
|
||||
income.getRecipient(),
|
||||
income.getPurpose())).toList());
|
||||
return notStandingOrders;
|
||||
}
|
||||
|
||||
|
||||
private TableDataDAO getStandingOrdersData() {
|
||||
TableDataDAO standingOrders = TableDataDAO.TableDataFactory.createTableDataDTO();
|
||||
standingOrders.setHeaders(Arrays.asList(BETRAG, DATUM, TURNUS, BEGUENSTIGTER, VERWENDUNGSZWECK));
|
||||
standingOrders.setRows(report.getSortedStandingOrders().stream()
|
||||
.map(income -> Arrays.asList(
|
||||
income.getAmount(),
|
||||
income.getDate(),
|
||||
income.getContractTurnaround(),
|
||||
income.getRecipient(),
|
||||
income.getPurpose())).toList());
|
||||
return standingOrders;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,67 @@
|
|||
package de.arminwolf.financeanalyzer.service.usecases;
|
||||
|
||||
import de.arminwolf.financeanalyzer.dao.ReportDAO;
|
||||
import de.arminwolf.financeanalyzer.dao.TransactionDAO;
|
||||
import org.apache.commons.math3.util.Pair;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.TreeMap;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import static de.arminwolf.financeanalyzer.util.Constants.AUSGABEN;
|
||||
import static de.arminwolf.financeanalyzer.util.Constants.EINNAHMEN;
|
||||
|
||||
@Service
|
||||
public class CashFlowService {
|
||||
|
||||
public void setCashFlowChart(final ReportDAO reportDAO,
|
||||
final List<TransactionDAO> filteredIncomeTransactions,
|
||||
final List<TransactionDAO> filteredExpenseTransactions) {
|
||||
Map<String, List<Float>> expenses = new TreeMap<>();
|
||||
Map<String, List<Float>> income = new TreeMap<>();
|
||||
|
||||
filteredIncomeTransactions.stream()
|
||||
.map(TransactionDAO::getAnalyseMonat)
|
||||
.forEach(month -> {
|
||||
income.put(month, new ArrayList<>());
|
||||
filteredIncomeTransactions.stream()
|
||||
.filter(t -> t.getAnalyseMonat().equals(month))
|
||||
.filter(t -> t.getAnalyseBetrag().equals(EINNAHMEN))
|
||||
.forEach(t -> income.get(month).add(t.getBetragAsFloat()));
|
||||
|
||||
});
|
||||
|
||||
filteredExpenseTransactions.stream()
|
||||
.map(TransactionDAO::getAnalyseMonat)
|
||||
.forEach(month -> {
|
||||
expenses.put(month, new ArrayList<>());
|
||||
filteredExpenseTransactions.stream()
|
||||
.filter(t -> t.getAnalyseMonat().equals(month))
|
||||
.filter(t -> t.getAnalyseBetrag().equals(AUSGABEN))
|
||||
.forEach(t -> expenses.get(month).add(t.getBetragAsFloat()));
|
||||
});
|
||||
|
||||
|
||||
|
||||
System.out.println("Number of Dataseries. Expenses: " + expenses.size() + ", Income: " + income.size());
|
||||
income.values().forEach(System.out::println);
|
||||
|
||||
System.out.println("-------------------");
|
||||
reportDAO.setCashFlowChart(expenses, income);
|
||||
|
||||
final List<TransactionDAO> allTransaction = new ArrayList<>();
|
||||
allTransaction.addAll(filteredIncomeTransactions);
|
||||
allTransaction.addAll(filteredExpenseTransactions);
|
||||
|
||||
// Line Chart
|
||||
reportDAO.setAccountBalanceLineChart(allTransaction.stream()
|
||||
.map(t -> Pair.create(t.getBuchungstag(), t.getKontostand()))
|
||||
.collect(Collectors.toList()));
|
||||
|
||||
// Bubble Chart
|
||||
reportDAO.setTransactionCategoriesBubbleChart(filteredExpenseTransactions);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,21 @@
|
|||
package de.arminwolf.financeanalyzer.service.usecases;
|
||||
|
||||
import de.arminwolf.financeanalyzer.dao.ReportDAO;
|
||||
import de.arminwolf.financeanalyzer.dao.TransactionDAO;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import static de.arminwolf.financeanalyzer.util.Constants.EINNAHMEN;
|
||||
|
||||
@Service
|
||||
public class IncomeService {
|
||||
|
||||
public void setIncome(final ReportDAO reportDAO, final List<TransactionDAO> filteredTransactions) {
|
||||
reportDAO.setIncomeList(filteredTransactions.stream()
|
||||
.filter(e -> e.getAnalyseBetrag().equals(EINNAHMEN))
|
||||
.collect(Collectors.toList()));
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,23 @@
|
|||
package de.arminwolf.financeanalyzer.service.usecases;
|
||||
|
||||
import de.arminwolf.financeanalyzer.dao.ReportDAO;
|
||||
import de.arminwolf.financeanalyzer.dao.TransactionDAO;
|
||||
import de.arminwolf.financeanalyzer.dao.model.OutputData;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
@Service
|
||||
public class OtherTransactionService {
|
||||
|
||||
public void setOtherTransaction(final ReportDAO reportDAO,
|
||||
final List<TransactionDAO> filteredTransactions) {
|
||||
|
||||
reportDAO.setNotStandingOrders(filteredTransactions.stream()
|
||||
.filter(t -> !reportDAO.getStandingOrders().contains(new OutputData(t)))
|
||||
.distinct()
|
||||
.collect(Collectors.toList()));
|
||||
|
||||
}
|
||||
}
|
|
@ -0,0 +1,29 @@
|
|||
package de.arminwolf.financeanalyzer.service.usecases;
|
||||
|
||||
import de.arminwolf.financeanalyzer.dao.ReportDAO;
|
||||
import de.arminwolf.financeanalyzer.dao.TransactionDAO;
|
||||
import de.arminwolf.financeanalyzer.util.StreamUtil;
|
||||
import de.arminwolf.financeanalyzer.util.TransactionDateStringReverseComparator;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
@Service
|
||||
public class StandingOrderService {
|
||||
|
||||
public static final String JA = "ja";
|
||||
|
||||
|
||||
public void setStandingOrder(final ReportDAO reportDAO, final List<TransactionDAO> filteredTransactions) {
|
||||
|
||||
List<TransactionDAO> transactions = filteredTransactions.stream()
|
||||
.filter(e -> e.getAnalyseVertrag().equals(JA)
|
||||
|| e.getAnalyseUmsatzart().equals("Dauerauftrag")
|
||||
|| e.getAnalyseUmsatzart().equals("Lastschrift"))
|
||||
.sorted(new TransactionDateStringReverseComparator())
|
||||
.toList();
|
||||
|
||||
List<TransactionDAO> standingOrderTransactions = StreamUtil.findDuplicateInStream(transactions);
|
||||
reportDAO.setStandingOrders(standingOrderTransactions);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,18 @@
|
|||
package de.arminwolf.financeanalyzer.util;
|
||||
|
||||
public class Constants {
|
||||
|
||||
public static final String INDEX = "upload";
|
||||
public static final String ERROR = "templates/error";
|
||||
public static final String REPORTS = "reports";
|
||||
|
||||
public static final String EINNAHMEN = "Einnahmen";
|
||||
public static final String AUSGABEN = "Ausgaben";
|
||||
public static final String GEHALT = "Gehalt";
|
||||
|
||||
public static final String TURNUS = "Turnus";
|
||||
public static final String VERWENDUNGSZWECK = "Verwendungszweck";
|
||||
public static final String BEGUENSTIGTER = "Begünstigter";
|
||||
public static final String DATUM = "Datum";
|
||||
public static final String BETRAG = "Betrag";
|
||||
}
|
|
@ -0,0 +1,9 @@
|
|||
package de.arminwolf.financeanalyzer.util;
|
||||
|
||||
import de.arminwolf.financeanalyzer.dao.model.OutputData;
|
||||
|
||||
import java.util.Comparator;
|
||||
|
||||
public interface DateFormatStringComparatorForOrder extends Comparator<OutputData> {
|
||||
|
||||
}
|
|
@ -0,0 +1,113 @@
|
|||
package de.arminwolf.financeanalyzer.util;
|
||||
|
||||
import java.text.DateFormat;
|
||||
import java.text.ParseException;
|
||||
import java.text.SimpleDateFormat;
|
||||
import java.time.Instant;
|
||||
import java.time.LocalDate;
|
||||
import java.time.YearMonth;
|
||||
import java.time.ZoneId;
|
||||
import java.time.format.DateTimeFormatter;
|
||||
import java.util.Calendar;
|
||||
import java.util.Date;
|
||||
import java.util.Locale;
|
||||
|
||||
public class DateUtil {
|
||||
|
||||
private final static DateFormat df = new SimpleDateFormat("dd-MMM-yyyy", Locale.GERMAN);
|
||||
private final static DateTimeFormatter formatter = DateTimeFormatter.ofPattern("dd.MM.yyyy");
|
||||
private final static DateTimeFormatter originalFormatter = DateTimeFormatter.ofPattern("dd-MMM-yyyy");
|
||||
private final static Calendar startCalendar = Calendar.getInstance();
|
||||
|
||||
|
||||
public static String format(final LocalDate start) {
|
||||
return start.format(formatter);
|
||||
}
|
||||
|
||||
|
||||
public static LocalDate getFirstDayOfMonth(final LocalDate localDate) {
|
||||
return LocalDate.of(localDate.getYear(), localDate.getMonth(), 1);
|
||||
}
|
||||
|
||||
|
||||
public static LocalDate getLastDayOfMonth(final LocalDate localDate) {
|
||||
return YearMonth.of(localDate.getYear(), localDate.getMonth()).atEndOfMonth();
|
||||
}
|
||||
|
||||
|
||||
public static boolean isBefore(String date, LocalDate end) {
|
||||
try {
|
||||
Date parse = df.parse(date);
|
||||
Instant instant = parse.toInstant();
|
||||
LocalDate localDate = instant.atZone(ZoneId.systemDefault()).toLocalDate();
|
||||
|
||||
return localDate.isBefore(end);
|
||||
} catch (ParseException e) {
|
||||
System.out.println("ERROR: " + date);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public static boolean isAfter(String date, LocalDate start) {
|
||||
try {
|
||||
Date parse = df.parse(date);
|
||||
Instant instant = parse.toInstant();
|
||||
LocalDate localDate = instant.atZone(ZoneId.systemDefault()).toLocalDate();
|
||||
|
||||
return localDate.isAfter(start);
|
||||
} catch (ParseException e) {
|
||||
System.out.println("ERROR: " + date);
|
||||
e.printStackTrace(System.err);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public static boolean isBetween(String date, LocalDate start, LocalDate end) {
|
||||
try {
|
||||
Date parse = df.parse(date);
|
||||
Instant instant = parse.toInstant();
|
||||
LocalDate localDate = instant.atZone(ZoneId.systemDefault()).toLocalDate();
|
||||
|
||||
return (localDate.isEqual(end) || localDate.isBefore(end)) && (localDate.isEqual(start) || localDate.isAfter(start));
|
||||
} catch (ParseException e) {
|
||||
System.out.println("ERROR: " + date);
|
||||
e.printStackTrace(System.err);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public static LocalDate parse(final String buchungstag) {
|
||||
return LocalDate.parse(buchungstag, originalFormatter);
|
||||
}
|
||||
|
||||
|
||||
public static LocalDate parseMonth(final String month) {
|
||||
String[] split = month.split("-");
|
||||
return LocalDate.of(Integer.parseInt(split[0]), Integer.parseInt(split[1]), 1);
|
||||
}
|
||||
|
||||
|
||||
public static String prettyPrint(final LocalDate date) {
|
||||
return date.format(formatter);
|
||||
}
|
||||
|
||||
public static int monthsBetween(LocalDate startDate, LocalDate endDate) {
|
||||
if (startDate == null || endDate == null) {
|
||||
throw new IllegalArgumentException("Both startDate and endDate must be provided");
|
||||
}
|
||||
|
||||
startCalendar.setTime(Date.from(startDate.atStartOfDay(ZoneId.systemDefault()).toInstant()));
|
||||
int startDateTotalMonths = 12 * startCalendar.get(Calendar.YEAR) + startCalendar.get(Calendar.MONTH);
|
||||
|
||||
Calendar endCalendar = Calendar.getInstance();
|
||||
endCalendar.setTime(Date.from(endDate.atStartOfDay(ZoneId.systemDefault()).toInstant()));
|
||||
|
||||
int endDateTotalMonths = 12 * endCalendar.get(Calendar.YEAR)
|
||||
+ endCalendar.get(Calendar.MONTH);
|
||||
|
||||
return endDateTotalMonths - startDateTotalMonths;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,16 @@
|
|||
package de.arminwolf.financeanalyzer.util;
|
||||
|
||||
import java.util.Objects;
|
||||
|
||||
public class NumberUtil {
|
||||
|
||||
public static Float round(final Float value) {
|
||||
return round(value, 2);
|
||||
}
|
||||
|
||||
|
||||
public static Float round(final Float value, final int precision) {
|
||||
return Math.round((Objects.isNull(value) ? 0f : value) * Math.pow(10, precision)) / (float) Math.pow(10, precision);
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,20 @@
|
|||
package de.arminwolf.financeanalyzer.util;
|
||||
|
||||
import de.arminwolf.financeanalyzer.dao.model.OutputData;
|
||||
|
||||
import java.text.ParseException;
|
||||
import java.text.SimpleDateFormat;
|
||||
import java.util.Comparator;
|
||||
|
||||
public class OrderDateStringComparator implements Comparator<OutputData> {
|
||||
|
||||
@Override
|
||||
public int compare(final OutputData o1, final OutputData o2) {
|
||||
SimpleDateFormat formatter = new SimpleDateFormat("dd-MMM-yyyy");
|
||||
try {
|
||||
return -1 * formatter.parse(o1.getDate()).compareTo(formatter.parse(o2.getDate()));
|
||||
} catch (ParseException e) {
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,17 @@
|
|||
package de.arminwolf.financeanalyzer.util;
|
||||
|
||||
import java.util.Random;
|
||||
|
||||
public class RandomColorUtil {
|
||||
|
||||
private static final Random random = new Random();
|
||||
|
||||
|
||||
public static String getRandomColor() {
|
||||
// create a big random number - maximum is ffffff (hex) = 16777215 (dez)
|
||||
int nextInt = random.nextInt(0xffffff + 1);
|
||||
|
||||
// format it as hexadecimal string (with hashtag and leading zeros)
|
||||
return String.format("#%06x", nextInt);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,29 @@
|
|||
package de.arminwolf.financeanalyzer.util;
|
||||
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
public class StreamUtil<T> {
|
||||
|
||||
public static <T> List<T> findDuplicateInStream(List<T> list) {
|
||||
|
||||
// Set to store the duplicate elements
|
||||
Set<T> items = new HashSet<>();
|
||||
|
||||
// Return the set of duplicate elements
|
||||
return list.stream()
|
||||
|
||||
// Set.add() returns false
|
||||
// if the element was
|
||||
// already present in the set.
|
||||
// Hence filter such elements
|
||||
.filter(items::add)
|
||||
|
||||
// Collect duplicate elements
|
||||
// in the set
|
||||
.collect(Collectors.toList());
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,22 @@
|
|||
package de.arminwolf.financeanalyzer.util;
|
||||
|
||||
import de.arminwolf.financeanalyzer.dao.TransactionDAO;
|
||||
|
||||
import java.text.ParseException;
|
||||
import java.text.SimpleDateFormat;
|
||||
import java.util.Comparator;
|
||||
|
||||
public class TransactionDateStringComparator implements Comparator<TransactionDAO> {
|
||||
|
||||
@Override
|
||||
public int compare(final TransactionDAO o1, final TransactionDAO o2) {
|
||||
SimpleDateFormat formatter = new SimpleDateFormat("dd-MMM-yyyy");
|
||||
try {
|
||||
return formatter.parse(o1.getBuchungstag()).compareTo(formatter.parse(o2.getBuchungstag()));
|
||||
} catch (ParseException e) {
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
|
@ -0,0 +1,22 @@
|
|||
package de.arminwolf.financeanalyzer.util;
|
||||
|
||||
import de.arminwolf.financeanalyzer.dao.TransactionDAO;
|
||||
|
||||
import java.text.ParseException;
|
||||
import java.text.SimpleDateFormat;
|
||||
import java.util.Comparator;
|
||||
|
||||
public class TransactionDateStringReverseComparator implements Comparator<TransactionDAO> {
|
||||
|
||||
@Override
|
||||
public int compare(final TransactionDAO o1, final TransactionDAO o2) {
|
||||
SimpleDateFormat formatter = new SimpleDateFormat("dd-MMM-yyyy");
|
||||
try {
|
||||
return -1 * formatter.parse(o1.getBuchungstag()).compareTo(formatter.parse(o2.getBuchungstag()));
|
||||
} catch (ParseException e) {
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
|
@ -0,0 +1,12 @@
|
|||
package de.arminwolf.financeanalyzer.util;
|
||||
|
||||
import jakarta.servlet.http.HttpServletRequest;
|
||||
|
||||
public class UrlUtil {
|
||||
|
||||
public static String getRelativeUrl(final HttpServletRequest request, final String path) {
|
||||
String requestURL = request.getRequestURL().toString();
|
||||
String servletPath = request.getServletPath();
|
||||
return requestURL.substring(0, requestURL.lastIndexOf(servletPath)).concat(path);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,68 @@
|
|||
package de.arminwolf.financeanalyzer.util;
|
||||
|
||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||
import org.apache.poi.openxml4j.util.ZipSecureFile;
|
||||
import org.apache.poi.ss.usermodel.Cell;
|
||||
import org.apache.poi.ss.usermodel.Row;
|
||||
import org.apache.poi.ss.usermodel.Sheet;
|
||||
import org.apache.poi.xssf.usermodel.XSSFWorkbook;
|
||||
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Locale;
|
||||
import java.util.Map;
|
||||
import java.util.Objects;
|
||||
import java.util.Optional;
|
||||
|
||||
public class XlsxToJsonConverter {
|
||||
|
||||
|
||||
public static final String JSON_EXTENSION = ".json";
|
||||
|
||||
|
||||
public static List<Map<String, String>> readXlsx(InputStream inputFile) {
|
||||
List<Map<String, String>> data = new ArrayList<>();
|
||||
ZipSecureFile.setMinInflateRatio(0.001);
|
||||
try (XSSFWorkbook workbook = new XSSFWorkbook(inputFile)) {
|
||||
Sheet sheet = workbook.getSheetAt(0);
|
||||
Row headerRow = sheet.getRow(0);
|
||||
int lastColumnNum = headerRow.getLastCellNum();
|
||||
for (int i = 1; i <= sheet.getLastRowNum(); i++) {
|
||||
Row row = sheet.getRow(i);
|
||||
Map<String, String> rowData = new HashMap<>();
|
||||
for (int j = 0; j < lastColumnNum; j++) {
|
||||
Cell cell = row.getCell(j);
|
||||
String cellValue = "";
|
||||
if (Objects.nonNull(cell)) {
|
||||
cellValue = cell.toString();
|
||||
}
|
||||
rowData.put(convert2jsonKey(headerRow.getCell(j).toString()), cellValue);
|
||||
}
|
||||
data.add(rowData);
|
||||
}
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
return data;
|
||||
}
|
||||
|
||||
|
||||
private static String convert2jsonKey(final String string) {
|
||||
return string.toLowerCase(Locale.GERMANY).replaceAll(" ", "-");
|
||||
}
|
||||
|
||||
|
||||
public static Optional<String> writeJson(List<Map<String, String>> data) {
|
||||
try (ByteArrayOutputStream fos = new ByteArrayOutputStream()) {
|
||||
ObjectMapper mapper = new ObjectMapper();
|
||||
mapper.writerWithDefaultPrettyPrinter().writeValue(fos, data);
|
||||
return Optional.of(fos.toString());
|
||||
} catch (Exception e) {
|
||||
return Optional.empty();
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1 @@
|
|||
|
|
@ -0,0 +1,137 @@
|
|||
:root {
|
||||
line-height: 1.6;
|
||||
font-size: 0.9rem;
|
||||
}
|
||||
|
||||
body {
|
||||
font-family: Courier, monospace;
|
||||
width: auto;
|
||||
color: #666; /* Helle Textfarbe */
|
||||
background-color: #fff;
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
transition: background-color 0.3s ease; /* Beispiel für Übergänge */
|
||||
}
|
||||
|
||||
.card-header {
|
||||
border-radius: calc(0.25rem - 1px) calc(0.25rem - 1px) 0 0;
|
||||
background-color: #343a40;
|
||||
}
|
||||
|
||||
.card-header p {
|
||||
color: #333;
|
||||
}
|
||||
|
||||
/* Überschriften */
|
||||
h1, h2, h3, h4, h5, h6 {
|
||||
font-weight: bold;
|
||||
color: #fff; /* Helle Textfarbe für Links und Schaltflächen */
|
||||
font-family: Courier, monospace;
|
||||
}
|
||||
|
||||
a, .btn {
|
||||
color: #fff; /* Helle Textfarbe für Links und Schaltflächen */
|
||||
}
|
||||
|
||||
a:hover, .btn:hover {
|
||||
background-color: #444; /* Dunklere Hintergrundfarbe beim Hovern über Links und Schaltflächen */
|
||||
}
|
||||
|
||||
|
||||
/* Texte */
|
||||
p, span, label {
|
||||
line-height: 1.25;
|
||||
font-family: Courier, monospace;
|
||||
}
|
||||
|
||||
/* Links */
|
||||
a {
|
||||
color: #007bff;
|
||||
}
|
||||
|
||||
.red {
|
||||
color: red;
|
||||
}
|
||||
|
||||
.green {
|
||||
color: green;
|
||||
}
|
||||
|
||||
/* Fehlermeldungen */
|
||||
.error {
|
||||
color: #dc3545;
|
||||
font-size: 14px;
|
||||
}
|
||||
|
||||
.content-section {
|
||||
width: 85%;
|
||||
margin: 0 auto;
|
||||
padding: 5em;
|
||||
}
|
||||
|
||||
hr {
|
||||
margin-top: 1rem;
|
||||
margin-bottom: 1rem;
|
||||
border: 0;
|
||||
border-top: 1px solid rgba(0, 0, 0, 0.1);
|
||||
}
|
||||
|
||||
/* Container */
|
||||
.container {
|
||||
margin: 2em auto;
|
||||
padding: 2em;
|
||||
background-color: #fff;
|
||||
box-shadow: 0px 2px 5px rgba(0, 0, 0, 0.3);
|
||||
font-family: Courier, monospace;
|
||||
}
|
||||
|
||||
.flex-container {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
}
|
||||
|
||||
ul {
|
||||
list-style: none;
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
font-family: Courier, monospace;
|
||||
}
|
||||
.scrollable-table {
|
||||
overflow: auto; /* Scrollen aktivieren, wenn der Inhalt überläuft */
|
||||
}
|
||||
|
||||
table {
|
||||
width: 100%;
|
||||
border-collapse: collapse;
|
||||
border-spacing: 0;
|
||||
}
|
||||
th, td {
|
||||
padding: 5px;
|
||||
text-align: right;
|
||||
}
|
||||
th {
|
||||
background-color: #f2f2f2;
|
||||
color: #333;
|
||||
font-weight: bold;
|
||||
text-align: right;
|
||||
}
|
||||
|
||||
tr:nth-child(even) {
|
||||
background-color: #f9f9f9;
|
||||
}
|
||||
|
||||
tr:hover {
|
||||
background-color: #f5f5f5;
|
||||
}
|
||||
/* Definiert die Trennlinie für die Zeile */
|
||||
tr.border-row td {
|
||||
border-top: 1px solid darkgrey;
|
||||
}
|
||||
|
||||
[data-analysis-value^="-"] {
|
||||
color: red;
|
||||
}
|
||||
|
||||
[data-analysis-value$="EUR"]:not([data-analysis-value^="-"]) {
|
||||
color: green;
|
||||
}
|
|
@ -0,0 +1,22 @@
|
|||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<title>Error 404 - Page not found</title>
|
||||
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<link rel="stylesheet" type="text/css" href="../../static/css/styles.css" th:href="@{/css/style.css}"/>
|
||||
<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/4.0.0/css/bootstrap.min.css">
|
||||
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/5.15.1/css/all.min.css"/>
|
||||
</head>
|
||||
<body>
|
||||
<main class="container">
|
||||
<div class="row">
|
||||
<div class="col-md-12 text-center">
|
||||
<h1>Error - Page not found</h1>
|
||||
<hr>
|
||||
</div>
|
||||
</div>
|
||||
</main>
|
||||
</body>
|
||||
</html>
|
|
@ -0,0 +1,22 @@
|
|||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<title>Error 404 - Page not found</title>
|
||||
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<link rel="stylesheet" type="text/css" href="../../static/css/styles.css" th:href="@{/css/style.css}"/>
|
||||
<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/4.0.0/css/bootstrap.min.css">
|
||||
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/5.15.1/css/all.min.css"/>
|
||||
</head>
|
||||
<body>
|
||||
<main class="container">
|
||||
<div class="row">
|
||||
<div class="col-md-12 text-center">
|
||||
<h1>Internal Server Error</h1>
|
||||
<hr>
|
||||
</div>
|
||||
</div>
|
||||
</main>
|
||||
</body>
|
||||
</html>
|
|
@ -0,0 +1,7 @@
|
|||
<div layout:fragment="scripts(id, data)">
|
||||
<script th:inline="javascript">
|
||||
/*<![CDATA[*/
|
||||
Highcharts.chart( /*[[${id}]]*/, /*[[${data}]]*/);
|
||||
/*]]>*/
|
||||
</script>
|
||||
</div>
|
|
@ -0,0 +1,19 @@
|
|||
<head xmlns:th="http://www.thymeleaf.org">
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title th:text="${title}">Dashboard</title>
|
||||
<meta http-equiv="X-UA-Compatible" content="IE=Edge"/>
|
||||
|
||||
|
||||
<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/4.0.0/css/bootstrap.min.css">
|
||||
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/5.15.1/css/all.min.css"/>
|
||||
<link rel="stylesheet" th:href="@{/css/styles.css}"/>
|
||||
|
||||
<script src="https://code.highcharts.com/highcharts.js"></script>
|
||||
<script src="https://code.highcharts.com/modules/exporting.js"></script>
|
||||
<script src="https://code.highcharts.com/modules/export-data.js"></script>
|
||||
<script src="https://code.highcharts.com/modules/accessibility.js"></script>
|
||||
<script src="https://code.highcharts.com/highcharts-more.js"></script>
|
||||
<script src="https://cdnjs.cloudflare.com/ajax/libs/popper.js/1.12.9/umd/popper.min.js"></script>
|
||||
<script src="https://maxcdn.bootstrapcdn.com/bootstrap/4.0.0/js/bootstrap.min.js"></script>
|
||||
</head>
|
|
@ -0,0 +1,16 @@
|
|||
<nav class="navbar navbar-expand-lg navbar-dark bg-dark">
|
||||
<a class="navbar-brand" href="/upload/"><i style='font-size:24px' class='fas'></i></a>
|
||||
<button class="navbar-toggler" type="button"
|
||||
data-toggle="collapse" data-target="#navbarNav"
|
||||
aria-controls="navbarNav" aria-expanded="false"
|
||||
aria-label="Toggle navigation">
|
||||
<span class="navbar-toggler-icon"></span>
|
||||
</button>
|
||||
<div class="collapse navbar-collapse" id="navbarNav">
|
||||
<ul class="navbar-nav">
|
||||
<li class="nav-item active">
|
||||
<a class="nav-link" href="/upload/">Upload</a>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
</nav>
|
|
@ -0,0 +1,3 @@
|
|||
<div class="page-header" xmlns:th="http://www.thymeleaf.org">
|
||||
<h1 th:text="${title}">Title</h1>
|
||||
</div>
|
|
@ -0,0 +1,15 @@
|
|||
<table layout:fragment="table(data)">
|
||||
<thead>
|
||||
<tr>
|
||||
<th th:each="header : ${data.getHeaders()}" th:text="${header}">Betrag</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr th:each="row : ${data.getRows()}">
|
||||
<td th:each="column : ${row}"
|
||||
th:text="${column}"
|
||||
th:attr="data-analysis-value=${column}"
|
||||
></td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
|
@ -0,0 +1,14 @@
|
|||
<!DOCTYPE html>
|
||||
<html>
|
||||
<!-- Header Fragment -->
|
||||
<th:block layout:insert="~{fragments/html_head}"/>
|
||||
|
||||
<body>
|
||||
<th:block layout:replace="~{fragments/navigation}"/>
|
||||
|
||||
<div class="container-fluid mt-3">
|
||||
<th:block layout:insert="~{fragments/page_title}"/>
|
||||
<th:block layout:fragment="content"/>
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
|
@ -0,0 +1,119 @@
|
|||
<!DOCTYPE html>
|
||||
<html lang="en" xmlns:th="http://www.thymeleaf.org"
|
||||
xmlns:layout="http://www.ultraq.net.nz/thymeleaf/layout"
|
||||
xmlns:with="http://www.thymeleaf.org/extras/with"
|
||||
layout:decorate="~{layout}"
|
||||
with:title="Reports">
|
||||
<th:block layout:fragment="content">
|
||||
<div class="container-fluid">
|
||||
<div class="row justify-content-center mb-3">
|
||||
<div class="col-md-12">
|
||||
<div class="card ">
|
||||
<div class="card-header bg-dark align-items-center">
|
||||
<span class="md-12 display-5 text-light">Kontodaten</span>
|
||||
</div>
|
||||
<div class="card-body">
|
||||
<p class="md-12 display-5" th:text="'Name: ' + ${accountName}"></p>
|
||||
<p class="md-12 display-5" th:text="'IBAN: ' + ${iban}"></p>
|
||||
<p class="md-12 display-5" th:text="'Datum: ' + ${date}"></p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="row justify-content-center mb-3">
|
||||
<div class="col-md-12">
|
||||
<div class="card">
|
||||
<div class="card-header bg-dark align-items-center">
|
||||
<span class="md-12 display-5 text-light">Cashflow Analyse</span>
|
||||
</div>
|
||||
<div class="card-body scrollable-table">
|
||||
<div layout:replace="~{fragments/table :: table(data=${cashFlow})}"></div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="row justify-content-center mb-3">
|
||||
<!-- Chart -->
|
||||
<div class="col-md-6">
|
||||
<div class="card">
|
||||
<div class="card-header bg-dark align-items-center">
|
||||
<span class="md-12 display-5 text-light">Kontostand Verlauf</span>
|
||||
</div>
|
||||
<div class="card-body">
|
||||
<div id="line-chart-container"></div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<!-- Chart End -->
|
||||
<!-- Chart -->
|
||||
<div class="col-md-6">
|
||||
<div class="card">
|
||||
<div class="card-header bg-dark align-items-center">
|
||||
<span class="md-12 display-5 text-light">Verteilung Einnahmen und Ausgaben</span>
|
||||
</div>
|
||||
<div class="card-body">
|
||||
<div id="chart-container"></div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<!-- Chart End -->,
|
||||
</div>
|
||||
<div class="row justify-content-center mb-3">
|
||||
<div class="col-md-12">
|
||||
<div class="card">
|
||||
<div class="card-header bg-dark align-items-center">
|
||||
<span class="md-12 display-5 text-light">Einkommen</span>
|
||||
</div>
|
||||
|
||||
<div class="card-body scrollable-table">
|
||||
<div layout:replace="~{fragments/table :: table(data=${income})}"></div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="row justify-content-center mb-3">
|
||||
<div class="col-md-12">
|
||||
<div class="card">
|
||||
<div class="card-header bg-dark align-items-center"><span class="md-12 display-5 text-light">Verträge</span></div>
|
||||
<div class="card-body scrollable-table">
|
||||
<div layout:replace="~{fragments/table :: table(data=${standingOrders})}"></div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row justify-content-center mb-3">
|
||||
<div class="col-md-12">
|
||||
<div class="card">
|
||||
<div class="card-header bg-dark align-items-center"><span class="md-12 display-5 text-light">Keine Verträge</span></div>
|
||||
<div class="card-body scrollable-table">
|
||||
<div layout:replace="~{fragments/table :: table(data=${notStandingOrders})}"></div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="row justify-content-center mb-3">
|
||||
<!-- Chart -->
|
||||
<div class="col-md-12">
|
||||
<div class="card">
|
||||
<div class="card-header bg-dark align-items-center"><span class="md-12 display-5 text-light">Kategorien der Ausgaben</span></div>
|
||||
<div class="card-body">
|
||||
<div id="bubble-chart-container"></div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<!-- Chart End -->
|
||||
</div>
|
||||
|
||||
|
||||
|
||||
</div>
|
||||
|
||||
<div layout:replace="~{fragments/body_end_scripts :: scripts(id=${'bubble-chart-container'}, data=${transactionCategories})}"/>
|
||||
<div layout:replace="~{fragments/body_end_scripts :: scripts(id=${'chart-container'}, data=${incomeExpenseColumnReport})}"/>
|
||||
<div layout:replace="~{fragments/body_end_scripts :: scripts(id=${'line-chart-container'}, data=${accountBalanceLineChart})}"/>
|
||||
|
||||
</th:block>
|
|
@ -0,0 +1,50 @@
|
|||
<!DOCTYPE html>
|
||||
<html lang="en" xmlns:th="http://www.thymeleaf.org"
|
||||
xmlns:layout="http://www.ultraq.net.nz/thymeleaf/layout"
|
||||
xmlns:with="http://www.thymeleaf.org/extras/with"
|
||||
layout:decorate="~{layout}"
|
||||
with:title="Upload">
|
||||
<th:block layout:fragment="content">
|
||||
<div class="container-fluid">
|
||||
<div class="row justify-content-center" th:if="${foundJsonFile != null}">
|
||||
<div class="col-md-12">
|
||||
<div class="card">
|
||||
<div class="card-header bg-dark align-items-center">
|
||||
<p class="md-12 display-5 text-light">Bestehnde Daten gefunden: </p>
|
||||
</div>
|
||||
<div class="card-body">
|
||||
<p class="md-12 display-5" th:text="${foundJsonFile}"></p>
|
||||
<form action="#" th:action="@{/data/load}" th:method="post">
|
||||
<div style="display: flex; flex-direction: row; justify-content: flex-start; gap: 1em;">
|
||||
<select name="account">
|
||||
<option th:each="account : ${accounts}" th:value="${account.iban}"
|
||||
th:text="${account.bankAccountName}">
|
||||
</option>
|
||||
</select>
|
||||
<input th:value="${#dates.format(#dates.createNow(), 'yyyy-MM')}" type="month" id="month" name="month"/>
|
||||
<input type="submit"/>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</br>
|
||||
<div class="row justify-content-center">
|
||||
<div class="col-md-12">
|
||||
<div class="card">
|
||||
<div class="card-header bg-dark align-items-center">
|
||||
<span class="md-12 display-5 text-light">Upload</span>
|
||||
</div>
|
||||
<div class="card-body">
|
||||
<form style="display: flex; justify-content: space-between;" action="#"
|
||||
th:action="@{/data/convert/}" th:method="post" enctype="multipart/form-data">
|
||||
<input type="file" name="file" required/>
|
||||
<input type="submit" value="Upload"/>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</th:block>
|
Loading…
Reference in New Issue