feature/config #78
							
								
								
									
										4
									
								
								.gitignore
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										4
									
								
								.gitignore
									
									
									
									
										vendored
									
									
								
							@ -89,3 +89,7 @@ local.properties
 | 
			
		||||
 | 
			
		||||
# SQLite
 | 
			
		||||
prototype/*.db
 | 
			
		||||
 | 
			
		||||
prototype/images
 | 
			
		||||
prototype/data
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										32
									
								
								delivery/.gitignore
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										32
									
								
								delivery/.gitignore
									
									
									
									
										vendored
									
									
										Normal file
									
								
							@ -0,0 +1,32 @@
 | 
			
		||||
HELP.md
 | 
			
		||||
.gradle
 | 
			
		||||
build/
 | 
			
		||||
!gradle/wrapper/gradle-wrapper.jar
 | 
			
		||||
!**/src/main/**
 | 
			
		||||
!**/src/test/**
 | 
			
		||||
 | 
			
		||||
### STS ###
 | 
			
		||||
.apt_generated
 | 
			
		||||
.classpath
 | 
			
		||||
.factorypath
 | 
			
		||||
.project
 | 
			
		||||
.settings
 | 
			
		||||
.springBeans
 | 
			
		||||
.sts4-cache
 | 
			
		||||
 | 
			
		||||
### IntelliJ IDEA ###
 | 
			
		||||
.idea
 | 
			
		||||
*.iws
 | 
			
		||||
*.iml
 | 
			
		||||
*.ipr
 | 
			
		||||
out/
 | 
			
		||||
 | 
			
		||||
### NetBeans ###
 | 
			
		||||
/nbproject/private/
 | 
			
		||||
/nbbuild/
 | 
			
		||||
/dist/
 | 
			
		||||
/nbdist/
 | 
			
		||||
/.nb-gradle/
 | 
			
		||||
 | 
			
		||||
### VS Code ###
 | 
			
		||||
.vscode/
 | 
			
		||||
							
								
								
									
										30
									
								
								delivery/build.gradle
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										30
									
								
								delivery/build.gradle
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,30 @@
 | 
			
		||||
plugins {
 | 
			
		||||
	id 'org.springframework.boot' version '2.2.7.RELEASE'
 | 
			
		||||
	id 'io.spring.dependency-management' version '1.0.9.RELEASE'
 | 
			
		||||
	id 'java'
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
group = 'org.hso.ecommerce'
 | 
			
		||||
version = '0.0.1-SNAPSHOT'
 | 
			
		||||
sourceCompatibility = '11'
 | 
			
		||||
 | 
			
		||||
apply plugin: 'java'
 | 
			
		||||
apply plugin: 'idea'
 | 
			
		||||
apply plugin: 'org.springframework.boot'
 | 
			
		||||
apply plugin: 'io.spring.dependency-management'
 | 
			
		||||
 | 
			
		||||
repositories {
 | 
			
		||||
	mavenCentral()
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
dependencies {
 | 
			
		||||
	implementation 'org.springframework.boot:spring-boot-starter-web'
 | 
			
		||||
	testImplementation('org.springframework.boot:spring-boot-starter-test') {
 | 
			
		||||
		exclude group: 'org.junit.vintage', module: 'junit-vintage-engine'
 | 
			
		||||
	}
 | 
			
		||||
	compile 'org.json:json:20190722'
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
test {
 | 
			
		||||
	useJUnitPlatform()
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										
											BIN
										
									
								
								delivery/gradle/wrapper/gradle-wrapper.jar
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										
											BIN
										
									
								
								delivery/gradle/wrapper/gradle-wrapper.jar
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
										
											Binary file not shown.
										
									
								
							
							
								
								
									
										6
									
								
								delivery/gradle/wrapper/gradle-wrapper.properties
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										6
									
								
								delivery/gradle/wrapper/gradle-wrapper.properties
									
									
									
									
										vendored
									
									
										Normal file
									
								
							@ -0,0 +1,6 @@
 | 
			
		||||
#Tue May 19 15:50:06 CEST 2020
 | 
			
		||||
distributionUrl=https\://services.gradle.org/distributions/gradle-6.4-all.zip
 | 
			
		||||
distributionBase=GRADLE_USER_HOME
 | 
			
		||||
distributionPath=wrapper/dists
 | 
			
		||||
zipStorePath=wrapper/dists
 | 
			
		||||
zipStoreBase=GRADLE_USER_HOME
 | 
			
		||||
							
								
								
									
										183
									
								
								delivery/gradlew
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										183
									
								
								delivery/gradlew
									
									
									
									
										vendored
									
									
										Normal file
									
								
							@ -0,0 +1,183 @@
 | 
			
		||||
#!/usr/bin/env sh
 | 
			
		||||
 | 
			
		||||
#
 | 
			
		||||
# Copyright 2015 the original author or authors.
 | 
			
		||||
#
 | 
			
		||||
# Licensed under the Apache License, Version 2.0 (the "License");
 | 
			
		||||
# you may not use this file except in compliance with the License.
 | 
			
		||||
# You may obtain a copy of the License at
 | 
			
		||||
#
 | 
			
		||||
#      https://www.apache.org/licenses/LICENSE-2.0
 | 
			
		||||
#
 | 
			
		||||
# Unless required by applicable law or agreed to in writing, software
 | 
			
		||||
# distributed under the License is distributed on an "AS IS" BASIS,
 | 
			
		||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 | 
			
		||||
# See the License for the specific language governing permissions and
 | 
			
		||||
# limitations under the License.
 | 
			
		||||
#
 | 
			
		||||
 | 
			
		||||
##############################################################################
 | 
			
		||||
##
 | 
			
		||||
##  Gradle start up script for UN*X
 | 
			
		||||
##
 | 
			
		||||
##############################################################################
 | 
			
		||||
 | 
			
		||||
# Attempt to set APP_HOME
 | 
			
		||||
# Resolve links: $0 may be a link
 | 
			
		||||
PRG="$0"
 | 
			
		||||
# Need this for relative symlinks.
 | 
			
		||||
while [ -h "$PRG" ] ; do
 | 
			
		||||
    ls=`ls -ld "$PRG"`
 | 
			
		||||
    link=`expr "$ls" : '.*-> \(.*\)$'`
 | 
			
		||||
    if expr "$link" : '/.*' > /dev/null; then
 | 
			
		||||
        PRG="$link"
 | 
			
		||||
    else
 | 
			
		||||
        PRG=`dirname "$PRG"`"/$link"
 | 
			
		||||
    fi
 | 
			
		||||
done
 | 
			
		||||
SAVED="`pwd`"
 | 
			
		||||
cd "`dirname \"$PRG\"`/" >/dev/null
 | 
			
		||||
APP_HOME="`pwd -P`"
 | 
			
		||||
cd "$SAVED" >/dev/null
 | 
			
		||||
 | 
			
		||||
APP_NAME="Gradle"
 | 
			
		||||
APP_BASE_NAME=`basename "$0"`
 | 
			
		||||
 | 
			
		||||
# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
 | 
			
		||||
DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"'
 | 
			
		||||
 | 
			
		||||
# Use the maximum available, or set MAX_FD != -1 to use that value.
 | 
			
		||||
MAX_FD="maximum"
 | 
			
		||||
 | 
			
		||||
warn () {
 | 
			
		||||
    echo "$*"
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
die () {
 | 
			
		||||
    echo
 | 
			
		||||
    echo "$*"
 | 
			
		||||
    echo
 | 
			
		||||
    exit 1
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
# OS specific support (must be 'true' or 'false').
 | 
			
		||||
cygwin=false
 | 
			
		||||
msys=false
 | 
			
		||||
darwin=false
 | 
			
		||||
nonstop=false
 | 
			
		||||
case "`uname`" in
 | 
			
		||||
  CYGWIN* )
 | 
			
		||||
    cygwin=true
 | 
			
		||||
    ;;
 | 
			
		||||
  Darwin* )
 | 
			
		||||
    darwin=true
 | 
			
		||||
    ;;
 | 
			
		||||
  MINGW* )
 | 
			
		||||
    msys=true
 | 
			
		||||
    ;;
 | 
			
		||||
  NONSTOP* )
 | 
			
		||||
    nonstop=true
 | 
			
		||||
    ;;
 | 
			
		||||
esac
 | 
			
		||||
 | 
			
		||||
CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar
 | 
			
		||||
 | 
			
		||||
# Determine the Java command to use to start the JVM.
 | 
			
		||||
if [ -n "$JAVA_HOME" ] ; then
 | 
			
		||||
    if [ -x "$JAVA_HOME/jre/sh/java" ] ; then
 | 
			
		||||
        # IBM's JDK on AIX uses strange locations for the executables
 | 
			
		||||
        JAVACMD="$JAVA_HOME/jre/sh/java"
 | 
			
		||||
    else
 | 
			
		||||
        JAVACMD="$JAVA_HOME/bin/java"
 | 
			
		||||
    fi
 | 
			
		||||
    if [ ! -x "$JAVACMD" ] ; then
 | 
			
		||||
        die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME
 | 
			
		||||
 | 
			
		||||
Please set the JAVA_HOME variable in your environment to match the
 | 
			
		||||
location of your Java installation."
 | 
			
		||||
    fi
 | 
			
		||||
else
 | 
			
		||||
    JAVACMD="java"
 | 
			
		||||
    which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
 | 
			
		||||
 | 
			
		||||
Please set the JAVA_HOME variable in your environment to match the
 | 
			
		||||
location of your Java installation."
 | 
			
		||||
fi
 | 
			
		||||
 | 
			
		||||
# Increase the maximum file descriptors if we can.
 | 
			
		||||
if [ "$cygwin" = "false" -a "$darwin" = "false" -a "$nonstop" = "false" ] ; then
 | 
			
		||||
    MAX_FD_LIMIT=`ulimit -H -n`
 | 
			
		||||
    if [ $? -eq 0 ] ; then
 | 
			
		||||
        if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then
 | 
			
		||||
            MAX_FD="$MAX_FD_LIMIT"
 | 
			
		||||
        fi
 | 
			
		||||
        ulimit -n $MAX_FD
 | 
			
		||||
        if [ $? -ne 0 ] ; then
 | 
			
		||||
            warn "Could not set maximum file descriptor limit: $MAX_FD"
 | 
			
		||||
        fi
 | 
			
		||||
    else
 | 
			
		||||
        warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT"
 | 
			
		||||
    fi
 | 
			
		||||
fi
 | 
			
		||||
 | 
			
		||||
# For Darwin, add options to specify how the application appears in the dock
 | 
			
		||||
if $darwin; then
 | 
			
		||||
    GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\""
 | 
			
		||||
fi
 | 
			
		||||
 | 
			
		||||
# For Cygwin or MSYS, switch paths to Windows format before running java
 | 
			
		||||
if [ "$cygwin" = "true" -o "$msys" = "true" ] ; then
 | 
			
		||||
    APP_HOME=`cygpath --path --mixed "$APP_HOME"`
 | 
			
		||||
    CLASSPATH=`cygpath --path --mixed "$CLASSPATH"`
 | 
			
		||||
    JAVACMD=`cygpath --unix "$JAVACMD"`
 | 
			
		||||
 | 
			
		||||
    # We build the pattern for arguments to be converted via cygpath
 | 
			
		||||
    ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null`
 | 
			
		||||
    SEP=""
 | 
			
		||||
    for dir in $ROOTDIRSRAW ; do
 | 
			
		||||
        ROOTDIRS="$ROOTDIRS$SEP$dir"
 | 
			
		||||
        SEP="|"
 | 
			
		||||
    done
 | 
			
		||||
    OURCYGPATTERN="(^($ROOTDIRS))"
 | 
			
		||||
    # Add a user-defined pattern to the cygpath arguments
 | 
			
		||||
    if [ "$GRADLE_CYGPATTERN" != "" ] ; then
 | 
			
		||||
        OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)"
 | 
			
		||||
    fi
 | 
			
		||||
    # Now convert the arguments - kludge to limit ourselves to /bin/sh
 | 
			
		||||
    i=0
 | 
			
		||||
    for arg in "$@" ; do
 | 
			
		||||
        CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -`
 | 
			
		||||
        CHECK2=`echo "$arg"|egrep -c "^-"`                                 ### Determine if an option
 | 
			
		||||
 | 
			
		||||
        if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then                    ### Added a condition
 | 
			
		||||
            eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"`
 | 
			
		||||
        else
 | 
			
		||||
            eval `echo args$i`="\"$arg\""
 | 
			
		||||
        fi
 | 
			
		||||
        i=`expr $i + 1`
 | 
			
		||||
    done
 | 
			
		||||
    case $i in
 | 
			
		||||
        0) set -- ;;
 | 
			
		||||
        1) set -- "$args0" ;;
 | 
			
		||||
        2) set -- "$args0" "$args1" ;;
 | 
			
		||||
        3) set -- "$args0" "$args1" "$args2" ;;
 | 
			
		||||
        4) set -- "$args0" "$args1" "$args2" "$args3" ;;
 | 
			
		||||
        5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;;
 | 
			
		||||
        6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;;
 | 
			
		||||
        7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;;
 | 
			
		||||
        8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;;
 | 
			
		||||
        9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;;
 | 
			
		||||
    esac
 | 
			
		||||
fi
 | 
			
		||||
 | 
			
		||||
# Escape application args
 | 
			
		||||
save () {
 | 
			
		||||
    for i do printf %s\\n "$i" | sed "s/'/'\\\\''/g;1s/^/'/;\$s/\$/' \\\\/" ; done
 | 
			
		||||
    echo " "
 | 
			
		||||
}
 | 
			
		||||
APP_ARGS=`save "$@"`
 | 
			
		||||
 | 
			
		||||
# Collect all arguments for the java command, following the shell quoting and substitution rules
 | 
			
		||||
eval set -- $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS "\"-Dorg.gradle.appname=$APP_BASE_NAME\"" -classpath "\"$CLASSPATH\"" org.gradle.wrapper.GradleWrapperMain "$APP_ARGS"
 | 
			
		||||
 | 
			
		||||
exec "$JAVACMD" "$@"
 | 
			
		||||
							
								
								
									
										100
									
								
								delivery/gradlew.bat
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										100
									
								
								delivery/gradlew.bat
									
									
									
									
										vendored
									
									
										Normal file
									
								
							@ -0,0 +1,100 @@
 | 
			
		||||
@rem
 | 
			
		||||
@rem Copyright 2015 the original author or authors.
 | 
			
		||||
@rem
 | 
			
		||||
@rem Licensed under the Apache License, Version 2.0 (the "License");
 | 
			
		||||
@rem you may not use this file except in compliance with the License.
 | 
			
		||||
@rem You may obtain a copy of the License at
 | 
			
		||||
@rem
 | 
			
		||||
@rem      https://www.apache.org/licenses/LICENSE-2.0
 | 
			
		||||
@rem
 | 
			
		||||
@rem Unless required by applicable law or agreed to in writing, software
 | 
			
		||||
@rem distributed under the License is distributed on an "AS IS" BASIS,
 | 
			
		||||
@rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 | 
			
		||||
@rem See the License for the specific language governing permissions and
 | 
			
		||||
@rem limitations under the License.
 | 
			
		||||
@rem
 | 
			
		||||
 | 
			
		||||
@if "%DEBUG%" == "" @echo off
 | 
			
		||||
@rem ##########################################################################
 | 
			
		||||
@rem
 | 
			
		||||
@rem  Gradle startup script for Windows
 | 
			
		||||
@rem
 | 
			
		||||
@rem ##########################################################################
 | 
			
		||||
 | 
			
		||||
@rem Set local scope for the variables with windows NT shell
 | 
			
		||||
if "%OS%"=="Windows_NT" setlocal
 | 
			
		||||
 | 
			
		||||
set DIRNAME=%~dp0
 | 
			
		||||
if "%DIRNAME%" == "" set DIRNAME=.
 | 
			
		||||
set APP_BASE_NAME=%~n0
 | 
			
		||||
set APP_HOME=%DIRNAME%
 | 
			
		||||
 | 
			
		||||
@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
 | 
			
		||||
set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m"
 | 
			
		||||
 | 
			
		||||
@rem Find java.exe
 | 
			
		||||
if defined JAVA_HOME goto findJavaFromJavaHome
 | 
			
		||||
 | 
			
		||||
set JAVA_EXE=java.exe
 | 
			
		||||
%JAVA_EXE% -version >NUL 2>&1
 | 
			
		||||
if "%ERRORLEVEL%" == "0" goto init
 | 
			
		||||
 | 
			
		||||
echo.
 | 
			
		||||
echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
 | 
			
		||||
echo.
 | 
			
		||||
echo Please set the JAVA_HOME variable in your environment to match the
 | 
			
		||||
echo location of your Java installation.
 | 
			
		||||
 | 
			
		||||
goto fail
 | 
			
		||||
 | 
			
		||||
:findJavaFromJavaHome
 | 
			
		||||
set JAVA_HOME=%JAVA_HOME:"=%
 | 
			
		||||
set JAVA_EXE=%JAVA_HOME%/bin/java.exe
 | 
			
		||||
 | 
			
		||||
if exist "%JAVA_EXE%" goto init
 | 
			
		||||
 | 
			
		||||
echo.
 | 
			
		||||
echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME%
 | 
			
		||||
echo.
 | 
			
		||||
echo Please set the JAVA_HOME variable in your environment to match the
 | 
			
		||||
echo location of your Java installation.
 | 
			
		||||
 | 
			
		||||
goto fail
 | 
			
		||||
 | 
			
		||||
:init
 | 
			
		||||
@rem Get command-line arguments, handling Windows variants
 | 
			
		||||
 | 
			
		||||
if not "%OS%" == "Windows_NT" goto win9xME_args
 | 
			
		||||
 | 
			
		||||
:win9xME_args
 | 
			
		||||
@rem Slurp the command line arguments.
 | 
			
		||||
set CMD_LINE_ARGS=
 | 
			
		||||
set _SKIP=2
 | 
			
		||||
 | 
			
		||||
:win9xME_args_slurp
 | 
			
		||||
if "x%~1" == "x" goto execute
 | 
			
		||||
 | 
			
		||||
set CMD_LINE_ARGS=%*
 | 
			
		||||
 | 
			
		||||
:execute
 | 
			
		||||
@rem Setup the command line
 | 
			
		||||
 | 
			
		||||
set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar
 | 
			
		||||
 | 
			
		||||
@rem Execute Gradle
 | 
			
		||||
"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS%
 | 
			
		||||
 | 
			
		||||
:end
 | 
			
		||||
@rem End local scope for the variables with windows NT shell
 | 
			
		||||
if "%ERRORLEVEL%"=="0" goto mainEnd
 | 
			
		||||
 | 
			
		||||
:fail
 | 
			
		||||
rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of
 | 
			
		||||
rem the _cmd.exe /c_ return code!
 | 
			
		||||
if  not "" == "%GRADLE_EXIT_CONSOLE%" exit 1
 | 
			
		||||
exit /b 1
 | 
			
		||||
 | 
			
		||||
:mainEnd
 | 
			
		||||
if "%OS%"=="Windows_NT" endlocal
 | 
			
		||||
 | 
			
		||||
:omega
 | 
			
		||||
							
								
								
									
										1
									
								
								delivery/settings.gradle
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										1
									
								
								delivery/settings.gradle
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1 @@
 | 
			
		||||
rootProject.name = 'delivery'
 | 
			
		||||
							
								
								
									
										11
									
								
								delivery/src/main/java/org/hso/ecommerce/supplier/App.java
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										11
									
								
								delivery/src/main/java/org/hso/ecommerce/supplier/App.java
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,11 @@
 | 
			
		||||
package org.hso.ecommerce.supplier;
 | 
			
		||||
 | 
			
		||||
import org.springframework.boot.SpringApplication;
 | 
			
		||||
import org.springframework.boot.autoconfigure.SpringBootApplication;
 | 
			
		||||
 | 
			
		||||
@SpringBootApplication
 | 
			
		||||
public class App {
 | 
			
		||||
    public static void main(String[] args) {
 | 
			
		||||
        SpringApplication.run(App.class, args);
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
@ -0,0 +1,32 @@
 | 
			
		||||
package org.hso.ecommerce.supplier;
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
import org.hso.ecommerce.supplier.data.Delivery;
 | 
			
		||||
import org.hso.ecommerce.supplier.data.DeliveryManager;
 | 
			
		||||
import org.hso.ecommerce.supplier.data.ReturnStatus;
 | 
			
		||||
import org.springframework.web.bind.annotation.*;
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
import javax.servlet.http.HttpServletRequest;
 | 
			
		||||
import javax.servlet.http.HttpServletResponse;
 | 
			
		||||
 | 
			
		||||
@RestController
 | 
			
		||||
public class RequestController {
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
    @PostMapping("/newDelivery")
 | 
			
		||||
    public String supplier(HttpServletResponse response, HttpServletRequest request, @RequestBody Delivery delivery) {
 | 
			
		||||
        DeliveryManager.getInstance().add(delivery);
 | 
			
		||||
 | 
			
		||||
        return delivery.getUuid().toString();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    @GetMapping("/status")
 | 
			
		||||
    public ReturnStatus searchArticles(@RequestParam(value = "trackingID") String trackingID, HttpServletRequest request, HttpServletResponse response) {
 | 
			
		||||
 | 
			
		||||
        Delivery delivery = DeliveryManager.getInstance().getDeliveryByeID(trackingID);
 | 
			
		||||
 | 
			
		||||
        return new ReturnStatus(delivery.getStatus(),delivery.getEstimatedArrival());
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
@ -0,0 +1,69 @@
 | 
			
		||||
package org.hso.ecommerce.supplier.data;
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
import java.text.SimpleDateFormat;
 | 
			
		||||
import java.util.Calendar;
 | 
			
		||||
import java.util.Date;
 | 
			
		||||
import java.util.UUID;
 | 
			
		||||
 | 
			
		||||
public class Delivery {
 | 
			
		||||
 | 
			
		||||
    private String[] states = {"Bestellung eingegangen","Bestellung auf dem Weg","Lieferung erfolgreich"};
 | 
			
		||||
    private int[] timeBorder = {4,24};
 | 
			
		||||
 | 
			
		||||
    private String name;
 | 
			
		||||
    private String address;
 | 
			
		||||
    private String estimatedArrival;
 | 
			
		||||
    private Date creationTime;
 | 
			
		||||
    private UUID uuid;
 | 
			
		||||
 | 
			
		||||
    public Delivery(String name, String address)
 | 
			
		||||
    {
 | 
			
		||||
        this.name = name;
 | 
			
		||||
        this.address = address;
 | 
			
		||||
        this.uuid = UUID.randomUUID();
 | 
			
		||||
        this.creationTime = new Date();
 | 
			
		||||
        SimpleDateFormat formatter = new SimpleDateFormat("dd-MM-yyyy");
 | 
			
		||||
        this.estimatedArrival = formatter.format(addDays((Date)this.creationTime.clone(),1));
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
    public String getStatus()
 | 
			
		||||
    {
 | 
			
		||||
        Date now = new Date();
 | 
			
		||||
        Long timeNow = now.getTime();
 | 
			
		||||
        Long creationTime = this.creationTime.getTime();
 | 
			
		||||
 | 
			
		||||
        Long diff = timeNow - creationTime;
 | 
			
		||||
        double hour = (((diff / 1000.0) / 3600.0));
 | 
			
		||||
 | 
			
		||||
        for (int i = 0; i <  timeBorder.length; i++) {
 | 
			
		||||
 | 
			
		||||
            if(hour < timeBorder[i])
 | 
			
		||||
                return states[i];
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        return states[timeBorder.length];
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public String getEstimatedArrival() {
 | 
			
		||||
 | 
			
		||||
        return estimatedArrival;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    private Date addDays(Date date, int days)
 | 
			
		||||
    {
 | 
			
		||||
        Calendar cal = Calendar.getInstance();
 | 
			
		||||
        cal.setTime(date);
 | 
			
		||||
        cal.add(Calendar.DATE, days);
 | 
			
		||||
        return cal.getTime();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public UUID getUuid() {
 | 
			
		||||
        return uuid;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public String getName() {
 | 
			
		||||
        return name;
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
@ -0,0 +1,34 @@
 | 
			
		||||
package org.hso.ecommerce.supplier.data;
 | 
			
		||||
 | 
			
		||||
import java.util.ArrayList;
 | 
			
		||||
import java.util.List;
 | 
			
		||||
import java.util.UUID;
 | 
			
		||||
 | 
			
		||||
public class DeliveryManager {
 | 
			
		||||
 | 
			
		||||
    private List<Delivery> deliveryList;
 | 
			
		||||
    private static DeliveryManager deliveryManager;
 | 
			
		||||
 | 
			
		||||
    private DeliveryManager()
 | 
			
		||||
    {
 | 
			
		||||
        deliveryList = new ArrayList<>();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public static DeliveryManager getInstance () {
 | 
			
		||||
 | 
			
		||||
        if (DeliveryManager.deliveryManager == null) {
 | 
			
		||||
            DeliveryManager.deliveryManager = new DeliveryManager();
 | 
			
		||||
        }
 | 
			
		||||
        return DeliveryManager.deliveryManager;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public boolean add(Delivery delivery)
 | 
			
		||||
    {
 | 
			
		||||
       return deliveryList.add(delivery);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public Delivery getDeliveryByeID(String uuid)
 | 
			
		||||
    {
 | 
			
		||||
        return deliveryList.parallelStream().filter(d -> d.getUuid().equals(UUID.fromString(uuid))).findAny().get();
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
@ -0,0 +1,20 @@
 | 
			
		||||
package org.hso.ecommerce.supplier.data;
 | 
			
		||||
 | 
			
		||||
public class ReturnStatus {
 | 
			
		||||
 | 
			
		||||
    private String status;
 | 
			
		||||
    private String estimatedArrival;
 | 
			
		||||
 | 
			
		||||
    public ReturnStatus(String status, String estimatedArrival) {
 | 
			
		||||
        this.status = status;
 | 
			
		||||
        this.estimatedArrival = estimatedArrival;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public String getStatus() {
 | 
			
		||||
        return status;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public String getEstimatedArrival() {
 | 
			
		||||
        return estimatedArrival;
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										2
									
								
								delivery/src/main/resources/application.properties
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										2
									
								
								delivery/src/main/resources/application.properties
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,2 @@
 | 
			
		||||
server.address=::1
 | 
			
		||||
server.port=8082
 | 
			
		||||
							
								
								
									
										2
									
								
								prototype/.gitignore
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										2
									
								
								prototype/.gitignore
									
									
									
									
										vendored
									
									
								
							@ -1,4 +1,4 @@
 | 
			
		||||
./test.db
 | 
			
		||||
e-commerce.db
 | 
			
		||||
./build
 | 
			
		||||
./gradle
 | 
			
		||||
./out
 | 
			
		||||
 | 
			
		||||
@ -3,7 +3,7 @@ buildscript {
 | 
			
		||||
        mavenCentral()
 | 
			
		||||
    }
 | 
			
		||||
    dependencies {
 | 
			
		||||
        classpath("org.springframework.boot:spring-boot-gradle-plugin:2.2.2.RELEASE")
 | 
			
		||||
        classpath("org.springframework.boot:spring-boot-gradle-plugin:2.2.7.RELEASE")
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@ -27,7 +27,7 @@ dependencies {
 | 
			
		||||
    // implementation 'org.springframework.session:spring-session-jdbc'
 | 
			
		||||
    implementation 'com.github.gwenn:sqlite-dialect:0.1.0'
 | 
			
		||||
    implementation 'org.springframework.boot:spring-boot-devtools'
 | 
			
		||||
    implementation 'org.xerial:sqlite-jdbc:3.28.0'
 | 
			
		||||
    implementation 'org.xerial:sqlite-jdbc:3.31.1'
 | 
			
		||||
    implementation 'org.yaml:snakeyaml:1.26'
 | 
			
		||||
    testCompile("org.springframework.boot:spring-boot-starter-test")
 | 
			
		||||
}
 | 
			
		||||
@ -36,5 +36,5 @@ group 'org.hso'
 | 
			
		||||
version '0.1.0'
 | 
			
		||||
 | 
			
		||||
bootRun {
 | 
			
		||||
  args = ["--spring.profiles.active=dev"]
 | 
			
		||||
  args = ["--spring.profiles.active=dev --spring.config.location=classpath:/application.properties"]
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										
											BIN
										
									
								
								prototype/gradle/wrapper/gradle-wrapper.jar
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										
											BIN
										
									
								
								prototype/gradle/wrapper/gradle-wrapper.jar
									
									
									
									
										vendored
									
									
								
							
										
											Binary file not shown.
										
									
								
							@ -1,5 +1,5 @@
 | 
			
		||||
distributionBase=GRADLE_USER_HOME
 | 
			
		||||
distributionPath=wrapper/dists
 | 
			
		||||
distributionUrl=https\://services.gradle.org/distributions/gradle-5.6.2-bin.zip
 | 
			
		||||
distributionUrl=https\://services.gradle.org/distributions/gradle-6.4-bin.zip
 | 
			
		||||
zipStoreBase=GRADLE_USER_HOME
 | 
			
		||||
zipStorePath=wrapper/dists
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										22
									
								
								prototype/gradlew
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										22
									
								
								prototype/gradlew
									
									
									
									
										vendored
									
									
								
							@ -1,5 +1,21 @@
 | 
			
		||||
#!/usr/bin/env sh
 | 
			
		||||
 | 
			
		||||
#
 | 
			
		||||
# Copyright 2015 the original author or authors.
 | 
			
		||||
#
 | 
			
		||||
# Licensed under the Apache License, Version 2.0 (the "License");
 | 
			
		||||
# you may not use this file except in compliance with the License.
 | 
			
		||||
# You may obtain a copy of the License at
 | 
			
		||||
#
 | 
			
		||||
#      https://www.apache.org/licenses/LICENSE-2.0
 | 
			
		||||
#
 | 
			
		||||
# Unless required by applicable law or agreed to in writing, software
 | 
			
		||||
# distributed under the License is distributed on an "AS IS" BASIS,
 | 
			
		||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 | 
			
		||||
# See the License for the specific language governing permissions and
 | 
			
		||||
# limitations under the License.
 | 
			
		||||
#
 | 
			
		||||
 | 
			
		||||
##############################################################################
 | 
			
		||||
##
 | 
			
		||||
##  Gradle start up script for UN*X
 | 
			
		||||
@ -28,7 +44,7 @@ APP_NAME="Gradle"
 | 
			
		||||
APP_BASE_NAME=`basename "$0"`
 | 
			
		||||
 | 
			
		||||
# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
 | 
			
		||||
DEFAULT_JVM_OPTS=""
 | 
			
		||||
DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"'
 | 
			
		||||
 | 
			
		||||
# Use the maximum available, or set MAX_FD != -1 to use that value.
 | 
			
		||||
MAX_FD="maximum"
 | 
			
		||||
@ -109,8 +125,8 @@ if $darwin; then
 | 
			
		||||
    GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\""
 | 
			
		||||
fi
 | 
			
		||||
 | 
			
		||||
# For Cygwin, switch paths to Windows format before running java
 | 
			
		||||
if $cygwin ; then
 | 
			
		||||
# For Cygwin or MSYS, switch paths to Windows format before running java
 | 
			
		||||
if [ "$cygwin" = "true" -o "$msys" = "true" ] ; then
 | 
			
		||||
    APP_HOME=`cygpath --path --mixed "$APP_HOME"`
 | 
			
		||||
    CLASSPATH=`cygpath --path --mixed "$CLASSPATH"`
 | 
			
		||||
    JAVACMD=`cygpath --unix "$JAVACMD"`
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										18
									
								
								prototype/gradlew.bat
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										18
									
								
								prototype/gradlew.bat
									
									
									
									
										vendored
									
									
								
							@ -1,3 +1,19 @@
 | 
			
		||||
@rem
 | 
			
		||||
@rem Copyright 2015 the original author or authors.
 | 
			
		||||
@rem
 | 
			
		||||
@rem Licensed under the Apache License, Version 2.0 (the "License");
 | 
			
		||||
@rem you may not use this file except in compliance with the License.
 | 
			
		||||
@rem You may obtain a copy of the License at
 | 
			
		||||
@rem
 | 
			
		||||
@rem      https://www.apache.org/licenses/LICENSE-2.0
 | 
			
		||||
@rem
 | 
			
		||||
@rem Unless required by applicable law or agreed to in writing, software
 | 
			
		||||
@rem distributed under the License is distributed on an "AS IS" BASIS,
 | 
			
		||||
@rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 | 
			
		||||
@rem See the License for the specific language governing permissions and
 | 
			
		||||
@rem limitations under the License.
 | 
			
		||||
@rem
 | 
			
		||||
 | 
			
		||||
@if "%DEBUG%" == "" @echo off
 | 
			
		||||
@rem ##########################################################################
 | 
			
		||||
@rem
 | 
			
		||||
@ -14,7 +30,7 @@ set APP_BASE_NAME=%~n0
 | 
			
		||||
set APP_HOME=%DIRNAME%
 | 
			
		||||
 | 
			
		||||
@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
 | 
			
		||||
set DEFAULT_JVM_OPTS=
 | 
			
		||||
set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m"
 | 
			
		||||
 | 
			
		||||
@rem Find java.exe
 | 
			
		||||
if defined JAVA_HOME goto findJavaFromJavaHome
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										15
									
								
								prototype/scripts/addarticles.sql
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										15
									
								
								prototype/scripts/addarticles.sql
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,15 @@
 | 
			
		||||
/*
 | 
			
		||||
* add a supplier first
 | 
			
		||||
*/
 | 
			
		||||
 | 
			
		||||
INSERT INTO article_offers ("manufacturer", "article_number", "price_per_unit_net", "title", "vat_percent", "should_be_advertised", "cheapest_supplier_id")
 | 
			
		||||
VALUES ("McDonalds", "1", 4242, "McPizza", 7, 1, 1);
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
* There is no need for the add article, you can add one form the UI on the offerd article page
 | 
			
		||||
*/
 | 
			
		||||
INSERT INTO articles ("related_id", "shop_price_per_unit_net_cent", "warehouse_units_per_slot", "should_reorder", "reorder_max_price", "title", "description", "image_id")
 | 
			
		||||
VALUES (1, 19.99, 10, 1, 15, "Huge Hamburger", "This huge Hamburger is awesome!", NULL);
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										6
									
								
								prototype/scripts/addsupplier.sql
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										6
									
								
								prototype/scripts/addsupplier.sql
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,6 @@
 | 
			
		||||
 | 
			
		||||
INSERT INTO suppliers ("api_url", "name", "uuid")
 | 
			
		||||
VALUES ("https://api.com", "Conrad", "fdfdfg4gdfgdf4gfg");
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										3
									
								
								prototype/scripts/addsupplierorders.sql
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										3
									
								
								prototype/scripts/addsupplierorders.sql
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,3 @@
 | 
			
		||||
 | 
			
		||||
INSERT INTO supplier_orders ("created", "delivered", "number_of_units", "price_per_unit_net_cent", "total_price_net", "ordered_id", "supplier_id") 
 | 
			
		||||
VALUES ('0', '0', '42', '42', '42', '1', '1');
 | 
			
		||||
@ -1,9 +1,9 @@
 | 
			
		||||
/* password is 123 */
 | 
			
		||||
INSERT INTO users ("created", "email", "password_hash", "gets_ads", "is_active", "is_employee", "isb2b")
 | 
			
		||||
VALUES (datetime('now','localtime') ||'.0', "emp@ecom", "$2a$10$zFiqcePBmXHErD86vkI.vO1dnX20ezoVSM8xjGi59nktXYQv0o.fK", "0", "1", "1", "0");
 | 
			
		||||
INSERT INTO users ("created", "email", "password_hash", "is_active", "is_employee")
 | 
			
		||||
VALUES (datetime('now','localtime') ||'.0', "emp@ecom", "$2a$10$zFiqcePBmXHErD86vkI.vO1dnX20ezoVSM8xjGi59nktXYQv0o.fK", "1", "1");
 | 
			
		||||
 | 
			
		||||
INSERT INTO users ("created", "email", "password_hash", "gets_ads", "is_active", "is_employee", "isb2b")
 | 
			
		||||
VALUES (datetime('now','localtime') ||'.0', "user@ecom", "$2a$10$zFiqcePBmXHErD86vkI.vO1dnX20ezoVSM8xjGi59nktXYQv0o.fK", "1", "1", "0", "0");
 | 
			
		||||
INSERT INTO users ("created", "email", "password_hash", "is_active", "is_employee")
 | 
			
		||||
VALUES (datetime('now','localtime') ||'.0', "user@ecom", "$2a$10$zFiqcePBmXHErD86vkI.vO1dnX20ezoVSM8xjGi59nktXYQv0o.fK", "1", "0");
 | 
			
		||||
 | 
			
		||||
INSERT INTO users ("created", "email", "password_hash", "gets_ads", "is_active", "is_employee", "isb2b")
 | 
			
		||||
VALUES (datetime('now','localtime') ||'.0', "blocked@ecom", "$2a$10$zFiqcePBmXHErD86vkI.vO1dnX20ezoVSM8xjGi59nktXYQv0o.fK", "1", "0", "0", "0");
 | 
			
		||||
INSERT INTO users ("created", "email", "password_hash", "is_active", "is_employee")
 | 
			
		||||
VALUES (datetime('now','localtime') ||'.0', "blocked@ecom", "$2a$10$zFiqcePBmXHErD86vkI.vO1dnX20ezoVSM8xjGi59nktXYQv0o.fK", "0", "0");
 | 
			
		||||
@ -0,0 +1,31 @@
 | 
			
		||||
package org.hso.ecommerce.action.booking;
 | 
			
		||||
 | 
			
		||||
import org.hso.ecommerce.entities.booking.Booking;
 | 
			
		||||
import org.hso.ecommerce.entities.booking.BookingAccountEntry;
 | 
			
		||||
import org.hso.ecommerce.entities.booking.BookingReason;
 | 
			
		||||
 | 
			
		||||
public class CreateBookingAction {
 | 
			
		||||
 | 
			
		||||
    private Booking booking;
 | 
			
		||||
 | 
			
		||||
    public CreateBookingAction(BookingAccountEntry source, BookingAccountEntry destination, BookingReason reason, int amountCent) {
 | 
			
		||||
        booking = new Booking();
 | 
			
		||||
        booking.created = new java.sql.Timestamp(System.currentTimeMillis());
 | 
			
		||||
        booking.reason = reason;
 | 
			
		||||
        booking.amountCent = amountCent;
 | 
			
		||||
 | 
			
		||||
        assert source != null || destination != null;
 | 
			
		||||
 | 
			
		||||
        if (source != null) {
 | 
			
		||||
            booking.source = source.copyAddAmount(-amountCent);
 | 
			
		||||
        }
 | 
			
		||||
        if (destination != null) {
 | 
			
		||||
            booking.destination = destination.copyAddAmount(amountCent);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public Booking finish() {
 | 
			
		||||
        return booking;
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
@ -0,0 +1,83 @@
 | 
			
		||||
package org.hso.ecommerce.action.cronjob;
 | 
			
		||||
 | 
			
		||||
import java.util.ArrayList;
 | 
			
		||||
import java.util.HashMap;
 | 
			
		||||
import java.util.List;
 | 
			
		||||
import java.util.Objects;
 | 
			
		||||
 | 
			
		||||
import org.hso.ecommerce.api.SupplierService;
 | 
			
		||||
import org.hso.ecommerce.api.data.Article;
 | 
			
		||||
import org.hso.ecommerce.api.data.Supplier;
 | 
			
		||||
 | 
			
		||||
public class ReadSupplierDataAction {
 | 
			
		||||
    private List<org.hso.ecommerce.entities.supplier.Supplier> suppliers;
 | 
			
		||||
 | 
			
		||||
    public static class ArticleIdentifier {
 | 
			
		||||
        public final String manufacturer;
 | 
			
		||||
        public final String articleNumber;
 | 
			
		||||
 | 
			
		||||
        public ArticleIdentifier(String manufacturer, String articleNumber) {
 | 
			
		||||
            this.manufacturer = manufacturer;
 | 
			
		||||
            this.articleNumber = articleNumber;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        @Override
 | 
			
		||||
        public int hashCode() {
 | 
			
		||||
            return Objects.hash(manufacturer, articleNumber);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        @Override
 | 
			
		||||
        public boolean equals(Object other) {
 | 
			
		||||
            if (!(other instanceof ArticleIdentifier)) {
 | 
			
		||||
                return false;
 | 
			
		||||
            }
 | 
			
		||||
            ArticleIdentifier otherId = (ArticleIdentifier) other;
 | 
			
		||||
            return this.manufacturer.equals(otherId.manufacturer) && this.articleNumber.equals(otherId.articleNumber);
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public ReadSupplierDataAction(List<org.hso.ecommerce.entities.supplier.Supplier> suppliers) {
 | 
			
		||||
        this.suppliers = suppliers;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public static class Offer {
 | 
			
		||||
        public final org.hso.ecommerce.entities.supplier.Supplier dbSupplier;
 | 
			
		||||
        public final Supplier apiSupplier;
 | 
			
		||||
 | 
			
		||||
        public Offer(org.hso.ecommerce.entities.supplier.Supplier dbSupplier, Supplier apiSupplier) {
 | 
			
		||||
            this.dbSupplier = dbSupplier;
 | 
			
		||||
            this.apiSupplier = apiSupplier;
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public static class Result {
 | 
			
		||||
        public final ArrayList<Supplier> supplierData;
 | 
			
		||||
        public final HashMap<ArticleIdentifier, Offer> cheapestOffer;
 | 
			
		||||
 | 
			
		||||
        public Result(ArrayList<Supplier> supplierData, HashMap<ArticleIdentifier, Offer> cheapestOffer) {
 | 
			
		||||
            this.supplierData = supplierData;
 | 
			
		||||
            this.cheapestOffer = cheapestOffer;
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public Result finish() {
 | 
			
		||||
        ArrayList<Supplier> suppliers = new ArrayList<>();
 | 
			
		||||
        HashMap<ArticleIdentifier, Integer> price = new HashMap<>();
 | 
			
		||||
        HashMap<ArticleIdentifier, Offer> cheapest = new HashMap<>();
 | 
			
		||||
        for (org.hso.ecommerce.entities.supplier.Supplier supplier : this.suppliers) {
 | 
			
		||||
            SupplierService service = new SupplierService(supplier.apiUrl);
 | 
			
		||||
            Supplier apiSupplier = service.getSupplier();
 | 
			
		||||
            suppliers.add(apiSupplier);
 | 
			
		||||
            for (Article article : apiSupplier.articles) {
 | 
			
		||||
                ArticleIdentifier identifier = new ArticleIdentifier(article.manufacturer, article.articleNumber);
 | 
			
		||||
                Integer previousPrice = price.get(identifier);
 | 
			
		||||
                if (previousPrice == null || article.pricePerUnitNet < previousPrice) {
 | 
			
		||||
                    price.put(identifier, article.pricePerUnitNet);
 | 
			
		||||
                    cheapest.put(identifier, new Offer(supplier, apiSupplier));
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        return new Result(suppliers, cheapest);
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
@ -0,0 +1,107 @@
 | 
			
		||||
package org.hso.ecommerce.action.cronjob;
 | 
			
		||||
 | 
			
		||||
import java.sql.Timestamp;
 | 
			
		||||
import java.util.HashMap;
 | 
			
		||||
 | 
			
		||||
import org.hso.ecommerce.action.cronjob.ReadSupplierDataAction.ArticleIdentifier;
 | 
			
		||||
import org.hso.ecommerce.action.cronjob.ReadSupplierDataAction.Offer;
 | 
			
		||||
import org.hso.ecommerce.api.SupplierService;
 | 
			
		||||
import org.hso.ecommerce.api.data.Order;
 | 
			
		||||
import org.hso.ecommerce.api.data.OrderConfirmation;
 | 
			
		||||
import org.hso.ecommerce.entities.shop.Article;
 | 
			
		||||
import org.hso.ecommerce.entities.supplier.ArticleOffer;
 | 
			
		||||
import org.hso.ecommerce.entities.supplier.SupplierOrder;
 | 
			
		||||
import org.slf4j.Logger;
 | 
			
		||||
import org.slf4j.LoggerFactory;
 | 
			
		||||
 | 
			
		||||
public class ReorderAction {
 | 
			
		||||
    private static final Logger log = LoggerFactory.getLogger(ReorderAction.class);
 | 
			
		||||
 | 
			
		||||
    private Article article;
 | 
			
		||||
    private Integer[] orderedAmounts;
 | 
			
		||||
    private Integer undeliveredReorders;
 | 
			
		||||
    private int amountInStock;
 | 
			
		||||
    private HashMap<ArticleIdentifier, Offer> cheapestOffer;
 | 
			
		||||
    private HashMap<ArticleIdentifier, ArticleOffer> articleOffers;
 | 
			
		||||
 | 
			
		||||
    public ReorderAction(
 | 
			
		||||
            Article article, Integer[] orderedAmounts,
 | 
			
		||||
            Integer undeliveredReorders,
 | 
			
		||||
            int amountInStock,
 | 
			
		||||
            HashMap<ArticleIdentifier, Offer> cheapestOffer,
 | 
			
		||||
            HashMap<ArticleIdentifier, ArticleOffer> articleOffers
 | 
			
		||||
    ) {
 | 
			
		||||
        this.article = article;
 | 
			
		||||
        this.orderedAmounts = orderedAmounts;
 | 
			
		||||
        this.undeliveredReorders = undeliveredReorders;
 | 
			
		||||
        this.amountInStock = amountInStock;
 | 
			
		||||
        this.cheapestOffer = cheapestOffer;
 | 
			
		||||
        this.articleOffers = articleOffers;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    private int null_to_zero(Integer input) {
 | 
			
		||||
        return input == null ? 0 : input;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    private int calculateAmountToReorder() {
 | 
			
		||||
        // Algorithm as described in the documentation
 | 
			
		||||
        int a = null_to_zero(orderedAmounts[0]);
 | 
			
		||||
        int b = null_to_zero(orderedAmounts[1]);
 | 
			
		||||
        int c = null_to_zero(orderedAmounts[2]);
 | 
			
		||||
 | 
			
		||||
        int x = Math.max(Math.max(a, b), c);
 | 
			
		||||
        int y = Math.min(Math.min(a, b), c);
 | 
			
		||||
 | 
			
		||||
        int n = 6 * x - 2 * y;
 | 
			
		||||
        if (n < 3) {
 | 
			
		||||
            n = 3;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        int i = null_to_zero(undeliveredReorders);
 | 
			
		||||
        int l = amountInStock;
 | 
			
		||||
 | 
			
		||||
        return n - i - l;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public SupplierOrder finish() {
 | 
			
		||||
        if (!article.shouldReorder) {
 | 
			
		||||
            return null;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        int amount = calculateAmountToReorder();
 | 
			
		||||
        if (amount <= 0) {
 | 
			
		||||
            return null;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        ArticleIdentifier identifier = new ArticleIdentifier(article.related.manufacturer, article.related.articleNumber);
 | 
			
		||||
        Offer offer = cheapestOffer.get(identifier);
 | 
			
		||||
        if (offer == null) {
 | 
			
		||||
            log.info("Could not order \"" + article.title + "\" because there is no supplier delivering it.");
 | 
			
		||||
            return null;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        ArticleOffer articleOffer = articleOffers.get(identifier);
 | 
			
		||||
        org.hso.ecommerce.api.data.Article apiArticle = offer.apiSupplier.findArticle(identifier.manufacturer,
 | 
			
		||||
                identifier.articleNumber);
 | 
			
		||||
        if (apiArticle.pricePerUnitNet > article.reorderMaxPrice) {
 | 
			
		||||
            log.info("Could not order \"" + article.title + "\" because it is currently too expensive.");
 | 
			
		||||
            return null;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        Order order = new Order();
 | 
			
		||||
        order.manufacturer = articleOffer.manufacturer;
 | 
			
		||||
        order.articleNumber = articleOffer.articleNumber;
 | 
			
		||||
        order.quantity = amount;
 | 
			
		||||
        order.maxTotalPriceCentNet = apiArticle.pricePerUnitNet * amount;
 | 
			
		||||
 | 
			
		||||
        OrderConfirmation confirm = new SupplierService(offer.dbSupplier.apiUrl).order(order);
 | 
			
		||||
        SupplierOrder createdOrder = new SupplierOrder();
 | 
			
		||||
        createdOrder.created = new Timestamp(System.currentTimeMillis());
 | 
			
		||||
        createdOrder.supplier = offer.dbSupplier;
 | 
			
		||||
        createdOrder.ordered = articleOffer;
 | 
			
		||||
        createdOrder.numberOfUnits = confirm.quantity;
 | 
			
		||||
        createdOrder.pricePerUnitNetCent = confirm.pricePerUnitNetCent;
 | 
			
		||||
        createdOrder.totalPriceNet = confirm.totalPriceNetCharged;
 | 
			
		||||
        return createdOrder;
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
@ -0,0 +1,63 @@
 | 
			
		||||
package org.hso.ecommerce.action.cronjob;
 | 
			
		||||
 | 
			
		||||
import java.util.HashMap;
 | 
			
		||||
import java.util.List;
 | 
			
		||||
import java.util.Map.Entry;
 | 
			
		||||
 | 
			
		||||
import org.hso.ecommerce.action.cronjob.ReadSupplierDataAction.ArticleIdentifier;
 | 
			
		||||
import org.hso.ecommerce.action.cronjob.ReadSupplierDataAction.Offer;
 | 
			
		||||
import org.hso.ecommerce.api.data.Article;
 | 
			
		||||
import org.hso.ecommerce.entities.supplier.ArticleOffer;
 | 
			
		||||
 | 
			
		||||
public class UpdateOffersAction {
 | 
			
		||||
    private List<ArticleOffer> offers;
 | 
			
		||||
    private HashMap<ArticleIdentifier, Offer> cheapestOffer;
 | 
			
		||||
 | 
			
		||||
    public UpdateOffersAction(List<ArticleOffer> offers, HashMap<ArticleIdentifier, Offer> cheapestOffer) {
 | 
			
		||||
        this.offers = offers;
 | 
			
		||||
        this.cheapestOffer = cheapestOffer;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    private HashMap<ArticleIdentifier, ArticleOffer> mapOffers() {
 | 
			
		||||
        HashMap<ArticleIdentifier, ArticleOffer> map = new HashMap<>();
 | 
			
		||||
        for (ArticleOffer offer : offers) {
 | 
			
		||||
            ArticleIdentifier identifier = new ArticleIdentifier(offer.manufacturer, offer.articleNumber);
 | 
			
		||||
            map.put(identifier, offer);
 | 
			
		||||
        }
 | 
			
		||||
        return map;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public List<ArticleOffer> finish() {
 | 
			
		||||
        HashMap<ArticleIdentifier, ArticleOffer> availableOffers = mapOffers();
 | 
			
		||||
 | 
			
		||||
        // Reset all advertise-flags and supplier relations first. They are set again below.
 | 
			
		||||
        for (ArticleOffer offer : availableOffers.values()) {
 | 
			
		||||
            offer.shouldBeAdvertised = false;
 | 
			
		||||
            offer.cheapestSupplier = null;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        for (Entry<ArticleIdentifier, Offer> cheapestOffer : cheapestOffer.entrySet()) {
 | 
			
		||||
            String manufacturer = cheapestOffer.getKey().manufacturer;
 | 
			
		||||
            String articleNumber = cheapestOffer.getKey().articleNumber;
 | 
			
		||||
            ArticleOffer currentOffer = availableOffers.get(cheapestOffer.getKey());
 | 
			
		||||
            if (currentOffer == null) {
 | 
			
		||||
                currentOffer = new ArticleOffer();
 | 
			
		||||
                currentOffer.manufacturer = manufacturer;
 | 
			
		||||
                currentOffer.articleNumber = articleNumber;
 | 
			
		||||
                offers.add(currentOffer);
 | 
			
		||||
            }
 | 
			
		||||
            Article currentOfferedArticle = cheapestOffer.getValue().apiSupplier.findArticle(manufacturer,
 | 
			
		||||
                    articleNumber);
 | 
			
		||||
            currentOffer.title = currentOfferedArticle.title;
 | 
			
		||||
            currentOffer.vatPercent = currentOfferedArticle.vatPercent;
 | 
			
		||||
            currentOffer.cheapestSupplier = cheapestOffer.getValue().dbSupplier;
 | 
			
		||||
            currentOffer.pricePerUnitNet = currentOfferedArticle.pricePerUnitNet;
 | 
			
		||||
 | 
			
		||||
            // Set advertise-flag if any supplier wants it to be set
 | 
			
		||||
            if (currentOfferedArticle.shouldBeAdvertised) {
 | 
			
		||||
                currentOffer.shouldBeAdvertised = true;
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
        return offers;
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
@ -0,0 +1,201 @@
 | 
			
		||||
package org.hso.ecommerce.action.shop;
 | 
			
		||||
 | 
			
		||||
import org.hso.ecommerce.action.booking.CreateBookingAction;
 | 
			
		||||
import org.hso.ecommerce.entities.booking.*;
 | 
			
		||||
import org.hso.ecommerce.entities.shop.Address;
 | 
			
		||||
import org.hso.ecommerce.entities.shop.Article;
 | 
			
		||||
import org.hso.ecommerce.entities.shop.CustomerOrder;
 | 
			
		||||
import org.hso.ecommerce.entities.shop.CustomerOrderPosition;
 | 
			
		||||
import org.hso.ecommerce.entities.user.User;
 | 
			
		||||
import org.hso.ecommerce.entities.warehouse.WarehouseBooking;
 | 
			
		||||
import org.hso.ecommerce.entities.warehouse.WarehouseBookingPosition;
 | 
			
		||||
import org.hso.ecommerce.entities.warehouse.WarehouseBookingPositionSlotEntry;
 | 
			
		||||
 | 
			
		||||
import java.sql.Timestamp;
 | 
			
		||||
import java.util.ArrayList;
 | 
			
		||||
import java.util.Date;
 | 
			
		||||
import java.util.List;
 | 
			
		||||
 | 
			
		||||
public class CreateOrderAction {
 | 
			
		||||
 | 
			
		||||
    private User user;
 | 
			
		||||
    Address destination;
 | 
			
		||||
 | 
			
		||||
    private int expectedTotalGrossCent;
 | 
			
		||||
 | 
			
		||||
    private int totalNetCent;
 | 
			
		||||
    private int totalVatCent;
 | 
			
		||||
    private PaymentMethod method;
 | 
			
		||||
 | 
			
		||||
    private BookingAccountEntry latestUserBooking;
 | 
			
		||||
    private BookingAccountEntry latestVatBooking;
 | 
			
		||||
    private BookingAccountEntry latestMainBooking;
 | 
			
		||||
 | 
			
		||||
    private List<OrderItem> orderItems = new ArrayList<>();
 | 
			
		||||
 | 
			
		||||
    public CreateOrderAction(
 | 
			
		||||
            User user,
 | 
			
		||||
            int expectedTotalGrossCent,
 | 
			
		||||
            Address destination,
 | 
			
		||||
            PaymentMethod method,
 | 
			
		||||
            BookingAccountEntry latestUserBooking,
 | 
			
		||||
            BookingAccountEntry latestVatBooking,
 | 
			
		||||
            BookingAccountEntry latestMainBooking
 | 
			
		||||
    ) {
 | 
			
		||||
        this.user = user;
 | 
			
		||||
        this.expectedTotalGrossCent = expectedTotalGrossCent;
 | 
			
		||||
        this.destination = destination;
 | 
			
		||||
        this.method = method;
 | 
			
		||||
 | 
			
		||||
        this.latestUserBooking = latestUserBooking;
 | 
			
		||||
        assert latestUserBooking.userAccount.id == user.id;
 | 
			
		||||
 | 
			
		||||
        this.latestVatBooking = latestVatBooking;
 | 
			
		||||
        assert latestVatBooking.isVATAccount;
 | 
			
		||||
 | 
			
		||||
        this.latestMainBooking = latestMainBooking;
 | 
			
		||||
        assert latestMainBooking.isMainAccount;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public void addArticle(Article article, int quantity, List<WarehouseBookingPositionSlotEntry> availableSlots) {
 | 
			
		||||
        for (WarehouseBookingPositionSlotEntry slot : availableSlots) {
 | 
			
		||||
            assert slot.article.id == article.id;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        orderItems.add(new OrderItem(article, availableSlots, quantity));
 | 
			
		||||
 | 
			
		||||
        totalNetCent += article.shopPricePerUnitNetCent * quantity;
 | 
			
		||||
        totalVatCent += article.getVat() * quantity;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
    public Result finish() throws ArticleNotInStockException {
 | 
			
		||||
        CustomerOrder order = createOrder();
 | 
			
		||||
        CustomerPayment payment = createPayment();
 | 
			
		||||
 | 
			
		||||
        List<Booking> bookingList = new ArrayList<>();
 | 
			
		||||
        Booking purchaseBooking = new CreateBookingAction(
 | 
			
		||||
                latestUserBooking, latestMainBooking, new BookingReason(order), order.totalGrossCent).finish();
 | 
			
		||||
        Booking paymentBooking = new CreateBookingAction(
 | 
			
		||||
                null, purchaseBooking.source /* userAccount */, new BookingReason(payment), order.totalGrossCent).finish();
 | 
			
		||||
        Booking vatBooking = new CreateBookingAction(
 | 
			
		||||
                purchaseBooking.destination /* mainAccount */, latestVatBooking, new BookingReason(order), order.totalVatCent).finish();
 | 
			
		||||
        bookingList.add(purchaseBooking);
 | 
			
		||||
        bookingList.add(paymentBooking);
 | 
			
		||||
        bookingList.add(vatBooking);
 | 
			
		||||
 | 
			
		||||
        WarehouseBooking warehouseBooking = createWarehouseBooking(order);
 | 
			
		||||
 | 
			
		||||
        return new Result(
 | 
			
		||||
                order,
 | 
			
		||||
                warehouseBooking,
 | 
			
		||||
                bookingList
 | 
			
		||||
        );
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    private WarehouseBooking createWarehouseBooking(CustomerOrder order) throws ArticleNotInStockException {
 | 
			
		||||
        WarehouseBooking booking = new WarehouseBooking();
 | 
			
		||||
        booking.created = new Timestamp(new Date().getTime());
 | 
			
		||||
        booking.reason = new BookingReason(order);
 | 
			
		||||
 | 
			
		||||
        for (OrderItem item : orderItems) {
 | 
			
		||||
            int needed = item.quantity;
 | 
			
		||||
 | 
			
		||||
            for (WarehouseBookingPositionSlotEntry slot : item.availableSlots) {
 | 
			
		||||
                int remove = Math.min(slot.newSumSlot, needed);
 | 
			
		||||
                needed -= remove;
 | 
			
		||||
 | 
			
		||||
                WarehouseBookingPosition bookingPosition = new WarehouseBookingPosition();
 | 
			
		||||
 | 
			
		||||
                bookingPosition.article = item.article;
 | 
			
		||||
                bookingPosition.amount = -remove;
 | 
			
		||||
                bookingPosition.slotEntry = slot.copyAddAmount(-remove, item.article);
 | 
			
		||||
                bookingPosition.booking = booking;
 | 
			
		||||
 | 
			
		||||
                booking.positions.add(bookingPosition);
 | 
			
		||||
 | 
			
		||||
                if (needed == 0) {
 | 
			
		||||
                    break;
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            if (needed > 0) {
 | 
			
		||||
                throw new ArticleNotInStockException(item.article);
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        return booking;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    private CustomerPayment createPayment() {
 | 
			
		||||
        CustomerPayment payment = new CustomerPayment();
 | 
			
		||||
        payment.amountCent = totalNetCent + totalVatCent;
 | 
			
		||||
        payment.payment = method;
 | 
			
		||||
        return payment;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
    private CustomerOrder createOrder() {
 | 
			
		||||
        assert totalNetCent + totalVatCent == expectedTotalGrossCent;
 | 
			
		||||
 | 
			
		||||
        CustomerOrder customerOrder = new CustomerOrder();
 | 
			
		||||
        customerOrder.customer = user;
 | 
			
		||||
        customerOrder.destination = destination;
 | 
			
		||||
 | 
			
		||||
        for (OrderItem item : orderItems) {
 | 
			
		||||
            CustomerOrderPosition position = new CustomerOrderPosition();
 | 
			
		||||
            position.article = item.article;
 | 
			
		||||
            position.pricePerUnit = item.article.shopPricePerUnitNetCent;
 | 
			
		||||
            position.quantity = item.quantity;
 | 
			
		||||
 | 
			
		||||
            position.order = customerOrder;
 | 
			
		||||
 | 
			
		||||
            customerOrder.positions.add(position);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        customerOrder.created = new Timestamp(new Date().getTime());
 | 
			
		||||
 | 
			
		||||
        customerOrder.totalNetCent = totalNetCent;
 | 
			
		||||
        customerOrder.totalVatCent = totalVatCent;
 | 
			
		||||
        customerOrder.totalGrossCent = totalNetCent + totalVatCent;
 | 
			
		||||
 | 
			
		||||
        return customerOrder;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public static class Result {
 | 
			
		||||
        public final CustomerOrder customerOrder;
 | 
			
		||||
        public final WarehouseBooking warehouseBooking;
 | 
			
		||||
        public final List<Booking> bookings;
 | 
			
		||||
 | 
			
		||||
        Result(CustomerOrder customerOrder, WarehouseBooking warehouseBooking, List<Booking> bookings) {
 | 
			
		||||
            this.customerOrder = customerOrder;
 | 
			
		||||
            this.warehouseBooking = warehouseBooking;
 | 
			
		||||
            this.bookings = bookings;
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    private static class OrderItem {
 | 
			
		||||
        List<WarehouseBookingPositionSlotEntry> availableSlots;
 | 
			
		||||
        int quantity;
 | 
			
		||||
        Article article;
 | 
			
		||||
 | 
			
		||||
        public OrderItem(Article article, List<WarehouseBookingPositionSlotEntry> availableSlots, int quantity) {
 | 
			
		||||
            this.article = article;
 | 
			
		||||
            this.availableSlots = availableSlots;
 | 
			
		||||
            this.quantity = quantity;
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public static class ArticleNotInStockException extends Exception {
 | 
			
		||||
        private Article article;
 | 
			
		||||
 | 
			
		||||
        public ArticleNotInStockException(Article article) {
 | 
			
		||||
            super("The quantity of article '" + article.title + "' is not in stock.");
 | 
			
		||||
            this.article = article;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        public Article getArticle() {
 | 
			
		||||
            return article;
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
@ -0,0 +1,11 @@
 | 
			
		||||
package org.hso.ecommerce.action.shop;
 | 
			
		||||
 | 
			
		||||
import org.hso.ecommerce.entities.shop.CustomerOrder;
 | 
			
		||||
 | 
			
		||||
public class EnableTrackingAction {
 | 
			
		||||
 | 
			
		||||
    public static void addTrackingInfo(CustomerOrder customerOrder) {
 | 
			
		||||
        // TODO:
 | 
			
		||||
        customerOrder.trackingId = "555-NASE";
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
@ -0,0 +1,19 @@
 | 
			
		||||
package org.hso.ecommerce.action.shop;
 | 
			
		||||
 | 
			
		||||
import org.hso.ecommerce.entities.shop.Article;
 | 
			
		||||
 | 
			
		||||
import java.util.ArrayList;
 | 
			
		||||
import java.util.List;
 | 
			
		||||
 | 
			
		||||
public class GetRandomArticlesAction {
 | 
			
		||||
 | 
			
		||||
    public static List<Article> getRandomArticles(int quantity, List<Article> advertisedArticles) {
 | 
			
		||||
        List<Article> randomisedArticles = new ArrayList<Article>();
 | 
			
		||||
        int loopcount = Math.min(quantity, advertisedArticles.size());
 | 
			
		||||
        for (int i = 0; i < loopcount; i++) {
 | 
			
		||||
            int index = (int) (Math.random() * advertisedArticles.size());
 | 
			
		||||
            randomisedArticles.add(advertisedArticles.remove(index));
 | 
			
		||||
        }
 | 
			
		||||
        return randomisedArticles;
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
@ -0,0 +1,40 @@
 | 
			
		||||
package org.hso.ecommerce.action.shop;
 | 
			
		||||
 | 
			
		||||
import org.hso.ecommerce.entities.shop.Article;
 | 
			
		||||
import org.hso.ecommerce.repos.shop.ArticleRepository;
 | 
			
		||||
import org.springframework.beans.factory.annotation.Autowired;
 | 
			
		||||
 | 
			
		||||
import java.util.ArrayList;
 | 
			
		||||
import java.util.Arrays;
 | 
			
		||||
import java.util.List;
 | 
			
		||||
 | 
			
		||||
public class SearchByTermAction {
 | 
			
		||||
 | 
			
		||||
    public static List<Article> searchByTerm(String sourceTerm, ArticleRepository repository) {
 | 
			
		||||
 | 
			
		||||
        List<String> terms = Arrays.asList(sourceTerm.split(" "));
 | 
			
		||||
        List<Article> resultArticles = new ArrayList<>();
 | 
			
		||||
 | 
			
		||||
        terms.forEach(term -> {
 | 
			
		||||
            List<Article> titleArticles = repository.getArticlesByTermInTitle(term); //search in Title
 | 
			
		||||
            titleArticles.forEach(article -> {
 | 
			
		||||
                if(!resultArticles.contains(article)){
 | 
			
		||||
                    resultArticles.add(article);
 | 
			
		||||
                }
 | 
			
		||||
            });
 | 
			
		||||
 | 
			
		||||
        });
 | 
			
		||||
 | 
			
		||||
        terms.forEach(term -> {
 | 
			
		||||
            List<Article> descArticles = repository.getArticlesByTermInDescription(term); //search by Term
 | 
			
		||||
            descArticles.forEach(article -> {
 | 
			
		||||
                if(!resultArticles.contains(article)){
 | 
			
		||||
                    resultArticles.add(article);
 | 
			
		||||
                }
 | 
			
		||||
            });
 | 
			
		||||
 | 
			
		||||
        });
 | 
			
		||||
 | 
			
		||||
        return resultArticles;
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
@ -1,7 +0,0 @@
 | 
			
		||||
package org.hso.ecommerce.action.somepackage;
 | 
			
		||||
 | 
			
		||||
public class DemoAction {
 | 
			
		||||
    // TODO: remove me.
 | 
			
		||||
    // mksubpackage
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
@ -0,0 +1,83 @@
 | 
			
		||||
package org.hso.ecommerce.action.user;
 | 
			
		||||
 | 
			
		||||
import org.hso.ecommerce.entities.booking.PaymentMethod;
 | 
			
		||||
import org.hso.ecommerce.entities.user.User;
 | 
			
		||||
import org.hso.ecommerce.repos.user.UserRepository;
 | 
			
		||||
 | 
			
		||||
public class UpdateUserSettingsAction {
 | 
			
		||||
 | 
			
		||||
    private User user;
 | 
			
		||||
    private UserRepository repository;
 | 
			
		||||
 | 
			
		||||
    public UpdateUserSettingsAction(User user, UserRepository repository) {
 | 
			
		||||
        this.user = user;
 | 
			
		||||
        this.repository = repository;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public UpdateResult updateEmail(String newMail) {
 | 
			
		||||
        UpdateResult result = new UpdateResult(false);
 | 
			
		||||
        if (!newMail.contains("@")) {
 | 
			
		||||
            result.errorString = "Ändern der Email-Addresse nicht möglich. Bitte versuchen Sie es erneut.";
 | 
			
		||||
        } else {
 | 
			
		||||
            this.user.email = newMail;
 | 
			
		||||
            this.repository.save(this.user);
 | 
			
		||||
            result.updated = true;
 | 
			
		||||
        }
 | 
			
		||||
        return result;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public UpdateResult updatePassword(String oldPassword, String password1, String password2) {
 | 
			
		||||
        UpdateResult result = new UpdateResult(false);
 | 
			
		||||
        if (this.user.validatePassword(oldPassword)) {
 | 
			
		||||
            if (password1.equals(password2)) {
 | 
			
		||||
                if (!password1.equals(oldPassword)) {
 | 
			
		||||
                    this.user.setPassword(password1);
 | 
			
		||||
                    this.repository.save(this.user);
 | 
			
		||||
                    result.updated = true;
 | 
			
		||||
                } else {
 | 
			
		||||
                    result.errorString = "Das neue Passwort entspricht dem alten Passwort.";
 | 
			
		||||
                }
 | 
			
		||||
            } else {
 | 
			
		||||
                result.errorString = "Die beiden neuen Passwörter stimmen nicht überein. Bitte versuchen Sie es erneut.";
 | 
			
		||||
            }
 | 
			
		||||
        } else {
 | 
			
		||||
            result.errorString = "Das eingegebene alte Passwort stimmt nicht mit dem momentan gespeicherten Passwort überein. Bitte versuchen Sie es erneut.";
 | 
			
		||||
        }
 | 
			
		||||
        return result;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public UpdateResult updateShippingInfo(String salutation, String name, String address) {
 | 
			
		||||
        this.user.salutation = salutation;
 | 
			
		||||
        this.user.name = name;
 | 
			
		||||
        this.user.defaultDeliveryAddress.addressString = address;
 | 
			
		||||
        this.repository.save(this.user);
 | 
			
		||||
        return new UpdateResult(true);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public UpdateResult updatePaymentInfo(String creditCardNumber) {
 | 
			
		||||
        UpdateResult result = new UpdateResult(false);
 | 
			
		||||
        if (creditCardNumber.matches("[0-9]+")) {
 | 
			
		||||
            this.user.defaultPayment = PaymentMethod.fromCreditCardNumber(creditCardNumber);
 | 
			
		||||
            this.repository.save(this.user);
 | 
			
		||||
            result.updated = true;
 | 
			
		||||
        } else {
 | 
			
		||||
            result.errorString = "Kreditkartennummer darf nur Zahlen enthalten. Bitte versuchen Sie es erneut.";
 | 
			
		||||
        }
 | 
			
		||||
        return result;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public class UpdateResult {
 | 
			
		||||
        public boolean updated;  //if true worked, if false not worked
 | 
			
		||||
        public String errorString;
 | 
			
		||||
 | 
			
		||||
        public UpdateResult(boolean updated, String errorString) {
 | 
			
		||||
            this.updated = updated;
 | 
			
		||||
            this.errorString = errorString;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        public UpdateResult(boolean updated) {
 | 
			
		||||
            this.updated = updated;
 | 
			
		||||
            this.errorString = "";
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
@ -0,0 +1,73 @@
 | 
			
		||||
package org.hso.ecommerce.action.warehouse;
 | 
			
		||||
 | 
			
		||||
import org.hso.ecommerce.entities.warehouse.WarehouseBookingPositionSlotEntry;
 | 
			
		||||
 | 
			
		||||
import java.util.HashSet;
 | 
			
		||||
import java.util.List;
 | 
			
		||||
 | 
			
		||||
public class CalculateWarehouseStatsAction {
 | 
			
		||||
 | 
			
		||||
    private List<WarehouseBookingPositionSlotEntry> entryList;
 | 
			
		||||
 | 
			
		||||
    public CalculateWarehouseStatsAction(List<WarehouseBookingPositionSlotEntry> everyCurrentEntry) {
 | 
			
		||||
        this.entryList = everyCurrentEntry;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public WarehouseStats finish() {
 | 
			
		||||
        int numArticles = calculateNumArticles();
 | 
			
		||||
        double efficiency = calculateEfficiency();
 | 
			
		||||
        double ratioUsedSlots = calculateRatioSlotsUsed();
 | 
			
		||||
 | 
			
		||||
        return new WarehouseStats(numArticles, efficiency, ratioUsedSlots);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    private double calculateRatioSlotsUsed() {
 | 
			
		||||
        int used = 0;
 | 
			
		||||
 | 
			
		||||
        for (WarehouseBookingPositionSlotEntry entry : entryList) {
 | 
			
		||||
            if (entry.newSumSlot > 0) {
 | 
			
		||||
                used++;
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        return ((double) used) / entryList.size();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    private double calculateEfficiency() {
 | 
			
		||||
        double e = 0;
 | 
			
		||||
 | 
			
		||||
        for (WarehouseBookingPositionSlotEntry entry : entryList) {
 | 
			
		||||
            if (entry.newSumSlot > 0) {
 | 
			
		||||
                e += entry.newSumSlot / (double) entry.article.warehouseUnitsPerSlot;
 | 
			
		||||
            } else {
 | 
			
		||||
                e += 0;
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        return e / entryList.size();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    private int calculateNumArticles() {
 | 
			
		||||
        HashSet<Long> articleIds = new HashSet<>();
 | 
			
		||||
 | 
			
		||||
        for (WarehouseBookingPositionSlotEntry entry : entryList) {
 | 
			
		||||
            if (entry.newSumSlot > 0) {
 | 
			
		||||
                articleIds.add(entry.article.id);
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        return articleIds.size();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    private static class WarehouseStats {
 | 
			
		||||
        public int numArticles;
 | 
			
		||||
        public double efficiency;
 | 
			
		||||
        public double ratioUsedSlots;
 | 
			
		||||
 | 
			
		||||
        WarehouseStats(int numArticles, double efficiency, double ratioUsedSlots) {
 | 
			
		||||
            this.numArticles = numArticles;
 | 
			
		||||
            this.efficiency = efficiency;
 | 
			
		||||
            this.ratioUsedSlots = ratioUsedSlots;
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
@ -0,0 +1,92 @@
 | 
			
		||||
package org.hso.ecommerce.action.warehouse;
 | 
			
		||||
 | 
			
		||||
import org.hso.ecommerce.entities.booking.BookingReason;
 | 
			
		||||
import org.hso.ecommerce.entities.shop.Article;
 | 
			
		||||
import org.hso.ecommerce.entities.warehouse.WarehouseBooking;
 | 
			
		||||
import org.hso.ecommerce.entities.warehouse.WarehouseBookingPosition;
 | 
			
		||||
import org.hso.ecommerce.entities.warehouse.WarehouseBookingPositionSlotEntry;
 | 
			
		||||
 | 
			
		||||
import java.sql.Timestamp;
 | 
			
		||||
import java.util.Date;
 | 
			
		||||
import java.util.Optional;
 | 
			
		||||
 | 
			
		||||
public class CreateManuelBookingAction {
 | 
			
		||||
 | 
			
		||||
    private Article article;
 | 
			
		||||
    private int amount;
 | 
			
		||||
    private Optional<WarehouseBookingPositionSlotEntry> source;
 | 
			
		||||
    private Optional<WarehouseBookingPositionSlotEntry> destination;
 | 
			
		||||
    private String reason;
 | 
			
		||||
 | 
			
		||||
    public CreateManuelBookingAction(Article article, int amount, Optional<WarehouseBookingPositionSlotEntry> source, Optional<WarehouseBookingPositionSlotEntry> destination, String reason) {
 | 
			
		||||
        this.article = article;
 | 
			
		||||
        this.amount = amount;
 | 
			
		||||
        this.source = source;
 | 
			
		||||
        this.destination = destination;
 | 
			
		||||
        this.reason = reason;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public WarehouseBooking finish() throws ArticleSlotConstraintFailedException {
 | 
			
		||||
        WarehouseBooking booking = new WarehouseBooking();
 | 
			
		||||
        booking.created = new Timestamp(new Date().getTime());
 | 
			
		||||
        booking.reason = new BookingReason(reason);
 | 
			
		||||
 | 
			
		||||
        if (source.isPresent()) {
 | 
			
		||||
 | 
			
		||||
            if (source.get().article.id != article.id) {
 | 
			
		||||
                throw new ArticleSlotConstraintArticleTypeFailedException();
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            WarehouseBookingPosition bookingPosition = new WarehouseBookingPosition();
 | 
			
		||||
            bookingPosition.booking = booking;
 | 
			
		||||
 | 
			
		||||
            bookingPosition.article = article;
 | 
			
		||||
            bookingPosition.amount = -amount;
 | 
			
		||||
            bookingPosition.slotEntry = source.get().copyAddAmount(-amount, article);
 | 
			
		||||
 | 
			
		||||
            if (bookingPosition.slotEntry.newSumSlot < 0 || bookingPosition.slotEntry.newSumSlot > article.warehouseUnitsPerSlot) {
 | 
			
		||||
                throw new ArticleSlotConstraintFailedException("The quantity of article can only be set in bounds.");
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            booking.positions.add(bookingPosition);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        if (destination.isPresent()) {
 | 
			
		||||
 | 
			
		||||
            if (destination.get().article.id != article.id && destination.get().newSumSlot > 0) {
 | 
			
		||||
                throw new ArticleSlotConstraintArticleTypeFailedException();
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            WarehouseBookingPosition bookingPosition = new WarehouseBookingPosition();
 | 
			
		||||
            bookingPosition.booking = booking;
 | 
			
		||||
 | 
			
		||||
            bookingPosition.article = article;
 | 
			
		||||
            bookingPosition.amount = amount;
 | 
			
		||||
            bookingPosition.slotEntry = destination.get().copyAddAmount(amount, article);
 | 
			
		||||
 | 
			
		||||
            if (bookingPosition.slotEntry.newSumSlot < 0 || bookingPosition.slotEntry.newSumSlot > article.warehouseUnitsPerSlot) {
 | 
			
		||||
                throw new ArticleSlotConstraintFailedException("The quantity of article can only be set in bounds.");
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            booking.positions.add(bookingPosition);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        return booking;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public static class ArticleSlotConstraintFailedException extends Exception {
 | 
			
		||||
        public ArticleSlotConstraintFailedException(String s) {
 | 
			
		||||
            super(s);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        public ArticleSlotConstraintFailedException() {
 | 
			
		||||
            super("The quantity of article can only be set in bounds.");
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public static class ArticleSlotConstraintArticleTypeFailedException extends ArticleSlotConstraintFailedException {
 | 
			
		||||
        public ArticleSlotConstraintArticleTypeFailedException() {
 | 
			
		||||
            super("The Article in the slot entry does not match.");
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
@ -0,0 +1,103 @@
 | 
			
		||||
package org.hso.ecommerce.action.warehouse;
 | 
			
		||||
 | 
			
		||||
import org.hso.ecommerce.entities.booking.BookingReason;
 | 
			
		||||
import org.hso.ecommerce.entities.shop.Article;
 | 
			
		||||
import org.hso.ecommerce.entities.supplier.SupplierOrder;
 | 
			
		||||
import org.hso.ecommerce.entities.warehouse.WarehouseBooking;
 | 
			
		||||
import org.hso.ecommerce.entities.warehouse.WarehouseBookingPosition;
 | 
			
		||||
import org.hso.ecommerce.entities.warehouse.WarehouseBookingPositionSlotEntry;
 | 
			
		||||
 | 
			
		||||
import java.sql.Timestamp;
 | 
			
		||||
import java.util.ArrayList;
 | 
			
		||||
import java.util.Date;
 | 
			
		||||
import java.util.List;
 | 
			
		||||
 | 
			
		||||
public class SupplierOrderArrivedAction {
 | 
			
		||||
 | 
			
		||||
    private final Article article;
 | 
			
		||||
    private final ArrayList<WarehouseBookingPositionSlotEntry> warehouseCandidates;
 | 
			
		||||
    private final SupplierOrder order;
 | 
			
		||||
 | 
			
		||||
    public SupplierOrderArrivedAction(List<WarehouseBookingPositionSlotEntry> warehouseCandidates, SupplierOrder order, Article article) {
 | 
			
		||||
        this.warehouseCandidates = new ArrayList<>(warehouseCandidates);
 | 
			
		||||
        this.order = order;
 | 
			
		||||
        this.article = article;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public Result finish() throws NoSpaceInWarehouseException {
 | 
			
		||||
        // Sort for most filled slot first;
 | 
			
		||||
        warehouseCandidates.sort((b, a) -> Integer.compare(a.newSumSlot, b.newSumSlot));
 | 
			
		||||
 | 
			
		||||
        int needed = order.numberOfUnits;
 | 
			
		||||
 | 
			
		||||
        WarehouseBooking booking = new WarehouseBooking();
 | 
			
		||||
        booking.created = new Timestamp(new Date().getTime());
 | 
			
		||||
        booking.reason = new BookingReason(order);
 | 
			
		||||
 | 
			
		||||
        for (WarehouseBookingPositionSlotEntry entry : warehouseCandidates) {
 | 
			
		||||
            int canBeAdded = article.warehouseUnitsPerSlot - entry.newSumSlot;
 | 
			
		||||
 | 
			
		||||
            if (canBeAdded == 0) {
 | 
			
		||||
                // this slot is full, skip
 | 
			
		||||
                continue;
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            int willBeAdded = Math.min(canBeAdded, needed);
 | 
			
		||||
            needed -= willBeAdded;
 | 
			
		||||
 | 
			
		||||
            WarehouseBookingPosition bookingPosition = new WarehouseBookingPosition();
 | 
			
		||||
 | 
			
		||||
            bookingPosition.article = article;
 | 
			
		||||
            bookingPosition.amount = willBeAdded;
 | 
			
		||||
            bookingPosition.slotEntry = entry.copyAddAmount(willBeAdded, article);
 | 
			
		||||
            bookingPosition.booking = booking;
 | 
			
		||||
 | 
			
		||||
            booking.positions.add(bookingPosition);
 | 
			
		||||
 | 
			
		||||
            if (needed == 0) {
 | 
			
		||||
                break;
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        if (needed > 0) {
 | 
			
		||||
            throw new NoSpaceInWarehouseException(article);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        order.delivered = new Timestamp(new Date().getTime());
 | 
			
		||||
        return new Result(order, booking);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public static class Result extends Exception {
 | 
			
		||||
 | 
			
		||||
        private final SupplierOrder order;
 | 
			
		||||
        private final WarehouseBooking booking;
 | 
			
		||||
 | 
			
		||||
        public Result(SupplierOrder order, WarehouseBooking booking) {
 | 
			
		||||
            this.order = order;
 | 
			
		||||
            this.booking = booking;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        public SupplierOrder getOrder() {
 | 
			
		||||
            return order;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        public WarehouseBooking getBooking() {
 | 
			
		||||
            return booking;
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
    public static class NoSpaceInWarehouseException extends Exception {
 | 
			
		||||
        private Article article;
 | 
			
		||||
 | 
			
		||||
        public NoSpaceInWarehouseException(Article article) {
 | 
			
		||||
            super("The quantity of article '" + article.title + "' does not fit in warehouse.");
 | 
			
		||||
            this.article = article;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        public Article getArticle() {
 | 
			
		||||
            return article;
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
@ -0,0 +1,27 @@
 | 
			
		||||
package org.hso.ecommerce.api;
 | 
			
		||||
 | 
			
		||||
import org.hso.ecommerce.api.data.Order;
 | 
			
		||||
import org.hso.ecommerce.api.data.OrderConfirmation;
 | 
			
		||||
import org.hso.ecommerce.api.data.Supplier;
 | 
			
		||||
import org.springframework.web.client.RestTemplate;
 | 
			
		||||
 | 
			
		||||
public class SupplierService {
 | 
			
		||||
 | 
			
		||||
    private final String url;
 | 
			
		||||
 | 
			
		||||
    public SupplierService(String url) {
 | 
			
		||||
        this.url = url;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public Supplier getSupplier() {
 | 
			
		||||
        RestTemplate restTemplate = new RestTemplate();
 | 
			
		||||
 | 
			
		||||
        return restTemplate.getForObject(url, Supplier.class);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public OrderConfirmation order(Order order) {
 | 
			
		||||
        RestTemplate restTemplate = new RestTemplate();
 | 
			
		||||
 | 
			
		||||
        return restTemplate.postForObject(url + "/order", order, OrderConfirmation.class);
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
@ -0,0 +1,11 @@
 | 
			
		||||
package org.hso.ecommerce.api.data;
 | 
			
		||||
 | 
			
		||||
public class Article {
 | 
			
		||||
    public String title;
 | 
			
		||||
    public String manufacturer;
 | 
			
		||||
    public String articleNumber;
 | 
			
		||||
 | 
			
		||||
    public int vatPercent;
 | 
			
		||||
    public int pricePerUnitNet;
 | 
			
		||||
    public boolean shouldBeAdvertised;
 | 
			
		||||
}
 | 
			
		||||
@ -0,0 +1,9 @@
 | 
			
		||||
package org.hso.ecommerce.api.data;
 | 
			
		||||
 | 
			
		||||
public class Order {
 | 
			
		||||
    public String manufacturer;
 | 
			
		||||
    public String articleNumber;
 | 
			
		||||
 | 
			
		||||
    public int quantity;
 | 
			
		||||
    public int maxTotalPriceCentNet;
 | 
			
		||||
}
 | 
			
		||||
@ -0,0 +1,12 @@
 | 
			
		||||
package org.hso.ecommerce.api.data;
 | 
			
		||||
 | 
			
		||||
public class OrderConfirmation {
 | 
			
		||||
    public String manufacturer;
 | 
			
		||||
    public String articleNumber;
 | 
			
		||||
 | 
			
		||||
    public int quantity;
 | 
			
		||||
 | 
			
		||||
    public int pricePerUnitNetCent;
 | 
			
		||||
    public int discountNetCent;
 | 
			
		||||
    public int totalPriceNetCharged;
 | 
			
		||||
}
 | 
			
		||||
@ -0,0 +1,21 @@
 | 
			
		||||
package org.hso.ecommerce.api.data;
 | 
			
		||||
 | 
			
		||||
import java.util.List;
 | 
			
		||||
 | 
			
		||||
public class Supplier {
 | 
			
		||||
 | 
			
		||||
    public String id;
 | 
			
		||||
    public String name;
 | 
			
		||||
    public SupplierDiscount discount;
 | 
			
		||||
    public List<Article> articles;
 | 
			
		||||
 | 
			
		||||
    public Article findArticle(String manufacturer, String articleNumber) {
 | 
			
		||||
        for (Article a : articles) {
 | 
			
		||||
            if (a.manufacturer.equals(manufacturer) && a.articleNumber.equals(articleNumber)) {
 | 
			
		||||
                return a;
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        return null;
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
@ -0,0 +1,6 @@
 | 
			
		||||
package org.hso.ecommerce.api.data;
 | 
			
		||||
 | 
			
		||||
public class SupplierDiscount {
 | 
			
		||||
    public int minimumDailySalesVolumeNetCent;
 | 
			
		||||
    public int percentDiscount;
 | 
			
		||||
}
 | 
			
		||||
@ -3,6 +3,7 @@ package org.hso.ecommerce.app;
 | 
			
		||||
import org.hso.ecommerce.components.ErrorDemoInterceptor;
 | 
			
		||||
import org.hso.ecommerce.components.InfoDemoInterceptor;
 | 
			
		||||
import org.hso.ecommerce.components.LoginIntercepter;
 | 
			
		||||
import org.hso.ecommerce.components.ShoppingCartInterceptor;
 | 
			
		||||
import org.springframework.context.annotation.Bean;
 | 
			
		||||
import org.springframework.context.annotation.Configuration;
 | 
			
		||||
import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
 | 
			
		||||
@ -23,5 +24,7 @@ public class Config implements WebMvcConfigurer {
 | 
			
		||||
        registry.addInterceptor(buildLoginIntercepter());
 | 
			
		||||
        registry.addInterceptor(new ErrorDemoInterceptor());
 | 
			
		||||
        registry.addInterceptor(new InfoDemoInterceptor());
 | 
			
		||||
        registry.addInterceptor(new ShoppingCartInterceptor());
 | 
			
		||||
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@ -1,15 +1,7 @@
 | 
			
		||||
package org.hso.ecommerce.app;
 | 
			
		||||
 | 
			
		||||
import org.hso.ecommerce.repos.user.UserRepository;
 | 
			
		||||
import org.hso.ecommerce.entities.user.User;
 | 
			
		||||
import org.springframework.beans.factory.annotation.Autowired;
 | 
			
		||||
import org.springframework.stereotype.Controller;
 | 
			
		||||
import org.springframework.web.bind.annotation.*;
 | 
			
		||||
 | 
			
		||||
import javax.servlet.http.HttpServletRequest;
 | 
			
		||||
import javax.servlet.http.HttpServletResponse;
 | 
			
		||||
import javax.servlet.http.HttpSession;
 | 
			
		||||
import java.util.Optional;
 | 
			
		||||
import org.springframework.web.bind.annotation.GetMapping;
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * TODO clean up this class
 | 
			
		||||
@ -17,260 +9,13 @@ import java.util.Optional;
 | 
			
		||||
@Controller
 | 
			
		||||
public class RequestController {
 | 
			
		||||
 | 
			
		||||
    @Autowired
 | 
			
		||||
    private final UserRepository userRepository = null;
 | 
			
		||||
	@GetMapping("/intern/customerOrders/")
 | 
			
		||||
	public String internCustomerOrder() {
 | 
			
		||||
		return "intern/customerOrders/index";
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
    static int notSoRandom = 0;
 | 
			
		||||
 | 
			
		||||
    @GetMapping("/")
 | 
			
		||||
    public String home() {
 | 
			
		||||
        return "redirect:/shop/";
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    @GetMapping("/login")
 | 
			
		||||
    public String login() {
 | 
			
		||||
        return "login";
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    @PostMapping("/login")
 | 
			
		||||
    public String loginPost(
 | 
			
		||||
            HttpServletRequest request,
 | 
			
		||||
            HttpServletResponse response,
 | 
			
		||||
            @RequestParam("username") String username,
 | 
			
		||||
            @RequestParam("password") String password,
 | 
			
		||||
            HttpSession session
 | 
			
		||||
    ) {
 | 
			
		||||
        String gto = (String) session.getAttribute("afterLogin");
 | 
			
		||||
 | 
			
		||||
        Optional<User> user = userRepository.findByEmail(username);
 | 
			
		||||
        if (user.isEmpty()) {
 | 
			
		||||
            request.setAttribute("error", "Email Adresse falsch.");
 | 
			
		||||
            response.setStatus(HttpServletResponse.SC_EXPECTATION_FAILED);
 | 
			
		||||
            return "login";
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        if (!user.get().validatePassword(password)) {
 | 
			
		||||
            request.setAttribute("error", "Passwort falsch.");
 | 
			
		||||
            response.setStatus(HttpServletResponse.SC_EXPECTATION_FAILED);
 | 
			
		||||
            return "login";
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        session.setAttribute("userId", user.get().getId());
 | 
			
		||||
 | 
			
		||||
        if (gto != null && gto.startsWith("/")) {
 | 
			
		||||
            return "redirect:" + gto;
 | 
			
		||||
        } else {
 | 
			
		||||
            return "redirect:/";
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    @PostMapping("/logout")
 | 
			
		||||
    public String logoutPost(HttpServletResponse response,
 | 
			
		||||
                             HttpSession session
 | 
			
		||||
    ) {
 | 
			
		||||
        session.removeAttribute("userId");
 | 
			
		||||
        return "redirect:/";
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    @GetMapping("/register")
 | 
			
		||||
    public String register() {
 | 
			
		||||
        return "register";
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    @PostMapping("/register")
 | 
			
		||||
    public String registerPost(
 | 
			
		||||
            @RequestParam("username") String username,
 | 
			
		||||
            @RequestParam("password") String password,
 | 
			
		||||
            @RequestParam("password2") String password2,
 | 
			
		||||
            @RequestParam("type") String type
 | 
			
		||||
    ) {
 | 
			
		||||
 | 
			
		||||
        return "redirect:/";
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    @GetMapping("/shop/")
 | 
			
		||||
    public String shop() {
 | 
			
		||||
        return "shop/index";
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    @GetMapping("/shop/search")
 | 
			
		||||
    public String shopSearch() {
 | 
			
		||||
        return "shop/search";
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    @GetMapping("/shop/checkout")
 | 
			
		||||
    public String shopCheckout(HttpSession session, HttpServletRequest request) {
 | 
			
		||||
        session.setAttribute("afterLogin", request.getRequestURI());
 | 
			
		||||
        return "shop/checkout";
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    @PostMapping("/shop/checkoutFinish")
 | 
			
		||||
    public String shopCheckoutFinish() {
 | 
			
		||||
        return "shop/checkoutFinish";
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    @GetMapping("/shop/checkoutFinish")
 | 
			
		||||
    public String shopCheckoutFinishGET() {
 | 
			
		||||
        return "shop/checkoutFinish";
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    @GetMapping("/shop/articles/{id}")
 | 
			
		||||
    public String shopArticlesById() {
 | 
			
		||||
        return "shop/articles/id";
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    @PostMapping("/shop/articles/{id}")
 | 
			
		||||
    public String shopArticlesByIdBuy(HttpSession session,
 | 
			
		||||
                                      @RequestAttribute(value = "user", required = false) User customer,
 | 
			
		||||
                                      @PathVariable("id") Integer id,
 | 
			
		||||
                                      @RequestParam("fastcheckout") Boolean fastcheckout
 | 
			
		||||
    ) {
 | 
			
		||||
        if (customer != null) {
 | 
			
		||||
            if (!fastcheckout) {
 | 
			
		||||
                return "shop/articles/post_add";
 | 
			
		||||
            } else {
 | 
			
		||||
                return "shop/checkout";
 | 
			
		||||
            }
 | 
			
		||||
        } else {
 | 
			
		||||
            session.setAttribute("afterLogin", "/shop/articles/" + id);
 | 
			
		||||
            return "redirect:/login";
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    @GetMapping("/about")
 | 
			
		||||
    public String about() {
 | 
			
		||||
        return "about";
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    @GetMapping("/terms")
 | 
			
		||||
    public String terms() {
 | 
			
		||||
        return "terms";
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    @GetMapping("/privacy")
 | 
			
		||||
    public String privacy() {
 | 
			
		||||
        return "privacy";
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
    @GetMapping("/intern/")
 | 
			
		||||
    public String intern() {
 | 
			
		||||
        return "intern/index";
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    @GetMapping("/intern/listedArticles/")
 | 
			
		||||
    public String internListedArticles() {
 | 
			
		||||
        return "intern/listedArticles/index";
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    @GetMapping("/intern/listedArticles/{id}")
 | 
			
		||||
    public String internListedArticlesId() {
 | 
			
		||||
        return "intern/listedArticles/id";
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
    @GetMapping("/intern/articles/")
 | 
			
		||||
    public String internArticles() {
 | 
			
		||||
        return "intern/articles/index";
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    @GetMapping("/intern/articles/{id}")
 | 
			
		||||
    public String internArticlesId() {
 | 
			
		||||
        return "intern/articles/id";
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    @GetMapping("/intern/customers/")
 | 
			
		||||
    public String internCustomers() {
 | 
			
		||||
        return "intern/customers/index";
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    @GetMapping("/intern/customers/{id}")
 | 
			
		||||
    public String internCustomersId() {
 | 
			
		||||
        return "intern/customers/id";
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    @GetMapping("/intern/customerOrders/")
 | 
			
		||||
    public String internCustomerOrder() {
 | 
			
		||||
        return "intern/customerOrders/index";
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    @GetMapping("/intern/customerOrders/{id}")
 | 
			
		||||
    public String internCustomerOrdersId() {
 | 
			
		||||
        return "intern/customerOrders/id";
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    @GetMapping("/intern/suppliers/")
 | 
			
		||||
    public String internSuppliers() {
 | 
			
		||||
        return "intern/suppliers/index";
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    @GetMapping("/intern/suppliers/{id}")
 | 
			
		||||
    public String internSuppliersId() {
 | 
			
		||||
        return "intern/suppliers/id";
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    @GetMapping("/intern/supplierOrders/")
 | 
			
		||||
    public String internSupplierOrders() {
 | 
			
		||||
        return "intern/supplierOrders/index";
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    @GetMapping("/intern/supplierOrders/{id}")
 | 
			
		||||
    public String internSupplierOrdersId() {
 | 
			
		||||
        return "intern/supplierOrders/id";
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    @GetMapping("/intern/accounting/")
 | 
			
		||||
    public String accounting() {
 | 
			
		||||
        return "intern/accounting/index";
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    @GetMapping("/intern/accounting/vat")
 | 
			
		||||
    public String accountingVat() {
 | 
			
		||||
        return "intern/accounting/vat";
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    @GetMapping("/intern/accounting/main")
 | 
			
		||||
    public String accountingIntern() {
 | 
			
		||||
        return "intern/accounting/main";
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    @GetMapping("/intern/accounting/addManual")
 | 
			
		||||
    public String accountingAddManual() {
 | 
			
		||||
        return "intern/accounting/addManual";
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    @GetMapping("/intern/warehouse/")
 | 
			
		||||
    public String accountingWarehouse() {
 | 
			
		||||
        return "intern/warehouse/index";
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    @GetMapping("/intern/warehouse/todo")
 | 
			
		||||
    public String accountingWarehouseTodo() {
 | 
			
		||||
        return "intern/warehouse/todo";
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    @GetMapping("/intern/warehouse/addManual")
 | 
			
		||||
    public String accountingWarehouseAddManual() {
 | 
			
		||||
        return "intern/warehouse/addManual";
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    @PostMapping("/intern/warehouse/progress/{id}")
 | 
			
		||||
    public String accountingWarehouseProgressIdPost(HttpServletResponse response) {
 | 
			
		||||
        if ((notSoRandom++) % 2 == 1) {
 | 
			
		||||
            return "redirect:/intern/warehouse/progress/450";
 | 
			
		||||
        } else {
 | 
			
		||||
            response.setStatus(409);
 | 
			
		||||
            return "intern/warehouse/error_progress_failed";
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    @GetMapping("/intern/warehouse/progress/{id}")
 | 
			
		||||
    public String accountingWarehouseProgressId() {
 | 
			
		||||
        return "intern/warehouse/id_progress";
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    @GetMapping("/intern/warehouse/slots/")
 | 
			
		||||
    public String accountingWarehouseSlots() {
 | 
			
		||||
        return "intern/warehouse/slots/index";
 | 
			
		||||
    }
 | 
			
		||||
	@GetMapping("/intern/customerOrders/{id}")
 | 
			
		||||
	public String internCustomerOrdersId() {
 | 
			
		||||
		return "intern/customerOrders/id";
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@ -1,36 +0,0 @@
 | 
			
		||||
package org.hso.ecommerce.app;
 | 
			
		||||
 | 
			
		||||
import org.springframework.stereotype.Controller;
 | 
			
		||||
import org.springframework.web.bind.annotation.GetMapping;
 | 
			
		||||
import org.springframework.web.bind.annotation.RequestMapping;
 | 
			
		||||
 | 
			
		||||
@Controller
 | 
			
		||||
@RequestMapping("user")
 | 
			
		||||
public class UserRequestController {
 | 
			
		||||
 | 
			
		||||
    @GetMapping("/")
 | 
			
		||||
    public String user() {
 | 
			
		||||
        return "redirect:/user/settings";
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    @GetMapping("/settings")
 | 
			
		||||
    public String userSettings() {
 | 
			
		||||
        return "user/settings";
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    @GetMapping("/orders/")
 | 
			
		||||
    public String userOrdeers() {
 | 
			
		||||
        return "user/orders/index";
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    @GetMapping("/bonuspoints")
 | 
			
		||||
    public String userBonuspoints() {
 | 
			
		||||
        return "user/bonuspoints";
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    @GetMapping("/notifications/")
 | 
			
		||||
    public String userNotifications() {
 | 
			
		||||
        return "user/notifications/index";
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@ -24,6 +24,7 @@ public class LoginIntercepter implements HandlerInterceptor {
 | 
			
		||||
 | 
			
		||||
        HttpSession session = request.getSession();
 | 
			
		||||
        Object userId = session.getAttribute("userId");
 | 
			
		||||
        Optional<User> user = null;
 | 
			
		||||
 | 
			
		||||
        if (request.getRequestURI().startsWith("/user/")) {
 | 
			
		||||
            System.out.println("USER");
 | 
			
		||||
@ -43,10 +44,24 @@ public class LoginIntercepter implements HandlerInterceptor {
 | 
			
		||||
                response.sendRedirect("/login");
 | 
			
		||||
                return false;
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            user = userRepository.findById((Long) userId);
 | 
			
		||||
 | 
			
		||||
            if(user.isPresent() && !user.get().isEmployee)
 | 
			
		||||
            {
 | 
			
		||||
                session.setAttribute("afterLogin", request.getRequestURI());
 | 
			
		||||
                response.sendRedirect("/");
 | 
			
		||||
                return false;
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        if (!request.getRequestURI().startsWith("/login")) {
 | 
			
		||||
            session.removeAttribute("afterLogin");
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        if (userId != null) {
 | 
			
		||||
            Optional<User> user = userRepository.findById((Long) userId);
 | 
			
		||||
            if (user == null)
 | 
			
		||||
                user = userRepository.findById((Long) userId);
 | 
			
		||||
            user.ifPresent(value -> request.setAttribute("user", value));
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@ -0,0 +1,43 @@
 | 
			
		||||
package org.hso.ecommerce.components;
 | 
			
		||||
 | 
			
		||||
import org.hso.ecommerce.entities.shop.ShoppingCart;
 | 
			
		||||
import org.springframework.web.servlet.HandlerInterceptor;
 | 
			
		||||
import org.springframework.web.servlet.ModelAndView;
 | 
			
		||||
 | 
			
		||||
import javax.servlet.http.HttpServletRequest;
 | 
			
		||||
import javax.servlet.http.HttpServletResponse;
 | 
			
		||||
import javax.servlet.http.HttpSession;
 | 
			
		||||
 | 
			
		||||
public class ShoppingCartInterceptor implements HandlerInterceptor {
 | 
			
		||||
 | 
			
		||||
    @Override
 | 
			
		||||
    public boolean preHandle(
 | 
			
		||||
            HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
 | 
			
		||||
 | 
			
		||||
        HttpSession session = request.getSession();
 | 
			
		||||
        Object shoppingCart = session.getAttribute("shoppingCart");
 | 
			
		||||
 | 
			
		||||
        if (shoppingCart == null) {
 | 
			
		||||
            shoppingCart = new ShoppingCart();
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        request.setAttribute("shoppingCart", shoppingCart);
 | 
			
		||||
 | 
			
		||||
        return true;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    @Override
 | 
			
		||||
    public void postHandle(
 | 
			
		||||
            HttpServletRequest request, HttpServletResponse response, Object handler,
 | 
			
		||||
            ModelAndView modelAndView) throws Exception {
 | 
			
		||||
 | 
			
		||||
        HttpSession session = request.getSession();
 | 
			
		||||
        Object shoppingCart = request.getAttribute("shoppingCart");
 | 
			
		||||
        session.setAttribute("shoppingCart", shoppingCart);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    @Override
 | 
			
		||||
    public void afterCompletion(HttpServletRequest request, HttpServletResponse response,
 | 
			
		||||
                                Object handler, Exception exception) throws Exception {
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
@ -0,0 +1,32 @@
 | 
			
		||||
package org.hso.ecommerce.components;
 | 
			
		||||
 | 
			
		||||
import org.hso.ecommerce.entities.warehouse.Slot;
 | 
			
		||||
import org.hso.ecommerce.repos.warehouse.SlotRepository;
 | 
			
		||||
import org.springframework.beans.factory.annotation.Autowired;
 | 
			
		||||
import org.springframework.stereotype.Component;
 | 
			
		||||
 | 
			
		||||
import javax.annotation.PostConstruct;
 | 
			
		||||
 | 
			
		||||
@Component
 | 
			
		||||
public class SlotInitializer {
 | 
			
		||||
 | 
			
		||||
    @Autowired
 | 
			
		||||
    private final SlotRepository slotRepository = null;
 | 
			
		||||
 | 
			
		||||
    // TODO: use values form cfg.
 | 
			
		||||
    private final int NUM_SLOTS = 50;
 | 
			
		||||
| 
					
	
	
	
	
	
	
	
	 | 
			||||
 | 
			
		||||
    @PostConstruct
 | 
			
		||||
    public void init() {
 | 
			
		||||
        for (int i = 1; i <= NUM_SLOTS; i++) {
 | 
			
		||||
            if (!slotRepository.findBySlotNum(i).isPresent()) {
 | 
			
		||||
                Slot slotAdded = new Slot();
 | 
			
		||||
                slotAdded.slotNum = i;
 | 
			
		||||
                slotRepository.save(slotAdded);
 | 
			
		||||
 | 
			
		||||
                System.out.println("Added Slot " + i + " to DB");
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
@ -1,8 +0,0 @@
 | 
			
		||||
package org.hso.ecommerce.controller;
 | 
			
		||||
 | 
			
		||||
import org.springframework.stereotype.Controller;
 | 
			
		||||
 | 
			
		||||
@Controller
 | 
			
		||||
//@RequestMapping("...")
 | 
			
		||||
public class BookingController {
 | 
			
		||||
}
 | 
			
		||||
@ -1,8 +1,69 @@
 | 
			
		||||
package org.hso.ecommerce.controller;
 | 
			
		||||
 | 
			
		||||
import java.util.Optional;
 | 
			
		||||
 | 
			
		||||
import javax.servlet.http.HttpServletRequest;
 | 
			
		||||
import javax.servlet.http.HttpServletResponse;
 | 
			
		||||
import javax.servlet.http.HttpSession;
 | 
			
		||||
 | 
			
		||||
import org.hso.ecommerce.entities.user.User;
 | 
			
		||||
import org.hso.ecommerce.repos.user.UserRepository;
 | 
			
		||||
import org.springframework.beans.factory.annotation.Autowired;
 | 
			
		||||
import org.springframework.stereotype.Controller;
 | 
			
		||||
import org.springframework.web.bind.annotation.GetMapping;
 | 
			
		||||
import org.springframework.web.bind.annotation.PostMapping;
 | 
			
		||||
import org.springframework.web.bind.annotation.RequestMapping;
 | 
			
		||||
import org.springframework.web.bind.annotation.RequestParam;
 | 
			
		||||
 | 
			
		||||
@Controller
 | 
			
		||||
//@RequestMapping("...")
 | 
			
		||||
@RequestMapping("/")
 | 
			
		||||
public class LoginController {
 | 
			
		||||
 | 
			
		||||
	@Autowired
 | 
			
		||||
	private final UserRepository userRepository = null;
 | 
			
		||||
 | 
			
		||||
	@GetMapping("login")
 | 
			
		||||
	public String login() {
 | 
			
		||||
		return "login";
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	@PostMapping("login")
 | 
			
		||||
	public String loginPost(HttpServletRequest request, HttpServletResponse response,
 | 
			
		||||
			@RequestParam("username") String username, @RequestParam("password") String password, HttpSession session) {
 | 
			
		||||
 | 
			
		||||
		String gto = (String) session.getAttribute("afterLogin");
 | 
			
		||||
 | 
			
		||||
		Optional<User> user = userRepository.findByEmail(username);
 | 
			
		||||
		if (!user.isPresent()) {
 | 
			
		||||
			request.setAttribute("error", "Die Email Adresse falsch.");
 | 
			
		||||
			response.setStatus(HttpServletResponse.SC_EXPECTATION_FAILED);
 | 
			
		||||
			return "login";
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		if (!user.get().validatePassword(password)) {
 | 
			
		||||
			request.setAttribute("error", "Das Passwort ist falsch.");
 | 
			
		||||
			response.setStatus(HttpServletResponse.SC_EXPECTATION_FAILED);
 | 
			
		||||
			return "login";
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		if (!user.get().isActive) {
 | 
			
		||||
			request.setAttribute("error", "Dieses Konto ist deaktiviert..");
 | 
			
		||||
			response.setStatus(HttpServletResponse.SC_EXPECTATION_FAILED);
 | 
			
		||||
			return "login";
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		session.setAttribute("userId", user.get().getId());
 | 
			
		||||
 | 
			
		||||
		if (gto != null && gto.startsWith("/")) {
 | 
			
		||||
			return "redirect:" + gto;
 | 
			
		||||
		} else {
 | 
			
		||||
			return "redirect:/";
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	@PostMapping("logout")
 | 
			
		||||
	public String logoutPost(HttpServletResponse response, HttpSession session) {
 | 
			
		||||
		session.removeAttribute("userId");
 | 
			
		||||
		return "redirect:/";
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@ -0,0 +1,82 @@
 | 
			
		||||
package org.hso.ecommerce.controller;
 | 
			
		||||
 | 
			
		||||
import org.hso.ecommerce.entities.booking.PaymentMethod;
 | 
			
		||||
import org.hso.ecommerce.entities.shop.Address;
 | 
			
		||||
import org.hso.ecommerce.entities.user.User;
 | 
			
		||||
import org.hso.ecommerce.repos.user.UserRepository;
 | 
			
		||||
import org.springframework.beans.factory.annotation.Autowired;
 | 
			
		||||
import org.springframework.stereotype.Controller;
 | 
			
		||||
import org.springframework.web.bind.annotation.GetMapping;
 | 
			
		||||
import org.springframework.web.bind.annotation.PostMapping;
 | 
			
		||||
import org.springframework.web.bind.annotation.RequestParam;
 | 
			
		||||
 | 
			
		||||
import javax.servlet.http.HttpServletRequest;
 | 
			
		||||
import javax.servlet.http.HttpServletResponse;
 | 
			
		||||
import javax.servlet.http.HttpSession;
 | 
			
		||||
import java.util.Optional;
 | 
			
		||||
 | 
			
		||||
@Controller
 | 
			
		||||
public class RegisterController {
 | 
			
		||||
 | 
			
		||||
	@Autowired
 | 
			
		||||
	private final UserRepository userRepository = null;
 | 
			
		||||
 | 
			
		||||
	@PostMapping("/register")
 | 
			
		||||
	public String registerPost(HttpServletRequest request, HttpServletResponse response,
 | 
			
		||||
			@RequestParam("username") String username, @RequestParam("password") String password,
 | 
			
		||||
			@RequestParam("password2") String password2, @RequestParam("salutation") String salutation,
 | 
			
		||||
			@RequestParam("name") String name, @RequestParam("address") String address,
 | 
			
		||||
			@RequestParam("type") String type, // TODO store
 | 
			
		||||
			@RequestParam("ad") String ad, // TODO store
 | 
			
		||||
			HttpSession session) {
 | 
			
		||||
		Optional<User> user = userRepository.findByEmail(username);
 | 
			
		||||
		if (user.isPresent()) {
 | 
			
		||||
			request.setAttribute("error", "Die Email Adresse existiert bereits.");
 | 
			
		||||
			response.setStatus(HttpServletResponse.SC_EXPECTATION_FAILED);
 | 
			
		||||
			return "register";
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		if (!password.equals(password2)) {
 | 
			
		||||
			request.setAttribute("error", "Die Passwörter stimmen nicht überein.");
 | 
			
		||||
			response.setStatus(HttpServletResponse.SC_BAD_REQUEST);
 | 
			
		||||
			return "register";
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		// set values for new user
 | 
			
		||||
		User newUser = new User();
 | 
			
		||||
		newUser.email = username;
 | 
			
		||||
		newUser.setPassword(password);
 | 
			
		||||
		newUser.email = username;
 | 
			
		||||
		newUser.isEmployee = false;
 | 
			
		||||
		newUser.salutation = salutation;
 | 
			
		||||
		newUser.defaultPayment = PaymentMethod.fromCreditCardNumber("");
 | 
			
		||||
 | 
			
		||||
		newUser.isActive = true;
 | 
			
		||||
		newUser.created = new java.sql.Timestamp(System.currentTimeMillis());
 | 
			
		||||
 | 
			
		||||
		Address newAddress = new Address();
 | 
			
		||||
		newAddress.name = name;
 | 
			
		||||
		newAddress.addressString = address;
 | 
			
		||||
		newUser.defaultDeliveryAddress = newAddress;
 | 
			
		||||
 | 
			
		||||
		userRepository.save(newUser); // save newUser
 | 
			
		||||
 | 
			
		||||
		user = userRepository.findByEmail(username);
 | 
			
		||||
		session.setAttribute("userId", user.get().getId());
 | 
			
		||||
 | 
			
		||||
		String gto = (String) session.getAttribute("afterLogin");
 | 
			
		||||
 | 
			
		||||
		//login after register
 | 
			
		||||
		if (gto != null && gto.startsWith("/")) {
 | 
			
		||||
			return "redirect:" + gto;	
 | 
			
		||||
		} else {
 | 
			
		||||
			return "redirect:/";
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	@GetMapping("/register")
 | 
			
		||||
	public String register() {
 | 
			
		||||
		return "register";
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
@ -1,8 +1,131 @@
 | 
			
		||||
package org.hso.ecommerce.controller;
 | 
			
		||||
 | 
			
		||||
import org.hso.ecommerce.action.user.UpdateUserSettingsAction;
 | 
			
		||||
import org.hso.ecommerce.entities.shop.Address;
 | 
			
		||||
import org.hso.ecommerce.entities.shop.CustomerOrder;
 | 
			
		||||
import org.hso.ecommerce.entities.user.User;
 | 
			
		||||
import org.hso.ecommerce.repos.shop.CustomerOrderRepository;
 | 
			
		||||
import org.hso.ecommerce.repos.user.UserRepository;
 | 
			
		||||
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.PostMapping;
 | 
			
		||||
import org.springframework.web.bind.annotation.RequestMapping;
 | 
			
		||||
import org.springframework.web.bind.annotation.RequestParam;
 | 
			
		||||
 | 
			
		||||
import javax.servlet.http.HttpServletRequest;
 | 
			
		||||
import javax.servlet.http.HttpSession;
 | 
			
		||||
import java.util.List;
 | 
			
		||||
 | 
			
		||||
@Controller
 | 
			
		||||
//@RequestMapping("...")
 | 
			
		||||
@RequestMapping("/user")
 | 
			
		||||
public class UserController {
 | 
			
		||||
 | 
			
		||||
    @Autowired
 | 
			
		||||
    private final UserRepository userRepository = null;
 | 
			
		||||
 | 
			
		||||
    @Autowired
 | 
			
		||||
    private final CustomerOrderRepository customerOrderRepository = null;
 | 
			
		||||
 | 
			
		||||
    @GetMapping("/")
 | 
			
		||||
    public String user() {
 | 
			
		||||
        return "redirect:/user/settings";
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    @GetMapping("/settings")
 | 
			
		||||
    public String userSettings(Model model,
 | 
			
		||||
                               HttpSession session
 | 
			
		||||
    ) {
 | 
			
		||||
        long userId = (long) session.getAttribute("userId");
 | 
			
		||||
        User user = userRepository.findById(userId).get();
 | 
			
		||||
        if(user.defaultDeliveryAddress == null){
 | 
			
		||||
            user.defaultDeliveryAddress = new Address();
 | 
			
		||||
        }
 | 
			
		||||
        model.addAttribute("user", user);
 | 
			
		||||
 | 
			
		||||
        return "user/settings";
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    @GetMapping("/orders/")
 | 
			
		||||
    public String userOrdeers(HttpSession session,
 | 
			
		||||
                              Model model
 | 
			
		||||
    ) {
 | 
			
		||||
        List<CustomerOrder> orders = customerOrderRepository.getOrdersByUserId((long) session.getAttribute("userId"));
 | 
			
		||||
        model.addAttribute("orders", orders);
 | 
			
		||||
 | 
			
		||||
        return "user/orders/index";
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    @PostMapping("/settings/changeMail")
 | 
			
		||||
    public String changeMail(HttpSession session,
 | 
			
		||||
                             @RequestParam("email") String email,
 | 
			
		||||
                             HttpServletRequest request
 | 
			
		||||
    ) {
 | 
			
		||||
        User user = userRepository.findById((long) session.getAttribute("userId")).get();
 | 
			
		||||
 | 
			
		||||
        UpdateUserSettingsAction cusa = new UpdateUserSettingsAction(user, userRepository);
 | 
			
		||||
        UpdateUserSettingsAction.UpdateResult result = cusa.updateEmail(email);
 | 
			
		||||
        if (result.updated == false) {
 | 
			
		||||
            request.setAttribute("error", result.errorString);
 | 
			
		||||
            return "user/settings";
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        return "redirect:/user/settings";
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    @PostMapping("/settings/changePwd")
 | 
			
		||||
    public String changePwd(HttpSession session,
 | 
			
		||||
                            @RequestParam("old-password") String oldPassword,
 | 
			
		||||
                            @RequestParam("password1") String password1,
 | 
			
		||||
                            @RequestParam("password2") String password2,
 | 
			
		||||
                            HttpServletRequest request
 | 
			
		||||
    ) {
 | 
			
		||||
        User user = userRepository.findById((long) session.getAttribute("userId")).get();
 | 
			
		||||
 | 
			
		||||
        UpdateUserSettingsAction cusa = new UpdateUserSettingsAction(user, userRepository);
 | 
			
		||||
        UpdateUserSettingsAction.UpdateResult result = cusa.updatePassword(oldPassword, password1, password2);
 | 
			
		||||
        if (result.updated == false) {
 | 
			
		||||
            request.setAttribute("error", result.errorString);
 | 
			
		||||
            return "user/settings";
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        return "redirect:/user/settings";
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    @PostMapping("/settings/changeAddress")
 | 
			
		||||
    public String changeAddress(HttpSession session,
 | 
			
		||||
                                @RequestParam("salutation") String salutation,
 | 
			
		||||
                                @RequestParam("name") String name,
 | 
			
		||||
                                @RequestParam("address") String address,
 | 
			
		||||
                                HttpServletRequest request
 | 
			
		||||
    ) {
 | 
			
		||||
        User user = userRepository.findById((long) session.getAttribute("userId")).get();
 | 
			
		||||
 | 
			
		||||
        UpdateUserSettingsAction cusa = new UpdateUserSettingsAction(user, userRepository);
 | 
			
		||||
        UpdateUserSettingsAction.UpdateResult result = cusa.updateShippingInfo(salutation, name, address);
 | 
			
		||||
        if (result.updated == false) {
 | 
			
		||||
            request.setAttribute("error", result.errorString);
 | 
			
		||||
            return "user/settings";
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        return "redirect:/user/settings";
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    @PostMapping("/settings/changePaymentInfo")
 | 
			
		||||
    public String changePaymentInfo(HttpSession session,
 | 
			
		||||
                                    @RequestParam("creditCardNumber") String creditCardNumber,
 | 
			
		||||
                                    HttpServletRequest request
 | 
			
		||||
    ) {
 | 
			
		||||
        User user = userRepository.findById((long) session.getAttribute("userId")).get();
 | 
			
		||||
 | 
			
		||||
        UpdateUserSettingsAction cusa = new UpdateUserSettingsAction(user, userRepository);
 | 
			
		||||
        UpdateUserSettingsAction.UpdateResult result = cusa.updatePaymentInfo(creditCardNumber);
 | 
			
		||||
        if (result.updated == false) {
 | 
			
		||||
            request.setAttribute("error", result.errorString);
 | 
			
		||||
            return "user/settings";
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        return "redirect:/user/settings";
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@ -0,0 +1,331 @@
 | 
			
		||||
package org.hso.ecommerce.controller.cronjob;
 | 
			
		||||
 | 
			
		||||
import java.sql.Timestamp;
 | 
			
		||||
import java.util.Calendar;
 | 
			
		||||
import java.util.Collections;
 | 
			
		||||
import java.util.GregorianCalendar;
 | 
			
		||||
import java.util.HashMap;
 | 
			
		||||
import java.util.List;
 | 
			
		||||
import java.util.Map;
 | 
			
		||||
import java.util.Map.Entry;
 | 
			
		||||
 | 
			
		||||
import javax.annotation.PostConstruct;
 | 
			
		||||
 | 
			
		||||
import org.hso.ecommerce.action.booking.CreateBookingAction;
 | 
			
		||||
import org.hso.ecommerce.action.cronjob.ReadSupplierDataAction;
 | 
			
		||||
import org.hso.ecommerce.action.cronjob.ReadSupplierDataAction.ArticleIdentifier;
 | 
			
		||||
import org.hso.ecommerce.action.cronjob.ReorderAction;
 | 
			
		||||
import org.hso.ecommerce.action.cronjob.UpdateOffersAction;
 | 
			
		||||
import org.hso.ecommerce.entities.booking.Booking;
 | 
			
		||||
import org.hso.ecommerce.entities.booking.BookingAccountEntry;
 | 
			
		||||
import org.hso.ecommerce.entities.booking.BookingReason;
 | 
			
		||||
import org.hso.ecommerce.entities.cron.BackgroundJob;
 | 
			
		||||
import org.hso.ecommerce.entities.shop.Article;
 | 
			
		||||
import org.hso.ecommerce.entities.supplier.ArticleOffer;
 | 
			
		||||
import org.hso.ecommerce.entities.supplier.Supplier;
 | 
			
		||||
import org.hso.ecommerce.entities.supplier.SupplierOrder;
 | 
			
		||||
import org.hso.ecommerce.repos.booking.BookingAccountEntryRepository;
 | 
			
		||||
import org.hso.ecommerce.repos.booking.BookingRepository;
 | 
			
		||||
import org.hso.ecommerce.repos.cronjob.BackgroundJobRepository;
 | 
			
		||||
import org.hso.ecommerce.repos.shop.ArticleRepository;
 | 
			
		||||
import org.hso.ecommerce.repos.shop.CustomerOrderRepository;
 | 
			
		||||
import org.hso.ecommerce.repos.supplier.ArticleOfferRepository;
 | 
			
		||||
import org.hso.ecommerce.repos.supplier.SupplierOrderRepository;
 | 
			
		||||
import org.hso.ecommerce.repos.supplier.SupplierRepository;
 | 
			
		||||
import org.hso.ecommerce.repos.warehouse.WarehouseBookingPositionSlotEntryRepository;
 | 
			
		||||
import org.slf4j.Logger;
 | 
			
		||||
import org.slf4j.LoggerFactory;
 | 
			
		||||
import org.springframework.beans.factory.annotation.Autowired;
 | 
			
		||||
import org.springframework.stereotype.Component;
 | 
			
		||||
 | 
			
		||||
interface ICronjob {
 | 
			
		||||
    /**
 | 
			
		||||
     * Calculate the earliest cronjob execution time that happens after the given reference time.
 | 
			
		||||
     *
 | 
			
		||||
     * @param reference Position in time to start searching. The implementor is allowed to modify the reference time.
 | 
			
		||||
     * @return A new Calendar instance (or the same) containing the time for next execution.
 | 
			
		||||
     */
 | 
			
		||||
    Calendar nextExecution(Calendar reference);
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Calculate the latest cronjob execution time that happens before or exactly at the given refernce time.
 | 
			
		||||
     *
 | 
			
		||||
     * @param reference Position in time to start searching. The implementor is allowed to modify the reference time.
 | 
			
		||||
     * @return A new Calendar instance (or the same) containing the time of the last execution.
 | 
			
		||||
     */
 | 
			
		||||
    Calendar previousExecution(Calendar reference);
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Execute this cronjob.
 | 
			
		||||
     *
 | 
			
		||||
     * @param time       The point in time this execution was scheduled. In case of a missed cronjob, the actual time of
 | 
			
		||||
     *                   this call might be much later.
 | 
			
		||||
     * @param controller Back-reference that allows to use repositories.
 | 
			
		||||
     */
 | 
			
		||||
    void executeAt(Calendar time, CronjobController controller);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@Component
 | 
			
		||||
class Reorder implements ICronjob {
 | 
			
		||||
    @Override
 | 
			
		||||
    public Calendar nextExecution(Calendar reference) {
 | 
			
		||||
        if (reference.get(Calendar.HOUR_OF_DAY) >= 8) {
 | 
			
		||||
            reference.add(Calendar.DAY_OF_MONTH, 1);
 | 
			
		||||
        }
 | 
			
		||||
        reference.set(Calendar.HOUR_OF_DAY, 8);
 | 
			
		||||
        reference.set(Calendar.MINUTE, 0);
 | 
			
		||||
        reference.set(Calendar.SECOND, 0);
 | 
			
		||||
        reference.set(Calendar.MILLISECOND, 0);
 | 
			
		||||
        return reference;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    @Override
 | 
			
		||||
    public Calendar previousExecution(Calendar reference) {
 | 
			
		||||
        if (reference.get(Calendar.HOUR_OF_DAY) < 8) {
 | 
			
		||||
            reference.add(Calendar.DAY_OF_MONTH, -1);
 | 
			
		||||
        }
 | 
			
		||||
        reference.set(Calendar.HOUR_OF_DAY, 8);
 | 
			
		||||
        reference.set(Calendar.MINUTE, 0);
 | 
			
		||||
        reference.set(Calendar.SECOND, 0);
 | 
			
		||||
        reference.set(Calendar.MILLISECOND, 0);
 | 
			
		||||
        return reference;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Calculates the amount of ordered articles by customers for the given article type in the time between begin and
 | 
			
		||||
     * end.
 | 
			
		||||
     *
 | 
			
		||||
     * @param article The article to search orders for.
 | 
			
		||||
     * @param begin   The start time for the search (included)
 | 
			
		||||
     * @param end     The end time for the search (excluded)
 | 
			
		||||
     * @return The number of articles that were ordered by customers in the given range.
 | 
			
		||||
     */
 | 
			
		||||
    private Integer getOrderedAmounts(Article article, Calendar begin, Calendar end, CronjobController controller) {
 | 
			
		||||
        return controller.customerOrderRepository.countOrdersOfArticleInTimespan(
 | 
			
		||||
                article.id,
 | 
			
		||||
                new Timestamp(begin.getTimeInMillis()), new Timestamp(end.getTimeInMillis()));
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Calculates the amount of ordered articles by customers for the given article type in the three days before the
 | 
			
		||||
     * given reference time. The return-array contains 3 fields: Index 0: Orders 72 to 48 hours ago; Index 1: Orders 48
 | 
			
		||||
     * to 24 hours ago; Index 2: Orders 24 to 0 hours ago.
 | 
			
		||||
     *
 | 
			
		||||
     * @param article The article for which the customer orders are checked.
 | 
			
		||||
     * @param time    The reference time to use for calculation of the last orders.
 | 
			
		||||
     * @return A 3-element array containing the orders of the last three days.
 | 
			
		||||
     */
 | 
			
		||||
    private Integer[] getOrderedAmounts(Article article, Calendar time, CronjobController controller) {
 | 
			
		||||
        Calendar oneDayBefore = (Calendar) time.clone();
 | 
			
		||||
        oneDayBefore.add(Calendar.DAY_OF_MONTH, -1);
 | 
			
		||||
        Calendar twoDaysBefore = (Calendar) time.clone();
 | 
			
		||||
        twoDaysBefore.add(Calendar.DAY_OF_MONTH, -2);
 | 
			
		||||
        Calendar threeDaysBefore = (Calendar) time.clone();
 | 
			
		||||
        threeDaysBefore.add(Calendar.DAY_OF_MONTH, -3);
 | 
			
		||||
 | 
			
		||||
        return new Integer[] { //
 | 
			
		||||
                getOrderedAmounts(article, threeDaysBefore, twoDaysBefore, controller), //
 | 
			
		||||
                getOrderedAmounts(article, twoDaysBefore, oneDayBefore, controller), //
 | 
			
		||||
                getOrderedAmounts(article, oneDayBefore, time, controller), //
 | 
			
		||||
        };
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    private HashMap<ArticleIdentifier, ArticleOffer> mapArticleOffers(List<ArticleOffer> articleOffers) {
 | 
			
		||||
        HashMap<ArticleIdentifier, ArticleOffer> map = new HashMap<>();
 | 
			
		||||
        for (ArticleOffer articleOffer : articleOffers) {
 | 
			
		||||
            ArticleIdentifier identifier = new ArticleIdentifier(articleOffer.manufacturer, articleOffer.articleNumber);
 | 
			
		||||
            map.put(identifier, articleOffer);
 | 
			
		||||
        }
 | 
			
		||||
        return map;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    @Override
 | 
			
		||||
    public void executeAt(Calendar time, CronjobController controller) {
 | 
			
		||||
        List<Supplier> suppliers = controller.supplierRepository.findAll();
 | 
			
		||||
        ReadSupplierDataAction.Result supplierData = new ReadSupplierDataAction(suppliers).finish();
 | 
			
		||||
 | 
			
		||||
        // Save the new offers in the database
 | 
			
		||||
        List<ArticleOffer> allOffers = controller.articleOfferRepository.findAll();
 | 
			
		||||
        allOffers = new UpdateOffersAction(allOffers, supplierData.cheapestOffer).finish();
 | 
			
		||||
        controller.articleOfferRepository.saveAll(allOffers);
 | 
			
		||||
 | 
			
		||||
        HashMap<ArticleIdentifier, ArticleOffer> mappedOffers = mapArticleOffers(allOffers);
 | 
			
		||||
 | 
			
		||||
        // Reorder
 | 
			
		||||
        List<Article> allArticles = controller.articleRepository.findAll();
 | 
			
		||||
        for (Article article : allArticles) {
 | 
			
		||||
            Integer[] orderedAmounts = getOrderedAmounts(article, time, controller);
 | 
			
		||||
 | 
			
		||||
            Integer undeliveredReorders = controller.supplierOrderRepository
 | 
			
		||||
                    .countUndeliveredReorders(article.related.articleNumber);
 | 
			
		||||
 | 
			
		||||
            int amountInStock = controller.warehouseBookingPositionSlotEntryRepository.getArticleStock(article.id)
 | 
			
		||||
                    .orElse(0);
 | 
			
		||||
 | 
			
		||||
            ReorderAction action = new ReorderAction(article, orderedAmounts,
 | 
			
		||||
                    undeliveredReorders,
 | 
			
		||||
                    amountInStock,
 | 
			
		||||
                    supplierData.cheapestOffer, mappedOffers);
 | 
			
		||||
            SupplierOrder order = action.finish();
 | 
			
		||||
            if (order != null) {
 | 
			
		||||
                controller.supplierOrderRepository.save(order);
 | 
			
		||||
 | 
			
		||||
                // Create bookings for this order
 | 
			
		||||
                int netPrice = order.totalPriceNet;
 | 
			
		||||
                int vatPercent = order.ordered.vatPercent;
 | 
			
		||||
                int vatAmount = netPrice * vatPercent / 100;
 | 
			
		||||
                int grossPrice = netPrice + vatAmount;
 | 
			
		||||
 | 
			
		||||
                // Obligation towards the supplier
 | 
			
		||||
                BookingAccountEntry mainAccount = controller.bookingAccountEntryRepository.getByMain()
 | 
			
		||||
                        .orElseGet(BookingAccountEntry::newMain);
 | 
			
		||||
                BookingAccountEntry supplierAccount = controller.bookingAccountEntryRepository
 | 
			
		||||
                        .getBySupplier(order.supplier.id)
 | 
			
		||||
                        .orElseGet(() -> BookingAccountEntry.newSupplier(order.supplier));
 | 
			
		||||
                BookingReason obligationReason = new BookingReason(order);
 | 
			
		||||
                Booking obligationBooking = new CreateBookingAction(mainAccount,
 | 
			
		||||
                        supplierAccount,
 | 
			
		||||
                        obligationReason,
 | 
			
		||||
                        grossPrice).finish();
 | 
			
		||||
                controller.bookingRepository.save(obligationBooking);
 | 
			
		||||
 | 
			
		||||
                // Input Tax
 | 
			
		||||
                BookingAccountEntry vatAccount = controller.bookingAccountEntryRepository.getByVat()
 | 
			
		||||
                        .orElseGet(BookingAccountEntry::newVat);
 | 
			
		||||
                mainAccount = controller.bookingAccountEntryRepository.getByMain().get();
 | 
			
		||||
                BookingReason inputTaxReason = new BookingReason(order);
 | 
			
		||||
                Booking inputTaxBooking = new CreateBookingAction(vatAccount, mainAccount, inputTaxReason, vatAmount)
 | 
			
		||||
                        .finish();
 | 
			
		||||
                controller.bookingRepository.save(inputTaxBooking);
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
class ScheduledCronjob {
 | 
			
		||||
    public final Calendar executionTime;
 | 
			
		||||
    public final ICronjob cronjob;
 | 
			
		||||
    public final BackgroundJob model;
 | 
			
		||||
 | 
			
		||||
    public ScheduledCronjob(Calendar executionTime, ICronjob cronjob, BackgroundJob model) {
 | 
			
		||||
        this.executionTime = executionTime;
 | 
			
		||||
        this.cronjob = cronjob;
 | 
			
		||||
        this.model = model;
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@Component
 | 
			
		||||
class CronjobController {
 | 
			
		||||
    private static final Logger log = LoggerFactory.getLogger(CronjobController.class);
 | 
			
		||||
 | 
			
		||||
    private static final Map<String, ICronjob> cronjobs = getCronjobs();
 | 
			
		||||
 | 
			
		||||
    @Autowired
 | 
			
		||||
    private final BackgroundJobRepository cronjobRepository = null;
 | 
			
		||||
 | 
			
		||||
    @Autowired
 | 
			
		||||
    final ArticleRepository articleRepository = null;
 | 
			
		||||
 | 
			
		||||
    @Autowired
 | 
			
		||||
    final ArticleOfferRepository articleOfferRepository = null;
 | 
			
		||||
 | 
			
		||||
    @Autowired
 | 
			
		||||
    final CustomerOrderRepository customerOrderRepository = null;
 | 
			
		||||
 | 
			
		||||
    @Autowired
 | 
			
		||||
    final BookingRepository bookingRepository = null;
 | 
			
		||||
 | 
			
		||||
    @Autowired
 | 
			
		||||
    final BookingAccountEntryRepository bookingAccountEntryRepository = null;
 | 
			
		||||
 | 
			
		||||
    @Autowired
 | 
			
		||||
    final WarehouseBookingPositionSlotEntryRepository warehouseBookingPositionSlotEntryRepository = null;
 | 
			
		||||
 | 
			
		||||
    @Autowired
 | 
			
		||||
    final SupplierRepository supplierRepository = null;
 | 
			
		||||
 | 
			
		||||
    @Autowired
 | 
			
		||||
    final SupplierOrderRepository supplierOrderRepository = null;
 | 
			
		||||
 | 
			
		||||
    private static Map<String, ICronjob> getCronjobs() {
 | 
			
		||||
        HashMap<String, ICronjob> map = new HashMap<>();
 | 
			
		||||
 | 
			
		||||
        // Register all existing cronjobs
 | 
			
		||||
        map.put(BackgroundJob.JOB_REORDER, new Reorder());
 | 
			
		||||
 | 
			
		||||
        return Collections.unmodifiableMap(map);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    private ScheduledCronjob getNextCronjob() {
 | 
			
		||||
        Calendar currentTime = new GregorianCalendar();
 | 
			
		||||
        Iterable<BackgroundJob> jobs = cronjobRepository.findAll();
 | 
			
		||||
        HashMap<String, BackgroundJob> alreadyExecuted = new HashMap<>();
 | 
			
		||||
        for (BackgroundJob job : jobs) {
 | 
			
		||||
            alreadyExecuted.put(job.jobName, job);
 | 
			
		||||
        }
 | 
			
		||||
        ScheduledCronjob earliestJob = null;
 | 
			
		||||
        for (Entry<String, ICronjob> entry : cronjobs.entrySet()) {
 | 
			
		||||
            ScheduledCronjob resultingJob;
 | 
			
		||||
            BackgroundJob dbEntry = alreadyExecuted.get(entry.getKey());
 | 
			
		||||
            if (dbEntry != null) {
 | 
			
		||||
                Calendar previousExecution = new GregorianCalendar();
 | 
			
		||||
                previousExecution.setTimeInMillis(dbEntry.lastExecution.getTime());
 | 
			
		||||
                Calendar followingSchedule = entry.getValue().nextExecution((Calendar) previousExecution.clone());
 | 
			
		||||
                Calendar lastSchedule = entry.getValue().previousExecution((Calendar) currentTime.clone());
 | 
			
		||||
                if (lastSchedule.getTimeInMillis() > followingSchedule.getTimeInMillis()) {
 | 
			
		||||
                    // This happens, if more than one execution was missed.
 | 
			
		||||
                    // In this case, run the job only once.
 | 
			
		||||
                    followingSchedule = lastSchedule;
 | 
			
		||||
                }
 | 
			
		||||
                resultingJob = new ScheduledCronjob(followingSchedule, entry.getValue(), dbEntry);
 | 
			
		||||
            } else {
 | 
			
		||||
                // This cronjob has never been executed before.
 | 
			
		||||
                Calendar lastScheduleTime = entry.getValue().previousExecution((Calendar) currentTime.clone());
 | 
			
		||||
                BackgroundJob model = new BackgroundJob();
 | 
			
		||||
                model.jobName = entry.getKey();
 | 
			
		||||
                resultingJob = new ScheduledCronjob(lastScheduleTime, entry.getValue(), model);
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            // Look for the job with earliest executionTime - it will run next
 | 
			
		||||
            if (earliestJob == null
 | 
			
		||||
                    || resultingJob.executionTime.getTimeInMillis() < earliestJob.executionTime.getTimeInMillis()) {
 | 
			
		||||
                earliestJob = resultingJob;
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
        return earliestJob;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    private void runCronjobExecutionLoop() {
 | 
			
		||||
        Thread.currentThread().setName("Cronjob");
 | 
			
		||||
        try {
 | 
			
		||||
            while (true) {
 | 
			
		||||
                ScheduledCronjob nextJob = getNextCronjob();
 | 
			
		||||
                if (nextJob == null) {
 | 
			
		||||
                    // In case there are no cronjobs
 | 
			
		||||
                    return;
 | 
			
		||||
                }
 | 
			
		||||
                long waitingTime = nextJob.executionTime.getTimeInMillis() - System.currentTimeMillis();
 | 
			
		||||
                if (waitingTime > 0) {
 | 
			
		||||
                    Thread.sleep(waitingTime);
 | 
			
		||||
                }
 | 
			
		||||
 | 
			
		||||
                try {
 | 
			
		||||
                    nextJob.cronjob.executeAt(nextJob.executionTime, this);
 | 
			
		||||
                } catch (Throwable t) {
 | 
			
		||||
                    log.error("Failed to execute cronjob " + nextJob.cronjob.getClass() + ":");
 | 
			
		||||
                    t.printStackTrace();
 | 
			
		||||
                }
 | 
			
		||||
 | 
			
		||||
                nextJob.model.lastExecution = new Timestamp(nextJob.executionTime.getTimeInMillis());
 | 
			
		||||
                cronjobRepository.save(nextJob.model);
 | 
			
		||||
            }
 | 
			
		||||
        } catch (InterruptedException e) {
 | 
			
		||||
            log.error("The cronjob execution thread has been interrupted");
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    @PostConstruct
 | 
			
		||||
    public void onPostConstruct() {
 | 
			
		||||
        new Thread(this::runCronjobExecutionLoop).start();
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
@ -1,8 +1,272 @@
 | 
			
		||||
package org.hso.ecommerce.controller.intern;
 | 
			
		||||
 | 
			
		||||
import org.hso.ecommerce.entities.shop.Article;
 | 
			
		||||
import org.hso.ecommerce.entities.shop.Category;
 | 
			
		||||
import org.hso.ecommerce.entities.shop.Image;
 | 
			
		||||
import org.hso.ecommerce.entities.supplier.ArticleOffer;
 | 
			
		||||
import org.hso.ecommerce.repos.shop.ArticleRepository;
 | 
			
		||||
import org.hso.ecommerce.repos.shop.CategoryRepository;
 | 
			
		||||
import org.hso.ecommerce.repos.shop.ImageRepository;
 | 
			
		||||
import org.hso.ecommerce.repos.shop.OffersRepository;
 | 
			
		||||
import org.hso.ecommerce.repos.warehouse.WarehouseBookingPositionSlotEntryRepository;
 | 
			
		||||
import org.springframework.beans.factory.annotation.Autowired;
 | 
			
		||||
import org.springframework.stereotype.Controller;
 | 
			
		||||
import org.springframework.ui.Model;
 | 
			
		||||
import org.springframework.util.DigestUtils;
 | 
			
		||||
import org.springframework.web.bind.annotation.*;
 | 
			
		||||
import org.springframework.web.multipart.MultipartFile;
 | 
			
		||||
import org.springframework.web.servlet.view.RedirectView;
 | 
			
		||||
 | 
			
		||||
import javax.imageio.ImageIO;
 | 
			
		||||
import java.awt.image.BufferedImage;
 | 
			
		||||
import java.io.File;
 | 
			
		||||
import java.io.IOException;
 | 
			
		||||
import java.nio.file.Files;
 | 
			
		||||
import java.nio.file.Paths;
 | 
			
		||||
import java.util.ArrayList;
 | 
			
		||||
import java.util.List;
 | 
			
		||||
import java.util.Optional;
 | 
			
		||||
 | 
			
		||||
@Controller
 | 
			
		||||
//@RequestMapping("...")
 | 
			
		||||
@RequestMapping("intern/articles")
 | 
			
		||||
public class InternArticleController {
 | 
			
		||||
	@Autowired
 | 
			
		||||
	private final ArticleRepository articleRepository = null;
 | 
			
		||||
 | 
			
		||||
	@Autowired
 | 
			
		||||
	private final WarehouseBookingPositionSlotEntryRepository warehouseEntryRepository = null;
 | 
			
		||||
 | 
			
		||||
	@Autowired
 | 
			
		||||
	private final CategoryRepository categoryRepository = null;
 | 
			
		||||
 | 
			
		||||
	@Autowired
 | 
			
		||||
	private final OffersRepository offersRepository = null;
 | 
			
		||||
 | 
			
		||||
	@Autowired
 | 
			
		||||
	private final ImageRepository imageRepository = null;
 | 
			
		||||
 | 
			
		||||
	@GetMapping("/")
 | 
			
		||||
	public String internListedArticles(Model model) {
 | 
			
		||||
 | 
			
		||||
		List<UImodelArticles> totals = new ArrayList<UImodelArticles>();
 | 
			
		||||
 | 
			
		||||
		for (Article article : articleRepository.findAll()) {
 | 
			
		||||
			UImodelArticles tmp = new UImodelArticles();
 | 
			
		||||
			tmp.addListedArticle(article, warehouseEntryRepository.getArticleStock(article.id).orElse(0));
 | 
			
		||||
			totals.add(tmp);
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		model.addAttribute("ListedArticles", totals);
 | 
			
		||||
		return "intern/listedArticles/index";
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	@GetMapping("/{id}")
 | 
			
		||||
	public String internListedArticlesId(Model model, @PathVariable String id) {
 | 
			
		||||
		int articleid = Integer.parseInt(id);
 | 
			
		||||
		UImodelArticle total = new UImodelArticle();
 | 
			
		||||
		total.addArticle(articleRepository.findArticleById(articleid),
 | 
			
		||||
				warehouseEntryRepository.getArticleStock(articleid).orElse(0));
 | 
			
		||||
 | 
			
		||||
		model.addAttribute("ArticleID", total);
 | 
			
		||||
		return "intern/listedArticles/id";
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	@PostMapping("/{id}/saveChanges")
 | 
			
		||||
	public RedirectView saveChanges(@PathVariable(required = true) int id,
 | 
			
		||||
			@RequestParam(value = "title", required = true) String title,
 | 
			
		||||
			@RequestParam(value = "description", required = true) String description,
 | 
			
		||||
			@RequestParam(value = "units-per-slot", required = true) String warehouseUnitsPerSlot,
 | 
			
		||||
			@RequestParam(value = "priceNet", required = true) String pricenetto,
 | 
			
		||||
			@RequestParam(value = "reorderMaxPrice", required = true) String reorderMaxPrice,
 | 
			
		||||
			@RequestParam(value = "autobuy", required = true) Boolean shouldReorder,
 | 
			
		||||
			@RequestParam(value = "categorie", required = true) String categories,
 | 
			
		||||
			@RequestParam(value = "img", required = true) MultipartFile imgFile) {
 | 
			
		||||
 | 
			
		||||
		Article tmpArticle = articleRepository.findArticleById(id); // get the old article
 | 
			
		||||
 | 
			
		||||
		String[] separatedCategories = categories.split("\n");
 | 
			
		||||
 | 
			
		||||
		tmpArticle.categories.clear();
 | 
			
		||||
 | 
			
		||||
		// loop through all categories strings and create a new category if a new one;
 | 
			
		||||
		// also adds the categories to the article
 | 
			
		||||
		for (String category : separatedCategories) {
 | 
			
		||||
			tmpArticle.categories.add(categoryRepository.findCategoryByName(category.trim())
 | 
			
		||||
					.orElseGet(() -> new Category(category.trim())));
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		tmpArticle.shouldReorder = shouldReorder;
 | 
			
		||||
		tmpArticle.reorderMaxPrice = (int) (Float.parseFloat(reorderMaxPrice) * 100);
 | 
			
		||||
		tmpArticle.shopPricePerUnitNetCent = (int) (Float.parseFloat(pricenetto) * 100);
 | 
			
		||||
		tmpArticle.warehouseUnitsPerSlot = Integer.parseInt(warehouseUnitsPerSlot);
 | 
			
		||||
		tmpArticle.title = title;
 | 
			
		||||
		updateImage(tmpArticle, imgFile);
 | 
			
		||||
		tmpArticle.description = description;
 | 
			
		||||
 | 
			
		||||
		articleRepository.save(tmpArticle); // save updated article
 | 
			
		||||
		return new RedirectView("../"); // return to overview page
 | 
			
		||||
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	@PostMapping("/addArticle/{id}")
 | 
			
		||||
	public RedirectView addArticle(@PathVariable(required = true) String id) {
 | 
			
		||||
		// article is not already listed, create new one
 | 
			
		||||
		int offeredArticleID = Integer.parseInt(id);
 | 
			
		||||
 | 
			
		||||
		Article tmpArticle = new Article();
 | 
			
		||||
 | 
			
		||||
		ArticleOffer offeredArticle = offersRepository.findOfferedArticleById(offeredArticleID);
 | 
			
		||||
 | 
			
		||||
		// set default values
 | 
			
		||||
		tmpArticle.description = "";
 | 
			
		||||
		tmpArticle.reorderMaxPrice = 0;
 | 
			
		||||
		tmpArticle.shopPricePerUnitNetCent = offeredArticle.pricePerUnitNet;
 | 
			
		||||
		tmpArticle.shouldReorder = false;
 | 
			
		||||
		tmpArticle.title = offeredArticle.title;
 | 
			
		||||
		tmpArticle.warehouseUnitsPerSlot = 1;
 | 
			
		||||
		setDefaultImage(tmpArticle);
 | 
			
		||||
		tmpArticle.related = offeredArticle;
 | 
			
		||||
		articleRepository.save(tmpArticle); // save new article
 | 
			
		||||
 | 
			
		||||
		// return to edit article page
 | 
			
		||||
		return new RedirectView("../" + articleRepository.findArticleIDByRelatedID(offeredArticleID).get());
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	private void setDefaultImage(Article article) {
 | 
			
		||||
		String defaultImagePath = "./data/img/no_product_img.jpg"; // path + name of default img
 | 
			
		||||
		Optional<Integer> imageID = imageRepository.findImageIDByPath(defaultImagePath); // get default img
 | 
			
		||||
 | 
			
		||||
		if (imageID.isPresent()) {
 | 
			
		||||
			// default img is in DB
 | 
			
		||||
			article.image = imageRepository.findImageById(imageID.get()); // set default img to new article
 | 
			
		||||
		} else {
 | 
			
		||||
			// default img is not in DB
 | 
			
		||||
			File tmpFile = new File(defaultImagePath);
 | 
			
		||||
			// test if default img file exits
 | 
			
		||||
			if (!tmpFile.exists()) {
 | 
			
		||||
				// fallback if the file not exists
 | 
			
		||||
				// create new file
 | 
			
		||||
				BufferedImage bufferedImage = new BufferedImage(422, 428, BufferedImage.TYPE_INT_RGB);
 | 
			
		||||
				try {
 | 
			
		||||
					ImageIO.write(bufferedImage, "jpg", new File(defaultImagePath)); // save new file on disk
 | 
			
		||||
				} catch (IOException e) {
 | 
			
		||||
					e.printStackTrace();
 | 
			
		||||
				}
 | 
			
		||||
			}
 | 
			
		||||
			Image defaultImage = new Image();
 | 
			
		||||
			defaultImage.path = defaultImagePath; // set new file to default img
 | 
			
		||||
			imageRepository.save(defaultImage); // save default img
 | 
			
		||||
			article.image = defaultImage; // set default img to new article
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	private void updateImage(Article article, MultipartFile imgFile) {
 | 
			
		||||
		// check if a file is present
 | 
			
		||||
		if (imgFile.getSize() > 0) {
 | 
			
		||||
			try {
 | 
			
		||||
				// get file name based on MD5 hash
 | 
			
		||||
				String fileName = DigestUtils.md5DigestAsHex(imgFile.getBytes()) + ".jpg";
 | 
			
		||||
				// check if img is already in system
 | 
			
		||||
				Optional<Integer> imageID = imageRepository.findImageIDByPath("./data/img/" + fileName);
 | 
			
		||||
				if (imageID.isPresent()) {
 | 
			
		||||
					article.image = imageRepository.findImageById(imageID.get()); // add existing img to article
 | 
			
		||||
				} else {
 | 
			
		||||
					// write new img file to disk
 | 
			
		||||
					Files.newOutputStream(Paths.get("./data/img/", fileName)).write(imgFile.getBytes());
 | 
			
		||||
					// create new img
 | 
			
		||||
					Image newImage = new Image();
 | 
			
		||||
					newImage.path = "./data/img/" + fileName; // set new file to new img
 | 
			
		||||
					imageRepository.save(newImage); // save new img
 | 
			
		||||
					article.image = newImage; // set new img to article
 | 
			
		||||
				}
 | 
			
		||||
			} catch (Exception e) {
 | 
			
		||||
				setDefaultImage(article); // if upload failed, reset to default img
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	public static class UImodelArticles {
 | 
			
		||||
 | 
			
		||||
		public String imgPath;
 | 
			
		||||
		public String title;
 | 
			
		||||
		public String price;
 | 
			
		||||
		public String priceNet;
 | 
			
		||||
		public String categorie;
 | 
			
		||||
		public int stock;
 | 
			
		||||
		public long offerID;
 | 
			
		||||
		public long id;
 | 
			
		||||
 | 
			
		||||
		void addListedArticle(Article article, int stock) {
 | 
			
		||||
 | 
			
		||||
			if (article.image != null) {
 | 
			
		||||
				this.imgPath = article.image.path;
 | 
			
		||||
			}
 | 
			
		||||
			this.title = article.title;
 | 
			
		||||
			this.priceNet = String.format("%.2f", ((float) article.shopPricePerUnitNetCent / 100));
 | 
			
		||||
			this.price = String.format("%.2f", ((float) article.getPriceGross() / 100));
 | 
			
		||||
 | 
			
		||||
			StringBuilder result = new StringBuilder();
 | 
			
		||||
 | 
			
		||||
			for (Category temp : article.categories) {
 | 
			
		||||
				result.append(temp.name + " ");
 | 
			
		||||
			}
 | 
			
		||||
			this.categorie = result.toString();
 | 
			
		||||
 | 
			
		||||
			this.stock = stock;
 | 
			
		||||
			this.offerID = article.related.id;
 | 
			
		||||
			this.id = article.id;
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	public static class UImodelArticle {
 | 
			
		||||
 | 
			
		||||
		public String imgPath;
 | 
			
		||||
		public String title;
 | 
			
		||||
		public String price;
 | 
			
		||||
		public String priceNet;
 | 
			
		||||
		public String reorderMaxPrice;
 | 
			
		||||
		public String categorie;
 | 
			
		||||
		public int stock;
 | 
			
		||||
		public long offerID;
 | 
			
		||||
		public long id;
 | 
			
		||||
		public boolean shouldReorder;
 | 
			
		||||
		public String warehouseUnitsPerSlot;
 | 
			
		||||
		public String description;
 | 
			
		||||
		public int vatPercent;
 | 
			
		||||
 | 
			
		||||
		public String getCategorie() {
 | 
			
		||||
			return categorie;
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		public String getDescription() {
 | 
			
		||||
			return description;
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		void addArticle(Article article, int stock) {
 | 
			
		||||
			if (article.image != null) {
 | 
			
		||||
				this.imgPath = article.image.path;
 | 
			
		||||
			}
 | 
			
		||||
			this.title = article.title;
 | 
			
		||||
			this.priceNet = String.format("%.2f", ((float) article.shopPricePerUnitNetCent / 100));
 | 
			
		||||
			this.price = String.format("%.2f", ((float) article.getPriceGross() / 100));
 | 
			
		||||
 | 
			
		||||
			StringBuilder result = new StringBuilder();
 | 
			
		||||
 | 
			
		||||
			for (Category temp : article.categories) {
 | 
			
		||||
				result.append(temp.name);
 | 
			
		||||
				result.append("\n");
 | 
			
		||||
			}
 | 
			
		||||
			this.categorie = result.toString();
 | 
			
		||||
 | 
			
		||||
			this.stock = stock;
 | 
			
		||||
			this.offerID = article.related.id;
 | 
			
		||||
			this.id = article.id;
 | 
			
		||||
			this.reorderMaxPrice = String.format("%.2f", ((float) article.reorderMaxPrice / 100));
 | 
			
		||||
			this.shouldReorder = article.shouldReorder;
 | 
			
		||||
			this.warehouseUnitsPerSlot = String.valueOf(article.warehouseUnitsPerSlot);
 | 
			
		||||
			this.description = article.description;
 | 
			
		||||
			this.vatPercent = article.related.vatPercent;
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@ -1,8 +1,34 @@
 | 
			
		||||
package org.hso.ecommerce.controller.intern;
 | 
			
		||||
 | 
			
		||||
import java.util.Optional;
 | 
			
		||||
 | 
			
		||||
import org.hso.ecommerce.controller.intern.accounting.AccountingController;
 | 
			
		||||
import org.hso.ecommerce.entities.booking.BookingAccountEntry;
 | 
			
		||||
import org.hso.ecommerce.repos.booking.BookingAccountEntryRepository;
 | 
			
		||||
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;
 | 
			
		||||
 | 
			
		||||
@Controller
 | 
			
		||||
//@RequestMapping("...")
 | 
			
		||||
@RequestMapping("/intern")
 | 
			
		||||
public class InternIndexController {
 | 
			
		||||
 | 
			
		||||
    @Autowired
 | 
			
		||||
    private final BookingAccountEntryRepository bookingAccountEntryRepository = null;
 | 
			
		||||
 | 
			
		||||
    @GetMapping("/")
 | 
			
		||||
    public String intern(Model model) {
 | 
			
		||||
        Optional<BookingAccountEntry> mainAccount = bookingAccountEntryRepository.getByMain();
 | 
			
		||||
        int mainAccountBalance = mainAccount.map(entry -> entry.newSumCent).orElse(0);
 | 
			
		||||
        Optional<BookingAccountEntry> vatAccount = bookingAccountEntryRepository.getByVat();
 | 
			
		||||
        int vatAccountBalance = vatAccount.map(entry -> entry.newSumCent).orElse(0);
 | 
			
		||||
 | 
			
		||||
        model.addAttribute("mainAccountBalance", AccountingController.fmtEuro(mainAccountBalance));
 | 
			
		||||
        model.addAttribute("vatAccountBalance", AccountingController.fmtEuro(vatAccountBalance));
 | 
			
		||||
 | 
			
		||||
        return "intern/index";
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@ -1,8 +1,27 @@
 | 
			
		||||
package org.hso.ecommerce.controller.intern;
 | 
			
		||||
 | 
			
		||||
import org.hso.ecommerce.repos.warehouse.WarehouseBookingRepository;
 | 
			
		||||
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 javax.servlet.http.HttpServletRequest;
 | 
			
		||||
 | 
			
		||||
@Controller
 | 
			
		||||
//@RequestMapping("...")
 | 
			
		||||
@RequestMapping("/intern/warehouse/")
 | 
			
		||||
public class WarehouseController {
 | 
			
		||||
 | 
			
		||||
    @Autowired
 | 
			
		||||
    private final WarehouseBookingRepository warehouseBookingRepository = null;
 | 
			
		||||
 | 
			
		||||
    @GetMapping("/")
 | 
			
		||||
    public String accountingWarehouse(
 | 
			
		||||
            Model model,
 | 
			
		||||
            HttpServletRequest request
 | 
			
		||||
    ) {
 | 
			
		||||
        model.addAttribute("bookings", warehouseBookingRepository.findAll());
 | 
			
		||||
        return "intern/warehouse/index";
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@ -0,0 +1,223 @@
 | 
			
		||||
package org.hso.ecommerce.controller.intern.accounting;
 | 
			
		||||
 | 
			
		||||
import java.text.SimpleDateFormat;
 | 
			
		||||
import java.util.ArrayList;
 | 
			
		||||
import java.util.List;
 | 
			
		||||
 | 
			
		||||
import org.hso.ecommerce.entities.booking.Booking;
 | 
			
		||||
import org.hso.ecommerce.entities.booking.BookingAccountEntry;
 | 
			
		||||
import org.hso.ecommerce.entities.booking.BookingReason;
 | 
			
		||||
import org.hso.ecommerce.repos.booking.BookingRepository;
 | 
			
		||||
import org.springframework.beans.factory.annotation.Autowired;
 | 
			
		||||
import org.springframework.stereotype.Controller;
 | 
			
		||||
import org.springframework.ui.Model;
 | 
			
		||||
import org.springframework.web.bind.annotation.GetMapping;
 | 
			
		||||
 | 
			
		||||
@Controller
 | 
			
		||||
public class AccountingController {
 | 
			
		||||
 | 
			
		||||
    @Autowired
 | 
			
		||||
    private BookingRepository bookingRepository = null;
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * A description used to render the html template for the overview of all bookings
 | 
			
		||||
     */
 | 
			
		||||
    static class TemplateBooking {
 | 
			
		||||
        public String datetime;
 | 
			
		||||
        public String amount;
 | 
			
		||||
        public String source;
 | 
			
		||||
        public String sourceAddr;
 | 
			
		||||
        public String sourceBalance;
 | 
			
		||||
        public String destination;
 | 
			
		||||
        public String destinationAddr;
 | 
			
		||||
        public String destinationBalance;
 | 
			
		||||
        public String reason;
 | 
			
		||||
        public String reference;
 | 
			
		||||
        public String referenceAddr;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * A description used to render the html template for bookings on a specific account
 | 
			
		||||
     */
 | 
			
		||||
    public static class ShortTemplateBooking {
 | 
			
		||||
        public String datetime;
 | 
			
		||||
        public String amount;
 | 
			
		||||
        public String source;
 | 
			
		||||
        public String sourceAddr;
 | 
			
		||||
        public String balance;
 | 
			
		||||
        public String reason;
 | 
			
		||||
        public String reference;
 | 
			
		||||
        public String referenceAddr;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public static class ShortTemplateBookingResult {
 | 
			
		||||
        public final String balance;
 | 
			
		||||
        public final List<ShortTemplateBooking> bookings;
 | 
			
		||||
 | 
			
		||||
        public ShortTemplateBookingResult(String balance, List<ShortTemplateBooking> bookings) {
 | 
			
		||||
            this.balance = balance;
 | 
			
		||||
            this.bookings = bookings;
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Used to check which side of the booking (source or destination) is the account we are currently looking at.
 | 
			
		||||
     */
 | 
			
		||||
    public interface AccountFilter {
 | 
			
		||||
        boolean matches(BookingAccountEntry account);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Renders template information for the bookings of one specific account.
 | 
			
		||||
     *
 | 
			
		||||
     * @param bookings       The (already fetched) booking entities to display
 | 
			
		||||
     * @param currentAccount A filter matching the account that is to be displayed
 | 
			
		||||
     * @return A collection result containing the final balance and all booking entries.
 | 
			
		||||
     */
 | 
			
		||||
    public ShortTemplateBookingResult buildShortTemplate(List<Booking> bookings, AccountFilter currentAccount) {
 | 
			
		||||
        List<ShortTemplateBooking> templateBookings = new ArrayList<>();
 | 
			
		||||
        for (Booking booking : bookings) {
 | 
			
		||||
            ShortTemplateBooking tb = new ShortTemplateBooking();
 | 
			
		||||
            tb.datetime = new SimpleDateFormat("dd.MM.yyyy HH:mm").format(booking.created);
 | 
			
		||||
            tb.reason = booking.reason.comment;
 | 
			
		||||
            tb.reference = describeReference(booking.reason);
 | 
			
		||||
            tb.referenceAddr = linkToReference(booking.reason);
 | 
			
		||||
            if (booking.destination != null && currentAccount.matches(booking.destination)) {
 | 
			
		||||
                // Money was transferred onto the account we are looking at.
 | 
			
		||||
                tb.amount = fmtEuro(booking.amountCent);
 | 
			
		||||
                if (booking.source != null) {
 | 
			
		||||
                    tb.source = describeAccount(booking.source);
 | 
			
		||||
                    tb.sourceAddr = linkAddrOfAccount(booking.source);
 | 
			
		||||
                } else {
 | 
			
		||||
                    tb.source = "-";
 | 
			
		||||
                    tb.sourceAddr = null;
 | 
			
		||||
                }
 | 
			
		||||
                tb.balance = fmtEuro(booking.destination.newSumCent);
 | 
			
		||||
            } else if (booking.source != null && currentAccount.matches(booking.source)) {
 | 
			
		||||
                // Money was transferred away from the account we are looking at.
 | 
			
		||||
                tb.amount = fmtEuro(-booking.amountCent); // Negative because of the transfer away
 | 
			
		||||
                if (booking.destination != null) {
 | 
			
		||||
                    tb.source = describeAccount(booking.destination); // 'source' means 'the other account' in this case
 | 
			
		||||
                    tb.sourceAddr = linkAddrOfAccount(booking.destination);
 | 
			
		||||
                } else {
 | 
			
		||||
                    tb.source = "-";
 | 
			
		||||
                    tb.sourceAddr = null;
 | 
			
		||||
                }
 | 
			
		||||
                tb.balance = fmtEuro(booking.source.newSumCent);
 | 
			
		||||
            } else {
 | 
			
		||||
                throw new RuntimeException(
 | 
			
		||||
                        "This booking should not appear in this list, because neither source nor destination is the account we are looking at.");
 | 
			
		||||
            }
 | 
			
		||||
            templateBookings.add(tb);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        String balance = templateBookings.isEmpty() ? fmtEuro(0) : templateBookings.get(0).balance;
 | 
			
		||||
        return new ShortTemplateBookingResult(balance, templateBookings);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public static String fmtEuro(long amountCent) {
 | 
			
		||||
        return String.format("%.2f EUR", amountCent / 100.0);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    private String describeAccount(BookingAccountEntry account) {
 | 
			
		||||
        if (account.isMainAccount) {
 | 
			
		||||
            return "Hauptkonto";
 | 
			
		||||
        } else if (account.isVATAccount) {
 | 
			
		||||
            return "Mehrwertsteuer";
 | 
			
		||||
        } else if (account.supplierAccount != null) {
 | 
			
		||||
            return "Lieferant " + account.supplierAccount.id;
 | 
			
		||||
        } else if (account.userAccount != null) {
 | 
			
		||||
            return "Kunde " + account.userAccount.id;
 | 
			
		||||
        } else {
 | 
			
		||||
            return "- unbekannt -";
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    private String linkAddrOfAccount(BookingAccountEntry account) {
 | 
			
		||||
        if (account.isMainAccount) {
 | 
			
		||||
            return "/intern/accounting/main";
 | 
			
		||||
        } else if (account.isVATAccount) {
 | 
			
		||||
            return "/intern/accounting/vat";
 | 
			
		||||
        } else if (account.supplierAccount != null) {
 | 
			
		||||
            return "/intern/suppliers/" + account.supplierAccount.id;
 | 
			
		||||
        } else if (account.userAccount != null) {
 | 
			
		||||
            return "/intern/customers/" + account.userAccount.id;
 | 
			
		||||
        } else {
 | 
			
		||||
            return null;
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    private String describeReference(BookingReason reason) {
 | 
			
		||||
        if (reason.customerOrder != null) {
 | 
			
		||||
            return reason.customerOrder.id + "";
 | 
			
		||||
        } else if (reason.customerPayment != null) {
 | 
			
		||||
            return "Bezahlung mit Kreditkarte " + reason.customerPayment.payment.creditCardNumber;
 | 
			
		||||
        } else if (reason.supplierOrder != null) {
 | 
			
		||||
            return "Lieferanten-Bestellung " + reason.supplierOrder.id;
 | 
			
		||||
        } else {
 | 
			
		||||
            return "-";
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    private String linkToReference(BookingReason reason) {
 | 
			
		||||
        if (reason.customerOrder != null) {
 | 
			
		||||
            return "/intern/customerOrders/" + reason.customerOrder.id;
 | 
			
		||||
        } else {
 | 
			
		||||
            return null;
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    @GetMapping("/intern/accounting/")
 | 
			
		||||
    public String accounting(Model model) {
 | 
			
		||||
        List<Booking> bookings = bookingRepository.allBookingsReverseChronologically();
 | 
			
		||||
        List<TemplateBooking> templateBookings = new ArrayList<>();
 | 
			
		||||
        for (Booking booking : bookings) {
 | 
			
		||||
            TemplateBooking tb = new TemplateBooking();
 | 
			
		||||
            tb.datetime = new SimpleDateFormat("dd.MM.yyyy HH:mm").format(booking.created);
 | 
			
		||||
            tb.amount = fmtEuro(booking.amountCent);
 | 
			
		||||
            if (booking.source != null) {
 | 
			
		||||
                tb.source = describeAccount(booking.source);
 | 
			
		||||
                tb.sourceAddr = linkAddrOfAccount(booking.source);
 | 
			
		||||
                tb.sourceBalance = fmtEuro(booking.source.newSumCent);
 | 
			
		||||
            } else {
 | 
			
		||||
                tb.source = "-";
 | 
			
		||||
                tb.sourceAddr = null;
 | 
			
		||||
                tb.sourceBalance = "-";
 | 
			
		||||
            }
 | 
			
		||||
            if (booking.destination != null) {
 | 
			
		||||
                tb.destination = describeAccount(booking.destination);
 | 
			
		||||
                tb.destinationAddr = linkAddrOfAccount(booking.destination);
 | 
			
		||||
                tb.destinationBalance = fmtEuro(booking.destination.newSumCent);
 | 
			
		||||
            } else {
 | 
			
		||||
                tb.destination = "-";
 | 
			
		||||
                tb.destinationAddr = null;
 | 
			
		||||
                tb.destinationBalance = "-";
 | 
			
		||||
            }
 | 
			
		||||
            tb.reason = booking.reason.comment;
 | 
			
		||||
            tb.reference = describeReference(booking.reason);
 | 
			
		||||
            tb.referenceAddr = linkToReference(booking.reason);
 | 
			
		||||
            templateBookings.add(tb);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        model.addAttribute("bookings", templateBookings);
 | 
			
		||||
        return "intern/accounting/index";
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    @GetMapping("/intern/accounting/vat")
 | 
			
		||||
    public String accountingVat(Model model) {
 | 
			
		||||
        List<Booking> bookings = bookingRepository.vatBookingsReverseChronologically();
 | 
			
		||||
        ShortTemplateBookingResult result = buildShortTemplate(bookings, account -> account.isVATAccount);
 | 
			
		||||
        model.addAttribute("balance", result.balance);
 | 
			
		||||
        model.addAttribute("bookings", result.bookings);
 | 
			
		||||
        return "intern/accounting/vat";
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    @GetMapping("/intern/accounting/main")
 | 
			
		||||
    public String accountingIntern(Model model) {
 | 
			
		||||
        List<Booking> bookings = bookingRepository.mainBookingsReverseChronologically();
 | 
			
		||||
        ShortTemplateBookingResult result = buildShortTemplate(bookings, account -> account.isMainAccount);
 | 
			
		||||
        model.addAttribute("balance", result.balance);
 | 
			
		||||
        model.addAttribute("bookings", result.bookings);
 | 
			
		||||
        return "intern/accounting/main";
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
@ -0,0 +1,270 @@
 | 
			
		||||
package org.hso.ecommerce.controller.intern.accounting;
 | 
			
		||||
 | 
			
		||||
import java.util.Optional;
 | 
			
		||||
 | 
			
		||||
import org.hso.ecommerce.action.booking.CreateBookingAction;
 | 
			
		||||
import org.hso.ecommerce.entities.booking.Booking;
 | 
			
		||||
import org.hso.ecommerce.entities.booking.BookingAccountEntry;
 | 
			
		||||
import org.hso.ecommerce.entities.booking.BookingReason;
 | 
			
		||||
import org.hso.ecommerce.repos.booking.BookingAccountEntryRepository;
 | 
			
		||||
import org.hso.ecommerce.repos.booking.BookingRepository;
 | 
			
		||||
import org.hso.ecommerce.repos.supplier.SupplierRepository;
 | 
			
		||||
import org.hso.ecommerce.repos.user.UserRepository;
 | 
			
		||||
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;
 | 
			
		||||
 | 
			
		||||
@Controller
 | 
			
		||||
public class ManualAccountingController {
 | 
			
		||||
 | 
			
		||||
    @Autowired
 | 
			
		||||
    final BookingRepository bookingRepository = null;
 | 
			
		||||
 | 
			
		||||
    @Autowired
 | 
			
		||||
    final BookingAccountEntryRepository bookingAccountEntryRepository = null;
 | 
			
		||||
 | 
			
		||||
    @Autowired
 | 
			
		||||
    final UserRepository userRepository = null;
 | 
			
		||||
 | 
			
		||||
    @Autowired
 | 
			
		||||
    final SupplierRepository supplierRepository = null;
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Collection for the form values used to create a manual booking
 | 
			
		||||
     */
 | 
			
		||||
    public static class ManualAccounting {
 | 
			
		||||
        String amount;
 | 
			
		||||
        String source;
 | 
			
		||||
        String sourceCustomer;
 | 
			
		||||
        String sourceSupplier;
 | 
			
		||||
        String destination;
 | 
			
		||||
        String destinationCustomer;
 | 
			
		||||
        String destinationSupplier;
 | 
			
		||||
        String reason;
 | 
			
		||||
        String reasonText;
 | 
			
		||||
 | 
			
		||||
        /**
 | 
			
		||||
         * Default constructor with default values for the form
 | 
			
		||||
         */
 | 
			
		||||
        public ManualAccounting() {
 | 
			
		||||
            amount = "0.00";
 | 
			
		||||
            reason = "Manual";
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        public String getAmount() {
 | 
			
		||||
            return amount;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        public void setAmount(String amount) {
 | 
			
		||||
            this.amount = amount;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        public String getSource() {
 | 
			
		||||
            return source;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        public void setSource(String source) {
 | 
			
		||||
            this.source = source;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        public String getSourceCustomer() {
 | 
			
		||||
            return sourceCustomer;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        public void setSourceCustomer(String sourceCustomer) {
 | 
			
		||||
            this.sourceCustomer = sourceCustomer;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        public String getSourceSupplier() {
 | 
			
		||||
            return sourceSupplier;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        public void setSourceSupplier(String sourceSupplier) {
 | 
			
		||||
            this.sourceSupplier = sourceSupplier;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        public String getDestination() {
 | 
			
		||||
            return destination;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        public void setDestination(String destination) {
 | 
			
		||||
            this.destination = destination;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        public String getDestinationCustomer() {
 | 
			
		||||
            return destinationCustomer;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        public void setDestinationCustomer(String destinationCustomer) {
 | 
			
		||||
            this.destinationCustomer = destinationCustomer;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        public String getDestinationSupplier() {
 | 
			
		||||
            return destinationSupplier;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        public void setDestinationSupplier(String destinationSupplier) {
 | 
			
		||||
            this.destinationSupplier = destinationSupplier;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        public String getReason() {
 | 
			
		||||
            return reason;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        public void setReason(String reason) {
 | 
			
		||||
            this.reason = reason;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        public String getReasonText() {
 | 
			
		||||
            return reasonText;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        public void setReasonText(String reasonText) {
 | 
			
		||||
            this.reasonText = reasonText;
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * An exception to represent errors that can be shown to the user
 | 
			
		||||
     */
 | 
			
		||||
    public static class InvalidFormDataException extends Exception {
 | 
			
		||||
        public InvalidFormDataException(String msg) {
 | 
			
		||||
            super(msg);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        private static final long serialVersionUID = 1L;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    private boolean sameAccountBothSides(ManualAccounting formData) {
 | 
			
		||||
        // No need to check for NumberFormatException because the numbers were already parsed before.
 | 
			
		||||
        if (!formData.getSource().equals(formData.getDestination())) {
 | 
			
		||||
            return false;
 | 
			
		||||
        } else if (formData.getSource().equals("Cust")
 | 
			
		||||
                && Long.parseLong(formData.getSourceCustomer()) != Long.parseLong(formData.getDestinationCustomer())) {
 | 
			
		||||
            return false;
 | 
			
		||||
        } else if (formData.getSource().equals("Sup")
 | 
			
		||||
                && Long.parseLong(formData.getSourceSupplier()) != Long.parseLong(formData.getDestinationSupplier())) {
 | 
			
		||||
            return false;
 | 
			
		||||
        } else {
 | 
			
		||||
            return true;
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public Booking createBooking(ManualAccounting formData) throws InvalidFormDataException {
 | 
			
		||||
        if (formData.getSource() == null) {
 | 
			
		||||
            throw new InvalidFormDataException("Bitte wählen Sie ein Quellkonto aus.");
 | 
			
		||||
        } else if (formData.getDestination() == null) {
 | 
			
		||||
            throw new InvalidFormDataException("Bitte wählen Sie ein Zielkonto aus.");
 | 
			
		||||
        }
 | 
			
		||||
        BookingAccountEntry source = getAccountFromFormData(formData.getSource(), formData.getSourceCustomer(),
 | 
			
		||||
                formData.getSourceSupplier());
 | 
			
		||||
        BookingAccountEntry destination = getAccountFromFormData(formData.getDestination(),
 | 
			
		||||
                formData.getDestinationCustomer(), formData.getDestinationSupplier());
 | 
			
		||||
 | 
			
		||||
        if (sameAccountBothSides(formData)) {
 | 
			
		||||
            throw new InvalidFormDataException("Quell- und Zielkonto dürfen nicht das selbe sein.");
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        double doubleAmount;
 | 
			
		||||
        try {
 | 
			
		||||
            doubleAmount = Double.parseDouble(formData.amount);
 | 
			
		||||
        } catch (NumberFormatException e) {
 | 
			
		||||
            throw new InvalidFormDataException("Der angegebene Betrag ist ungültig.");
 | 
			
		||||
        }
 | 
			
		||||
        int amountCent = (int) Math.round(doubleAmount * 100);
 | 
			
		||||
 | 
			
		||||
        BookingReason reason = new BookingReason();
 | 
			
		||||
        if (formData.getReason().equals("Start")) {
 | 
			
		||||
            reason.isStartBooking = true;
 | 
			
		||||
        } else if (formData.getReason().equals("Manual")) {
 | 
			
		||||
            reason.isManuel = true;
 | 
			
		||||
        } else {
 | 
			
		||||
            throw new RuntimeException("Invalid form value for the booking reason: " + formData.getReason());
 | 
			
		||||
        }
 | 
			
		||||
        reason.comment = formData.reasonText;
 | 
			
		||||
 | 
			
		||||
        CreateBookingAction action = new CreateBookingAction(source, destination, reason, amountCent);
 | 
			
		||||
        return action.finish();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Retrieve the corresponding account based on user-input
 | 
			
		||||
     *
 | 
			
		||||
     * @param account  The chosen value on the radio buttons
 | 
			
		||||
     * @param customer The given customer id from the corresponding text field
 | 
			
		||||
     * @param supplier the given supplier id from the corresponding text field
 | 
			
		||||
     * @return The account entry that can be used to create the new booking
 | 
			
		||||
     * @throws InvalidFormDataException If the user provided incorrect data in any way
 | 
			
		||||
     */
 | 
			
		||||
    private BookingAccountEntry getAccountFromFormData(String account, String customer, String supplier)
 | 
			
		||||
            throws InvalidFormDataException {
 | 
			
		||||
        if (account.equals("None")) {
 | 
			
		||||
            return null;
 | 
			
		||||
        } else if (account.equals("Main")) {
 | 
			
		||||
            return bookingAccountEntryRepository.getByMain().orElseGet(BookingAccountEntry::newMain);
 | 
			
		||||
        } else if (account.equals("Vat")) {
 | 
			
		||||
            return bookingAccountEntryRepository.getByVat().orElseGet(BookingAccountEntry::newVat);
 | 
			
		||||
        } else if (account.equals("Cust")) {
 | 
			
		||||
            long userId;
 | 
			
		||||
            try {
 | 
			
		||||
                userId = Long.parseLong(customer);
 | 
			
		||||
            } catch (NumberFormatException e) {
 | 
			
		||||
                throw new InvalidFormDataException("Die angegebene Kunden-Nr. ist ungültig.");
 | 
			
		||||
            }
 | 
			
		||||
            Optional<BookingAccountEntry> bookingAccount = bookingAccountEntryRepository.getByUser(userId);
 | 
			
		||||
            if (!bookingAccount.isPresent()) {
 | 
			
		||||
                bookingAccount = userRepository.findById(userId).map((user) -> BookingAccountEntry.newUser(user));
 | 
			
		||||
            }
 | 
			
		||||
            if (bookingAccount.isPresent()) {
 | 
			
		||||
                return bookingAccount.get();
 | 
			
		||||
            } else {
 | 
			
		||||
                throw new InvalidFormDataException("Der Kunde Nr. " + userId + " konnte nicht gefunden werden.");
 | 
			
		||||
            }
 | 
			
		||||
        } else if (account.equals("Sup")) {
 | 
			
		||||
            long supplierId;
 | 
			
		||||
            try {
 | 
			
		||||
                supplierId = Long.parseLong(supplier);
 | 
			
		||||
            } catch (NumberFormatException e) {
 | 
			
		||||
                throw new InvalidFormDataException("Die angegebene Lieferanten-Nr. ist ungültig.");
 | 
			
		||||
            }
 | 
			
		||||
            Optional<BookingAccountEntry> bookingAccount = bookingAccountEntryRepository.getBySupplier(supplierId);
 | 
			
		||||
            if (!bookingAccount.isPresent()) {
 | 
			
		||||
                bookingAccount = supplierRepository.findById(supplierId)
 | 
			
		||||
                        .map((sup) -> BookingAccountEntry.newSupplier(sup));
 | 
			
		||||
            }
 | 
			
		||||
            if (bookingAccount.isPresent()) {
 | 
			
		||||
                return bookingAccount.get();
 | 
			
		||||
            } else {
 | 
			
		||||
                throw new InvalidFormDataException(
 | 
			
		||||
                        "Der Lieferant Nr. " + supplierId + " konnte nicht gefunden werden.");
 | 
			
		||||
            }
 | 
			
		||||
        } else {
 | 
			
		||||
            throw new RuntimeException("Invalid form value for an account: " + account);
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    @GetMapping("/intern/accounting/addManual")
 | 
			
		||||
    public String accountingAddManual(Model model) {
 | 
			
		||||
        model.addAttribute("form_vals", new ManualAccounting());
 | 
			
		||||
        return "intern/accounting/addManual";
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    @PostMapping("/intern/accounting/addManual")
 | 
			
		||||
    public String accountingAddManualSubmit(Model model, @ModelAttribute ManualAccounting formData) {
 | 
			
		||||
        Booking booking;
 | 
			
		||||
        try {
 | 
			
		||||
            booking = createBooking(formData);
 | 
			
		||||
            bookingRepository.save(booking);
 | 
			
		||||
            model.addAttribute("info", "Die Buchung wurde erfolgreich erstellt.");
 | 
			
		||||
            model.addAttribute("form_vals", new ManualAccounting()); // Reply with empty form on success
 | 
			
		||||
        } catch (InvalidFormDataException e) {
 | 
			
		||||
            model.addAttribute("error", e.getMessage());
 | 
			
		||||
            model.addAttribute("form_vals", formData);
 | 
			
		||||
        }
 | 
			
		||||
        return "intern/accounting/addManual";
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
@ -1,8 +1,120 @@
 | 
			
		||||
package org.hso.ecommerce.controller.intern.customers;
 | 
			
		||||
 | 
			
		||||
import java.util.List;
 | 
			
		||||
 | 
			
		||||
import javax.servlet.http.HttpServletRequest;
 | 
			
		||||
 | 
			
		||||
import org.hso.ecommerce.controller.intern.accounting.AccountingController;
 | 
			
		||||
import org.hso.ecommerce.controller.intern.accounting.AccountingController.ShortTemplateBookingResult;
 | 
			
		||||
import org.hso.ecommerce.entities.booking.Booking;
 | 
			
		||||
import org.hso.ecommerce.entities.shop.CustomerOrder;
 | 
			
		||||
import org.hso.ecommerce.entities.user.User;
 | 
			
		||||
import org.hso.ecommerce.repos.booking.BookingRepository;
 | 
			
		||||
import org.hso.ecommerce.repos.shop.CustomerOrderRepository;
 | 
			
		||||
import org.hso.ecommerce.repos.user.UserRepository;
 | 
			
		||||
import org.springframework.beans.factory.annotation.Autowired;
 | 
			
		||||
 | 
			
		||||
import org.springframework.stereotype.Controller;
 | 
			
		||||
import org.springframework.ui.Model;
 | 
			
		||||
import org.springframework.web.bind.annotation.*;
 | 
			
		||||
 | 
			
		||||
import javax.servlet.http.HttpServletResponse;
 | 
			
		||||
import java.util.Optional;
 | 
			
		||||
 | 
			
		||||
@Controller
 | 
			
		||||
//@RequestMapping("...")
 | 
			
		||||
@RequestMapping("/intern/customers")
 | 
			
		||||
public class CustomersIndexController {
 | 
			
		||||
 | 
			
		||||
    @Autowired
 | 
			
		||||
    private BookingRepository bookingRepository = null;
 | 
			
		||||
 | 
			
		||||
    @Autowired
 | 
			
		||||
    private final CustomerOrderRepository customerOrderRepository = null;
 | 
			
		||||
 | 
			
		||||
    @Autowired
 | 
			
		||||
    private final UserRepository userRepository = null;
 | 
			
		||||
 | 
			
		||||
    @Autowired
 | 
			
		||||
    private AccountingController accountingController = null;
 | 
			
		||||
 | 
			
		||||
    @GetMapping("")
 | 
			
		||||
    public String internCustomers(Model model) {
 | 
			
		||||
        List<User> users = userRepository.findAll();
 | 
			
		||||
 | 
			
		||||
        model.addAttribute("users", users);
 | 
			
		||||
 | 
			
		||||
        return "intern/customers/index";
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    @GetMapping("/{id}")
 | 
			
		||||
    public String internCustomersId(Model model,
 | 
			
		||||
                                    @PathVariable("id") Long id,
 | 
			
		||||
                                    HttpServletResponse response,
 | 
			
		||||
                                    HttpServletRequest request
 | 
			
		||||
    ) {
 | 
			
		||||
        Optional<User> optUser = userRepository.findById(id);
 | 
			
		||||
        if (!optUser.isPresent()) {
 | 
			
		||||
            request.setAttribute("error", "Der User wurde nicht gefunden.");
 | 
			
		||||
            response.setStatus(HttpServletResponse.SC_NOT_FOUND);
 | 
			
		||||
            return "error/404";
 | 
			
		||||
        }
 | 
			
		||||
        User user = optUser.get();
 | 
			
		||||
        model.addAttribute("user", user);
 | 
			
		||||
 | 
			
		||||
        List<CustomerOrder> orders = customerOrderRepository.getOrdersByUserId(id);
 | 
			
		||||
        model.addAttribute("orders", orders);
 | 
			
		||||
 | 
			
		||||
        List<Booking> bookings = bookingRepository.customerBookingsReverseChronologically(id);
 | 
			
		||||
        ShortTemplateBookingResult result = accountingController.buildShortTemplate(
 | 
			
		||||
                bookings,
 | 
			
		||||
                account -> account.userAccount != null && account.userAccount.id == id);
 | 
			
		||||
        model.addAttribute("balance", result.balance);
 | 
			
		||||
        model.addAttribute("bookings", result.bookings);
 | 
			
		||||
 | 
			
		||||
        return "intern/customers/id";
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    @PostMapping("/{id}/changeState")
 | 
			
		||||
    public String changeState(@PathVariable("id") Long id,
 | 
			
		||||
                              @RequestParam(value = "active", required = false) String active,
 | 
			
		||||
                              @RequestParam(value = "ma", required = false) String ma
 | 
			
		||||
    ) {
 | 
			
		||||
        User user = userRepository.findById(id).get();
 | 
			
		||||
 | 
			
		||||
        if (active == null)
 | 
			
		||||
            user.isActive = false;
 | 
			
		||||
        else
 | 
			
		||||
            user.isActive = true;
 | 
			
		||||
 | 
			
		||||
        if (ma == null)
 | 
			
		||||
            user.isEmployee = false;
 | 
			
		||||
        else
 | 
			
		||||
            user.isEmployee = true;
 | 
			
		||||
 | 
			
		||||
        userRepository.save(user);
 | 
			
		||||
 | 
			
		||||
        return "redirect:/intern/customers/" + id.toString();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    @PostMapping("/{id}/resetPassword")
 | 
			
		||||
    public String resetPassword(@PathVariable("id") Long id,
 | 
			
		||||
                                @RequestParam("password") String password,
 | 
			
		||||
                                @RequestParam("password2") String password2,
 | 
			
		||||
                                HttpServletRequest request
 | 
			
		||||
    ) {
 | 
			
		||||
        if (!password.equals(password2)) {
 | 
			
		||||
            request.setAttribute("error", "Passwörter stimmen nicht überein!");
 | 
			
		||||
            return "/intern/customers/id";
 | 
			
		||||
        }
 | 
			
		||||
        User user = userRepository.findById(id).get();
 | 
			
		||||
        if (!user.validatePassword(password)) {
 | 
			
		||||
            request.setAttribute("error", "Die Passwörter stimmen nicht mit dem Original überein!");
 | 
			
		||||
            return "/intern/customers/id";
 | 
			
		||||
        }
 | 
			
		||||
        user.setPassword("12345");
 | 
			
		||||
        userRepository.save(user);
 | 
			
		||||
        request.setAttribute("info", "Passwort wurde auf 12345 geändert!");
 | 
			
		||||
 | 
			
		||||
        return "/intern/customers/id";
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@ -1,8 +1,157 @@
 | 
			
		||||
package org.hso.ecommerce.controller.intern.suppliers;
 | 
			
		||||
 | 
			
		||||
import java.text.SimpleDateFormat;
 | 
			
		||||
import java.util.ArrayList;
 | 
			
		||||
import java.util.Date;
 | 
			
		||||
import java.util.List;
 | 
			
		||||
 | 
			
		||||
import org.hso.ecommerce.controller.intern.accounting.AccountingController;
 | 
			
		||||
import org.hso.ecommerce.controller.intern.accounting.AccountingController.ShortTemplateBooking;
 | 
			
		||||
import org.hso.ecommerce.controller.intern.accounting.AccountingController.ShortTemplateBookingResult;
 | 
			
		||||
import org.hso.ecommerce.entities.booking.Booking;
 | 
			
		||||
import org.hso.ecommerce.entities.supplier.Supplier;
 | 
			
		||||
import org.hso.ecommerce.entities.supplier.SupplierOrder;
 | 
			
		||||
import org.hso.ecommerce.repos.booking.BookingRepository;
 | 
			
		||||
import org.hso.ecommerce.repos.supplier.SupplierOrderRepository;
 | 
			
		||||
import org.hso.ecommerce.repos.supplier.SupplierRepository;
 | 
			
		||||
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.PathVariable;
 | 
			
		||||
import org.springframework.web.bind.annotation.RequestMapping;
 | 
			
		||||
 | 
			
		||||
@Controller
 | 
			
		||||
//@RequestMapping("...")
 | 
			
		||||
@RequestMapping("/intern/")
 | 
			
		||||
public class SupplierIndexController {
 | 
			
		||||
 | 
			
		||||
	@Autowired
 | 
			
		||||
	private final SupplierRepository supplierRepository = null;
 | 
			
		||||
 | 
			
		||||
	@Autowired
 | 
			
		||||
	private final SupplierOrderRepository supplierOrderRepository = null;
 | 
			
		||||
 | 
			
		||||
	@Autowired
 | 
			
		||||
	private final BookingRepository bookingRepository = null;
 | 
			
		||||
 | 
			
		||||
	@Autowired
 | 
			
		||||
	private final AccountingController accountingController = null;
 | 
			
		||||
 | 
			
		||||
	@GetMapping("suppliers")
 | 
			
		||||
	public String listSuppliers(Model model) {
 | 
			
		||||
 | 
			
		||||
		List<UImodelSuppliers> totals = new ArrayList<UImodelSuppliers>();
 | 
			
		||||
 | 
			
		||||
		for (Supplier supplier : supplierRepository.findAll()) {
 | 
			
		||||
			UImodelSuppliers tmp = new UImodelSuppliers(supplier.id, supplier.name);
 | 
			
		||||
			totals.add(tmp);
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		model.addAttribute("suppliers", totals);
 | 
			
		||||
		return "intern/suppliers/index";
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	@GetMapping("/suppliers/{id}")
 | 
			
		||||
	public String supplierDetail(Model model, @PathVariable String id) {
 | 
			
		||||
 | 
			
		||||
		long supplierId = Long.parseLong(id);
 | 
			
		||||
 | 
			
		||||
		// add orders from supplier to UImodel
 | 
			
		||||
		List<UImodelSupplierDetailOrders> orders = new ArrayList<UImodelSupplierDetailOrders>();
 | 
			
		||||
		for (SupplierOrder supplierOrder : supplierOrderRepository.findOrderBySupplierID(supplierId)) {
 | 
			
		||||
			orders.add(new UImodelSupplierDetailOrders(supplierOrder));
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		// Table of bookings
 | 
			
		||||
		List<Booking> bookings = bookingRepository.supplierBookingsReverseChronologically(supplierId);
 | 
			
		||||
		ShortTemplateBookingResult bookingResult = accountingController.buildShortTemplate(bookings,
 | 
			
		||||
				account -> account.supplierAccount != null && account.supplierAccount.id == supplierId);
 | 
			
		||||
 | 
			
		||||
		UImodelSupplierDetail total = new UImodelSupplierDetail(supplierRepository.findSupplierById(supplierId).name,
 | 
			
		||||
				bookingResult.balance, orders, bookingResult.bookings);
 | 
			
		||||
 | 
			
		||||
		model.addAttribute("SupplierDetail", total);
 | 
			
		||||
 | 
			
		||||
		return "intern/suppliers/id";
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	public class UImodelSuppliers {
 | 
			
		||||
		public long id;
 | 
			
		||||
		public String name;
 | 
			
		||||
 | 
			
		||||
		public UImodelSuppliers(long id, String name) {
 | 
			
		||||
			this.id = id;
 | 
			
		||||
			this.name = name;
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	public class UImodelSupplierDetail {
 | 
			
		||||
 | 
			
		||||
		public String name;
 | 
			
		||||
		public String balance;
 | 
			
		||||
		public List<UImodelSupplierDetailOrders> orders;
 | 
			
		||||
		public List<ShortTemplateBooking> bookings;
 | 
			
		||||
 | 
			
		||||
		public UImodelSupplierDetail(String name, String balance, List<UImodelSupplierDetailOrders> orders,
 | 
			
		||||
				List<ShortTemplateBooking> bookings
 | 
			
		||||
		) {
 | 
			
		||||
			this.name = name;
 | 
			
		||||
			this.balance = balance;
 | 
			
		||||
			this.orders = orders;
 | 
			
		||||
			this.bookings = bookings;
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	public class UImodelSupplierDetailOrders {
 | 
			
		||||
		public long id;
 | 
			
		||||
		public String dateOrder;
 | 
			
		||||
		public String articleName;
 | 
			
		||||
		public long articleId;
 | 
			
		||||
		public String priceNet;
 | 
			
		||||
		public String quantity;
 | 
			
		||||
		public String priceTotal;
 | 
			
		||||
		public boolean arrived;
 | 
			
		||||
 | 
			
		||||
		public UImodelSupplierDetailOrders(SupplierOrder order) {
 | 
			
		||||
			this.id = order.id;
 | 
			
		||||
			this.articleName = order.ordered.title;
 | 
			
		||||
			this.articleId = order.ordered.id;
 | 
			
		||||
			this.priceNet = String.format("%.2f", ((float) order.pricePerUnitNetCent / 100));
 | 
			
		||||
			this.quantity = String.valueOf(order.numberOfUnits);
 | 
			
		||||
			this.priceTotal = String.format("%.2f", ((float) order.totalPriceNet / 100));
 | 
			
		||||
 | 
			
		||||
			Date date = new Date();
 | 
			
		||||
			date.setTime(order.created.getTime());
 | 
			
		||||
			this.dateOrder = new SimpleDateFormat("dd.MM.yyyy").format(date);
 | 
			
		||||
 | 
			
		||||
			if (order.delivered != null) {
 | 
			
		||||
				arrived = true;
 | 
			
		||||
			} else {
 | 
			
		||||
				arrived = false;
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	public class UImodelSupplierDetailBookings {
 | 
			
		||||
 | 
			
		||||
		public String dateBooking;
 | 
			
		||||
		public String price;
 | 
			
		||||
		public String srcName;
 | 
			
		||||
		public String balance;
 | 
			
		||||
		public String reason;
 | 
			
		||||
		public long orderID;
 | 
			
		||||
 | 
			
		||||
		public UImodelSupplierDetailBookings(Booking booking) {
 | 
			
		||||
			Date date = new Date();
 | 
			
		||||
			date.setTime(booking.reason.supplierOrder.created.getTime());
 | 
			
		||||
			this.dateBooking = new SimpleDateFormat("dd.MM.yyyy").format(date);
 | 
			
		||||
			this.price = String.format("%.2f", ((float) booking.amountCent / 100));
 | 
			
		||||
			this.srcName = ((booking.source.isMainAccount) ? "Hauptkonto" : booking.source.supplierAccount.name);
 | 
			
		||||
			this.balance = String.format("%.2f", ((float) booking.destination.newSumCent / 100));
 | 
			
		||||
			this.reason = booking.reason.comment;
 | 
			
		||||
			this.orderID = booking.reason.supplierOrder.id;
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@ -1,8 +1,77 @@
 | 
			
		||||
package org.hso.ecommerce.controller.intern.suppliers;
 | 
			
		||||
 | 
			
		||||
import java.util.ArrayList;
 | 
			
		||||
import java.util.List;
 | 
			
		||||
import java.util.Optional;
 | 
			
		||||
 | 
			
		||||
import org.hso.ecommerce.entities.supplier.ArticleOffer;
 | 
			
		||||
import org.hso.ecommerce.repos.shop.ArticleRepository;
 | 
			
		||||
import org.hso.ecommerce.repos.shop.OffersRepository;
 | 
			
		||||
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;
 | 
			
		||||
 | 
			
		||||
@Controller
 | 
			
		||||
//@RequestMapping("...")
 | 
			
		||||
@RequestMapping("/intern/")
 | 
			
		||||
public class SupplierOfferController {
 | 
			
		||||
 | 
			
		||||
	@Autowired
 | 
			
		||||
	private final OffersRepository offersRepository = null;
 | 
			
		||||
 | 
			
		||||
	@Autowired
 | 
			
		||||
	private final ArticleRepository articleRepository = null;
 | 
			
		||||
 | 
			
		||||
	@GetMapping("supplierOffers")
 | 
			
		||||
	public String internListedArticles(Model model) {
 | 
			
		||||
 | 
			
		||||
		List<UImodelOfferedArticle> totals = new ArrayList<>();
 | 
			
		||||
 | 
			
		||||
		for (ArticleOffer article : offersRepository.findAll()) {
 | 
			
		||||
			UImodelOfferedArticle tmp = new UImodelOfferedArticle(article,
 | 
			
		||||
					articleRepository.findArticleIDByRelatedID(article.id));
 | 
			
		||||
			totals.add(tmp);
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		model.addAttribute("OfferedArticles", totals);
 | 
			
		||||
		return "intern/offeredArticles/index";
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	public class UImodelOfferedArticle {
 | 
			
		||||
 | 
			
		||||
		public long offerId;
 | 
			
		||||
		public String title;
 | 
			
		||||
		public String manufacturer;
 | 
			
		||||
		public String articleNumber;
 | 
			
		||||
		public String supplierName;
 | 
			
		||||
		public String price;
 | 
			
		||||
		public String ads;
 | 
			
		||||
		public int listedArticleId;
 | 
			
		||||
		public boolean offerIsListed; // true --> offered article is listed
 | 
			
		||||
 | 
			
		||||
		public UImodelOfferedArticle(ArticleOffer article, Optional<Integer> listedArticleId) {
 | 
			
		||||
 | 
			
		||||
			this.offerId = article.id;
 | 
			
		||||
			this.title = article.title;
 | 
			
		||||
			this.manufacturer = article.manufacturer;
 | 
			
		||||
			this.articleNumber = article.articleNumber;
 | 
			
		||||
			if (article.cheapestSupplier != null) {
 | 
			
		||||
				this.supplierName = article.cheapestSupplier.name;
 | 
			
		||||
			} else {
 | 
			
		||||
				this.supplierName = "-";
 | 
			
		||||
			}
 | 
			
		||||
			this.price = String.format("%.2f", ((float) article.pricePerUnitNet / 100));
 | 
			
		||||
			this.ads = (article.shouldBeAdvertised) ? "Ja" : "Nein";
 | 
			
		||||
 | 
			
		||||
			if (listedArticleId.isPresent()) {
 | 
			
		||||
				// this offer is listed --> show link
 | 
			
		||||
				this.listedArticleId = listedArticleId.get();
 | 
			
		||||
				offerIsListed = true;
 | 
			
		||||
			} else {
 | 
			
		||||
				// this offer is not listed
 | 
			
		||||
				offerIsListed = false;
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@ -1,8 +1,135 @@
 | 
			
		||||
package org.hso.ecommerce.controller.intern.suppliers;
 | 
			
		||||
 | 
			
		||||
import org.hso.ecommerce.action.warehouse.SupplierOrderArrivedAction;
 | 
			
		||||
import org.hso.ecommerce.entities.shop.Article;
 | 
			
		||||
import org.hso.ecommerce.entities.supplier.SupplierOrder;
 | 
			
		||||
import org.hso.ecommerce.entities.warehouse.WarehouseBookingPositionSlotEntry;
 | 
			
		||||
import org.hso.ecommerce.repos.shop.ArticleRepository;
 | 
			
		||||
import org.hso.ecommerce.repos.supplier.SupplierOrderRepository;
 | 
			
		||||
import org.hso.ecommerce.repos.warehouse.SlotRepository;
 | 
			
		||||
import org.hso.ecommerce.repos.warehouse.WarehouseBookingPositionSlotEntryRepository;
 | 
			
		||||
import org.hso.ecommerce.repos.warehouse.WarehouseBookingRepository;
 | 
			
		||||
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.PathVariable;
 | 
			
		||||
import org.springframework.web.bind.annotation.PostMapping;
 | 
			
		||||
import org.springframework.web.bind.annotation.RequestMapping;
 | 
			
		||||
 | 
			
		||||
import javax.servlet.http.HttpServletResponse;
 | 
			
		||||
import java.text.SimpleDateFormat;
 | 
			
		||||
import java.util.ArrayList;
 | 
			
		||||
import java.util.Date;
 | 
			
		||||
import java.util.List;
 | 
			
		||||
import java.util.stream.Collectors;
 | 
			
		||||
 | 
			
		||||
@Controller
 | 
			
		||||
//@RequestMapping("...")
 | 
			
		||||
@RequestMapping("/intern/")
 | 
			
		||||
public class SupplierOrderController {
 | 
			
		||||
 | 
			
		||||
	@Autowired
 | 
			
		||||
	private final SupplierOrderRepository supplierOrderRepository = null;
 | 
			
		||||
 | 
			
		||||
	@Autowired
 | 
			
		||||
	private final ArticleRepository articleRepository = null;
 | 
			
		||||
 | 
			
		||||
	@Autowired
 | 
			
		||||
	private final WarehouseBookingPositionSlotEntryRepository warehouseBookingPositionSlotEntryRepository = null;
 | 
			
		||||
 | 
			
		||||
	@Autowired
 | 
			
		||||
	private final WarehouseBookingRepository warehouseBookingRepository = null;
 | 
			
		||||
 | 
			
		||||
	@Autowired
 | 
			
		||||
	private final SlotRepository slotRepository = null;
 | 
			
		||||
 | 
			
		||||
	@GetMapping("supplierOrders")
 | 
			
		||||
	public String listSuppliers(Model model) {
 | 
			
		||||
 | 
			
		||||
		List<UImodelSupplierOrder> totals = new ArrayList<UImodelSupplierOrder>();
 | 
			
		||||
 | 
			
		||||
		for (SupplierOrder order : supplierOrderRepository.findAll()) {
 | 
			
		||||
			final Article article = articleRepository.findArticleByArticleOffer(order.ordered).orElse(null);
 | 
			
		||||
			totals.add(new UImodelSupplierOrder(order, article));
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		model.addAttribute("orders", totals);
 | 
			
		||||
 | 
			
		||||
		return "intern/supplierOrders/index";
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	@PostMapping("/supplierOrders/store/{id}")
 | 
			
		||||
	public String storeOrder(@PathVariable("id") Long supplierOrderID, Model model, HttpServletResponse response) {
 | 
			
		||||
		SupplierOrder order = supplierOrderRepository.findById(supplierOrderID).orElse(null);
 | 
			
		||||
		if (order == null) {
 | 
			
		||||
			model.addAttribute("error", "Die ausgewählte Lieferung konnte nicht gefunden werden.");
 | 
			
		||||
			response.setStatus(HttpServletResponse.SC_EXPECTATION_FAILED);
 | 
			
		||||
			return listSuppliers(model);
 | 
			
		||||
		}
 | 
			
		||||
		if (order.wasDelivered()) {
 | 
			
		||||
			model.addAttribute("error", "Die ausgewählte Lieferung wurde schon zugestellt.");
 | 
			
		||||
			response.setStatus(HttpServletResponse.SC_EXPECTATION_FAILED);
 | 
			
		||||
			return listSuppliers(model);
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
		final Article article = articleRepository.findArticleByArticleOffer(order.ordered).orElse(null);
 | 
			
		||||
		if (article == null) {
 | 
			
		||||
			model.addAttribute("error", "Der bestellte Artikel wurde nicht angelegt, er hätte nicht bestellt werden dürfen.");
 | 
			
		||||
			response.setStatus(HttpServletResponse.SC_EXPECTATION_FAILED);
 | 
			
		||||
			return listSuppliers(model);
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		// Hard to do efficiently, this should be fine.
 | 
			
		||||
		List<WarehouseBookingPositionSlotEntry> candidates = slotRepository
 | 
			
		||||
				.findAll()
 | 
			
		||||
				.stream()
 | 
			
		||||
				.map(slot ->
 | 
			
		||||
						warehouseBookingPositionSlotEntryRepository.getBySlotNum(slot.slotNum).orElseGet(() ->
 | 
			
		||||
								WarehouseBookingPositionSlotEntry.empty(article, slot)
 | 
			
		||||
						)
 | 
			
		||||
				)
 | 
			
		||||
				.filter(entry -> entry.article.id == article.id || entry.newSumSlot == 0)
 | 
			
		||||
				.collect(Collectors.toList());
 | 
			
		||||
 | 
			
		||||
		SupplierOrderArrivedAction action = new SupplierOrderArrivedAction(candidates, order, article);
 | 
			
		||||
 | 
			
		||||
		try {
 | 
			
		||||
			SupplierOrderArrivedAction.Result result = action.finish();
 | 
			
		||||
			supplierOrderRepository.save(result.getOrder());
 | 
			
		||||
			warehouseBookingRepository.save(result.getBooking());
 | 
			
		||||
		} catch (SupplierOrderArrivedAction.NoSpaceInWarehouseException e) {
 | 
			
		||||
			e.printStackTrace();
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		return "redirect:/intern/warehouse/todo";
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	public class UImodelSupplierOrder {
 | 
			
		||||
		public long id;
 | 
			
		||||
		public String dateOrder;
 | 
			
		||||
		public String supplierName;
 | 
			
		||||
		public String articleName;
 | 
			
		||||
		public long articleId;
 | 
			
		||||
		public String priceNet;
 | 
			
		||||
		public String quantity;
 | 
			
		||||
		public String priceTotal;
 | 
			
		||||
		public boolean arrived;
 | 
			
		||||
 | 
			
		||||
		public UImodelSupplierOrder(SupplierOrder order, Article article) {
 | 
			
		||||
			this.id = order.id;
 | 
			
		||||
			this.supplierName = order.supplier.name;
 | 
			
		||||
			this.articleName = article != null ? article.title : "error";
 | 
			
		||||
			this.articleId = article != null ? article.id : 0;
 | 
			
		||||
			this.priceNet = String.format("%.2f", ((float) order.pricePerUnitNetCent / 100));
 | 
			
		||||
			this.quantity = String.valueOf(order.numberOfUnits);
 | 
			
		||||
			this.priceTotal = String.format("%.2f", ((float) order.totalPriceNet / 100));
 | 
			
		||||
 | 
			
		||||
			Date date = new Date();
 | 
			
		||||
			date.setTime(order.created.getTime());
 | 
			
		||||
			this.dateOrder = new SimpleDateFormat("dd.MM.yyyy").format(date);
 | 
			
		||||
 | 
			
		||||
			arrived = order.delivered != null;
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@ -0,0 +1,140 @@
 | 
			
		||||
package org.hso.ecommerce.controller.intern.warehouse;
 | 
			
		||||
 | 
			
		||||
import org.hso.ecommerce.action.warehouse.CreateManuelBookingAction;
 | 
			
		||||
import org.hso.ecommerce.entities.shop.Article;
 | 
			
		||||
import org.hso.ecommerce.entities.warehouse.Slot;
 | 
			
		||||
import org.hso.ecommerce.entities.warehouse.WarehouseBookingPositionSlotEntry;
 | 
			
		||||
import org.hso.ecommerce.repos.shop.ArticleRepository;
 | 
			
		||||
import org.hso.ecommerce.repos.warehouse.SlotRepository;
 | 
			
		||||
import org.hso.ecommerce.repos.warehouse.WarehouseBookingPositionSlotEntryRepository;
 | 
			
		||||
import org.hso.ecommerce.repos.warehouse.WarehouseBookingRepository;
 | 
			
		||||
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.PostMapping;
 | 
			
		||||
import org.springframework.web.bind.annotation.RequestMapping;
 | 
			
		||||
import org.springframework.web.bind.annotation.RequestParam;
 | 
			
		||||
 | 
			
		||||
import javax.servlet.http.HttpServletRequest;
 | 
			
		||||
import javax.servlet.http.HttpServletResponse;
 | 
			
		||||
import java.util.Optional;
 | 
			
		||||
 | 
			
		||||
@Controller
 | 
			
		||||
@RequestMapping("/intern/warehouse/")
 | 
			
		||||
public class ManuelBookingController {
 | 
			
		||||
 | 
			
		||||
    @Autowired
 | 
			
		||||
    private final ArticleRepository articleRepository = null;
 | 
			
		||||
 | 
			
		||||
    @Autowired
 | 
			
		||||
    private final SlotRepository slotRepository = null;
 | 
			
		||||
 | 
			
		||||
    @Autowired
 | 
			
		||||
    private final WarehouseBookingPositionSlotEntryRepository warehouseBookingPositionSlotEntryRepository = null;
 | 
			
		||||
 | 
			
		||||
    @Autowired
 | 
			
		||||
    private final WarehouseBookingRepository warehouseBookingRepository = null;
 | 
			
		||||
 | 
			
		||||
    @GetMapping("addManual")
 | 
			
		||||
    public String warehouseAddManual(
 | 
			
		||||
            Model model
 | 
			
		||||
    ) {
 | 
			
		||||
 | 
			
		||||
        model.addAttribute("articles", articleRepository.findAll());
 | 
			
		||||
        model.addAttribute("slots", slotRepository.findAll());
 | 
			
		||||
 | 
			
		||||
        return "intern/warehouse/addManual";
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    @PostMapping("addManual")
 | 
			
		||||
    public String warehouseAddMaualPost(
 | 
			
		||||
            Model model,
 | 
			
		||||
            HttpServletRequest request,
 | 
			
		||||
            HttpServletResponse response,
 | 
			
		||||
            @RequestParam("articleId") String articleIdText,
 | 
			
		||||
            @RequestParam("amount") Integer amount,
 | 
			
		||||
            @RequestParam("reason") String reason,
 | 
			
		||||
            @RequestParam("sourceIsSlot") Boolean sourceIsSlot,
 | 
			
		||||
            @RequestParam("sourceSlot") Integer sourceSlotNum,
 | 
			
		||||
            @RequestParam("destinationIsSlot") Boolean destinationIsSlot,
 | 
			
		||||
            @RequestParam("destinationSlot") Integer destinationSlotNum
 | 
			
		||||
    ) {
 | 
			
		||||
 | 
			
		||||
        // The suggestions for articleId in the UI show articles names, seperated by a " - ".
 | 
			
		||||
        // The Number must be extracted first.
 | 
			
		||||
        long articleId = -1;
 | 
			
		||||
        try {
 | 
			
		||||
            articleId = Long.parseLong(articleIdText.split(" - ", 2)[0].trim());
 | 
			
		||||
        } catch (NumberFormatException e) {
 | 
			
		||||
            model.addAttribute("error", "Die Artikel Id konnte nicht erkannt werden.");
 | 
			
		||||
            response.setStatus(HttpServletResponse.SC_BAD_REQUEST);
 | 
			
		||||
            return "intern/warehouse/addManual";
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
        Optional<Article> optionalArticle = articleRepository.findById(articleId);
 | 
			
		||||
        Article article = null;
 | 
			
		||||
        if (!optionalArticle.isPresent()) {
 | 
			
		||||
            model.addAttribute("error", "Der Artikel konnte nicht gefunden werden.");
 | 
			
		||||
            response.setStatus(HttpServletResponse.SC_EXPECTATION_FAILED);
 | 
			
		||||
            return "intern/warehouse/addManual";
 | 
			
		||||
        } else {
 | 
			
		||||
            article = optionalArticle.get();
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        if (amount <= 0) {
 | 
			
		||||
            model.addAttribute("error", "Eine  Anzahl <= 0 kann nicht verbucht werden.");
 | 
			
		||||
            response.setStatus(HttpServletResponse.SC_EXPECTATION_FAILED);
 | 
			
		||||
            return "intern/warehouse/addManual";
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        if (sourceIsSlot == false && destinationIsSlot == false) {
 | 
			
		||||
            model.addAttribute("error", "Jede Buchung benötigt ein Ziel oder eine Quelle.");
 | 
			
		||||
            response.setStatus(HttpServletResponse.SC_EXPECTATION_FAILED);
 | 
			
		||||
            return "intern/warehouse/addManual";
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        Optional<WarehouseBookingPositionSlotEntry> sourceSlot = Optional.empty();
 | 
			
		||||
        if (sourceIsSlot == true) {
 | 
			
		||||
            sourceSlot = warehouseBookingPositionSlotEntryRepository.getBySlotNum(sourceSlotNum);
 | 
			
		||||
            if (!sourceSlot.isPresent()) {
 | 
			
		||||
                request.setAttribute("error", "Quelllagerplatz wurde nicht gefunden oder ist leer.");
 | 
			
		||||
                response.setStatus(HttpServletResponse.SC_EXPECTATION_FAILED);
 | 
			
		||||
                return "intern/warehouse/addManual";
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        Optional<WarehouseBookingPositionSlotEntry> destinationSlot = Optional.empty();
 | 
			
		||||
        if (destinationIsSlot == true) {
 | 
			
		||||
            Optional<Slot> slot = slotRepository.findBySlotNum(destinationSlotNum);
 | 
			
		||||
            if (!slot.isPresent()) {
 | 
			
		||||
                request.setAttribute("error", "Ziellagerplatz wurde nicht gefunden.");
 | 
			
		||||
                response.setStatus(HttpServletResponse.SC_EXPECTATION_FAILED);
 | 
			
		||||
                return "intern/warehouse/addManual";
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            Article finalArticle = article;
 | 
			
		||||
            destinationSlot = Optional.of(warehouseBookingPositionSlotEntryRepository.getBySlotNum(destinationSlotNum).orElseGet(
 | 
			
		||||
                    () -> WarehouseBookingPositionSlotEntry.empty(finalArticle, slot.get())
 | 
			
		||||
            ));
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        try {
 | 
			
		||||
            warehouseBookingRepository.save(
 | 
			
		||||
                    new CreateManuelBookingAction(article, amount, sourceSlot, destinationSlot, reason).finish()
 | 
			
		||||
            );
 | 
			
		||||
        } catch (CreateManuelBookingAction.ArticleSlotConstraintArticleTypeFailedException e) {
 | 
			
		||||
            model.addAttribute("error", "Es befindet sich der falsche Artikeltyp in Quell- oder Ziellagerplatz. ");
 | 
			
		||||
            response.setStatus(HttpServletResponse.SC_EXPECTATION_FAILED);
 | 
			
		||||
            return "intern/warehouse/addManual";
 | 
			
		||||
        } catch (CreateManuelBookingAction.ArticleSlotConstraintFailedException e) {
 | 
			
		||||
            model.addAttribute("error", "Die maximale Anzahl an lagerbaren Artikeln im Ziellagerplatz wurde überschritten.");
 | 
			
		||||
            response.setStatus(HttpServletResponse.SC_EXPECTATION_FAILED);
 | 
			
		||||
            return "intern/warehouse/addManual";
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        return "redirect:/intern/warehouse/todo";
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
@ -0,0 +1,46 @@
 | 
			
		||||
package org.hso.ecommerce.controller.intern.warehouse;
 | 
			
		||||
 | 
			
		||||
import org.hso.ecommerce.action.warehouse.CalculateWarehouseStatsAction;
 | 
			
		||||
import org.hso.ecommerce.entities.warehouse.WarehouseBookingPositionSlotEntry;
 | 
			
		||||
import org.hso.ecommerce.repos.warehouse.SlotRepository;
 | 
			
		||||
import org.hso.ecommerce.repos.warehouse.WarehouseBookingPositionSlotEntryRepository;
 | 
			
		||||
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 javax.servlet.http.HttpServletRequest;
 | 
			
		||||
import java.util.List;
 | 
			
		||||
import java.util.stream.Collectors;
 | 
			
		||||
 | 
			
		||||
@Controller
 | 
			
		||||
@RequestMapping("/intern/warehouse/")
 | 
			
		||||
public class SlotsController {
 | 
			
		||||
 | 
			
		||||
    @Autowired
 | 
			
		||||
    private final WarehouseBookingPositionSlotEntryRepository warehouseBookingPositionSlotEntryRepository = null;
 | 
			
		||||
 | 
			
		||||
    @Autowired
 | 
			
		||||
    private final SlotRepository slotRepository = null;
 | 
			
		||||
 | 
			
		||||
    @GetMapping("slots/")
 | 
			
		||||
    public String accountingWarehouseSlots(
 | 
			
		||||
            Model model,
 | 
			
		||||
            HttpServletRequest request
 | 
			
		||||
    ) {
 | 
			
		||||
 | 
			
		||||
        // Doing this in a single would be hard and error prone.
 | 
			
		||||
        // Writing native queries should be minimized.
 | 
			
		||||
        // Therefore this method was prefered
 | 
			
		||||
        List<WarehouseBookingPositionSlotEntry> entries = slotRepository.findAll().stream().map(
 | 
			
		||||
                s -> warehouseBookingPositionSlotEntryRepository
 | 
			
		||||
                        .getBySlotNum(s.slotNum)
 | 
			
		||||
                        .orElseGet(() -> WarehouseBookingPositionSlotEntry.empty(null, s))
 | 
			
		||||
        ).collect(Collectors.toList());
 | 
			
		||||
        model.addAttribute("entries", entries);
 | 
			
		||||
 | 
			
		||||
        model.addAttribute("stats", new CalculateWarehouseStatsAction(entries).finish());
 | 
			
		||||
        return "intern/warehouse/slots/index";
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
@ -0,0 +1,112 @@
 | 
			
		||||
package org.hso.ecommerce.controller.intern.warehouse;
 | 
			
		||||
 | 
			
		||||
import org.hso.ecommerce.action.shop.EnableTrackingAction;
 | 
			
		||||
import org.hso.ecommerce.entities.warehouse.WarehouseBooking;
 | 
			
		||||
import org.hso.ecommerce.repos.warehouse.WarehouseBookingRepository;
 | 
			
		||||
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.PathVariable;
 | 
			
		||||
import org.springframework.web.bind.annotation.PostMapping;
 | 
			
		||||
import org.springframework.web.bind.annotation.RequestMapping;
 | 
			
		||||
 | 
			
		||||
import javax.servlet.http.HttpServletRequest;
 | 
			
		||||
import javax.servlet.http.HttpServletResponse;
 | 
			
		||||
import java.util.Optional;
 | 
			
		||||
 | 
			
		||||
@Controller
 | 
			
		||||
@RequestMapping("/intern/warehouse/")
 | 
			
		||||
public class TodoController {
 | 
			
		||||
 | 
			
		||||
    @Autowired
 | 
			
		||||
    private final WarehouseBookingRepository warehouseBookingRepository = null;
 | 
			
		||||
 | 
			
		||||
    @GetMapping("todo")
 | 
			
		||||
    public String accountingWarehouseTodo(
 | 
			
		||||
            Model model
 | 
			
		||||
    ) {
 | 
			
		||||
        model.addAttribute("bookings", warehouseBookingRepository.findNotDone());
 | 
			
		||||
        return "intern/warehouse/todo";
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
    @PostMapping("progress/{id}")
 | 
			
		||||
    public String postProgressId(
 | 
			
		||||
            Model model,
 | 
			
		||||
            HttpServletRequest request,
 | 
			
		||||
            HttpServletResponse response,
 | 
			
		||||
            @PathVariable("id") Long id
 | 
			
		||||
    ) {
 | 
			
		||||
        Optional<WarehouseBooking> booking = warehouseBookingRepository.findById(id);
 | 
			
		||||
        if (!booking.isPresent()) {
 | 
			
		||||
            model.addAttribute("error", "Die Buchung wurde nicht gefunden.");
 | 
			
		||||
            response.setStatus(HttpServletResponse.SC_BAD_REQUEST);
 | 
			
		||||
            return "error/404";
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        if (booking.get().isInProgress) {
 | 
			
		||||
            response.setStatus(409);
 | 
			
		||||
            return "intern/warehouse/error_progress_failed";
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        booking.get().isInProgress = true;
 | 
			
		||||
        warehouseBookingRepository.save(booking.get());
 | 
			
		||||
 | 
			
		||||
        return "redirect:/intern/warehouse/progress/" + id;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    @PostMapping("progress/{id}/finish")
 | 
			
		||||
    public String postProgressIdFinish(
 | 
			
		||||
            Model model,
 | 
			
		||||
            HttpServletRequest request,
 | 
			
		||||
            HttpServletResponse response,
 | 
			
		||||
            @PathVariable("id") Long id
 | 
			
		||||
    ) {
 | 
			
		||||
        Optional<WarehouseBooking> booking = warehouseBookingRepository.findById(id);
 | 
			
		||||
        if (!booking.isPresent()) {
 | 
			
		||||
            model.addAttribute("error", "Die Buchung wurde nicht gefunden.");
 | 
			
		||||
            response.setStatus(HttpServletResponse.SC_BAD_REQUEST);
 | 
			
		||||
            return "error/404";
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        booking.get().isInProgress = true;
 | 
			
		||||
        booking.get().isDone = true;
 | 
			
		||||
 | 
			
		||||
        // Update Delivery Date
 | 
			
		||||
        if (booking.get().reason.customerOrder != null) {
 | 
			
		||||
            EnableTrackingAction.addTrackingInfo(booking.get().reason.customerOrder);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        warehouseBookingRepository.save(booking.get());
 | 
			
		||||
 | 
			
		||||
        return "redirect:/intern/warehouse/todo";
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    @GetMapping("progress/{id}")
 | 
			
		||||
    public String getProgressId(Model model,
 | 
			
		||||
                                HttpServletRequest request,
 | 
			
		||||
                                HttpServletResponse response,
 | 
			
		||||
                                @PathVariable("id") Long id) {
 | 
			
		||||
        Optional<WarehouseBooking> booking = warehouseBookingRepository.findById(id);
 | 
			
		||||
        if (!booking.isPresent()) {
 | 
			
		||||
            model.addAttribute("error", "Die Buchung wurde nicht gefunden.");
 | 
			
		||||
            response.setStatus(HttpServletResponse.SC_BAD_REQUEST);
 | 
			
		||||
            return "error/404";
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        if (booking.get().isDone) {
 | 
			
		||||
            model.addAttribute("info", "Die Buchung wurde schon abgeschlossen.");
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        if (!booking.get().isInProgress) {
 | 
			
		||||
            // Only reachable if path is manipulated.
 | 
			
		||||
            model.addAttribute("error", "Die Buchung wurde noch nicht zugewiesen!");
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        model.addAttribute("booking", booking.get());
 | 
			
		||||
        return "intern/warehouse/id_progress";
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
@ -1,8 +1,118 @@
 | 
			
		||||
package org.hso.ecommerce.controller.shop;
 | 
			
		||||
 | 
			
		||||
import org.apache.tomcat.util.http.fileupload.IOUtils;
 | 
			
		||||
import org.hso.ecommerce.action.shop.GetRandomArticlesAction;
 | 
			
		||||
import org.hso.ecommerce.entities.shop.Article;
 | 
			
		||||
import org.hso.ecommerce.entities.shop.ShoppingCart;
 | 
			
		||||
import org.hso.ecommerce.repos.shop.ArticleRepository;
 | 
			
		||||
import org.hso.ecommerce.repos.shop.CategoryRepository;
 | 
			
		||||
import org.hso.ecommerce.repos.warehouse.WarehouseBookingPositionSlotEntryRepository;
 | 
			
		||||
import org.springframework.beans.factory.annotation.Autowired;
 | 
			
		||||
import org.springframework.http.MediaType;
 | 
			
		||||
import org.springframework.stereotype.Controller;
 | 
			
		||||
import org.springframework.ui.Model;
 | 
			
		||||
import org.springframework.web.bind.annotation.*;
 | 
			
		||||
 | 
			
		||||
import javax.servlet.http.HttpServletRequest;
 | 
			
		||||
import javax.servlet.http.HttpServletResponse;
 | 
			
		||||
import javax.servlet.http.HttpSession;
 | 
			
		||||
import java.io.File;
 | 
			
		||||
import java.io.FileInputStream;
 | 
			
		||||
import java.io.IOException;
 | 
			
		||||
import java.io.InputStream;
 | 
			
		||||
import java.util.List;
 | 
			
		||||
 | 
			
		||||
@Controller
 | 
			
		||||
//@RequestMapping("...")
 | 
			
		||||
@RequestMapping("/shop/articles")
 | 
			
		||||
public class ShopArticleController {
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
    @Autowired
 | 
			
		||||
    private final ArticleRepository articleRepository = null;
 | 
			
		||||
 | 
			
		||||
    @Autowired
 | 
			
		||||
    private final WarehouseBookingPositionSlotEntryRepository warehouseBookingPositionSlotEntryRepository = null;
 | 
			
		||||
 | 
			
		||||
    @Autowired
 | 
			
		||||
    private final CategoryRepository categoryRepository = null;
 | 
			
		||||
 | 
			
		||||
    @GetMapping("/{id}")
 | 
			
		||||
    public String shopArticlesById(Model model,
 | 
			
		||||
                                   @PathVariable("id") Long id,
 | 
			
		||||
                                   HttpServletRequest request,
 | 
			
		||||
                                   HttpServletResponse response
 | 
			
		||||
    ) {
 | 
			
		||||
        model.addAttribute("categories", categoryRepository.getCategories());   //for sidebar
 | 
			
		||||
 | 
			
		||||
        Article article = articleRepository.findArticleById(id);
 | 
			
		||||
 | 
			
		||||
        if (article == null) {
 | 
			
		||||
            request.setAttribute("error", "Der Artikel wurde nicht gefunden.");
 | 
			
		||||
            response.setStatus(HttpServletResponse.SC_NOT_FOUND);
 | 
			
		||||
            return "error/404";
 | 
			
		||||
        }
 | 
			
		||||
        model.addAttribute("article", article);
 | 
			
		||||
 | 
			
		||||
        if (warehouseBookingPositionSlotEntryRepository.getByArticle(id).get(0).newSumSlot > 0) {   //check if in Stock
 | 
			
		||||
            model.addAttribute("inStock", true);
 | 
			
		||||
        } else {
 | 
			
		||||
            model.addAttribute("inStock", false);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        List<Article> commercialArticles = GetRandomArticlesAction.getRandomArticles(3, articleRepository.getAdvertisedArticles()); //get 3 advertised Articles
 | 
			
		||||
        model.addAttribute("commercialArticles", commercialArticles);
 | 
			
		||||
 | 
			
		||||
        return "shop/articles/id";
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    @PostMapping("/{id}")
 | 
			
		||||
    public String shopArticlesByIdBuy(HttpServletRequest request,
 | 
			
		||||
                                      HttpServletResponse response,
 | 
			
		||||
                                      HttpSession session,
 | 
			
		||||
                                      @RequestAttribute(value = "shoppingCart") ShoppingCart shoppingCart,
 | 
			
		||||
                                      @PathVariable("id") Long id,
 | 
			
		||||
                                      @RequestParam("quantity") Integer quantity,
 | 
			
		||||
                                      @RequestParam(value = "set_amount", required = false) Boolean setAmount,
 | 
			
		||||
                                      @RequestParam("fastcheckout") Boolean fastcheckout
 | 
			
		||||
    ) {
 | 
			
		||||
        Article article = articleRepository.findArticleById(id);
 | 
			
		||||
 | 
			
		||||
        if (article == null) {
 | 
			
		||||
            request.setAttribute("error", "Der Artikel wurde nicht gefunden.");
 | 
			
		||||
            response.setStatus(HttpServletResponse.SC_NOT_FOUND);
 | 
			
		||||
            return "error/404";
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        if (setAmount != null && setAmount) {
 | 
			
		||||
            shoppingCart.setArticleCount(article, quantity);
 | 
			
		||||
        } else {
 | 
			
		||||
            shoppingCart.addArticle(article, quantity);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        if (!fastcheckout) {
 | 
			
		||||
            return "shop/articles/post_add";
 | 
			
		||||
        } else {
 | 
			
		||||
            return "redirect:/shop/checkout";
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    @GetMapping("/{id}/image.jpg")
 | 
			
		||||
    public void getImageAsByteArray(HttpServletRequest request,
 | 
			
		||||
                                    HttpServletResponse response,
 | 
			
		||||
                                    @PathVariable("id") Long id
 | 
			
		||||
    ) throws IOException {
 | 
			
		||||
        Article article = articleRepository.findArticleById(id);
 | 
			
		||||
 | 
			
		||||
        if(article.image != null) {
 | 
			
		||||
            File file = new File(article.image.path);
 | 
			
		||||
            File allowedPath = new File("./data/img/");
 | 
			
		||||
 | 
			
		||||
            if (file.getCanonicalPath().startsWith(allowedPath.getCanonicalPath())) {
 | 
			
		||||
                InputStream in = new FileInputStream(file);
 | 
			
		||||
                response.setContentType(MediaType.IMAGE_JPEG_VALUE);
 | 
			
		||||
                IOUtils.copy(in, response.getOutputStream());
 | 
			
		||||
            } else {
 | 
			
		||||
                throw new RuntimeException("Got illegal file path. DB was modified.");
 | 
			
		||||
            }
 | 
			
		||||
        }        
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
@ -1,8 +1,158 @@
 | 
			
		||||
package org.hso.ecommerce.controller.shop;
 | 
			
		||||
 | 
			
		||||
import org.hso.ecommerce.action.shop.CreateOrderAction;
 | 
			
		||||
import org.hso.ecommerce.entities.booking.BookingAccountEntry;
 | 
			
		||||
import org.hso.ecommerce.entities.booking.PaymentMethod;
 | 
			
		||||
import org.hso.ecommerce.entities.shop.Address;
 | 
			
		||||
import org.hso.ecommerce.entities.shop.Article;
 | 
			
		||||
import org.hso.ecommerce.entities.shop.ShoppingCart;
 | 
			
		||||
import org.hso.ecommerce.entities.user.User;
 | 
			
		||||
import org.hso.ecommerce.repos.booking.BookingAccountEntryRepository;
 | 
			
		||||
import org.hso.ecommerce.repos.booking.BookingRepository;
 | 
			
		||||
import org.hso.ecommerce.repos.shop.ArticleRepository;
 | 
			
		||||
import org.hso.ecommerce.repos.shop.CustomerOrderRepository;
 | 
			
		||||
import org.hso.ecommerce.repos.user.UserRepository;
 | 
			
		||||
import org.hso.ecommerce.repos.warehouse.WarehouseBookingPositionSlotEntryRepository;
 | 
			
		||||
import org.hso.ecommerce.repos.warehouse.WarehouseBookingRepository;
 | 
			
		||||
import org.springframework.beans.factory.annotation.Autowired;
 | 
			
		||||
import org.springframework.stereotype.Controller;
 | 
			
		||||
import org.springframework.web.bind.annotation.*;
 | 
			
		||||
 | 
			
		||||
import javax.servlet.http.HttpServletRequest;
 | 
			
		||||
import javax.servlet.http.HttpServletResponse;
 | 
			
		||||
import javax.servlet.http.HttpSession;
 | 
			
		||||
import java.util.ArrayList;
 | 
			
		||||
import java.util.TreeMap;
 | 
			
		||||
 | 
			
		||||
@Controller
 | 
			
		||||
//@RequestMapping("...")
 | 
			
		||||
@RequestMapping("/shop/")
 | 
			
		||||
public class ShopCheckoutController {
 | 
			
		||||
 | 
			
		||||
    @Autowired
 | 
			
		||||
    private final UserRepository userRepository = null;
 | 
			
		||||
 | 
			
		||||
    @Autowired
 | 
			
		||||
    private final ArticleRepository articleRepository = null;
 | 
			
		||||
 | 
			
		||||
    @Autowired
 | 
			
		||||
    private final BookingAccountEntryRepository bookingEntryRepository = null;
 | 
			
		||||
 | 
			
		||||
    @Autowired
 | 
			
		||||
    private final BookingRepository bookingRepository = null;
 | 
			
		||||
 | 
			
		||||
    @Autowired
 | 
			
		||||
    private final WarehouseBookingRepository warehouseBookingRepository = null;
 | 
			
		||||
 | 
			
		||||
    @Autowired
 | 
			
		||||
    private final CustomerOrderRepository customerOderRepository = null;
 | 
			
		||||
 | 
			
		||||
    @Autowired
 | 
			
		||||
    private final WarehouseBookingPositionSlotEntryRepository wbeseRepo = null;
 | 
			
		||||
 | 
			
		||||
    @GetMapping("/checkout")
 | 
			
		||||
    public String shopCheckout(HttpSession session,
 | 
			
		||||
                               HttpServletRequest request,
 | 
			
		||||
                               @RequestAttribute(value = "shoppingCart") ShoppingCart shoppingCart) {
 | 
			
		||||
        session.setAttribute("afterLogin", request.getRequestURI());
 | 
			
		||||
 | 
			
		||||
        CheckoutListTotals totals = new CheckoutListTotals();
 | 
			
		||||
        ArrayList<CheckoutListItem> items = new ArrayList<>();
 | 
			
		||||
        for (ShoppingCart.ShoppingCartItem item : shoppingCart.getItems()) {
 | 
			
		||||
            Article article = articleRepository.findById(item.getArticleId()).get();
 | 
			
		||||
 | 
			
		||||
            totals.addItem(article, item.getAmount());
 | 
			
		||||
            items.add(new CheckoutListItem(item.getAmount(), article));
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        request.setAttribute("checkoutItems", items);
 | 
			
		||||
        request.setAttribute("checkoutTotals", totals);
 | 
			
		||||
 | 
			
		||||
        return "shop/checkout";
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public static class CheckoutListTotals {
 | 
			
		||||
        public int net;
 | 
			
		||||
        public TreeMap<Integer, Integer> vatAmounts = new TreeMap<>();
 | 
			
		||||
        public int total;
 | 
			
		||||
 | 
			
		||||
        void addItem(Article article, int amount) {
 | 
			
		||||
            net += article.shopPricePerUnitNetCent * amount;
 | 
			
		||||
            Integer vatPos = vatAmounts.getOrDefault(article.related.vatPercent, 0) + article.getVat() * amount;
 | 
			
		||||
            vatAmounts.put(article.related.vatPercent, vatPos);
 | 
			
		||||
            total += article.getPriceGross() * amount;
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public static class CheckoutListItem {
 | 
			
		||||
        public int amount;
 | 
			
		||||
        public Article article;
 | 
			
		||||
        public int total;
 | 
			
		||||
 | 
			
		||||
        public CheckoutListItem(int amount, Article article) {
 | 
			
		||||
            this.amount = amount;
 | 
			
		||||
            this.article = article;
 | 
			
		||||
            this.total = amount * article.getPriceGross();
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    @PostMapping("/checkoutFinish")
 | 
			
		||||
    public String shopCheckoutFinish(
 | 
			
		||||
            HttpSession session,
 | 
			
		||||
            HttpServletRequest request,
 | 
			
		||||
            HttpServletResponse response,
 | 
			
		||||
            @RequestAttribute(value = "user") User user,
 | 
			
		||||
            @RequestAttribute(value = "shoppingCart") ShoppingCart shoppingCart,
 | 
			
		||||
            @RequestParam("address") String address,
 | 
			
		||||
            @RequestParam("cardnumber") String cardnumber,
 | 
			
		||||
            @RequestParam("shopping_cart_revision") Integer cartRevision,
 | 
			
		||||
            @RequestParam("expected_total") Integer expectedPrice
 | 
			
		||||
    ) {
 | 
			
		||||
 | 
			
		||||
        if (shoppingCart.getRevision() != cartRevision) {
 | 
			
		||||
            request.setAttribute("error", "Der Warenkorb wurde zwischenzeitlich bearbeitet. Daher die Kaufvorgang nicht abgeschlossen werden. Bitte versuchen Sie es erneut.");
 | 
			
		||||
            response.setStatus(HttpServletResponse.SC_CONFLICT);
 | 
			
		||||
            return "shop/checkout";
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        // Must be refetched for persitence.
 | 
			
		||||
        user = userRepository.findById(user.id).get();
 | 
			
		||||
 | 
			
		||||
        CreateOrderAction action = new CreateOrderAction(
 | 
			
		||||
                user,
 | 
			
		||||
                expectedPrice,
 | 
			
		||||
                Address.fromString(address),
 | 
			
		||||
                PaymentMethod.fromCreditCardNumber(cardnumber),
 | 
			
		||||
                bookingEntryRepository.getByUser(user.id).orElse(BookingAccountEntry.newUser(user)),
 | 
			
		||||
                bookingEntryRepository.getByVat().orElse(BookingAccountEntry.newVat()),
 | 
			
		||||
                bookingEntryRepository.getByMain().orElse(BookingAccountEntry.newMain())
 | 
			
		||||
        );
 | 
			
		||||
 | 
			
		||||
        for (ShoppingCart.ShoppingCartItem item : shoppingCart.getItems()) {
 | 
			
		||||
            Article article = articleRepository.findById(item.getArticleId()).get();
 | 
			
		||||
            action.addArticle(article, item.getAmount(), wbeseRepo.getByArticle(article.id));
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        CreateOrderAction.Result result = null;
 | 
			
		||||
        try {
 | 
			
		||||
            result = action.finish();
 | 
			
		||||
 | 
			
		||||
            customerOderRepository.save(result.customerOrder);
 | 
			
		||||
            bookingRepository.saveAll(result.bookings);
 | 
			
		||||
            warehouseBookingRepository.save(result.warehouseBooking);
 | 
			
		||||
 | 
			
		||||
            shoppingCart.clear();
 | 
			
		||||
 | 
			
		||||
        } catch (CreateOrderAction.ArticleNotInStockException e) {
 | 
			
		||||
            request.setAttribute("error", "Der Artikel '" + e.getArticle().title + "' ist leider nicht mehr in ausreichender Menge verfügbar. Bitte passen Sie die Artikelmenge an.");
 | 
			
		||||
            return shopCheckout(session, request, shoppingCart);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
        return "shop/checkoutFinish";
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    @GetMapping("/checkoutFinish")
 | 
			
		||||
    public String shopCheckoutFinishGET() {
 | 
			
		||||
        return "shop/checkoutFinish";
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@ -1,8 +1,72 @@
 | 
			
		||||
package org.hso.ecommerce.controller.shop;
 | 
			
		||||
 | 
			
		||||
import org.hso.ecommerce.action.shop.GetRandomArticlesAction;
 | 
			
		||||
import org.hso.ecommerce.entities.shop.Article;
 | 
			
		||||
import org.hso.ecommerce.repos.shop.ArticleRepository;
 | 
			
		||||
import org.hso.ecommerce.repos.warehouse.WarehouseBookingPositionSlotEntryRepository;
 | 
			
		||||
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 javax.servlet.http.HttpSession;
 | 
			
		||||
import java.util.List;
 | 
			
		||||
 | 
			
		||||
@Controller
 | 
			
		||||
//@RequestMapping("...")
 | 
			
		||||
@RequestMapping("/")
 | 
			
		||||
public class ShopIndexController {
 | 
			
		||||
 | 
			
		||||
    @Autowired
 | 
			
		||||
    private final ArticleRepository articleRepository = null;
 | 
			
		||||
 | 
			
		||||
    @Autowired
 | 
			
		||||
    private final WarehouseBookingPositionSlotEntryRepository warehouseBookingPositionSlotEntryRepository = null;
 | 
			
		||||
 | 
			
		||||
    @GetMapping("/")
 | 
			
		||||
    public String home() {
 | 
			
		||||
        return "redirect:/shop/";
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    @GetMapping("/shop/")
 | 
			
		||||
    public String shop(Model model, HttpSession session) {
 | 
			
		||||
 | 
			
		||||
        List<Article> commercialArticles = GetRandomArticlesAction.getRandomArticles(8, articleRepository.getAdvertisedArticles()); //get random advertised Articles
 | 
			
		||||
        model.addAttribute("commercialArticles", commercialArticles);
 | 
			
		||||
 | 
			
		||||
        boolean isLoggedIn = false;
 | 
			
		||||
        boolean hasOrders = false;
 | 
			
		||||
 | 
			
		||||
        if (session != null && session.getAttribute("userId") != null) {    //check if logged in
 | 
			
		||||
            long userId = (long) session.getAttribute("userId");
 | 
			
		||||
            isLoggedIn = true;
 | 
			
		||||
 | 
			
		||||
            List<Article> suggestedArticles = articleRepository.getOrderedArticles(userId);
 | 
			
		||||
            suggestedArticles = suggestedArticles.size() > 3 ? suggestedArticles.subList(0, 4) : suggestedArticles; //only latest 4 ordered articles
 | 
			
		||||
            if (suggestedArticles.size() > 0) {
 | 
			
		||||
                model.addAttribute("suggestedArticles", suggestedArticles);
 | 
			
		||||
                hasOrders = true;
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        model.addAttribute("isLoggedIn", isLoggedIn);
 | 
			
		||||
        model.addAttribute("hasOrders", hasOrders);
 | 
			
		||||
 | 
			
		||||
        return "shop/index";
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    @GetMapping("/about")
 | 
			
		||||
    public String about() {
 | 
			
		||||
        return "about";
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    @GetMapping("/terms")
 | 
			
		||||
    public String terms() {
 | 
			
		||||
        return "terms";
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    @GetMapping("/privacy")
 | 
			
		||||
    public String privacy() {
 | 
			
		||||
        return "privacy";
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@ -1,8 +1,50 @@
 | 
			
		||||
package org.hso.ecommerce.controller.shop;
 | 
			
		||||
 | 
			
		||||
import org.hso.ecommerce.action.shop.SearchByTermAction;
 | 
			
		||||
import org.hso.ecommerce.entities.shop.Article;
 | 
			
		||||
import org.hso.ecommerce.repos.shop.ArticleRepository;
 | 
			
		||||
import org.hso.ecommerce.repos.shop.CategoryRepository;
 | 
			
		||||
import org.springframework.beans.factory.annotation.Autowired;
 | 
			
		||||
import org.springframework.stereotype.Controller;
 | 
			
		||||
import org.springframework.ui.Model;
 | 
			
		||||
import org.springframework.web.bind.annotation.*;
 | 
			
		||||
 | 
			
		||||
import javax.servlet.http.HttpServletRequest;
 | 
			
		||||
import javax.servlet.http.HttpServletResponse;
 | 
			
		||||
import java.util.List;
 | 
			
		||||
 | 
			
		||||
@Controller
 | 
			
		||||
//@RequestMapping("...")
 | 
			
		||||
@RequestMapping("/shop/search")
 | 
			
		||||
public class ShopSearchController {
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
    @Autowired
 | 
			
		||||
    private final ArticleRepository articleRepository = null;
 | 
			
		||||
 | 
			
		||||
    @Autowired
 | 
			
		||||
    private final CategoryRepository categoryRepository = null;
 | 
			
		||||
 | 
			
		||||
    @GetMapping("")
 | 
			
		||||
    public String searchArticles(@RequestParam(required = false, value = "term") String term,
 | 
			
		||||
                                 @RequestParam(required = false, value = "category") String category,
 | 
			
		||||
                                 Model model,
 | 
			
		||||
                                 HttpServletRequest request,
 | 
			
		||||
                                 HttpServletResponse response
 | 
			
		||||
    ) {
 | 
			
		||||
        model.addAttribute("categories", categoryRepository.getCategories());   //for sidebar
 | 
			
		||||
 | 
			
		||||
        if (term != null) { //if search by Term
 | 
			
		||||
            term = term.trim();
 | 
			
		||||
            List<Article> articles = SearchByTermAction.searchByTerm(term, articleRepository);
 | 
			
		||||
            model.addAttribute("articles", articles);
 | 
			
		||||
        } else if (category != null) {  //if search by Category
 | 
			
		||||
            List<Article> articles = articleRepository.getArticlesByCategory(category); //search by Category
 | 
			
		||||
            model.addAttribute("articles", articles);
 | 
			
		||||
        } else {
 | 
			
		||||
            request.setAttribute("error", "Es wurden keine Suchparameter angegeben.");
 | 
			
		||||
            response.setStatus(HttpServletResponse.SC_NOT_FOUND);
 | 
			
		||||
            return "error/404";
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        return "/shop/search";
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
@ -1,6 +1,7 @@
 | 
			
		||||
package org.hso.ecommerce.entities.booking;
 | 
			
		||||
 | 
			
		||||
import javax.persistence.*;
 | 
			
		||||
import javax.validation.constraints.NotNull;
 | 
			
		||||
 | 
			
		||||
@Entity
 | 
			
		||||
@Table(name = "bookings")
 | 
			
		||||
@ -14,12 +15,15 @@ public class Booking {
 | 
			
		||||
    // always >= 0
 | 
			
		||||
    public int amountCent;
 | 
			
		||||
 | 
			
		||||
    @ManyToOne(optional = true)
 | 
			
		||||
    @NotNull
 | 
			
		||||
    public java.sql.Timestamp created;
 | 
			
		||||
 | 
			
		||||
    @ManyToOne(optional = true, cascade = CascadeType.ALL)
 | 
			
		||||
    public BookingAccountEntry source;
 | 
			
		||||
 | 
			
		||||
    @ManyToOne(optional = true)
 | 
			
		||||
    @ManyToOne(optional = true, cascade = CascadeType.ALL)
 | 
			
		||||
    public BookingAccountEntry destination;
 | 
			
		||||
 | 
			
		||||
    @OneToOne(optional = false)
 | 
			
		||||
    @OneToOne(optional = false, cascade = CascadeType.ALL)
 | 
			
		||||
    public BookingReason reason;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@ -16,13 +16,57 @@ public class BookingAccountEntry {
 | 
			
		||||
 | 
			
		||||
    public int newSumCent;
 | 
			
		||||
 | 
			
		||||
    @ManyToOne(optional = true)
 | 
			
		||||
    @ManyToOne(optional = true, cascade = CascadeType.MERGE)
 | 
			
		||||
    public User userAccount;
 | 
			
		||||
 | 
			
		||||
    @ManyToOne(optional = true)
 | 
			
		||||
    @ManyToOne(optional = true, cascade = CascadeType.MERGE)
 | 
			
		||||
    public Supplier supplierAccount;
 | 
			
		||||
 | 
			
		||||
    public boolean isMainAccount;
 | 
			
		||||
    public boolean isVATAccount;
 | 
			
		||||
 | 
			
		||||
    public BookingAccountEntry copyAddAmount(int amountCent) {
 | 
			
		||||
        BookingAccountEntry e = new BookingAccountEntry();
 | 
			
		||||
 | 
			
		||||
        e.userAccount = userAccount;
 | 
			
		||||
        e.supplierAccount = supplierAccount;
 | 
			
		||||
        e.isMainAccount = isMainAccount;
 | 
			
		||||
        e.isVATAccount = isVATAccount;
 | 
			
		||||
 | 
			
		||||
        e.newSumCent = newSumCent + amountCent;
 | 
			
		||||
 | 
			
		||||
        return e;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public static BookingAccountEntry newUser(User user) {
 | 
			
		||||
        BookingAccountEntry e = new BookingAccountEntry();
 | 
			
		||||
        e.userAccount = user;
 | 
			
		||||
        e.newSumCent = 0;
 | 
			
		||||
 | 
			
		||||
        return e;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public static BookingAccountEntry newSupplier(Supplier supplier) {
 | 
			
		||||
        BookingAccountEntry e = new BookingAccountEntry();
 | 
			
		||||
        e.supplierAccount = supplier;
 | 
			
		||||
        e.newSumCent = 0;
 | 
			
		||||
 | 
			
		||||
        return e;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public static BookingAccountEntry newMain() {
 | 
			
		||||
        BookingAccountEntry e = new BookingAccountEntry();
 | 
			
		||||
        e.isMainAccount = true;
 | 
			
		||||
        e.newSumCent = 0;
 | 
			
		||||
 | 
			
		||||
        return e;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public static BookingAccountEntry newVat() {
 | 
			
		||||
        BookingAccountEntry e = new BookingAccountEntry();
 | 
			
		||||
        e.isVATAccount = true;
 | 
			
		||||
        e.newSumCent = 0;
 | 
			
		||||
 | 
			
		||||
        return e;
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@ -22,9 +22,30 @@ public class BookingReason {
 | 
			
		||||
    @ManyToOne(optional = true)
 | 
			
		||||
    public CustomerOrder customerOrder;
 | 
			
		||||
 | 
			
		||||
    @ManyToOne(optional = true)
 | 
			
		||||
    @OneToOne(optional = true, cascade = CascadeType.ALL)
 | 
			
		||||
    public CustomerPayment customerPayment;
 | 
			
		||||
 | 
			
		||||
    @ManyToOne(optional = true)
 | 
			
		||||
    public SupplierOrder supplierOrder;
 | 
			
		||||
 | 
			
		||||
    // Default Constructor is needed for construction by ORM
 | 
			
		||||
    public BookingReason() {
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public BookingReason(CustomerOrder order) {
 | 
			
		||||
        this.customerOrder = order;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public BookingReason(CustomerPayment customerPayment) {
 | 
			
		||||
        this.customerPayment = customerPayment;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public BookingReason(SupplierOrder supplierOrder) {
 | 
			
		||||
        this.supplierOrder = supplierOrder;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public BookingReason(String comment) {
 | 
			
		||||
        this.isManuel = true;
 | 
			
		||||
        this.comment = comment;
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@ -1,10 +1,16 @@
 | 
			
		||||
package org.hso.ecommerce.entities.booking;
 | 
			
		||||
 | 
			
		||||
import javax.persistence.Embeddable;
 | 
			
		||||
import javax.validation.constraints.NotNull;
 | 
			
		||||
 | 
			
		||||
@Embeddable
 | 
			
		||||
public class PaymentMethod {
 | 
			
		||||
    @NotNull
 | 
			
		||||
 | 
			
		||||
    public String creditCardNumber;
 | 
			
		||||
 | 
			
		||||
    public static PaymentMethod fromCreditCardNumber(String cardnumber) {
 | 
			
		||||
        PaymentMethod m = new PaymentMethod();
 | 
			
		||||
        m.creditCardNumber = cardnumber;
 | 
			
		||||
 | 
			
		||||
        return m;
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@ -7,8 +7,8 @@ import javax.validation.constraints.NotNull;
 | 
			
		||||
@Table(name = "background_jobs")
 | 
			
		||||
public class BackgroundJob {
 | 
			
		||||
 | 
			
		||||
    public final String JOB_DASHBOARD = "Dashboard";
 | 
			
		||||
    public final String JOB_REORDER = "SupplierOrder";
 | 
			
		||||
    public static final String JOB_DASHBOARD = "Dashboard";
 | 
			
		||||
    public static final String JOB_REORDER = "SupplierOrder";
 | 
			
		||||
 | 
			
		||||
    @Id
 | 
			
		||||
    @GeneratedValue(strategy = GenerationType.IDENTITY)
 | 
			
		||||
 | 
			
		||||
@ -4,7 +4,24 @@ import javax.persistence.Embeddable;
 | 
			
		||||
 | 
			
		||||
@Embeddable
 | 
			
		||||
public class Address {
 | 
			
		||||
    public String name;
 | 
			
		||||
    public String addressString;
 | 
			
		||||
    public String name = "";
 | 
			
		||||
    public String addressString = "";
 | 
			
		||||
    public String country = "DE";
 | 
			
		||||
 | 
			
		||||
    @Override
 | 
			
		||||
    public String toString() {
 | 
			
		||||
        return name + "\n" + addressString;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public static Address fromString(String addr) {
 | 
			
		||||
        Address a = new Address();
 | 
			
		||||
 | 
			
		||||
        String[] arr = addr.split("\n", 2);
 | 
			
		||||
        a.name = arr[0];
 | 
			
		||||
        if (arr.length > 1) {
 | 
			
		||||
            a.addressString = arr[1];
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        return a;
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@ -16,7 +16,7 @@ public class Article {
 | 
			
		||||
    @Basic
 | 
			
		||||
    public long id;
 | 
			
		||||
 | 
			
		||||
    @ManyToOne(optional = false)
 | 
			
		||||
    @OneToOne(optional = false)
 | 
			
		||||
    public ArticleOffer related;
 | 
			
		||||
 | 
			
		||||
    public int shopPricePerUnitNetCent;
 | 
			
		||||
@ -32,9 +32,18 @@ public class Article {
 | 
			
		||||
    public String description;
 | 
			
		||||
 | 
			
		||||
    @OneToOne(optional = true)
 | 
			
		||||
    @Basic(fetch = FetchType.LAZY)
 | 
			
		||||
    public Image image;
 | 
			
		||||
 | 
			
		||||
    @ManyToMany
 | 
			
		||||
    @ManyToMany(cascade = CascadeType.ALL)
 | 
			
		||||
    @JoinTable(name = "article_categories_bindings")
 | 
			
		||||
    public Set<Category> categories = new HashSet<>();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
    public int getVat() {
 | 
			
		||||
        return (shopPricePerUnitNetCent * related.vatPercent) / 100;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public int getPriceGross() {
 | 
			
		||||
        return shopPricePerUnitNetCent + getVat();
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
@ -1,7 +1,5 @@
 | 
			
		||||
package org.hso.ecommerce.entities.shop;
 | 
			
		||||
 | 
			
		||||
import org.hso.ecommerce.entities.shop.Article;
 | 
			
		||||
 | 
			
		||||
import javax.persistence.*;
 | 
			
		||||
import javax.validation.constraints.NotNull;
 | 
			
		||||
import java.util.HashSet;
 | 
			
		||||
@ -22,4 +20,15 @@ public class Category {
 | 
			
		||||
 | 
			
		||||
    @ManyToMany(mappedBy = "categories")
 | 
			
		||||
    public Set<Article> articles = new HashSet<>();
 | 
			
		||||
    
 | 
			
		||||
    
 | 
			
		||||
    public Category() {
 | 
			
		||||
    	
 | 
			
		||||
    }
 | 
			
		||||
    
 | 
			
		||||
    
 | 
			
		||||
    public Category (String name) {
 | 
			
		||||
    	this.name = name;
 | 
			
		||||
    }
 | 
			
		||||
    
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@ -4,6 +4,7 @@ import org.hso.ecommerce.entities.user.User;
 | 
			
		||||
 | 
			
		||||
import javax.persistence.*;
 | 
			
		||||
import javax.validation.constraints.NotNull;
 | 
			
		||||
import java.text.SimpleDateFormat;
 | 
			
		||||
import java.util.ArrayList;
 | 
			
		||||
import java.util.List;
 | 
			
		||||
 | 
			
		||||
@ -24,14 +25,14 @@ public class CustomerOrder {
 | 
			
		||||
 | 
			
		||||
    @OneToMany(
 | 
			
		||||
            targetEntity = CustomerOrderPosition.class,
 | 
			
		||||
            mappedBy = "order"
 | 
			
		||||
            mappedBy = "order", cascade = CascadeType.ALL
 | 
			
		||||
    )
 | 
			
		||||
    public List<CustomerOrderPosition> positions = new ArrayList<>();
 | 
			
		||||
 | 
			
		||||
    @NotNull
 | 
			
		||||
    public java.sql.Timestamp created;
 | 
			
		||||
 | 
			
		||||
    @NotNull
 | 
			
		||||
    @Column(nullable = true)
 | 
			
		||||
    public String trackingId;
 | 
			
		||||
 | 
			
		||||
    @Column(nullable = true)
 | 
			
		||||
@ -43,4 +44,21 @@ public class CustomerOrder {
 | 
			
		||||
    public int totalNetCent;
 | 
			
		||||
    public int totalGrossCent;
 | 
			
		||||
    public int totalVatCent;
 | 
			
		||||
 | 
			
		||||
    public String formatInDeliverySince(){
 | 
			
		||||
        return new SimpleDateFormat("dd.MM.yyyy HH:mm").format(inDeliverySince);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public String formatCreated(){
 | 
			
		||||
        return new SimpleDateFormat("dd.MM.yyyy HH:mm").format(created);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public String formatDeliveredAt(){
 | 
			
		||||
        return new SimpleDateFormat("dd.MM.yyyy HH:mm").format(deliveredAt);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public String getEstimatedArrival() {
 | 
			
		||||
        //TODO: get estimated arrival from api
 | 
			
		||||
        return "TODO TODO TODO";
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@ -19,4 +19,8 @@ public class CustomerOrderPosition {
 | 
			
		||||
 | 
			
		||||
    public int pricePerUnit;
 | 
			
		||||
    public int quantity;
 | 
			
		||||
 | 
			
		||||
    public int getSumPrice(){
 | 
			
		||||
        return article.getPriceGross() * quantity;
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@ -11,7 +11,5 @@ public class Image {
 | 
			
		||||
    @Basic
 | 
			
		||||
    public long id;
 | 
			
		||||
 | 
			
		||||
    @Lob
 | 
			
		||||
    @Column(name = "data", columnDefinition = "BLOB", nullable = false)
 | 
			
		||||
    private byte[] data;
 | 
			
		||||
}
 | 
			
		||||
    public String path;
 | 
			
		||||
}
 | 
			
		||||
@ -0,0 +1,103 @@
 | 
			
		||||
package org.hso.ecommerce.entities.shop;
 | 
			
		||||
 | 
			
		||||
import java.util.ArrayList;
 | 
			
		||||
import java.util.List;
 | 
			
		||||
 | 
			
		||||
// Not a db entity. Just for session storage
 | 
			
		||||
public class ShoppingCart {
 | 
			
		||||
 | 
			
		||||
    private final static int MAX_ITEMS = 10;
 | 
			
		||||
 | 
			
		||||
    private int revision;
 | 
			
		||||
    private ArrayList<ShoppingCartItem> items;
 | 
			
		||||
 | 
			
		||||
    public ShoppingCart() {
 | 
			
		||||
        clear();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public void clear() {
 | 
			
		||||
        items = new ArrayList<>();
 | 
			
		||||
        revision = (int) Math.round(Math.random() * 0xFFFF);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public List<ShoppingCartItem> getItems() {
 | 
			
		||||
        return items;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public int getItemCount() {
 | 
			
		||||
        int count = 0;
 | 
			
		||||
 | 
			
		||||
        for (ShoppingCartItem i : items) {
 | 
			
		||||
            count += i.getAmount();
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        return count;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public int getRevision() {
 | 
			
		||||
        return revision;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public void addArticle(Article article, int quantity) {
 | 
			
		||||
        this.revision++;
 | 
			
		||||
 | 
			
		||||
        for (ShoppingCartItem i : items) {
 | 
			
		||||
            if (i.getArticleId() == article.id) {
 | 
			
		||||
                i.addAmount(quantity);
 | 
			
		||||
                return;
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        items.add(new ShoppingCartItem(quantity, article));
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public void setArticleCount(Article article, Integer quantity) {
 | 
			
		||||
        this.revision++;
 | 
			
		||||
 | 
			
		||||
        boolean found = false;
 | 
			
		||||
        for (ShoppingCartItem i : items) {
 | 
			
		||||
            if (i.getArticleId() == article.id) {
 | 
			
		||||
                i.setAmount(quantity);
 | 
			
		||||
                found = true;
 | 
			
		||||
                break;
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
        if (!found) {
 | 
			
		||||
            items.add(new ShoppingCartItem(quantity, article));
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        items.removeIf(i -> i.getAmount() <= 0);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public static class ShoppingCartItem {
 | 
			
		||||
        private int amount;
 | 
			
		||||
        private final long articleId;
 | 
			
		||||
 | 
			
		||||
        public ShoppingCartItem(int amount, Article article) {
 | 
			
		||||
            this.amount = amount;
 | 
			
		||||
            this.articleId = article.id;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        public int getAmount() {
 | 
			
		||||
            return amount;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        public void addAmount(int amount) {
 | 
			
		||||
            this.amount += amount;
 | 
			
		||||
            if (this.amount > MAX_ITEMS) {
 | 
			
		||||
                this.amount = MAX_ITEMS;
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        public long getArticleId() {
 | 
			
		||||
            return articleId;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        public void setAmount(Integer amount) {
 | 
			
		||||
            this.amount = amount;
 | 
			
		||||
            if (this.amount > MAX_ITEMS) {
 | 
			
		||||
                this.amount = MAX_ITEMS;
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
@ -14,9 +14,20 @@ public class ArticleOffer {
 | 
			
		||||
 | 
			
		||||
    @NotNull
 | 
			
		||||
    public String manufacturer;
 | 
			
		||||
    
 | 
			
		||||
    @NotNull
 | 
			
		||||
    public String title;
 | 
			
		||||
    
 | 
			
		||||
    @NotNull
 | 
			
		||||
    public int pricePerUnitNet;
 | 
			
		||||
 | 
			
		||||
    @NotNull
 | 
			
		||||
    public String articleNumber;
 | 
			
		||||
 | 
			
		||||
    public int vatPercent;
 | 
			
		||||
 | 
			
		||||
    public boolean shouldBeAdvertised;
 | 
			
		||||
    
 | 
			
		||||
    @ManyToOne(optional = true)
 | 
			
		||||
    public Supplier cheapestSupplier;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@ -24,16 +24,21 @@ public class User {
 | 
			
		||||
    @Column(unique = true)
 | 
			
		||||
    public String email;
 | 
			
		||||
 | 
			
		||||
    @Column(insertable = false, updatable = false)
 | 
			
		||||
    public String name;
 | 
			
		||||
 | 
			
		||||
    public String salutation;
 | 
			
		||||
 | 
			
		||||
    public String passwordHash;
 | 
			
		||||
 | 
			
		||||
    public boolean isActive;
 | 
			
		||||
    public boolean isEmployee;
 | 
			
		||||
 | 
			
		||||
    @Embedded
 | 
			
		||||
    private Address defaultDeliveryAddress;
 | 
			
		||||
    public Address defaultDeliveryAddress;
 | 
			
		||||
 | 
			
		||||
    @Embedded
 | 
			
		||||
    private PaymentMethod defaultPayment;
 | 
			
		||||
    public PaymentMethod defaultPayment;
 | 
			
		||||
 | 
			
		||||
    public long getId() {
 | 
			
		||||
        return id;
 | 
			
		||||
 | 
			
		||||
@ -0,0 +1,17 @@
 | 
			
		||||
package org.hso.ecommerce.entities.warehouse;
 | 
			
		||||
 | 
			
		||||
import javax.persistence.*;
 | 
			
		||||
import javax.validation.constraints.NotNull;
 | 
			
		||||
 | 
			
		||||
@Entity
 | 
			
		||||
@Table(name = "warehouse_slots")
 | 
			
		||||
public class Slot {
 | 
			
		||||
    @Id
 | 
			
		||||
    @GeneratedValue(strategy = GenerationType.IDENTITY)
 | 
			
		||||
    @Basic
 | 
			
		||||
    public long id;
 | 
			
		||||
 | 
			
		||||
    @NotNull
 | 
			
		||||
    @Column(unique = true)
 | 
			
		||||
    public int slotNum;
 | 
			
		||||
}
 | 
			
		||||
@ -1,5 +1,7 @@
 | 
			
		||||
package org.hso.ecommerce.entities.warehouse;
 | 
			
		||||
 | 
			
		||||
import org.hso.ecommerce.entities.booking.BookingReason;
 | 
			
		||||
 | 
			
		||||
import javax.persistence.*;
 | 
			
		||||
import javax.validation.constraints.NotNull;
 | 
			
		||||
import java.util.ArrayList;
 | 
			
		||||
@ -21,7 +23,11 @@ public class WarehouseBooking {
 | 
			
		||||
    public boolean isDone;
 | 
			
		||||
 | 
			
		||||
    @OneToMany(
 | 
			
		||||
            mappedBy = "booking"
 | 
			
		||||
            mappedBy = "booking", cascade = CascadeType.ALL
 | 
			
		||||
    )
 | 
			
		||||
    public List<WarehouseBookingPosition> positions = new ArrayList<>();
 | 
			
		||||
 | 
			
		||||
    // TODO FIX ME
 | 
			
		||||
    @OneToOne(optional = false, cascade = CascadeType.ALL)
 | 
			
		||||
    public BookingReason reason;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@ -23,10 +23,6 @@ public class WarehouseBookingPosition {
 | 
			
		||||
 | 
			
		||||
    public int amount; // positive or negative
 | 
			
		||||
 | 
			
		||||
    @ManyToOne(optional = true)
 | 
			
		||||
    public WarehouseBookingPositionSlotEntry source;
 | 
			
		||||
 | 
			
		||||
    @ManyToOne(optional = true)
 | 
			
		||||
    public WarehouseBookingPositionSlotEntry destination;
 | 
			
		||||
 | 
			
		||||
    @ManyToOne(optional = true, cascade = CascadeType.ALL)
 | 
			
		||||
    public WarehouseBookingPositionSlotEntry slotEntry;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@ -3,6 +3,7 @@ package org.hso.ecommerce.entities.warehouse;
 | 
			
		||||
import org.hso.ecommerce.entities.shop.Article;
 | 
			
		||||
 | 
			
		||||
import javax.persistence.*;
 | 
			
		||||
import javax.validation.constraints.NotNull;
 | 
			
		||||
 | 
			
		||||
@Entity
 | 
			
		||||
@Table(name = "warehouse_booking_position_entries")
 | 
			
		||||
@ -13,11 +14,43 @@ public class WarehouseBookingPositionSlotEntry {
 | 
			
		||||
    @Basic
 | 
			
		||||
    public long id;
 | 
			
		||||
 | 
			
		||||
    @NotNull
 | 
			
		||||
    @ManyToOne
 | 
			
		||||
    public Article article;
 | 
			
		||||
 | 
			
		||||
    public int newSumArticles;
 | 
			
		||||
    public int newSumWarehousePosition;
 | 
			
		||||
    @NotNull
 | 
			
		||||
    public int newSumSlot;
 | 
			
		||||
 | 
			
		||||
    public int slot;
 | 
			
		||||
    @NotNull
 | 
			
		||||
    @ManyToOne
 | 
			
		||||
    public Slot slot;
 | 
			
		||||
 | 
			
		||||
    public WarehouseBookingPositionSlotEntry copyAddAmount(int amount, Article article) {
 | 
			
		||||
        // Article can be changed if newSumSlot == 0.
 | 
			
		||||
        if (this.newSumSlot != 0 && this.article.id != article.id) {
 | 
			
		||||
            throw new IllegalArgumentException("Article does not match.");
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        WarehouseBookingPositionSlotEntry e = new WarehouseBookingPositionSlotEntry();
 | 
			
		||||
 | 
			
		||||
        e.article = article;
 | 
			
		||||
        e.slot = slot;
 | 
			
		||||
 | 
			
		||||
        e.newSumSlot = newSumSlot + amount;
 | 
			
		||||
 | 
			
		||||
        assert e.article.warehouseUnitsPerSlot >= e.newSumSlot;
 | 
			
		||||
        assert e.newSumSlot >= 0;
 | 
			
		||||
 | 
			
		||||
        return e;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public static WarehouseBookingPositionSlotEntry empty(Article article, Slot slot) {
 | 
			
		||||
        WarehouseBookingPositionSlotEntry e = new WarehouseBookingPositionSlotEntry();
 | 
			
		||||
 | 
			
		||||
        e.article = article;
 | 
			
		||||
        e.slot = slot;
 | 
			
		||||
        e.newSumSlot = 0;
 | 
			
		||||
 | 
			
		||||
        return e;
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@ -23,4 +23,12 @@ public class WarehouseBookingReason {
 | 
			
		||||
    public CustomerOrder customerOrder;
 | 
			
		||||
 | 
			
		||||
    public boolean isManuel;
 | 
			
		||||
 | 
			
		||||
    // Default Constructor is needed for construction by ORM
 | 
			
		||||
    public WarehouseBookingReason() {
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public WarehouseBookingReason(CustomerOrder order) {
 | 
			
		||||
        this.customerOrder = order;
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@ -0,0 +1,28 @@
 | 
			
		||||
package org.hso.ecommerce.repos.booking;
 | 
			
		||||
 | 
			
		||||
import java.util.Optional;
 | 
			
		||||
 | 
			
		||||
import org.hso.ecommerce.entities.booking.BookingAccountEntry;
 | 
			
		||||
import org.springframework.data.jpa.repository.JpaRepository;
 | 
			
		||||
import org.springframework.data.jpa.repository.Query;
 | 
			
		||||
import org.springframework.stereotype.Repository;
 | 
			
		||||
 | 
			
		||||
@Repository
 | 
			
		||||
public interface BookingAccountEntryRepository extends JpaRepository<BookingAccountEntry, Long> {
 | 
			
		||||
 | 
			
		||||
    @Query(value = "SELECT * FROM booking_account_entries as e WHERE e.user_account_id = :user ORDER BY e.id DESC LIMIT 1", nativeQuery = true)
 | 
			
		||||
    Optional<BookingAccountEntry> getByUser(Long user);
 | 
			
		||||
 | 
			
		||||
    @Query(value = "SELECT * FROM booking_account_entries as e WHERE e.supplier_account_id = :supplier ORDER BY e.id DESC LIMIT 1", nativeQuery = true)
 | 
			
		||||
    Optional<BookingAccountEntry> getBySupplier(Long supplier);
 | 
			
		||||
 | 
			
		||||
    @Query(value = "SELECT * FROM booking_account_entries as e WHERE e.is_main_account = 1 ORDER BY e.id DESC LIMIT 1", nativeQuery = true)
 | 
			
		||||
    Optional<BookingAccountEntry> getByMain();
 | 
			
		||||
 | 
			
		||||
    @Query(value = "SELECT * FROM booking_account_entries as e WHERE e.isvataccount = 1 ORDER BY e.id DESC LIMIT 1", nativeQuery = true)
 | 
			
		||||
    Optional<BookingAccountEntry> getByVat();
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@ -0,0 +1,28 @@
 | 
			
		||||
package org.hso.ecommerce.repos.booking;
 | 
			
		||||
 | 
			
		||||
import java.util.List;
 | 
			
		||||
 | 
			
		||||
import org.hso.ecommerce.entities.booking.Booking;
 | 
			
		||||
import org.springframework.data.jpa.repository.JpaRepository;
 | 
			
		||||
import org.springframework.data.jpa.repository.Query;
 | 
			
		||||
import org.springframework.stereotype.Repository;
 | 
			
		||||
 | 
			
		||||
@Repository
 | 
			
		||||
public interface BookingRepository extends JpaRepository<Booking, Long> {
 | 
			
		||||
 | 
			
		||||
    @Query("SELECT b FROM Booking b ORDER BY b.id DESC")
 | 
			
		||||
    List<Booking> allBookingsReverseChronologically();
 | 
			
		||||
 | 
			
		||||
    @Query("SELECT b FROM Booking b LEFT JOIN b.source s LEFT JOIN b.destination d WHERE s.isMainAccount = 1 OR d.isMainAccount = 1 ORDER BY b.id DESC")
 | 
			
		||||
    List<Booking> mainBookingsReverseChronologically();
 | 
			
		||||
 | 
			
		||||
    @Query("SELECT b FROM Booking b LEFT JOIN b.source s LEFT JOIN b.destination d WHERE s.isVATAccount = 1 OR d.isVATAccount = 1 ORDER BY b.id DESC")
 | 
			
		||||
    List<Booking> vatBookingsReverseChronologically();
 | 
			
		||||
 | 
			
		||||
    @Query("SELECT b FROM Booking b LEFT JOIN b.source s LEFT JOIN b.destination d WHERE s.userAccount.id = :customerId OR d.userAccount.id = :customerId ORDER BY b.id DESC")
 | 
			
		||||
    List<Booking> customerBookingsReverseChronologically(long customerId);
 | 
			
		||||
 | 
			
		||||
    @Query("SELECT b FROM Booking b LEFT JOIN b.source s LEFT JOIN b.destination d WHERE s.supplierAccount.id = :supplierId OR d.supplierAccount.id = :supplierId ORDER BY b.id DESC")
 | 
			
		||||
    List<Booking> supplierBookingsReverseChronologically(long supplierId);
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
@ -0,0 +1,10 @@
 | 
			
		||||
package org.hso.ecommerce.repos.cronjob;
 | 
			
		||||
 | 
			
		||||
import org.hso.ecommerce.entities.cron.BackgroundJob;
 | 
			
		||||
import org.springframework.data.jpa.repository.JpaRepository;
 | 
			
		||||
import org.springframework.stereotype.Repository;
 | 
			
		||||
 | 
			
		||||
@Repository
 | 
			
		||||
public interface BackgroundJobRepository extends JpaRepository<BackgroundJob, Long> {
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
@ -0,0 +1,53 @@
 | 
			
		||||
package org.hso.ecommerce.repos.shop;
 | 
			
		||||
 | 
			
		||||
import org.hso.ecommerce.entities.shop.Article;
 | 
			
		||||
import org.hso.ecommerce.entities.supplier.ArticleOffer;
 | 
			
		||||
import org.springframework.data.jpa.repository.JpaRepository;
 | 
			
		||||
import org.springframework.data.jpa.repository.Query;
 | 
			
		||||
import org.springframework.data.repository.query.Param;
 | 
			
		||||
import org.springframework.stereotype.Repository;
 | 
			
		||||
 | 
			
		||||
import java.util.List;
 | 
			
		||||
import java.util.Optional;
 | 
			
		||||
 | 
			
		||||
@Repository
 | 
			
		||||
public interface ArticleRepository extends JpaRepository<Article, Long> {
 | 
			
		||||
 | 
			
		||||
    /***
 | 
			
		||||
     * use findById instead.
 | 
			
		||||
     */
 | 
			
		||||
    @Deprecated
 | 
			
		||||
    @Query("SELECT a FROM Article a WHERE a.id = :articleId")
 | 
			
		||||
    Article findArticleById(@Param("articleId") long articleId);
 | 
			
		||||
 | 
			
		||||
    @Query("SELECT a FROM Article a")
 | 
			
		||||
    List<Article> findAll();
 | 
			
		||||
 | 
			
		||||
    @Query(value = "Select a.* from articles as a, article_offers as ao, warehouse_booking_position_entries as wbpe where a.related_id = ao.id and wbpe.article_id = a.id and ao.should_be_advertised = true group by wbpe.slot_id having max(wbpe.id) and wbpe.new_sum_slot != 0", nativeQuery = true)
 | 
			
		||||
    List<Article> getAdvertisedArticles();
 | 
			
		||||
 | 
			
		||||
    @Query("SELECT a FROM CustomerOrderPosition cop JOIN cop.order co JOIN co.customer c JOIN cop.article a ORDER BY co.id DESC")
 | 
			
		||||
    List<Article> getOrderedArticles();
 | 
			
		||||
 | 
			
		||||
    @Query("SELECT a FROM CustomerOrderPosition cop JOIN cop.order co JOIN co.customer c JOIN cop.article a WHERE c.id = :customerId ORDER BY co.id DESC")
 | 
			
		||||
    List<Article> getOrderedArticles(long customerId);
 | 
			
		||||
 | 
			
		||||
    /***
 | 
			
		||||
     * use type safe findArticleByArticleOffer instead.
 | 
			
		||||
     */
 | 
			
		||||
    @Deprecated
 | 
			
		||||
    @Query(value = "SELECT a.id FROM articles a WHERE a.related_id = :relatedId", nativeQuery = true)
 | 
			
		||||
    Optional<Integer> findArticleIDByRelatedID(@Param("relatedId") long relatedId);
 | 
			
		||||
 | 
			
		||||
    @Query(value = "SELECT a FROM Article a Where a.related = :related")
 | 
			
		||||
    Optional<Article> findArticleByArticleOffer(ArticleOffer related);
 | 
			
		||||
 | 
			
		||||
    @Query(value = "Select a.* from articles as a, warehouse_booking_position_entries as wbpe where wbpe.article_id = a.id and a.title LIKE %:term% group by wbpe.slot_id having max(wbpe.id) and wbpe.new_sum_slot != 0", nativeQuery = true)
 | 
			
		||||
    List<Article> getArticlesByTermInTitle(String term);
 | 
			
		||||
 | 
			
		||||
    @Query(value = "Select a.* from articles as a, warehouse_booking_position_entries as wbpe where wbpe.article_id = a.id and a.description LIKE %:term% group by wbpe.slot_id having max(wbpe.id) and wbpe.new_sum_slot != 0", nativeQuery = true)
 | 
			
		||||
    List<Article> getArticlesByTermInDescription(String term);
 | 
			
		||||
 | 
			
		||||
    @Query(value = "Select a.* from articles as a, categories as c, article_categories_bindings as acb, warehouse_booking_position_entries as wbpe where wbpe.article_id = a.id and acb.articles_id = a.id and acb.categories_id = c.id and c.name = :category group by wbpe.slot_id having max(wbpe.id) and wbpe.new_sum_slot != 0", nativeQuery = true)
 | 
			
		||||
    List<Article> getArticlesByCategory(String category);
 | 
			
		||||
}
 | 
			
		||||
@ -0,0 +1,20 @@
 | 
			
		||||
package org.hso.ecommerce.repos.shop;
 | 
			
		||||
 | 
			
		||||
import org.hso.ecommerce.entities.shop.Category;
 | 
			
		||||
import org.springframework.data.jpa.repository.JpaRepository;
 | 
			
		||||
import org.springframework.data.jpa.repository.Query;
 | 
			
		||||
import org.springframework.data.repository.query.Param;
 | 
			
		||||
import org.springframework.stereotype.Repository;
 | 
			
		||||
 | 
			
		||||
import java.util.List;
 | 
			
		||||
import java.util.Optional;
 | 
			
		||||
 | 
			
		||||
@Repository
 | 
			
		||||
public interface CategoryRepository extends JpaRepository<Category, Long> {
 | 
			
		||||
 | 
			
		||||
	@Query("SELECT a FROM Category a WHERE a.name = :name")
 | 
			
		||||
	Optional<Category> findCategoryByName(@Param("name") String name);
 | 
			
		||||
 | 
			
		||||
    @Query("SELECT c FROM Category c")
 | 
			
		||||
    List<Category> getCategories();
 | 
			
		||||
}
 | 
			
		||||
@ -0,0 +1,21 @@
 | 
			
		||||
package org.hso.ecommerce.repos.shop;
 | 
			
		||||
 | 
			
		||||
import org.hso.ecommerce.entities.shop.CustomerOrder;
 | 
			
		||||
import org.springframework.data.jpa.repository.JpaRepository;
 | 
			
		||||
import org.springframework.data.jpa.repository.Query;
 | 
			
		||||
import org.springframework.stereotype.Repository;
 | 
			
		||||
 | 
			
		||||
import java.util.List;
 | 
			
		||||
 | 
			
		||||
@Repository
 | 
			
		||||
public interface CustomerOrderRepository extends JpaRepository<CustomerOrder, Long> {
 | 
			
		||||
 | 
			
		||||
    @Query("SELECT SUM(cop.quantity) FROM CustomerOrderPosition cop JOIN cop.order co WHERE cop.article.id = :articleId AND co.created >= :begin AND co.created < :end")
 | 
			
		||||
    Integer countOrdersOfArticleInTimespan(
 | 
			
		||||
            long articleId, java.sql.Timestamp begin, java.sql.Timestamp end
 | 
			
		||||
    );
 | 
			
		||||
 | 
			
		||||
    @Query("SELECT co FROM CustomerOrder co WHERE co.customer.id = :userId ORDER BY co.id DESC")
 | 
			
		||||
    List<CustomerOrder> getOrdersByUserId(long userId);
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
@ -0,0 +1,20 @@
 | 
			
		||||
package org.hso.ecommerce.repos.shop;
 | 
			
		||||
 | 
			
		||||
import org.hso.ecommerce.entities.shop.Image;
 | 
			
		||||
import org.springframework.data.jpa.repository.JpaRepository;
 | 
			
		||||
import org.springframework.data.jpa.repository.Query;
 | 
			
		||||
import org.springframework.data.repository.query.Param;
 | 
			
		||||
import org.springframework.stereotype.Repository;
 | 
			
		||||
 | 
			
		||||
import java.util.Optional;
 | 
			
		||||
 | 
			
		||||
@Repository
 | 
			
		||||
public interface ImageRepository extends JpaRepository<Image, Long> {
 | 
			
		||||
 | 
			
		||||
	@Query("SELECT i.id FROM Image i WHERE i.path = :path")
 | 
			
		||||
	Optional<Integer> findImageIDByPath(@Param("path") String path);
 | 
			
		||||
 | 
			
		||||
	@Query("SELECT i FROM Image i WHERE i.id = :imageId")
 | 
			
		||||
	Image findImageById(@Param("imageId") long imageId);
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
@ -0,0 +1,20 @@
 | 
			
		||||
package org.hso.ecommerce.repos.shop;
 | 
			
		||||
 | 
			
		||||
import java.util.List;
 | 
			
		||||
 | 
			
		||||
import org.hso.ecommerce.entities.supplier.ArticleOffer;
 | 
			
		||||
import org.springframework.data.jpa.repository.JpaRepository;
 | 
			
		||||
import org.springframework.data.jpa.repository.Query;
 | 
			
		||||
import org.springframework.data.repository.query.Param;
 | 
			
		||||
import org.springframework.stereotype.Repository;
 | 
			
		||||
 | 
			
		||||
@Repository
 | 
			
		||||
public interface OffersRepository extends JpaRepository<ArticleOffer, Long> {
 | 
			
		||||
 | 
			
		||||
	@Query("SELECT a FROM ArticleOffer a")
 | 
			
		||||
	List<ArticleOffer> findAll();
 | 
			
		||||
	
 | 
			
		||||
	@Query("SELECT a FROM ArticleOffer a WHERE a.id = :offeredarticleId")
 | 
			
		||||
	ArticleOffer findOfferedArticleById(@Param("offeredarticleId") long offeredarticleId);
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
@ -0,0 +1,8 @@
 | 
			
		||||
package org.hso.ecommerce.repos.supplier;
 | 
			
		||||
 | 
			
		||||
import org.hso.ecommerce.entities.supplier.ArticleOffer;
 | 
			
		||||
import org.springframework.data.jpa.repository.JpaRepository;
 | 
			
		||||
 | 
			
		||||
public interface ArticleOfferRepository extends JpaRepository<ArticleOffer, Long> {
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
@ -0,0 +1,22 @@
 | 
			
		||||
package org.hso.ecommerce.repos.supplier;
 | 
			
		||||
 | 
			
		||||
import java.util.List;
 | 
			
		||||
 | 
			
		||||
import org.hso.ecommerce.entities.supplier.SupplierOrder;
 | 
			
		||||
import org.springframework.data.jpa.repository.JpaRepository;
 | 
			
		||||
import org.springframework.data.jpa.repository.Query;
 | 
			
		||||
import org.springframework.data.repository.query.Param;
 | 
			
		||||
import org.springframework.stereotype.Repository;
 | 
			
		||||
 | 
			
		||||
@Repository
 | 
			
		||||
public interface SupplierOrderRepository extends JpaRepository<SupplierOrder, Long> {
 | 
			
		||||
 | 
			
		||||
    @Query("SELECT SUM(so.numberOfUnits) FROM SupplierOrder so JOIN so.ordered ao WHERE ao.articleNumber = :articleNumber AND so.delivered IS NULL")
 | 
			
		||||
    Integer countUndeliveredReorders(String articleNumber);
 | 
			
		||||
 | 
			
		||||
	@Query(value = "SELECT * FROM supplier_orders as a WHERE a.supplier_id = :supplierId", nativeQuery = true)
 | 
			
		||||
	List<SupplierOrder> findOrderBySupplierID(@Param("supplierId") long supplierId);
 | 
			
		||||
    
 | 
			
		||||
	@Query("SELECT a FROM SupplierOrder a")
 | 
			
		||||
	List<SupplierOrder> findAll();
 | 
			
		||||
}
 | 
			
		||||
@ -0,0 +1,19 @@
 | 
			
		||||
package org.hso.ecommerce.repos.supplier;
 | 
			
		||||
 | 
			
		||||
import java.util.List;
 | 
			
		||||
 | 
			
		||||
import org.hso.ecommerce.entities.supplier.Supplier;
 | 
			
		||||
import org.springframework.data.jpa.repository.JpaRepository;
 | 
			
		||||
import org.springframework.data.jpa.repository.Query;
 | 
			
		||||
import org.springframework.data.repository.query.Param;
 | 
			
		||||
import org.springframework.stereotype.Repository;
 | 
			
		||||
 | 
			
		||||
@Repository
 | 
			
		||||
public interface SupplierRepository extends JpaRepository<Supplier, Long> {
 | 
			
		||||
	
 | 
			
		||||
	@Query("SELECT a FROM Supplier a")
 | 
			
		||||
	List<Supplier> findAll();
 | 
			
		||||
	
 | 
			
		||||
	@Query("SELECT a FROM Supplier a WHERE a.id = :supplierId")
 | 
			
		||||
	Supplier findSupplierById(@Param("supplierId") long supplierId);
 | 
			
		||||
}
 | 
			
		||||
Some files were not shown because too many files have changed in this diff Show More
		Reference in New Issue
	
	Block a user
	
Muss in init() eingelesen werden wegen obigen Problem