Add initial application setup with configurations, controllers, DTOs, and error handling.

This commit is contained in:
Jan 2025-11-02 19:15:01 +01:00
commit 015b0d0f93
88 changed files with 5299 additions and 0 deletions

7
.env Normal file
View file

@ -0,0 +1,7 @@
# Database Configuration
SPRING_DATASOURCE_URL=jdbc:mysql://localhost:3306/taric
SPRING_DATASOURCE_USERNAME=spring
SPRING_DATASOURCE_PASSWORD=wrHpGVYwX5YHpmEsXX7y
DB_ROOT_PASSWORD=ok88pbzFocFpTZb4ezGK
SERVER_PORT=8090

2
.gitattributes vendored Normal file
View file

@ -0,0 +1,2 @@
/mvnw text eol=lf
*.cmd text eol=crlf

33
.gitignore vendored Normal file
View file

@ -0,0 +1,33 @@
HELP.md
target/
.mvn/wrapper/maven-wrapper.jar
!**/src/main/**/target/
!**/src/test/**/target/
### STS ###
.apt_generated
.classpath
.factorypath
.project
.settings
.springBeans
.sts4-cache
### IntelliJ IDEA ###
.idea
*.iws
*.iml
*.ipr
### NetBeans ###
/nbproject/private/
/nbbuild/
/dist/
/nbdist/
/.nb-gradle/
build/
!**/src/main/**/build/
!**/src/test/**/build/
### VS Code ###
.vscode/

3
.mvn/wrapper/maven-wrapper.properties vendored Normal file
View file

@ -0,0 +1,3 @@
wrapperVersion=3.3.4
distributionType=only-script
distributionUrl=https://repo.maven.apache.org/maven2/org/apache/maven/apache-maven/3.9.11/apache-maven-3.9.11-bin.zip

295
mvnw vendored Normal file
View file

@ -0,0 +1,295 @@
#!/bin/sh
# ----------------------------------------------------------------------------
# Licensed to the Apache Software Foundation (ASF) under one
# or more contributor license agreements. See the NOTICE file
# distributed with this work for additional information
# regarding copyright ownership. The ASF licenses this file
# to you under the Apache License, Version 2.0 (the
# "License"); you may not use this file except in compliance
# with the License. You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing,
# software distributed under the License is distributed on an
# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
# KIND, either express or implied. See the License for the
# specific language governing permissions and limitations
# under the License.
# ----------------------------------------------------------------------------
# ----------------------------------------------------------------------------
# Apache Maven Wrapper startup batch script, version 3.3.4
#
# Optional ENV vars
# -----------------
# JAVA_HOME - location of a JDK home dir, required when download maven via java source
# MVNW_REPOURL - repo url base for downloading maven distribution
# MVNW_USERNAME/MVNW_PASSWORD - user and password for downloading maven
# MVNW_VERBOSE - true: enable verbose log; debug: trace the mvnw script; others: silence the output
# ----------------------------------------------------------------------------
set -euf
[ "${MVNW_VERBOSE-}" != debug ] || set -x
# OS specific support.
native_path() { printf %s\\n "$1"; }
case "$(uname)" in
CYGWIN* | MINGW*)
[ -z "${JAVA_HOME-}" ] || JAVA_HOME="$(cygpath --unix "$JAVA_HOME")"
native_path() { cygpath --path --windows "$1"; }
;;
esac
# set JAVACMD and JAVACCMD
set_java_home() {
# For Cygwin and MinGW, ensure paths are in Unix format before anything is touched
if [ -n "${JAVA_HOME-}" ]; then
if [ -x "$JAVA_HOME/jre/sh/java" ]; then
# IBM's JDK on AIX uses strange locations for the executables
JAVACMD="$JAVA_HOME/jre/sh/java"
JAVACCMD="$JAVA_HOME/jre/sh/javac"
else
JAVACMD="$JAVA_HOME/bin/java"
JAVACCMD="$JAVA_HOME/bin/javac"
if [ ! -x "$JAVACMD" ] || [ ! -x "$JAVACCMD" ]; then
echo "The JAVA_HOME environment variable is not defined correctly, so mvnw cannot run." >&2
echo "JAVA_HOME is set to \"$JAVA_HOME\", but \"\$JAVA_HOME/bin/java\" or \"\$JAVA_HOME/bin/javac\" does not exist." >&2
return 1
fi
fi
else
JAVACMD="$(
'set' +e
'unset' -f command 2>/dev/null
'command' -v java
)" || :
JAVACCMD="$(
'set' +e
'unset' -f command 2>/dev/null
'command' -v javac
)" || :
if [ ! -x "${JAVACMD-}" ] || [ ! -x "${JAVACCMD-}" ]; then
echo "The java/javac command does not exist in PATH nor is JAVA_HOME set, so mvnw cannot run." >&2
return 1
fi
fi
}
# hash string like Java String::hashCode
hash_string() {
str="${1:-}" h=0
while [ -n "$str" ]; do
char="${str%"${str#?}"}"
h=$(((h * 31 + $(LC_CTYPE=C printf %d "'$char")) % 4294967296))
str="${str#?}"
done
printf %x\\n $h
}
verbose() { :; }
[ "${MVNW_VERBOSE-}" != true ] || verbose() { printf %s\\n "${1-}"; }
die() {
printf %s\\n "$1" >&2
exit 1
}
trim() {
# MWRAPPER-139:
# Trims trailing and leading whitespace, carriage returns, tabs, and linefeeds.
# Needed for removing poorly interpreted newline sequences when running in more
# exotic environments such as mingw bash on Windows.
printf "%s" "${1}" | tr -d '[:space:]'
}
scriptDir="$(dirname "$0")"
scriptName="$(basename "$0")"
# parse distributionUrl and optional distributionSha256Sum, requires .mvn/wrapper/maven-wrapper.properties
while IFS="=" read -r key value; do
case "${key-}" in
distributionUrl) distributionUrl=$(trim "${value-}") ;;
distributionSha256Sum) distributionSha256Sum=$(trim "${value-}") ;;
esac
done <"$scriptDir/.mvn/wrapper/maven-wrapper.properties"
[ -n "${distributionUrl-}" ] || die "cannot read distributionUrl property in $scriptDir/.mvn/wrapper/maven-wrapper.properties"
case "${distributionUrl##*/}" in
maven-mvnd-*bin.*)
MVN_CMD=mvnd.sh _MVNW_REPO_PATTERN=/maven/mvnd/
case "${PROCESSOR_ARCHITECTURE-}${PROCESSOR_ARCHITEW6432-}:$(uname -a)" in
*AMD64:CYGWIN* | *AMD64:MINGW*) distributionPlatform=windows-amd64 ;;
:Darwin*x86_64) distributionPlatform=darwin-amd64 ;;
:Darwin*arm64) distributionPlatform=darwin-aarch64 ;;
:Linux*x86_64*) distributionPlatform=linux-amd64 ;;
*)
echo "Cannot detect native platform for mvnd on $(uname)-$(uname -m), use pure java version" >&2
distributionPlatform=linux-amd64
;;
esac
distributionUrl="${distributionUrl%-bin.*}-$distributionPlatform.zip"
;;
maven-mvnd-*) MVN_CMD=mvnd.sh _MVNW_REPO_PATTERN=/maven/mvnd/ ;;
*) MVN_CMD="mvn${scriptName#mvnw}" _MVNW_REPO_PATTERN=/org/apache/maven/ ;;
esac
# apply MVNW_REPOURL and calculate MAVEN_HOME
# maven home pattern: ~/.m2/wrapper/dists/{apache-maven-<version>,maven-mvnd-<version>-<platform>}/<hash>
[ -z "${MVNW_REPOURL-}" ] || distributionUrl="$MVNW_REPOURL$_MVNW_REPO_PATTERN${distributionUrl#*"$_MVNW_REPO_PATTERN"}"
distributionUrlName="${distributionUrl##*/}"
distributionUrlNameMain="${distributionUrlName%.*}"
distributionUrlNameMain="${distributionUrlNameMain%-bin}"
MAVEN_USER_HOME="${MAVEN_USER_HOME:-${HOME}/.m2}"
MAVEN_HOME="${MAVEN_USER_HOME}/wrapper/dists/${distributionUrlNameMain-}/$(hash_string "$distributionUrl")"
exec_maven() {
unset MVNW_VERBOSE MVNW_USERNAME MVNW_PASSWORD MVNW_REPOURL || :
exec "$MAVEN_HOME/bin/$MVN_CMD" "$@" || die "cannot exec $MAVEN_HOME/bin/$MVN_CMD"
}
if [ -d "$MAVEN_HOME" ]; then
verbose "found existing MAVEN_HOME at $MAVEN_HOME"
exec_maven "$@"
fi
case "${distributionUrl-}" in
*?-bin.zip | *?maven-mvnd-?*-?*.zip) ;;
*) die "distributionUrl is not valid, must match *-bin.zip or maven-mvnd-*.zip, but found '${distributionUrl-}'" ;;
esac
# prepare tmp dir
if TMP_DOWNLOAD_DIR="$(mktemp -d)" && [ -d "$TMP_DOWNLOAD_DIR" ]; then
clean() { rm -rf -- "$TMP_DOWNLOAD_DIR"; }
trap clean HUP INT TERM EXIT
else
die "cannot create temp dir"
fi
mkdir -p -- "${MAVEN_HOME%/*}"
# Download and Install Apache Maven
verbose "Couldn't find MAVEN_HOME, downloading and installing it ..."
verbose "Downloading from: $distributionUrl"
verbose "Downloading to: $TMP_DOWNLOAD_DIR/$distributionUrlName"
# select .zip or .tar.gz
if ! command -v unzip >/dev/null; then
distributionUrl="${distributionUrl%.zip}.tar.gz"
distributionUrlName="${distributionUrl##*/}"
fi
# verbose opt
__MVNW_QUIET_WGET=--quiet __MVNW_QUIET_CURL=--silent __MVNW_QUIET_UNZIP=-q __MVNW_QUIET_TAR=''
[ "${MVNW_VERBOSE-}" != true ] || __MVNW_QUIET_WGET='' __MVNW_QUIET_CURL='' __MVNW_QUIET_UNZIP='' __MVNW_QUIET_TAR=v
# normalize http auth
case "${MVNW_PASSWORD:+has-password}" in
'') MVNW_USERNAME='' MVNW_PASSWORD='' ;;
has-password) [ -n "${MVNW_USERNAME-}" ] || MVNW_USERNAME='' MVNW_PASSWORD='' ;;
esac
if [ -z "${MVNW_USERNAME-}" ] && command -v wget >/dev/null; then
verbose "Found wget ... using wget"
wget ${__MVNW_QUIET_WGET:+"$__MVNW_QUIET_WGET"} "$distributionUrl" -O "$TMP_DOWNLOAD_DIR/$distributionUrlName" || die "wget: Failed to fetch $distributionUrl"
elif [ -z "${MVNW_USERNAME-}" ] && command -v curl >/dev/null; then
verbose "Found curl ... using curl"
curl ${__MVNW_QUIET_CURL:+"$__MVNW_QUIET_CURL"} -f -L -o "$TMP_DOWNLOAD_DIR/$distributionUrlName" "$distributionUrl" || die "curl: Failed to fetch $distributionUrl"
elif set_java_home; then
verbose "Falling back to use Java to download"
javaSource="$TMP_DOWNLOAD_DIR/Downloader.java"
targetZip="$TMP_DOWNLOAD_DIR/$distributionUrlName"
cat >"$javaSource" <<-END
public class Downloader extends java.net.Authenticator
{
protected java.net.PasswordAuthentication getPasswordAuthentication()
{
return new java.net.PasswordAuthentication( System.getenv( "MVNW_USERNAME" ), System.getenv( "MVNW_PASSWORD" ).toCharArray() );
}
public static void main( String[] args ) throws Exception
{
setDefault( new Downloader() );
java.nio.file.Files.copy( java.net.URI.create( args[0] ).toURL().openStream(), java.nio.file.Paths.get( args[1] ).toAbsolutePath().normalize() );
}
}
END
# For Cygwin/MinGW, switch paths to Windows format before running javac and java
verbose " - Compiling Downloader.java ..."
"$(native_path "$JAVACCMD")" "$(native_path "$javaSource")" || die "Failed to compile Downloader.java"
verbose " - Running Downloader.java ..."
"$(native_path "$JAVACMD")" -cp "$(native_path "$TMP_DOWNLOAD_DIR")" Downloader "$distributionUrl" "$(native_path "$targetZip")"
fi
# If specified, validate the SHA-256 sum of the Maven distribution zip file
if [ -n "${distributionSha256Sum-}" ]; then
distributionSha256Result=false
if [ "$MVN_CMD" = mvnd.sh ]; then
echo "Checksum validation is not supported for maven-mvnd." >&2
echo "Please disable validation by removing 'distributionSha256Sum' from your maven-wrapper.properties." >&2
exit 1
elif command -v sha256sum >/dev/null; then
if echo "$distributionSha256Sum $TMP_DOWNLOAD_DIR/$distributionUrlName" | sha256sum -c - >/dev/null 2>&1; then
distributionSha256Result=true
fi
elif command -v shasum >/dev/null; then
if echo "$distributionSha256Sum $TMP_DOWNLOAD_DIR/$distributionUrlName" | shasum -a 256 -c >/dev/null 2>&1; then
distributionSha256Result=true
fi
else
echo "Checksum validation was requested but neither 'sha256sum' or 'shasum' are available." >&2
echo "Please install either command, or disable validation by removing 'distributionSha256Sum' from your maven-wrapper.properties." >&2
exit 1
fi
if [ $distributionSha256Result = false ]; then
echo "Error: Failed to validate Maven distribution SHA-256, your Maven distribution might be compromised." >&2
echo "If you updated your Maven version, you need to update the specified distributionSha256Sum property." >&2
exit 1
fi
fi
# unzip and move
if command -v unzip >/dev/null; then
unzip ${__MVNW_QUIET_UNZIP:+"$__MVNW_QUIET_UNZIP"} "$TMP_DOWNLOAD_DIR/$distributionUrlName" -d "$TMP_DOWNLOAD_DIR" || die "failed to unzip"
else
tar xzf${__MVNW_QUIET_TAR:+"$__MVNW_QUIET_TAR"} "$TMP_DOWNLOAD_DIR/$distributionUrlName" -C "$TMP_DOWNLOAD_DIR" || die "failed to untar"
fi
# Find the actual extracted directory name (handles snapshots where filename != directory name)
actualDistributionDir=""
# First try the expected directory name (for regular distributions)
if [ -d "$TMP_DOWNLOAD_DIR/$distributionUrlNameMain" ]; then
if [ -f "$TMP_DOWNLOAD_DIR/$distributionUrlNameMain/bin/$MVN_CMD" ]; then
actualDistributionDir="$distributionUrlNameMain"
fi
fi
# If not found, search for any directory with the Maven executable (for snapshots)
if [ -z "$actualDistributionDir" ]; then
# enable globbing to iterate over items
set +f
for dir in "$TMP_DOWNLOAD_DIR"/*; do
if [ -d "$dir" ]; then
if [ -f "$dir/bin/$MVN_CMD" ]; then
actualDistributionDir="$(basename "$dir")"
break
fi
fi
done
set -f
fi
if [ -z "$actualDistributionDir" ]; then
verbose "Contents of $TMP_DOWNLOAD_DIR:"
verbose "$(ls -la "$TMP_DOWNLOAD_DIR")"
die "Could not find Maven distribution directory in extracted archive"
fi
verbose "Found extracted Maven distribution directory: $actualDistributionDir"
printf %s\\n "$distributionUrl" >"$TMP_DOWNLOAD_DIR/$actualDistributionDir/mvnw.url"
mv -- "$TMP_DOWNLOAD_DIR/$actualDistributionDir" "$MAVEN_HOME" || [ -d "$MAVEN_HOME" ] || die "fail to move MAVEN_HOME"
clean || :
exec_maven "$@"

189
mvnw.cmd vendored Normal file
View file

@ -0,0 +1,189 @@
<# : batch portion
@REM ----------------------------------------------------------------------------
@REM Licensed to the Apache Software Foundation (ASF) under one
@REM or more contributor license agreements. See the NOTICE file
@REM distributed with this work for additional information
@REM regarding copyright ownership. The ASF licenses this file
@REM to you under the Apache License, Version 2.0 (the
@REM "License"); you may not use this file except in compliance
@REM with the License. You may obtain a copy of the License at
@REM
@REM http://www.apache.org/licenses/LICENSE-2.0
@REM
@REM Unless required by applicable law or agreed to in writing,
@REM software distributed under the License is distributed on an
@REM "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
@REM KIND, either express or implied. See the License for the
@REM specific language governing permissions and limitations
@REM under the License.
@REM ----------------------------------------------------------------------------
@REM ----------------------------------------------------------------------------
@REM Apache Maven Wrapper startup batch script, version 3.3.4
@REM
@REM Optional ENV vars
@REM MVNW_REPOURL - repo url base for downloading maven distribution
@REM MVNW_USERNAME/MVNW_PASSWORD - user and password for downloading maven
@REM MVNW_VERBOSE - true: enable verbose log; others: silence the output
@REM ----------------------------------------------------------------------------
@IF "%__MVNW_ARG0_NAME__%"=="" (SET __MVNW_ARG0_NAME__=%~nx0)
@SET __MVNW_CMD__=
@SET __MVNW_ERROR__=
@SET __MVNW_PSMODULEP_SAVE=%PSModulePath%
@SET PSModulePath=
@FOR /F "usebackq tokens=1* delims==" %%A IN (`powershell -noprofile "& {$scriptDir='%~dp0'; $script='%__MVNW_ARG0_NAME__%'; icm -ScriptBlock ([Scriptblock]::Create((Get-Content -Raw '%~f0'))) -NoNewScope}"`) DO @(
IF "%%A"=="MVN_CMD" (set __MVNW_CMD__=%%B) ELSE IF "%%B"=="" (echo %%A) ELSE (echo %%A=%%B)
)
@SET PSModulePath=%__MVNW_PSMODULEP_SAVE%
@SET __MVNW_PSMODULEP_SAVE=
@SET __MVNW_ARG0_NAME__=
@SET MVNW_USERNAME=
@SET MVNW_PASSWORD=
@IF NOT "%__MVNW_CMD__%"=="" ("%__MVNW_CMD__%" %*)
@echo Cannot start maven from wrapper >&2 && exit /b 1
@GOTO :EOF
: end batch / begin powershell #>
$ErrorActionPreference = "Stop"
if ($env:MVNW_VERBOSE -eq "true") {
$VerbosePreference = "Continue"
}
# calculate distributionUrl, requires .mvn/wrapper/maven-wrapper.properties
$distributionUrl = (Get-Content -Raw "$scriptDir/.mvn/wrapper/maven-wrapper.properties" | ConvertFrom-StringData).distributionUrl
if (!$distributionUrl) {
Write-Error "cannot read distributionUrl property in $scriptDir/.mvn/wrapper/maven-wrapper.properties"
}
switch -wildcard -casesensitive ( $($distributionUrl -replace '^.*/','') ) {
"maven-mvnd-*" {
$USE_MVND = $true
$distributionUrl = $distributionUrl -replace '-bin\.[^.]*$',"-windows-amd64.zip"
$MVN_CMD = "mvnd.cmd"
break
}
default {
$USE_MVND = $false
$MVN_CMD = $script -replace '^mvnw','mvn'
break
}
}
# apply MVNW_REPOURL and calculate MAVEN_HOME
# maven home pattern: ~/.m2/wrapper/dists/{apache-maven-<version>,maven-mvnd-<version>-<platform>}/<hash>
if ($env:MVNW_REPOURL) {
$MVNW_REPO_PATTERN = if ($USE_MVND -eq $False) { "/org/apache/maven/" } else { "/maven/mvnd/" }
$distributionUrl = "$env:MVNW_REPOURL$MVNW_REPO_PATTERN$($distributionUrl -replace "^.*$MVNW_REPO_PATTERN",'')"
}
$distributionUrlName = $distributionUrl -replace '^.*/',''
$distributionUrlNameMain = $distributionUrlName -replace '\.[^.]*$','' -replace '-bin$',''
$MAVEN_M2_PATH = "$HOME/.m2"
if ($env:MAVEN_USER_HOME) {
$MAVEN_M2_PATH = "$env:MAVEN_USER_HOME"
}
if (-not (Test-Path -Path $MAVEN_M2_PATH)) {
New-Item -Path $MAVEN_M2_PATH -ItemType Directory | Out-Null
}
$MAVEN_WRAPPER_DISTS = $null
if ((Get-Item $MAVEN_M2_PATH).Target[0] -eq $null) {
$MAVEN_WRAPPER_DISTS = "$MAVEN_M2_PATH/wrapper/dists"
} else {
$MAVEN_WRAPPER_DISTS = (Get-Item $MAVEN_M2_PATH).Target[0] + "/wrapper/dists"
}
$MAVEN_HOME_PARENT = "$MAVEN_WRAPPER_DISTS/$distributionUrlNameMain"
$MAVEN_HOME_NAME = ([System.Security.Cryptography.SHA256]::Create().ComputeHash([byte[]][char[]]$distributionUrl) | ForEach-Object {$_.ToString("x2")}) -join ''
$MAVEN_HOME = "$MAVEN_HOME_PARENT/$MAVEN_HOME_NAME"
if (Test-Path -Path "$MAVEN_HOME" -PathType Container) {
Write-Verbose "found existing MAVEN_HOME at $MAVEN_HOME"
Write-Output "MVN_CMD=$MAVEN_HOME/bin/$MVN_CMD"
exit $?
}
if (! $distributionUrlNameMain -or ($distributionUrlName -eq $distributionUrlNameMain)) {
Write-Error "distributionUrl is not valid, must end with *-bin.zip, but found $distributionUrl"
}
# prepare tmp dir
$TMP_DOWNLOAD_DIR_HOLDER = New-TemporaryFile
$TMP_DOWNLOAD_DIR = New-Item -Itemtype Directory -Path "$TMP_DOWNLOAD_DIR_HOLDER.dir"
$TMP_DOWNLOAD_DIR_HOLDER.Delete() | Out-Null
trap {
if ($TMP_DOWNLOAD_DIR.Exists) {
try { Remove-Item $TMP_DOWNLOAD_DIR -Recurse -Force | Out-Null }
catch { Write-Warning "Cannot remove $TMP_DOWNLOAD_DIR" }
}
}
New-Item -Itemtype Directory -Path "$MAVEN_HOME_PARENT" -Force | Out-Null
# Download and Install Apache Maven
Write-Verbose "Couldn't find MAVEN_HOME, downloading and installing it ..."
Write-Verbose "Downloading from: $distributionUrl"
Write-Verbose "Downloading to: $TMP_DOWNLOAD_DIR/$distributionUrlName"
$webclient = New-Object System.Net.WebClient
if ($env:MVNW_USERNAME -and $env:MVNW_PASSWORD) {
$webclient.Credentials = New-Object System.Net.NetworkCredential($env:MVNW_USERNAME, $env:MVNW_PASSWORD)
}
[Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls12
$webclient.DownloadFile($distributionUrl, "$TMP_DOWNLOAD_DIR/$distributionUrlName") | Out-Null
# If specified, validate the SHA-256 sum of the Maven distribution zip file
$distributionSha256Sum = (Get-Content -Raw "$scriptDir/.mvn/wrapper/maven-wrapper.properties" | ConvertFrom-StringData).distributionSha256Sum
if ($distributionSha256Sum) {
if ($USE_MVND) {
Write-Error "Checksum validation is not supported for maven-mvnd. `nPlease disable validation by removing 'distributionSha256Sum' from your maven-wrapper.properties."
}
Import-Module $PSHOME\Modules\Microsoft.PowerShell.Utility -Function Get-FileHash
if ((Get-FileHash "$TMP_DOWNLOAD_DIR/$distributionUrlName" -Algorithm SHA256).Hash.ToLower() -ne $distributionSha256Sum) {
Write-Error "Error: Failed to validate Maven distribution SHA-256, your Maven distribution might be compromised. If you updated your Maven version, you need to update the specified distributionSha256Sum property."
}
}
# unzip and move
Expand-Archive "$TMP_DOWNLOAD_DIR/$distributionUrlName" -DestinationPath "$TMP_DOWNLOAD_DIR" | Out-Null
# Find the actual extracted directory name (handles snapshots where filename != directory name)
$actualDistributionDir = ""
# First try the expected directory name (for regular distributions)
$expectedPath = Join-Path "$TMP_DOWNLOAD_DIR" "$distributionUrlNameMain"
$expectedMvnPath = Join-Path "$expectedPath" "bin/$MVN_CMD"
if ((Test-Path -Path $expectedPath -PathType Container) -and (Test-Path -Path $expectedMvnPath -PathType Leaf)) {
$actualDistributionDir = $distributionUrlNameMain
}
# If not found, search for any directory with the Maven executable (for snapshots)
if (!$actualDistributionDir) {
Get-ChildItem -Path "$TMP_DOWNLOAD_DIR" -Directory | ForEach-Object {
$testPath = Join-Path $_.FullName "bin/$MVN_CMD"
if (Test-Path -Path $testPath -PathType Leaf) {
$actualDistributionDir = $_.Name
}
}
}
if (!$actualDistributionDir) {
Write-Error "Could not find Maven distribution directory in extracted archive"
}
Write-Verbose "Found extracted Maven distribution directory: $actualDistributionDir"
Rename-Item -Path "$TMP_DOWNLOAD_DIR/$actualDistributionDir" -NewName $MAVEN_HOME_NAME | Out-Null
try {
Move-Item -Path "$TMP_DOWNLOAD_DIR/$MAVEN_HOME_NAME" -Destination $MAVEN_HOME_PARENT | Out-Null
} catch {
if (! (Test-Path -Path "$MAVEN_HOME" -PathType Container)) {
Write-Error "fail to move MAVEN_HOME"
}
} finally {
try { Remove-Item $TMP_DOWNLOAD_DIR -Recurse -Force | Out-Null }
catch { Write-Warning "Cannot remove $TMP_DOWNLOAD_DIR" }
}
Write-Output "MVN_CMD=$MAVEN_HOME/bin/$MVN_CMD"

104
pom.xml Normal file
View file

@ -0,0 +1,104 @@
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>3.5.7</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<groupId>de.avatic</groupId>
<artifactId>taric</artifactId>
<version>0.0.1-SNAPSHOT</version>
<name>taric</name>
<description>taric</description>
<url/>
<licenses>
<license/>
</licenses>
<developers>
<developer/>
</developers>
<scm>
<connection/>
<developerConnection/>
<tag/>
<url/>
</scm>
<properties>
<java.version>17</java.version>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-actuator</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-jdbc</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-oauth2-resource-server</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-security</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-validation</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>com.mysql</groupId>
<artifactId>mysql-connector-j</artifactId>
<scope>runtime</scope>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.springframework.security</groupId>
<artifactId>spring-security-test</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.springdoc</groupId>
<artifactId>springdoc-openapi-starter-webmvc-ui</artifactId>
<version>2.8.13</version>
</dependency>
<dependency>
<groupId>org.flywaydb</groupId>
<artifactId>flyway-core</artifactId>
</dependency>
<dependency>
<groupId>org.flywaydb</groupId>
<artifactId>flyway-mysql</artifactId>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
</project>

View file

@ -0,0 +1,13 @@
package de.avatic.taric;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
@SpringBootApplication
public class TaricApplication {
public static void main(String[] args) {
SpringApplication.run(TaricApplication.class, args);
}
}

View file

@ -0,0 +1,31 @@
package de.avatic.taric.config;
import de.avatic.taric.serializer.DescSetSerializer;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import org.springframework.stereotype.Component;
import org.springframework.web.servlet.HandlerInterceptor;
@Component
public class LanguageInterceptor implements HandlerInterceptor {
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response,
Object handler) {
String lang = request.getParameter("lang");
if (lang == null) {
lang = request.getHeader("Accept-Language");
if (lang != null && lang.length() >= 2) {
lang = lang.substring(0, 2).toUpperCase();
}
}
DescSetSerializer.setLanguage(lang);
return true;
}
@Override
public void afterCompletion(HttpServletRequest request, HttpServletResponse response,
Object handler, Exception ex) {
DescSetSerializer.clearLanguage();
}
}

View file

@ -0,0 +1,28 @@
package de.avatic.taric.config;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Profile;
import org.springframework.http.HttpMethod;
import org.springframework.security.config.annotation.method.configuration.EnableMethodSecurity;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.web.SecurityFilterChain;
@Configuration
@EnableMethodSecurity
public class SecurityConfig {
@Bean
public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {
http.authorizeHttpRequests(auth -> auth
.requestMatchers(HttpMethod.OPTIONS, "/**").permitAll()
.requestMatchers("/actuator/health").permitAll()
.requestMatchers("/actuator/**").hasRole("SERVICE")
.requestMatchers("/api/**").permitAll()
.anyRequest().permitAll()
);
return http.build();
}
}

View file

@ -0,0 +1,20 @@
package de.avatic.taric.config;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
@Configuration
public class WebConfig implements WebMvcConfigurer {
private final LanguageInterceptor languageInterceptor;
public WebConfig(LanguageInterceptor languageInterceptor) {
this.languageInterceptor = languageInterceptor;
}
@Override
public void addInterceptors(InterceptorRegistry registry) {
registry.addInterceptor(languageInterceptor);
}
}

View file

@ -0,0 +1,42 @@
package de.avatic.taric.controller;
import de.avatic.taric.model.Geo;
import de.avatic.taric.model.GeoGroup;
import de.avatic.taric.service.GeoService;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
import java.util.Collections;
import java.util.List;
import java.util.Optional;
@RestController
@RequestMapping("/api/v1/geo")
public class GeoController {
private final GeoService geoService;
public GeoController(GeoService geoService) {
this.geoService = geoService;
}
@GetMapping("")
public Optional<Geo> getGeo(@RequestParam String countryCode) {
return geoService.getGeo(countryCode);
}
@GetMapping("/group")
public List<GeoGroup> getGeoGroup(@RequestParam(required = false) String countryCode, @RequestParam(required = false) String abbr) {
if (countryCode != null && abbr == null)
return geoService.getGeoGroupByCountryCode(countryCode);
if (countryCode == null && abbr != null)
return geoService.getGeoGroup(abbr);
return Collections.emptyList();
}
}

View file

@ -0,0 +1,39 @@
package de.avatic.taric.controller;
import de.avatic.taric.model.Nomenclature;
import de.avatic.taric.service.NomenclatureService;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
import java.util.List;
import java.util.Optional;
@RestController
@RequestMapping("/api/v1/nomenclature")
public class NomenclatureController {
private final NomenclatureService nomenclatureService;
public NomenclatureController(NomenclatureService nomenclatureService) {
this.nomenclatureService = nomenclatureService;
}
@GetMapping("")
public Optional<Nomenclature> getNomenclature(@RequestParam String hscode) {
return nomenclatureService.getNomenclature(hscode);
}
@GetMapping("/declarable")
public List<Nomenclature> getDeclarable(@RequestParam String hscode) {
return nomenclatureService.getDeclarableChildren(hscode);
}
@GetMapping("/cascade")
public List<Nomenclature> getCascade(@RequestParam String hscode) {
var found = nomenclatureService.getNomenclatureCascade(hscode);
return found;
}
}

View file

@ -0,0 +1,27 @@
package de.avatic.taric.controller;
import de.avatic.taric.service.TariffService;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
@RestController
@RequestMapping("/api/v1/tariff")
public class TariffController {
private final TariffService tariffService;
public TariffController(TariffService tariffService) {
this.tariffService = tariffService;
}
@GetMapping("")
public void getTariffRate(@RequestParam String hsCode, @RequestParam String countryCode) {
tariffService.importTariffs( hsCode, countryCode);
}
}

View file

@ -0,0 +1,131 @@
package de.avatic.taric.controller;
import de.avatic.taric.service.TariffService2;
import de.avatic.taric.service.TariffService2.TariffResult;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.Parameter;
import io.swagger.v3.oas.annotations.responses.ApiResponse;
import io.swagger.v3.oas.annotations.responses.ApiResponses;
import io.swagger.v3.oas.annotations.tags.Tag;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.*;
import jakarta.validation.constraints.NotBlank;
import jakarta.validation.constraints.Pattern;
import java.math.BigDecimal;
import java.util.HashMap;
import java.util.Map;
//@RestController
//@RequestMapping("/api/v1/tariff")
@Tag(name = "Tariff API", description = "API zur Abfrage von Zolltarifen")
public class TariffController2 {
private static final org.slf4j.Logger log = org.slf4j.LoggerFactory.getLogger(TariffController2.class);
private final TariffService2 tariffService;
public TariffController2(TariffService2 tariffService) {
this.tariffService = tariffService;
}
@GetMapping("/rate")
@Operation(summary = "Zolltarif abfragen",
description = "Ermittelt den Zolltarif für einen HS-Code und ein Herkunftsland")
@ApiResponses(value = {
@ApiResponse(responseCode = "200", description = "Tarif erfolgreich gefunden"),
@ApiResponse(responseCode = "404", description = "Kein Tarif gefunden"),
@ApiResponse(responseCode = "400", description = "Ungültige Eingabeparameter")
})
public ResponseEntity<TariffResponse> getTariffRate(
@Parameter(description = "HS-Code (6, 8 oder 10 Stellen)", example = "850410")
@RequestParam
@NotBlank(message = "HS Code ist erforderlich")
@Pattern(regexp = "^[0-9]{4,10}$", message = "HS Code muss 4-10 Ziffern enthalten")
String hsCode,
@Parameter(description = "ISO-2 Ländercode", example = "CN")
@RequestParam
@NotBlank(message = "Ländercode ist erforderlich")
@Pattern(regexp = "^[A-Z]{2}$", message = "Ländercode muss 2 Großbuchstaben sein")
String countryCode) {
log.info("Tariff rate request - HS Code: {}, Country: {}", hsCode, countryCode);
try {
TariffResult result = tariffService.getTariffRate(hsCode, countryCode);
if (result.isFound()) {
TariffResponse response = TariffResponse.success(
result.getRate(),
result.getHsCode(),
result.getCountryCode()
);
return ResponseEntity.ok(response);
} else {
TariffResponse response = TariffResponse.notFound(result.getMessage());
return ResponseEntity.status(HttpStatus.NOT_FOUND).body(response);
}
} catch (Exception e) {
log.error("Error getting tariff rate", e);
TariffResponse response = TariffResponse.error("Internal server error: " + e.getMessage());
return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).body(response);
}
}
@GetMapping("/health")
@Operation(summary = "Health Check", description = "Prüft ob der Service verfügbar ist")
public ResponseEntity<Map<String, String>> health() {
Map<String, String> response = new HashMap<>();
response.put("status", "UP");
response.put("service", "TARIC Tariff Service");
return ResponseEntity.ok(response);
}
/**
* Response-Klasse für Tarif-Abfragen
*/
public static class TariffResponse {
private final boolean success;
private final BigDecimal tariffRate;
private final String hsCode;
private final String countryCode;
private final String message;
private final String formattedRate;
private TariffResponse(boolean success, BigDecimal tariffRate,
String hsCode, String countryCode, String message) {
this.success = success;
this.tariffRate = tariffRate;
this.hsCode = hsCode;
this.countryCode = countryCode;
this.message = message;
this.formattedRate = tariffRate != null ?
tariffRate.toString() + " %" : null;
}
public static TariffResponse success(BigDecimal rate, String hsCode, String countryCode) {
return new TariffResponse(true, rate, hsCode, countryCode,
"Tariff rate found successfully");
}
public static TariffResponse notFound(String message) {
return new TariffResponse(false, null, null, null, message);
}
public static TariffResponse error(String message) {
return new TariffResponse(false, null, null, null, message);
}
// Getters
public boolean isSuccess() { return success; }
public BigDecimal getTariffRate() { return tariffRate; }
public String getHsCode() { return hsCode; }
public String getCountryCode() { return countryCode; }
public String getMessage() { return message; }
public String getFormattedRate() { return formattedRate; }
}
}

View file

@ -0,0 +1,13 @@
package de.avatic.taric.dto;
import de.avatic.taric.model.Nomenclature;
import java.util.List;
public class NomenclatureDTO {
private List<Nomenclature> cascade;
private List<Nomenclature> declarables;
}

View file

@ -0,0 +1,16 @@
package de.avatic.taric.error;
import lombok.Getter;
@Getter
public class ArgumentException extends RuntimeException {
private final String arg;
public ArgumentException(String arg) {
super();
this.arg = arg;
}
}

View file

@ -0,0 +1,22 @@
package de.avatic.taric.error;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.ResponseStatus;
import javax.swing.text.html.HTML;
@ControllerAdvice
public class ErrorController {
@ResponseStatus(HttpStatus.BAD_REQUEST)
@ExceptionHandler
public ResponseEntity<ErrorDTO> handleException(ArgumentException ex) {
var dto = new ErrorDTO();
dto.setField(ex.getArg());
dto.setMessage("Invalid argument");
return new ResponseEntity<>(dto, HttpStatus.BAD_REQUEST);
}
}

View file

@ -0,0 +1,11 @@
package de.avatic.taric.error;
import lombok.Getter;
import lombok.Setter;
@Getter
@Setter
public class ErrorDTO {
private String field;
private String message;
}

View file

@ -0,0 +1,83 @@
package de.avatic.taric.model;
import java.time.LocalDate;
import java.util.HashSet;
import java.util.Set;
import org.springframework.data.annotation.Id;
import org.springframework.data.relational.core.mapping.MappedCollection;
import org.springframework.data.relational.core.mapping.Table;
import jakarta.validation.constraints.Size;
@Table("additional_code")
public class AdditionalCode {
@Id
private Integer id;
@Size(max = 4)
private String additionalCode;
private LocalDate startDate;
private LocalDate endDate;
@MappedCollection(idColumn = "ref_id")
private Set<AdditionalCodeDesc> desc;
public AdditionalCode(String additionalCode, LocalDate startDate, LocalDate endDate) {
this.desc = new HashSet<>();
this.additionalCode = additionalCode;
this.startDate = startDate;
this.endDate = endDate;
}
public void addDesc(AdditionalCodeDesc desc) {
this.desc.add(desc);
}
public Integer getId() {
return id;
}
public void setId(Integer id) {
this.id = id;
}
public String getAdditionalCode() {
return additionalCode;
}
public void setAdditionalCode(String additionalCode) {
this.additionalCode = additionalCode;
}
public LocalDate getStartDate() {
return startDate;
}
public void setStartDate(LocalDate startDate) {
this.startDate = startDate;
}
public LocalDate getEndDate() {
return endDate;
}
public void setEndDate(LocalDate endDate) {
this.endDate = endDate;
}
public Set<AdditionalCodeDesc> getDesc() {
return desc;
}
public void setDesc(Set<AdditionalCodeDesc> desc) {
this.desc = desc;
}
}

View file

@ -0,0 +1,62 @@
package de.avatic.taric.model;
import java.time.LocalDate;
import org.springframework.data.annotation.Id;
import org.springframework.data.relational.core.mapping.Table;
import jakarta.validation.constraints.Size;
@Table("additional_code_desc")
public class AdditionalCodeDesc {
@Id
private Integer id;
@Size(max = 2)
private String lang;
private String desc;
private LocalDate descStartDate;
public AdditionalCodeDesc(String lang, String desc, LocalDate descStartDate) {
this.lang = lang;
this.desc = desc;
this.descStartDate = descStartDate;
}
public Integer getId() {
return id;
}
public void setId(Integer id) {
this.id = id;
}
public String getLang() {
return lang;
}
public void setLang(String lang) {
this.lang = lang;
}
public String getDesc() {
return desc;
}
public void setDesc(String desc) {
this.desc = desc;
}
public LocalDate getDescStartDate() {
return descStartDate;
}
public void setDescStartDate(LocalDate descStartDate) {
this.descStartDate = descStartDate;
}
}

View file

@ -0,0 +1,127 @@
package de.avatic.taric.model;
import java.time.LocalDate;
import java.util.Set;
import org.springframework.data.annotation.Id;
import org.springframework.data.jdbc.core.mapping.AggregateReference;
import org.springframework.data.relational.core.mapping.Column;
import org.springframework.data.relational.core.mapping.MappedCollection;
import jakarta.validation.constraints.NotNull;
public class AppliedMeasure {
@Id
private Integer id;
private LocalDate startDate;
private LocalDate endDate;
private String amount;
@Column("order_number")
private Integer orderNumber;
@MappedCollection(idColumn = "applied_measure_id")
private Set<MeasureFootnote> measureFootnotes;
@NotNull
@Column("measure_id")
private AggregateReference<Measure, Integer> measure;
@Column("legal_base_id")
private AggregateReference<LegalBase, Integer> legalBase;
@Column("legal_base")
private String additionalLegalBase;
@MappedCollection(idColumn = "applied_measure_id")
private Set<MeasureExclusion> exclusions;
@MappedCollection(idColumn = "applied_measure_id")
private Set<AppliedMeasureCondition> conditions;
public AppliedMeasure(AggregateReference<Measure, Integer> measure, Set<MeasureFootnote> measureFootnotes,
AggregateReference<LegalBase, Integer> legalBase, String additionalLegalBase, Set<MeasureExclusion> exclusions,
Set<AppliedMeasureCondition> conditions, LocalDate startDate, LocalDate endDate, String amount, Integer orderNumber) {
this.measure = measure;
this.measureFootnotes = measureFootnotes;
this.legalBase = legalBase;
this.exclusions = exclusions;
this.conditions = conditions;
this.startDate = startDate;
this.endDate = endDate;
this.amount = amount;
this.orderNumber = orderNumber;
this.additionalLegalBase = additionalLegalBase;
}
public Integer getId() {
return id;
}
public void setId(final Integer id) {
this.id = id;
}
public LocalDate getStartDate() {
return startDate;
}
public void setStartDate(final LocalDate startDate) {
this.startDate = startDate;
}
public LocalDate getEndDate() {
return endDate;
}
public void setEndDate(final LocalDate endDate) {
this.endDate = endDate;
}
public String getAmount() {
return amount;
}
public void setAmount(final String amount) {
this.amount = amount;
}
public AggregateReference<Measure, Integer> getMeasure() {
return measure;
}
public void setMeasure(final AggregateReference<Measure, Integer> measure) {
this.measure = measure;
}
public AggregateReference<LegalBase, Integer> getLegalBase() {
return legalBase;
}
public void setLegalBase(final AggregateReference<LegalBase, Integer> legalBase) {
this.legalBase = legalBase;
}
public Integer getOrderNumber() {
return orderNumber;
}
public Set<MeasureFootnote> getMeasureFootnotes() {
return measureFootnotes;
}
public Set<MeasureExclusion> getExclusions() {
return exclusions;
}
public Set<AppliedMeasureCondition> getConditions() {
return conditions;
}
}

View file

@ -0,0 +1,118 @@
package de.avatic.taric.model;
import org.springframework.data.annotation.Id;
import org.springframework.data.jdbc.core.mapping.AggregateReference;
import org.springframework.data.relational.core.mapping.Column;
import org.springframework.lang.Nullable;
import jakarta.validation.constraints.NotNull;
public class AppliedMeasureCondition {
@Id
private Integer id;
private Integer sequenceNo;
private String amount;
@NotNull
@Column("measure_action_id")
private AggregateReference<MeasureAction, Integer> measureAction;
@Column("monetary_unit_id")
@Nullable
private AggregateReference<MonetaryUnit, Integer> monetaryUnit;
@Column("unit_id")
@Nullable
private AggregateReference<Unit, Integer> unit;
@Column("certificate_id")
@Nullable
private AggregateReference<Certificate, Integer> certificate;
@NotNull
@Column("condition_type_id")
private AggregateReference<ConditionType, Integer> conditionType;
public AppliedMeasureCondition(AggregateReference<MeasureAction, Integer> measureAction,
AggregateReference<MonetaryUnit, Integer> monetaryUnit,
AggregateReference<Unit, Integer> unit,
AggregateReference<Certificate, Integer> certificate,
AggregateReference<ConditionType, Integer> conditionType, String amount, Integer squenceNo) {
this.measureAction = measureAction;
this.monetaryUnit = monetaryUnit;
this.unit = unit;
this.certificate = certificate;
this.conditionType = conditionType;
this.amount = amount;
this.sequenceNo = squenceNo;
}
public Integer getId() {
return id;
}
public void setId(final Integer id) {
this.id = id;
}
public Integer getSequenceNo() {
return sequenceNo;
}
public void setSequenceNo(final Integer sequenceNo) {
this.sequenceNo = sequenceNo;
}
public String getAmount() {
return amount;
}
public void setAmount(final String amount) {
this.amount = amount;
}
public AggregateReference<MeasureAction, Integer> getMeasureAction() {
return measureAction;
}
public void setMeasureAction(final AggregateReference<MeasureAction, Integer> measureAction) {
this.measureAction = measureAction;
}
public AggregateReference<MonetaryUnit, Integer> getMonetaryUnit() {
return monetaryUnit;
}
public void setMonetaryUnit(final AggregateReference<MonetaryUnit, Integer> monetaryUnit) {
this.monetaryUnit = monetaryUnit;
}
public AggregateReference<Unit, Integer> getUnit() {
return unit;
}
public void setUnit(final AggregateReference<Unit, Integer> unit) {
this.unit = unit;
}
public AggregateReference<Certificate, Integer> getCertificate() {
return certificate;
}
public void setCertificate(final AggregateReference<Certificate, Integer> certificate) {
this.certificate = certificate;
}
public AggregateReference<ConditionType, Integer> getConditionType() {
return conditionType;
}
public void setConditionType(final AggregateReference<ConditionType, Integer> conditionType) {
this.conditionType = conditionType;
}
}

View file

@ -0,0 +1,88 @@
package de.avatic.taric.model;
import java.time.LocalDate;
import java.util.HashSet;
import java.util.Set;
import org.springframework.data.annotation.Id;
import org.springframework.data.jdbc.core.mapping.AggregateReference;
import org.springframework.data.relational.core.mapping.Column;
import org.springframework.data.relational.core.mapping.MappedCollection;
import jakarta.validation.constraints.NotNull;
import jakarta.validation.constraints.Size;
public class Certificate {
@Id
private Integer id;
@Size(max = 4)
private String certificateCode;
private LocalDate startDate;
private LocalDate endDate;
@NotNull
@Column("certificate_type_id")
private AggregateReference<CertificateType, Integer> certificateType;
@MappedCollection(idColumn = "ref_id")
private Set<CertificateDesc> certificateDesc;
public Certificate(String certificateCode, LocalDate startDate, LocalDate endDate, AggregateReference<CertificateType, Integer> certificateType) {
this.certificateCode = certificateCode;
this.startDate = startDate;
this.endDate = endDate;
this.certificateType = certificateType;
this.certificateDesc = new HashSet<>();
}
public Integer getId() {
return id;
}
public void setId(final Integer id) {
this.id = id;
}
public String getCertificateCode() {
return certificateCode;
}
public void setCertificateCode(final String certificateCode) {
this.certificateCode = certificateCode;
}
public LocalDate getStartDate() {
return startDate;
}
public void setStartDate(final LocalDate startDate) {
this.startDate = startDate;
}
public LocalDate getEndDate() {
return endDate;
}
public void setEndDate(final LocalDate endDate) {
this.endDate = endDate;
}
public AggregateReference<CertificateType, Integer> getCertificateType() {
return certificateType;
}
public void setCertificateType(final AggregateReference<CertificateType, Integer> certificateType) {
this.certificateType = certificateType;
}
public void addCertificateDesc(CertificateDesc certificateDesc) {
this.certificateDesc.add(certificateDesc);
}
}

View file

@ -0,0 +1,63 @@
package de.avatic.taric.model;
import java.time.LocalDate;
import org.springframework.data.annotation.Id;
import jakarta.validation.constraints.Size;
public class CertificateDesc {
@Id
private Integer id;
@Size(max = 2)
private String lang;
private String desc;
private LocalDate descStartDate;
public CertificateDesc(String lang, String desc, LocalDate descStartDate) {
this.lang = lang;
this.desc = desc;
this.descStartDate = descStartDate;
}
public Integer getId() {
return id;
}
public void setId(final Integer id) {
this.id = id;
}
public String getLang() {
return lang;
}
public void setLang(final String lang) {
this.lang = lang;
}
public String getDescc() {
return desc;
}
public void setDescc(final String descc) {
this.desc = descc;
}
public LocalDate getDescStartDate() {
return descStartDate;
}
public void setDescStartDate(final LocalDate descStartDate) {
this.descStartDate = descStartDate;
}
}

View file

@ -0,0 +1,49 @@
package de.avatic.taric.model;
import java.util.HashSet;
import java.util.Set;
import org.springframework.data.annotation.Id;
import org.springframework.data.relational.core.mapping.MappedCollection;
import jakarta.validation.constraints.Size;
public class CertificateType {
@Id
private Integer id;
@Size(max = 1)
private String certificateTypeCode;
@MappedCollection(idColumn = "ref_id")
private Set<CertificateTypeDesc> certificateTypeDesc;
public CertificateType(String certificateTypeCode) {
this.certificateTypeCode = certificateTypeCode;
this.certificateTypeDesc = new HashSet<>();
}
public Integer getId() {
return id;
}
public void setId(final Integer id) {
this.id = id;
}
public String getCertificateTypeCode() {
return certificateTypeCode;
}
public void setCertificateTypeCode(final String certificateTypeCode) {
this.certificateTypeCode = certificateTypeCode;
}
public void addCertificateTypeDesc(CertificateTypeDesc certificateTypeDesc) {
this.certificateTypeDesc.add(certificateTypeDesc);
}
}

View file

@ -0,0 +1,62 @@
package de.avatic.taric.model;
import java.time.LocalDate;
import org.springframework.data.annotation.Id;
import jakarta.validation.constraints.Size;
public class CertificateTypeDesc {
@Id
private Integer id;
@Size(max = 2)
private String lang;
private String desc;
private LocalDate descStartDate;
public CertificateTypeDesc(String lang, String desc, LocalDate descStartDate) {
this.lang = lang;
this.desc = desc;
this.descStartDate = descStartDate;
}
public Integer getId() {
return id;
}
public void setId(final Integer id) {
this.id = id;
}
public String getLang() {
return lang;
}
public void setLang(final String lang) {
this.lang = lang;
}
public String getDescc() {
return desc;
}
public void setDescc(final String desc) {
this.desc = desc;
}
public LocalDate getDescStartDate() {
return descStartDate;
}
public void setDescStartDate(final LocalDate descStartDate) {
this.descStartDate = descStartDate;
}
}

View file

@ -0,0 +1,47 @@
package de.avatic.taric.model;
import java.util.HashSet;
import java.util.Set;
import org.springframework.data.annotation.Id;
import org.springframework.data.relational.core.mapping.MappedCollection;
import jakarta.validation.constraints.Size;
public class ConditionType {
@Id
private Integer id;
@Size(max = 2)
private String conditionTypeCode;
@MappedCollection(idColumn = "ref_id")
private Set<ConditionTypeDesc> conditionTypeDesc;
public ConditionType(String conditionTypeCode) {
this.conditionTypeCode = conditionTypeCode;
this.conditionTypeDesc = new HashSet<>();
}
public Integer getId() {
return id;
}
public void setId(final Integer id) {
this.id = id;
}
public String getConditionTypeCode() {
return conditionTypeCode;
}
public void setConditionTypeCode(final String conditionTypeCode) {
this.conditionTypeCode = conditionTypeCode;
}
public void addConditionTypeDesc(ConditionTypeDesc conditionTypeDesc) {
this.conditionTypeDesc.add(conditionTypeDesc);
}
}

View file

@ -0,0 +1,61 @@
package de.avatic.taric.model;
import java.time.LocalDate;
import org.springframework.data.annotation.Id;
import jakarta.validation.constraints.Size;
public class ConditionTypeDesc {
@Id
private Integer id;
@Size(max = 2)
private String lang;
private String desc;
private LocalDate descStartDate;
public ConditionTypeDesc(String lang, String desc, LocalDate descStartDate) {
this.lang = lang;
this.desc = desc;
this.descStartDate = descStartDate;
}
public Integer getId() {
return id;
}
public void setId(final Integer id) {
this.id = id;
}
public String getLang() {
return lang;
}
public void setLang(final String lang) {
this.lang = lang;
}
public String getDescc() {
return desc;
}
public void setDesc(final String desc) {
this.desc = desc;
}
public LocalDate getDescStartDate() {
return descStartDate;
}
public void setDescStartDate(final LocalDate descStartDate) {
this.descStartDate = descStartDate;
}
}

View file

@ -0,0 +1,8 @@
package de.avatic.taric.model;
public interface Description {
String getLang();
}

View file

@ -0,0 +1,46 @@
package de.avatic.taric.model;
import java.time.LocalDate;
import java.util.HashSet;
import java.util.Set;
import com.fasterxml.jackson.annotation.JsonIgnore;
import com.fasterxml.jackson.annotation.JsonProperty;
import com.fasterxml.jackson.databind.annotation.JsonSerialize;
import de.avatic.taric.serializer.DescSetSerializer;
import lombok.Getter;
import lombok.Setter;
import org.springframework.data.annotation.Id;
import org.springframework.data.relational.core.mapping.Column;
import org.springframework.data.relational.core.mapping.MappedCollection;
import org.springframework.data.relational.core.mapping.Table;
import jakarta.validation.constraints.Size;
@Getter
@Setter
@Table("footnote")
public class Footnote {
@Id
@JsonIgnore
private Integer id;
@Size(max = 8)
@Column("footnote")
private String footnote;
@Column("start_date")
private LocalDate startDate;
@Column("end_date")
private LocalDate endDate;
@MappedCollection(idColumn = "ref_id")
@JsonSerialize(using = DescSetSerializer.class)
@JsonProperty("desc")
private Set<FootnotesDesc> footnotesDesc;
}

View file

@ -0,0 +1,31 @@
package de.avatic.taric.model;
import java.time.LocalDate;
import com.fasterxml.jackson.annotation.JsonIgnore;
import com.fasterxml.jackson.databind.annotation.JsonSerialize;
import de.avatic.taric.serializer.DescriptionSerializer;
import lombok.Getter;
import lombok.Setter;
import org.springframework.data.relational.core.mapping.Table;
import jakarta.validation.constraints.Size;
@Getter
@Setter
@Table("footnotes_desc")
public class FootnotesDesc implements Description {
@JsonIgnore
private Integer id;
@Size(max = 2)
private String lang;
@JsonSerialize(using = DescriptionSerializer.class)
private String desc;
private LocalDate descStartDate;
}

View file

@ -0,0 +1,33 @@
package de.avatic.taric.model;
import com.fasterxml.jackson.annotation.JsonAnyGetter;
import com.fasterxml.jackson.annotation.JsonIgnore;
import com.fasterxml.jackson.databind.annotation.JsonSerialize;
import de.avatic.taric.serializer.DescSetSerializer;
import jakarta.validation.constraints.Size;
import lombok.Getter;
import lombok.Setter;
import org.springframework.data.annotation.Id;
import org.springframework.data.relational.core.mapping.Column;
import org.springframework.data.relational.core.mapping.MappedCollection;
import java.util.Set;
@Getter
@Setter
public class Geo {
@Id
@JsonIgnore
private Integer id;
@Size(max = 2)
@Column("iso_3166_code")
private String iso3166Code;
@MappedCollection(idColumn = "ref_id")
@JsonSerialize(using = DescSetSerializer.class)
private Set<GeoDesc> geoDesc;
}

View file

@ -0,0 +1,32 @@
package de.avatic.taric.model;
import java.time.LocalDate;
import com.fasterxml.jackson.annotation.JsonIgnore;
import com.fasterxml.jackson.databind.annotation.JsonSerialize;
import de.avatic.taric.serializer.DescriptionSerializer;
import lombok.Getter;
import lombok.Setter;
import org.springframework.data.annotation.Id;
import jakarta.validation.constraints.Size;
@Getter
@Setter
public class GeoDesc implements Description{
@Id
@JsonIgnore
private Integer id;
@Size(max = 2)
private String lang;
@JsonSerialize(using = DescriptionSerializer.class)
private String desc;
private LocalDate descStartDate;
}

View file

@ -0,0 +1,44 @@
package de.avatic.taric.model;
import java.time.LocalDate;
import java.util.HashSet;
import java.util.Set;
import com.fasterxml.jackson.annotation.JsonIgnore;
import com.fasterxml.jackson.databind.annotation.JsonSerialize;
import de.avatic.taric.serializer.DescSetSerializer;
import lombok.Getter;
import lombok.Setter;
import org.springframework.data.annotation.Id;
import org.springframework.data.relational.core.mapping.MappedCollection;
import jakarta.validation.constraints.Size;
@Getter
@Setter
public class GeoGroup {
@Id
@JsonIgnore
private Integer id;
@Size(max = 4)
private String geoGroupCode;
private String abbr;
private LocalDate startDate;
private LocalDate endDate;
@MappedCollection(idColumn = "geo_group_id")
private Set<GeoGroupMembership> geoGroupMembers;
@MappedCollection(idColumn = "ref_id")
@JsonSerialize(using = DescSetSerializer.class)
private Set<GeoGroupDesc> geoGroupDescs;
}

View file

@ -0,0 +1,27 @@
package de.avatic.taric.model;
import java.time.LocalDate;
import com.fasterxml.jackson.annotation.JsonIgnore;
import lombok.Getter;
import lombok.Setter;
import org.springframework.data.annotation.Id;
import jakarta.validation.constraints.Size;
@Getter
@Setter
public class GeoGroupDesc implements Description {
@Id
@JsonIgnore
private Integer id;
@Size(max = 2)
private String lang;
private String desc;
private LocalDate descStartDate;
}

View file

@ -0,0 +1,67 @@
package de.avatic.taric.model;
import java.time.LocalDate;
import com.fasterxml.jackson.annotation.JsonIgnore;
import com.fasterxml.jackson.databind.annotation.JsonSerialize;
import de.avatic.taric.serializer.GeoReferenceSerializer;
import org.springframework.data.annotation.Id;
import org.springframework.data.jdbc.core.mapping.AggregateReference;
import org.springframework.data.relational.core.mapping.Column;
public class GeoGroupMembership {
@Id
@JsonIgnore
private Integer id;
private LocalDate startDate;
private LocalDate endDate;
@Column("geo_id")
@JsonSerialize(using = GeoReferenceSerializer.class)
private AggregateReference<Geo, Integer> geo;
public GeoGroupMembership(LocalDate startDate, LocalDate endDate,
AggregateReference<Geo, Integer> geo) {
this.startDate = startDate;
this.endDate = endDate;
this.geo = geo;
}
public Integer getId() {
return id;
}
public void setId(Integer id) {
this.id = id;
}
public LocalDate getStartDate() {
return startDate;
}
public void setStartDate(LocalDate startDate) {
this.startDate = startDate;
}
public LocalDate getEndDate() {
return endDate;
}
public void setEndDate(LocalDate endDate) {
this.endDate = endDate;
}
public AggregateReference<Geo, Integer> getGeo() {
return geo;
}
public void setGeo(AggregateReference<Geo, Integer> geo) {
this.geo = geo;
}
}

View file

@ -0,0 +1,87 @@
package de.avatic.taric.model;
import java.util.Set;
import org.springframework.data.annotation.Id;
import org.springframework.data.jdbc.core.mapping.AggregateReference;
import org.springframework.data.relational.core.mapping.Column;
import org.springframework.data.relational.core.mapping.MappedCollection;
import org.springframework.data.relational.core.mapping.Table;
import jakarta.validation.constraints.NotNull;
@Table("import")
public class Import {
@Id
private Integer id;
@NotNull
@Column("nomenclature_id")
private AggregateReference<Nomenclature, Integer> nomenclature;
@Column("additional_code_id")
private AggregateReference<AdditionalCode, Integer> additionalCode;
@Column("geo_id")
private AggregateReference<Geo, Integer> geo;
@Column("geo_group_id")
private AggregateReference<GeoGroup, Integer> geoGroup;
@MappedCollection(idColumn = "import_id")
Set<AppliedMeasure> appliedMeasures;
public Import(AggregateReference<Nomenclature, Integer> nomenclature,
AggregateReference<AdditionalCode, Integer> additionalCode, Set<AppliedMeasure> appliedMeasures, AggregateReference<Geo,Integer> geo,
AggregateReference<GeoGroup, Integer> geoGroup) {
this.nomenclature = nomenclature;
this.additionalCode = additionalCode;
this.appliedMeasures = appliedMeasures;
this.geo = geo;
this.geoGroup = geoGroup;
}
public Integer getId() {
return id;
}
public void setId(final Integer id) {
this.id = id;
}
public AggregateReference<Nomenclature, Integer> getNomenclature() {
return nomenclature;
}
public void setNomenclature(final AggregateReference<Nomenclature, Integer> nomenclature) {
this.nomenclature = nomenclature;
}
public AggregateReference<AdditionalCode, Integer> getAdditionalCode() {
return additionalCode;
}
public void setAdditionalCode(final AggregateReference<AdditionalCode, Integer> additionalCode) {
this.additionalCode = additionalCode;
}
public AggregateReference<Geo, Integer> getGeo() {
return geo;
}
public void setGeo(final AggregateReference<Geo, Integer> geo) {
this.geo = geo;
}
public AggregateReference<GeoGroup, Integer> getGeoGroup() {
return geoGroup;
}
public void setGeoGroup(final AggregateReference<GeoGroup, Integer> geoGroup) {
this.geoGroup = geoGroup;
}
}

View file

@ -0,0 +1,29 @@
package de.avatic.taric.model;
import jakarta.validation.constraints.Size;
import lombok.Getter;
import lombok.Setter;
import org.springframework.data.annotation.Id;
import java.time.LocalDate;
@Setter
@Getter
public class LegalBase {
@Id
private Integer id;
@Size(max = 255)
private String legalBase;
@Size(max = 255)
private String journal;
private Integer page;
private LocalDate date;
}

View file

@ -0,0 +1,39 @@
package de.avatic.taric.model;
import jakarta.validation.constraints.Size;
import lombok.Getter;
import lombok.Setter;
import org.springframework.data.annotation.Id;
import org.springframework.data.jdbc.core.mapping.AggregateReference;
import org.springframework.data.relational.core.mapping.Column;
import org.springframework.data.relational.core.mapping.MappedCollection;
import org.springframework.data.relational.core.mapping.Table;
import java.time.LocalDate;
import java.util.Set;
@Setter
@Getter
@Table("measure")
public class Measure {
@Id
private Integer id;
@Size(max = 3)
private String measureCode;
private String shortDesc;
private Integer tmCode;
private LocalDate startDate;
@MappedCollection(idColumn = "ref_id")
private Set<MeasureDesc> measureDesc;
@Column("measure_series_id")
AggregateReference<MeasureSeries, Integer> measureSeries;
}

View file

@ -0,0 +1,49 @@
package de.avatic.taric.model;
import java.util.HashSet;
import java.util.Set;
import org.springframework.data.annotation.Id;
import org.springframework.data.relational.core.mapping.MappedCollection;
import org.springframework.data.relational.core.mapping.Table;
import jakarta.validation.constraints.Size;
@Table("measure_action")
public class MeasureAction {
@Id
private Integer id;
@Size(max = 2)
private String measureActionCode;
@MappedCollection(idColumn = "ref_id")
private Set<MeasureActionDesc> measureActionDesc;
public MeasureAction(String measureActionCode) {
this.measureActionCode = measureActionCode;
this.measureActionDesc = new HashSet<>();
}
public Integer getId() {
return id;
}
public void setId(final Integer id) {
this.id = id;
}
public String getMeasureActionCode() {
return measureActionCode;
}
public void setMeasureActionCode(final String measureActionCode) {
this.measureActionCode = measureActionCode;
}
public void addMeasureActionDesc(MeasureActionDesc measureActionDesc) {
this.measureActionDesc.add(measureActionDesc);
}
}

View file

@ -0,0 +1,58 @@
package de.avatic.taric.model;
import java.time.LocalDate;
import jakarta.validation.constraints.Size;
public class MeasureActionDesc {
private Integer id;
@Size(max = 2)
private String lang;
private String desc;
private LocalDate descStartDate;
public MeasureActionDesc(String lang, String desc, LocalDate descStartDate) {
this.lang = lang;
this.desc = desc;
this.descStartDate = descStartDate;
}
public Integer getId() {
return id;
}
public void setId(final Integer id) {
this.id = id;
}
public String getLang() {
return lang;
}
public void setLang(final String lang) {
this.lang = lang;
}
public String getDesc() {
return desc;
}
public void setDesc(final String desc) {
this.desc = desc;
}
public LocalDate getDescStartDate() {
return descStartDate;
}
public void setDescStartDate(final LocalDate descStartDate) {
this.descStartDate = descStartDate;
}
}

View file

@ -0,0 +1,60 @@
package de.avatic.taric.model;
import java.time.LocalDate;
import org.springframework.data.annotation.Id;
import jakarta.validation.constraints.Size;
public class MeasureDesc {
@Id
private Integer id;
@Size(max = 2)
private String lang;
private String desc;
private LocalDate descStartDate;
public MeasureDesc(String lang, String desc) {
this.lang = lang;
this.desc = desc;
}
public Integer getId() {
return id;
}
public void setId(final Integer id) {
this.id = id;
}
public String getLang() {
return lang;
}
public void setLang(final String lang) {
this.lang = lang;
}
public String getDesc() {
return desc;
}
public void setDesc(final String desc) {
this.desc = desc;
}
public LocalDate getDescStartDate() {
return descStartDate;
}
public void setDescStartDate(final LocalDate descStartDate) {
this.descStartDate = descStartDate;
}
}

View file

@ -0,0 +1,30 @@
package de.avatic.taric.model;
import lombok.Getter;
import lombok.Setter;
import org.springframework.data.annotation.Id;
import org.springframework.data.jdbc.core.mapping.AggregateReference;
import org.springframework.data.relational.core.mapping.Column;
import jakarta.validation.constraints.NotNull;
import java.time.LocalDate;
@Getter
@Setter
public class MeasureExclusion {
@Id
private Integer id;
LocalDate startDate;
LocalDate endDate;
@NotNull
@Column("geo_id")
private AggregateReference<Geo, Integer> geo;
}

View file

@ -0,0 +1,27 @@
package de.avatic.taric.model;
import lombok.Getter;
import lombok.Setter;
import org.springframework.data.annotation.Id;
import org.springframework.data.jdbc.core.mapping.AggregateReference;
import org.springframework.data.relational.core.mapping.Column;
import java.time.LocalDate;
@Getter
@Setter
public class MeasureFootnote {
@Id
private Integer id;
LocalDate startDate;
LocalDate endDate;
@Column("footnote_id")
private AggregateReference<Footnote, Integer> footnote;
}

View file

@ -0,0 +1,49 @@
package de.avatic.taric.model;
import java.util.HashSet;
import java.util.Set;
import org.springframework.data.annotation.Id;
import org.springframework.data.relational.core.mapping.MappedCollection;
import org.springframework.data.relational.core.mapping.Table;
import jakarta.validation.constraints.Size;
@Table("measure_series")
public class MeasureSeries {
@Id
private Integer id;
@Size(max = 1)
private String measureSeriesCode;
@MappedCollection(idColumn = "ref_id")
private Set<MeasureSeriesDesc> measureSeriesDesc;
public MeasureSeries(String measureSeriesCode) {
this.measureSeriesCode = measureSeriesCode;
this.measureSeriesDesc = new HashSet<>();
}
public Integer getId() {
return id;
}
public void setId(final Integer id) {
this.id = id;
}
public String getMeasureSeriesCode() {
return measureSeriesCode;
}
public void setMeasureSeriesCode(final String measureSeriesCode) {
this.measureSeriesCode = measureSeriesCode;
}
public void addMeasureSeriesDesc(MeasureSeriesDesc measureSeriesDesc) {
this.measureSeriesDesc.add(measureSeriesDesc);
}
}

View file

@ -0,0 +1,61 @@
package de.avatic.taric.model;
import java.time.LocalDate;
import org.springframework.data.relational.core.mapping.Table;
import jakarta.validation.constraints.Size;
@Table("measure_series_desc")
public class MeasureSeriesDesc {
private Integer id;
@Size(max = 2)
private String lang;
private String desc;
private LocalDate descStartDate;
public MeasureSeriesDesc(String lang, String desc) {
this.lang = lang;
this.desc = desc;
}
public Integer getId() {
return id;
}
public void setId(final Integer id) {
this.id = id;
}
public String getLang() {
return lang;
}
public void setLang(final String lang) {
this.lang = lang;
}
public String getDesc() {
return desc;
}
public void setDescc(final String desc) {
this.desc = desc;
}
public LocalDate getDescStartDate() {
return descStartDate;
}
public void setDescStartDate(final LocalDate descStartDate) {
this.descStartDate = descStartDate;
}
}

View file

@ -0,0 +1,48 @@
package de.avatic.taric.model;
import java.util.HashSet;
import java.util.Set;
import org.springframework.data.annotation.Id;
import org.springframework.data.relational.core.mapping.MappedCollection;
import jakarta.validation.constraints.Size;
public class MonetaryUnit {
@Id
private Integer id;
@Size(max = 3)
private String monetaryUnitCode;
@MappedCollection(idColumn = "ref_id")
private Set<MonetaryUnitDesc> monetaryUnitDesc;
public MonetaryUnit(String monetaryUnitCode) {
this.monetaryUnitCode = monetaryUnitCode;
this.monetaryUnitDesc = new HashSet<>();
}
public Integer getId() {
return id;
}
public void setId(final Integer id) {
this.id = id;
}
public String getMonetaryUnitCode() {
return monetaryUnitCode;
}
public void setMonetaryUnitCode(final String monetaryUnitCode) {
this.monetaryUnitCode = monetaryUnitCode;
}
public void addMonetaryUnitDesc(MonetaryUnitDesc monetaryUnitDesc) {
this.monetaryUnitDesc.add(monetaryUnitDesc);
}
}

View file

@ -0,0 +1,61 @@
package de.avatic.taric.model;
import java.time.LocalDate;
import org.springframework.data.annotation.Id;
import jakarta.validation.constraints.Size;
public class MonetaryUnitDesc {
@Id
private Integer id;
@Size(max = 2)
private String lang;
private String desc;
private LocalDate descStartDate;
public MonetaryUnitDesc(String lang, String desc, LocalDate descStartDate) {
this.lang = lang;
this.desc = desc;
this.descStartDate = descStartDate;
}
public Integer getId() {
return id;
}
public void setId(final Integer id) {
this.id = id;
}
public String getLang() {
return lang;
}
public void setLang(final String lang) {
this.lang = lang;
}
public String getDesc() {
return desc;
}
public void setDescc(final String desc) {
this.desc = desc;
}
public LocalDate getDescStartDate() {
return descStartDate;
}
public void setDescStartDate(final LocalDate descStartDate) {
this.descStartDate = descStartDate;
}
}

View file

@ -0,0 +1,54 @@
package de.avatic.taric.model;
import com.fasterxml.jackson.annotation.JsonIgnore;
import com.fasterxml.jackson.annotation.JsonProperty;
import com.fasterxml.jackson.databind.annotation.JsonSerialize;
import de.avatic.taric.serializer.DescSetSerializer;
import jakarta.validation.constraints.Size;
import lombok.Getter;
import lombok.Setter;
import org.springframework.data.annotation.Id;
import org.springframework.data.relational.core.mapping.MappedCollection;
import java.time.LocalDate;
import java.util.Set;
@Getter
@Setter
public class Nomenclature {
@Id
@JsonIgnore
private Integer id;
@Size(max = 10)
private String hscode;
@Size(max = 2)
private String suffix;
private Integer hierachy;
private Integer indent;
private LocalDate startDate;
private LocalDate endDate;
@JsonProperty("isLeaf")
private Boolean isLeaf;
private LocalDate isLeafStartDate;
private Integer parentId;
@MappedCollection(idColumn = "ref_id")
@JsonSerialize(using = DescSetSerializer.class)
@JsonProperty("desc")
private Set<NomenclatureDesc> nomenclatureDescs;
@MappedCollection(idColumn = "nomenclature_id")
private Set<NomenclatureFootnote> footnotes;
}

View file

@ -0,0 +1,31 @@
package de.avatic.taric.model;
import java.time.LocalDate;
import com.fasterxml.jackson.annotation.JsonIgnore;
import com.fasterxml.jackson.databind.annotation.JsonSerialize;
import de.avatic.taric.serializer.DescriptionSerializer;
import lombok.Getter;
import lombok.Setter;
import org.springframework.data.annotation.Id;
import jakarta.validation.constraints.Size;
@Getter
@Setter
public class NomenclatureDesc implements Description {
@Id
@JsonIgnore
private Integer id;
@Size(max = 2)
private String lang;
@JsonSerialize(using = DescriptionSerializer.class)
private String desc;
private LocalDate descStartDate;
}

View file

@ -0,0 +1,26 @@
package de.avatic.taric.model;
import com.fasterxml.jackson.annotation.JsonIgnore;
import com.fasterxml.jackson.databind.annotation.JsonSerialize;
import de.avatic.taric.serializer.FootnoteReferenceSerializer;
import lombok.Getter;
import lombok.Setter;
import org.springframework.data.jdbc.core.mapping.AggregateReference;
import org.springframework.data.relational.core.mapping.Column;
import jakarta.validation.constraints.NotNull;
@Getter
@Setter
public class NomenclatureFootnote {
@JsonIgnore
private Integer id;
@NotNull
@Column("footnote_id")
@JsonSerialize(using = FootnoteReferenceSerializer.class)
private AggregateReference<Footnote, Integer> footnote;
}

View file

@ -0,0 +1,83 @@
package de.avatic.taric.model;
import org.springframework.data.annotation.Id;
import org.springframework.data.relational.core.mapping.Table;
import jakarta.validation.constraints.Size;
@Table("setup_status")
public class SetupStatus {
@Id
private Integer id;
private Integer currentRecord;
private Integer maxRecord;
@Size(max = 255)
private String statusText;
private Boolean running;
@Size(max = 255)
private String exitStatus;
public SetupStatus(int currentRecord, int maxRecord, String statusText, boolean running, String exitStatus) {
this.currentRecord = currentRecord;
this.maxRecord = maxRecord;
this.statusText = statusText;
this.running = running;
this.exitStatus = exitStatus;
}
public Integer getId() {
return id;
}
public void setId(final Integer id) {
this.id = id;
}
public Integer getCurrentRecord() {
return currentRecord;
}
public void setCurrentRecord(final Integer currentRecord) {
this.currentRecord = currentRecord;
}
public Integer getMaxRecord() {
return maxRecord;
}
public void setMaxRecord(final Integer maxRecord) {
this.maxRecord = maxRecord;
}
public String getStatusText() {
return statusText;
}
public void setStatusText(final String statusText) {
this.statusText = statusText;
}
public Boolean getRunning() {
return running;
}
public void setRunning(final Boolean running) {
this.running = running;
}
public String getExitStatus() {
return exitStatus;
}
public void setExitStatus(final String exitStatus) {
this.exitStatus = exitStatus;
}
}

View file

@ -0,0 +1,71 @@
package de.avatic.taric.model;
import java.util.HashSet;
import java.util.Set;
import org.springframework.data.annotation.Id;
import org.springframework.data.relational.core.mapping.MappedCollection;
import jakarta.validation.constraints.Size;
public class Unit {
@Id
private Integer id;
@Size(max = 3)
private String unitCode;
@Size(max = 1)
private String unitQualifier;
private String label;
@MappedCollection(idColumn = "ref_id")
private Set<UnitDesc> unitDesc;
public Unit(String unitCode, String unitQualifier, String label) {
this.unitCode = unitCode;
this.unitQualifier = unitQualifier;
this.label = label;
this.unitDesc = new HashSet<>();
}
public Integer getId() {
return id;
}
public void setId(final Integer id) {
this.id = id;
}
public String getUnitCode() {
return unitCode;
}
public void setUnitCode(final String unitCode) {
this.unitCode = unitCode;
}
public String getUnitQualifier() {
return unitQualifier;
}
public void setUnitQualifier(final String unitQualifier) {
this.unitQualifier = unitQualifier;
}
public String getLabel() {
return label;
}
public void setLabel(final String label) {
this.label = label;
}
public void addUnitDesc(UnitDesc desc) {
unitDesc.add(desc);
}
}

View file

@ -0,0 +1,62 @@
package de.avatic.taric.model;
import java.time.LocalDate;
import org.springframework.data.annotation.Id;
import jakarta.validation.constraints.Size;
public class UnitDesc {
@Id
private Integer id;
@Size(max = 2)
private String lang;
private String desc;
private LocalDate descStartDate;
public UnitDesc(String lang, String desc, LocalDate descStartDate) {
this.lang = lang;
this.desc = desc;
this.descStartDate = descStartDate;
}
public Integer getId() {
return id;
}
public void setId(final Integer id) {
this.id = id;
}
public String getLang() {
return lang;
}
public void setLang(final String lang) {
this.lang = lang;
}
public String getDescc() {
return desc;
}
public void setDesc(final String desc) {
this.desc = desc;
}
public LocalDate getDescStartDate() {
return descStartDate;
}
public void setDescStartDate(final LocalDate descStartDate) {
this.descStartDate = descStartDate;
}
}

View file

@ -0,0 +1,9 @@
package de.avatic.taric.repository;
import org.springframework.data.repository.CrudRepository;
import de.avatic.taric.model.AdditionalCode;
public interface AdditionalCodeRepository extends CrudRepository<AdditionalCode, Integer> {
}

View file

@ -0,0 +1,9 @@
package de.avatic.taric.repository;
import org.springframework.data.repository.CrudRepository;
import de.avatic.taric.model.AppliedMeasureCondition;
public interface AppliedMeasureConditionRepository extends CrudRepository<AppliedMeasureCondition, Integer> {
}

View file

@ -0,0 +1,18 @@
package de.avatic.taric.repository;
import de.avatic.taric.model.Import;
import org.springframework.data.jdbc.core.mapping.AggregateReference;
import org.springframework.data.jdbc.repository.query.Query;
import org.springframework.data.repository.CrudRepository;
import de.avatic.taric.model.AppliedMeasure;
import org.springframework.data.repository.query.Param;
import java.util.List;
public interface AppliedMeasureRepository extends CrudRepository<AppliedMeasure, Integer> {
@Query("SELECT * FROM applied_measure WHERE import_id = :importId")
List<AppliedMeasure> findByImport(@Param("importId") AggregateReference<Import, Integer> importRef);
}

View file

@ -0,0 +1,9 @@
package de.avatic.taric.repository;
import org.springframework.data.repository.CrudRepository;
import de.avatic.taric.model.Certificate;
public interface CertificateRepository extends CrudRepository<Certificate, Integer> {
}

View file

@ -0,0 +1,9 @@
package de.avatic.taric.repository;
import org.springframework.data.repository.CrudRepository;
import de.avatic.taric.model.CertificateType;
public interface CertificateTypeRepository extends CrudRepository<CertificateType, Integer> {
}

View file

@ -0,0 +1,9 @@
package de.avatic.taric.repository;
import org.springframework.data.repository.CrudRepository;
import de.avatic.taric.model.ConditionType;
public interface ConditionTypeRepository extends CrudRepository<ConditionType, Integer> {
}

View file

@ -0,0 +1,11 @@
package de.avatic.taric.repository;
import org.springframework.data.repository.CrudRepository;
import de.avatic.taric.model.Footnote;
public interface FootnoteRepository extends CrudRepository<Footnote, Integer> {
}

View file

@ -0,0 +1,19 @@
package de.avatic.taric.repository;
import org.springframework.data.jdbc.repository.query.Query;
import org.springframework.data.repository.CrudRepository;
import de.avatic.taric.model.GeoGroupMembership;
import org.springframework.data.repository.query.Param;
import java.util.List;
public interface GeoGroupMembershipRepository extends CrudRepository<GeoGroupMembership, Integer> {
@Query("SELECT * FROM geo_group_membership WHERE geo_id = :geoId")
List<GeoGroupMembership> findByGeoId(@Param("geoId") Integer geoId);
@Query("SELECT geo_group_id FROM geo_group_membership WHERE id = :membershipId")
Integer findGeoGroupIdByMembershipId(@Param("membershipId") Integer membershipId);
}

View file

@ -0,0 +1,25 @@
package de.avatic.taric.repository;
import org.springframework.data.jdbc.repository.query.Query;
import org.springframework.data.repository.CrudRepository;
import de.avatic.taric.model.GeoGroup;
import org.springframework.data.repository.query.Param;
import java.util.List;
import java.util.Optional;
public interface GeoGroupRepository extends CrudRepository<GeoGroup, Integer> {
@Query("SELECT * FROM geo_group WHERE geo_group_code = :code")
Optional<GeoGroup> findByGeoGroupCode(@Param("code") String code);
@Query("""
SELECT * FROM geo_group AS gg
LEFT JOIN geo_group_membership AS ggm ON gg.id = ggm.geo_group_id
LEFT JOIN geo AS g ON ggm.geo_id = g.id
WHERE iso_3166_code = :countryCode""")
List<GeoGroup> findByCountryCode(@Param("countryCode") String countryCode);
List<GeoGroup> findByAbbr(String abbr);
}

View file

@ -0,0 +1,20 @@
package de.avatic.taric.repository;
import de.avatic.taric.model.Geo;
import de.avatic.taric.model.GeoGroup;
import org.springframework.data.jdbc.repository.query.Query;
import org.springframework.data.repository.CrudRepository;
import org.springframework.data.repository.query.Param;
import org.springframework.stereotype.Repository;
import java.util.Optional;
@Repository
public interface GeoRepository extends CrudRepository<Geo, Integer> {
@Query("SELECT * FROM geo WHERE iso_3166_code = :code AND (end_date IS NULL OR end_date >= CURRENT_DATE)")
Optional<Geo> findByIso3166Code(@Param("code") String code);
@Query("SELECT * FROM geo_group WHERE geo_group_code = '1011'")
Optional<GeoGroup> findErgaOmnes();
}

View file

@ -0,0 +1,17 @@
package de.avatic.taric.repository;
import de.avatic.taric.model.Import;
import org.springframework.data.jdbc.repository.query.Query;
import org.springframework.data.repository.CrudRepository;
import org.springframework.stereotype.Repository;
import java.util.List;
@Repository
public interface ImportRepository extends CrudRepository<Import, Integer> {
@Query("SELECT * FROM import WHERE nomenclature_id = :nomenclatureId AND geo_id = :geoId")
List<Import> findByNomenclatureIdAndGeoId(Integer nomenclatureId, Integer geoId);
@Query("SELECT * FROM import WHERE nomenclature_id = :nomenclatureId AND geo_group_id = :geoGroupId")
List<Import> findByNomenclatureIdAndGeoGroupId(Integer nomenclatureId, Integer geoGroupId);
}

View file

@ -0,0 +1,9 @@
package de.avatic.taric.repository;
import org.springframework.data.repository.CrudRepository;
import de.avatic.taric.model.LegalBase;
public interface LegalBaseRepository extends CrudRepository<LegalBase, Integer> {
}

View file

@ -0,0 +1,9 @@
package de.avatic.taric.repository;
import org.springframework.data.repository.CrudRepository;
import de.avatic.taric.model.MeasureAction;
public interface MeasureActionRepository extends CrudRepository<MeasureAction, Integer> {
}

View file

@ -0,0 +1,20 @@
package de.avatic.taric.repository;
import de.avatic.taric.model.AppliedMeasure;
import org.springframework.data.jdbc.core.mapping.AggregateReference;
import org.springframework.data.jdbc.repository.query.Query;
import org.springframework.data.repository.CrudRepository;
import de.avatic.taric.model.MeasureExclusion;
import org.springframework.data.repository.query.Param;
import java.util.List;
public interface MeasureExclusionRepository extends CrudRepository<MeasureExclusion, Integer>
{
@Query("SELECT * FROM measure_exclusion WHERE applied_measure_id = :appliedMeasureId")
List<MeasureExclusion> findByAppliedMeasure(@Param("appliedMeasureId") AggregateReference<AppliedMeasure, Integer> appliedMeasureRef);
}

View file

@ -0,0 +1,9 @@
package de.avatic.taric.repository;
import org.springframework.data.repository.CrudRepository;
import de.avatic.taric.model.MeasureFootnote;
public interface MeasureFootnoteRepository extends CrudRepository<MeasureFootnote, Integer> {
}

View file

@ -0,0 +1,15 @@
package de.avatic.taric.repository;
import java.time.LocalDate;
import org.springframework.data.jdbc.repository.query.Query;
import org.springframework.data.repository.CrudRepository;
import org.springframework.data.repository.query.Param;
import de.avatic.taric.model.Measure;
public interface MeasureRepository extends CrudRepository<Measure, Integer> {
}

View file

@ -0,0 +1,11 @@
package de.avatic.taric.repository;
import org.springframework.data.repository.CrudRepository;
import de.avatic.taric.model.MeasureSeries;
public interface MeasureSeriesRepository extends CrudRepository<MeasureSeries, Integer> {
public MeasureSeries findByMeasureSeriesCode(String measureSeriesCode);
}

View file

@ -0,0 +1,9 @@
package de.avatic.taric.repository;
import org.springframework.data.repository.CrudRepository;
import de.avatic.taric.model.MonetaryUnit;
public interface MonetaryUnitRepository extends CrudRepository<MonetaryUnit, Integer> {
}

View file

@ -0,0 +1,9 @@
package de.avatic.taric.repository;
import org.springframework.data.repository.CrudRepository;
import de.avatic.taric.model.NomenclatureFootnote;
public interface NomenclatureFootnoteRepository extends CrudRepository<NomenclatureFootnote, Integer> {
}

View file

@ -0,0 +1,20 @@
package de.avatic.taric.repository;
import de.avatic.taric.model.Nomenclature;
import org.springframework.data.jdbc.repository.query.Query;
import org.springframework.data.repository.CrudRepository;
import org.springframework.data.repository.query.Param;
import org.springframework.stereotype.Repository;
import java.util.List;
import java.util.Optional;
@Repository
public interface NomenclatureRepository extends CrudRepository<Nomenclature, Integer> {
@Query("SELECT * FROM nomenclature WHERE hscode = :hscode AND (end_date IS NULL OR end_date >= CURRENT_DATE)")
Optional<Nomenclature> findByHscode(String hscode);
@Query("SELECT * FROM nomenclature WHERE is_leaf = 1 AND hscode LIKE CONCAT(:code, '%') AND (end_date IS NULL OR end_date >= CURRENT_DATE)")
List<Nomenclature> findDeclarableChildren(@Param("code") String code);
}

View file

@ -0,0 +1,9 @@
package de.avatic.taric.repository;
import org.springframework.data.repository.CrudRepository;
import de.avatic.taric.model.Unit;
public interface UnitRepository extends CrudRepository<Unit, Integer> {
}

View file

@ -0,0 +1,52 @@
package de.avatic.taric.serializer;
import com.fasterxml.jackson.core.JsonGenerator;
import com.fasterxml.jackson.databind.JsonSerializer;
import com.fasterxml.jackson.databind.SerializerProvider;
import de.avatic.taric.model.Description;
import org.springframework.stereotype.Component;
import java.io.IOException;
import java.util.Set;
import java.util.stream.Collectors;
@Component
public class DescSetSerializer extends JsonSerializer<Set<Description>> {
private static final ThreadLocal<String> LANGUAGE_CONTEXT = new ThreadLocal<>();
public static void setLanguage(String language) {
LANGUAGE_CONTEXT.set(language);
}
public static void clearLanguage() {
LANGUAGE_CONTEXT.remove();
}
@Override
public void serialize(Set<Description> value, JsonGenerator gen, SerializerProvider serializer) throws IOException {
if (value != null) {
var filtered = value;
String language = LANGUAGE_CONTEXT.get();
if (language != null) {
filtered = value.stream()
.filter(desc -> language.equalsIgnoreCase(desc.getLang()))
.collect(Collectors.toSet());
}
if (filtered.isEmpty()) {
filtered = value.stream()
.filter(desc -> "EN".equalsIgnoreCase(desc.getLang()))
.collect(Collectors.toSet());
}
if(filtered.size() == 1)
gen.writeObject(filtered.iterator().next());
else
gen.writeObject(filtered);
} else {
gen.writeNull();
}
}
}

View file

@ -0,0 +1,35 @@
package de.avatic.taric.serializer;
import com.fasterxml.jackson.core.JsonGenerator;
import com.fasterxml.jackson.databind.JsonSerializer;
import com.fasterxml.jackson.databind.SerializerProvider;
import org.springframework.stereotype.Component;
import java.io.IOException;
@Component
public class DescriptionSerializer extends JsonSerializer<String> {
@Override
public void serialize(String value, JsonGenerator gen, SerializerProvider serializers) throws IOException {
if (value != null) {
String converted = value
.replace("!1!", "\n") // Paragraph mark (carriage return)
.replace("|", "\u00A0") // Unbreakable space (non-breaking space)
.replace("!X!", "×") // Multiply sign
.replace("!x!", "×") // Multiply sign
.replace("!o!", "°") // Degree symbol
.replace("!O!", "°") // Degree symbol
.replace("!<=!", "") // Less than or equal to
.replace("!>=!", "") // Greater than or equal to
.replace("\\n", "\n")
.replaceAll("\\$(.)", "<sup>$1</sup>") // Superscript
.replaceAll("@(.)", "<sub>$1</sub>"); // Subscript
gen.writeString(converted);
} else {
gen.writeNull();
}
}
}

View file

@ -0,0 +1,34 @@
package de.avatic.taric.serializer;
import com.fasterxml.jackson.core.JsonGenerator;
import com.fasterxml.jackson.databind.JsonSerializer;
import com.fasterxml.jackson.databind.SerializerProvider;
import de.avatic.taric.model.Footnote;
import de.avatic.taric.repository.FootnoteRepository;
import org.springframework.data.jdbc.core.mapping.AggregateReference;
import org.springframework.stereotype.Component;
import java.io.IOException;
@Component
public class FootnoteReferenceSerializer extends JsonSerializer<AggregateReference<Footnote, Integer>> {
protected final FootnoteRepository footnoteRepository;
public FootnoteReferenceSerializer(FootnoteRepository footnoteRepository) {
this.footnoteRepository = footnoteRepository;
}
@Override
public void serialize(AggregateReference<Footnote, Integer> value, JsonGenerator gen,
SerializerProvider serializers) throws IOException {
if (value != null) {
Footnote footnote = footnoteRepository.findById(value.getId())
.orElse(null);
gen.writeObject(footnote);
} else {
gen.writeNull();
}
}
}

View file

@ -0,0 +1,34 @@
package de.avatic.taric.serializer;
import com.fasterxml.jackson.core.JsonGenerator;
import com.fasterxml.jackson.databind.JsonSerializer;
import com.fasterxml.jackson.databind.SerializerProvider;
import de.avatic.taric.model.Footnote;
import de.avatic.taric.model.Geo;
import de.avatic.taric.repository.GeoRepository;
import org.springframework.data.jdbc.core.mapping.AggregateReference;
import org.springframework.stereotype.Component;
import java.io.IOException;
@Component
public class GeoReferenceSerializer extends JsonSerializer<AggregateReference<Geo, Integer>> {
private final GeoRepository geoRepository;
public GeoReferenceSerializer(GeoRepository geoRepository) {
this.geoRepository = geoRepository;
}
@Override
public void serialize(AggregateReference<Geo, Integer> value, JsonGenerator gen, SerializerProvider serializer) throws IOException {
if (value != null) {
Geo geo = geoRepository.findById(value.getId()).orElse(null);
gen.writeObject(geo);
} else {
gen.writeNull();
}
}
}

View file

@ -0,0 +1,34 @@
package de.avatic.taric.service;
import de.avatic.taric.model.Geo;
import de.avatic.taric.model.GeoGroup;
import de.avatic.taric.repository.GeoGroupRepository;
import de.avatic.taric.repository.GeoRepository;
import org.springframework.stereotype.Service;
import java.util.List;
import java.util.Optional;
@Service
public class GeoService {
private final GeoGroupRepository geoGroupRepository;
private final GeoRepository geoRepository;
public GeoService(GeoGroupRepository geoGroupRepository, GeoRepository geoRepository) {
this.geoGroupRepository = geoGroupRepository;
this.geoRepository = geoRepository;
}
public Optional<Geo> getGeo(String countryCode) {
return geoRepository.findByIso3166Code(countryCode);
}
public List<GeoGroup> getGeoGroupByCountryCode(String countryCode) {
return geoGroupRepository.findByCountryCode(countryCode);
}
public List<GeoGroup> getGeoGroup(String abbr) {
return geoGroupRepository.findByAbbr(abbr);
}
}

View file

@ -0,0 +1,92 @@
package de.avatic.taric.service;
import de.avatic.taric.model.Nomenclature;
import de.avatic.taric.repository.NomenclatureRepository;
import org.springframework.stereotype.Service;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Optional;
@Service
public class NomenclatureService {
private final NomenclatureRepository nomenclatureRepository;
public NomenclatureService(NomenclatureRepository nomenclatureRepository) {
this.nomenclatureRepository = nomenclatureRepository;
}
public Optional<Nomenclature> getNomenclature(String hscode) {
return nomenclatureRepository.findByHscode(normalize(hscode.replaceAll("[^0-9]", "")));
}
public boolean isDeclarable(String hscode) {
var nomenclature = getNomenclature(hscode);
if(nomenclature.isEmpty()) return false;
return nomenclature.get().getIsLeaf();
}
public List<Nomenclature> getDeclarableChildren(String hscode) {
var normalized = normalize(hscode.replaceAll("[^0-9]", ""));
var level = getHierarchyLevel(normalized);
return nomenclatureRepository.findDeclarableChildren(normalized.substring(0, level));
}
public List<Nomenclature> getNomenclatureCascade(String hscode) {
if (hscode == null) return Collections.emptyList();
List<String> cascade = getCascade(normalize(hscode.replaceAll("[^0-9]", "")));
var cascadeResp = cascade.stream().map(nomenclatureRepository::findByHscode).toList();
return cascade.stream().map(nomenclatureRepository::findByHscode).flatMap(Optional::stream).toList();
}
private List<String> getCascade(String hscode) {
var parents = new ArrayList<String>();
var hierarchyLevel = getHierarchyLevel(hscode);
while (hierarchyLevel > 0) {
parents.add(getParent(hscode, hierarchyLevel));
hierarchyLevel -= 2;
}
return parents;
}
private String getParent(String hscode, int level) {
return normalize(hscode.substring(0, level));
}
private int getHierarchyLevel(String hscode) {
int idx = hscode.length();
while(idx > 0) {
idx--;
if (hscode.charAt(idx) != '0') {
break;
}
}
return (idx+1) % 2 == 0 ? idx + 1 : idx + 2;
}
private String normalize(String hscode) {
StringBuilder normalizedHsCode = new StringBuilder(hscode);
while (normalizedHsCode.length() < 10) {
normalizedHsCode.append("0");
}
if (normalizedHsCode.length() > 10) {
normalizedHsCode = new StringBuilder(normalizedHsCode.substring(0, 10));
}
return normalizedHsCode.toString();
}
}

View file

@ -0,0 +1,35 @@
package de.avatic.taric.service;
import de.avatic.taric.error.ArgumentException;
import de.avatic.taric.model.Nomenclature;
import org.springframework.stereotype.Service;
@Service
public class TariffService {
private final GeoService geoService;
private final NomenclatureService nomenclatureService;
public TariffService(GeoService geoService, NomenclatureService nomenclatureService) {
this.geoService = geoService;
this.nomenclatureService = nomenclatureService;
}
public void importTariffs(String hsCode, String countryCode) {
var geoGroups = geoService.getGeoGroupByCountryCode(countryCode);
var geo = geoService.getGeo(countryCode);
var nomenclature = nomenclatureService.getNomenclature(hsCode);
var cascade = nomenclatureService.getNomenclatureCascade(hsCode);
if(nomenclature.isEmpty() || !nomenclature.get().getIsLeaf()) throw new ArgumentException("hsCode");
if(geo.isEmpty()) throw new ArgumentException("countryCode");
}
}

View file

@ -0,0 +1,303 @@
package de.avatic.taric.service;
import de.avatic.taric.model.*;
import de.avatic.taric.repository.*;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.data.jdbc.core.mapping.AggregateReference;
import java.math.BigDecimal;
import java.time.LocalDate;
import java.util.*;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
@Service
public class TariffService2 {
private static final org.slf4j.Logger log = org.slf4j.LoggerFactory.getLogger(TariffService2.class);
private final ImportRepository importRepository;
private final AppliedMeasureRepository appliedMeasureRepository;
private final NomenclatureRepository nomenclatureRepository;
private final GeoRepository geoRepository;
private final GeoGroupRepository geoGroupRepository;
private final GeoGroupMembershipRepository geoGroupMembershipRepository;
private final MeasureRepository measureRepository;
private final MeasureExclusionRepository measureExclusionRepository;
public TariffService2(ImportRepository importRepository, AppliedMeasureRepository appliedMeasureRepository, NomenclatureRepository nomenclatureRepository, GeoRepository geoRepository, GeoGroupRepository geoGroupRepository, GeoGroupMembershipRepository geoGroupMembershipRepository, MeasureRepository measureRepository, MeasureExclusionRepository measureExclusionRepository) {
this.importRepository = importRepository;
this.appliedMeasureRepository = appliedMeasureRepository;
this.nomenclatureRepository = nomenclatureRepository;
this.geoRepository = geoRepository;
this.geoGroupRepository = geoGroupRepository;
this.geoGroupMembershipRepository = geoGroupMembershipRepository;
this.measureRepository = measureRepository;
this.measureExclusionRepository = measureExclusionRepository;
}
/**
* Ermittelt den Zolltarif für einen HS-Code und ein Herkunftsland
*
* @param hsCode HS-Code (kann 6, 8 oder 10 Stellen haben)
* @param countryCode ISO-2 Ländercode (z.B. "CN" für China)
* @return Zolltarif in Prozent
*/
@Transactional(readOnly = true)
public TariffResult getTariffRate(String hsCode, String countryCode) {
log.info("Getting tariff rate for HS Code: {} from country: {}", hsCode, countryCode);
// Normalisiere HS-Code auf 10 Stellen
String normalizedHsCode = normalizeHsCode(hsCode);
// Finde alle relevanten Nomenclature-Codes (inkl. Parent-Codes durch Cascade-Prinzip)
List<String> relevantCodes = findRelevantNomenclatureCodes(normalizedHsCode);
log.debug("Found relevant codes: {}", relevantCodes);
// Hole das Land
Optional<Geo> countryOpt = geoRepository.findByIso3166Code(countryCode);
if (countryOpt.isEmpty()) {
log.warn("Country not found: {}", countryCode);
return TariffResult.notFound("Country code not found: " + countryCode);
}
Geo country = countryOpt.get();
// Finde alle Imports für die relevanten Codes
List<Import> imports = findRelevantImports(relevantCodes, country);
if (imports.isEmpty()) {
log.info("No imports found for codes: {} and country: {}", relevantCodes, countryCode);
// Versuche Erga Omnes (alle Länder)
imports = findErgaOmnesImports(relevantCodes);
}
if (imports.isEmpty()) {
return TariffResult.notFound("No tariff data found for HS code: " + hsCode);
}
// Finde die anwendbaren Maßnahmen
BigDecimal tariffRate = calculateTariffRate(imports, country);
return TariffResult.success(tariffRate, normalizedHsCode, countryCode);
}
private String normalizeHsCode(String hsCode) {
// Entferne alle nicht-numerischen Zeichen
String cleaned = hsCode.replaceAll("[^0-9]", "");
// Fülle auf 10 Stellen mit Nullen auf
while (cleaned.length() < 10) {
cleaned += "0";
}
// Begrenze auf 10 Stellen
if (cleaned.length() > 10) {
cleaned = cleaned.substring(0, 10);
}
return cleaned;
}
private List<String> findRelevantNomenclatureCodes(String hsCode) {
List<String> codes = new ArrayList<>();
codes.add(hsCode);
// Füge Parent-Codes hinzu (Cascade-Prinzip)
// Beispiel: 8504101010 -> auch 85041010, 850410, 8504, 85
String code = hsCode;
while (code.length() > 2) {
// Entferne die letzten 2 Nullen
if (code.endsWith("00")) {
code = code.substring(0, code.length() - 2);
codes.add(code + "0".repeat(10 - code.length()));
} else {
break;
}
}
return codes;
}
private List<Import> findRelevantImports(List<String> nomenclatureCodes, Geo country) {
List<Import> imports = new ArrayList<>();
for (String code : nomenclatureCodes) {
// Suche direkte Länder-Zuordnungen
Optional<Nomenclature> nomenclatureOpt = nomenclatureRepository.findByHscode(code);
if (nomenclatureOpt.isPresent()) {
Nomenclature nomenclature = nomenclatureOpt.get();
// Suche Imports mit direkter Geo-Zuordnung
imports.addAll(importRepository.findByNomenclatureIdAndGeoId(
nomenclature.getId(), country.getId()));
// Suche auch nach Ländergruppen-Mitgliedschaften
List<GeoGroupMembership> memberships =
geoGroupMembershipRepository.findByGeoId(country.getId());
for (GeoGroupMembership membership : memberships) {
// Hole die geo_group_id aus der membership
Integer geoGroupId = geoGroupMembershipRepository
.findGeoGroupIdByMembershipId(membership.getId());
if (geoGroupId != null) {
imports.addAll(importRepository.findByNomenclatureIdAndGeoGroupId(
nomenclature.getId(), geoGroupId));
}
}
}
}
return imports;
}
private List<Import> findErgaOmnesImports(List<String> nomenclatureCodes) {
List<Import> imports = new ArrayList<>();
// Erga Omnes hat normalerweise den Code "1011"
Optional<GeoGroup> ergaOmnes = geoGroupRepository.findByGeoGroupCode("1011");
if (ergaOmnes.isEmpty()) {
return imports;
}
for (String code : nomenclatureCodes) {
Optional<Nomenclature> nomenclatureOpt = nomenclatureRepository.findByHscode(code);
if (nomenclatureOpt.isPresent()) {
imports.addAll(importRepository.findByNomenclatureIdAndGeoGroupId(
nomenclatureOpt.get().getId(), ergaOmnes.get().getId()));
}
}
return imports;
}
private BigDecimal calculateTariffRate(List<Import> imports, Geo country) {
BigDecimal lowestRate = null;
LocalDate today = LocalDate.now();
for (Import imp : imports) {
// Nutze die korrekte Repository-Methode mit Import-Reference
List<AppliedMeasure> measures = appliedMeasureRepository
.findByImport(AggregateReference.to(imp.getId()));
for (AppliedMeasure appliedMeasure : measures) {
// Prüfe ob Maßnahme gültig ist
if (!isMeasureValid(appliedMeasure, today)) {
continue;
}
// Prüfe ob das Land ausgeschlossen ist
if (isCountryExcluded(appliedMeasure, country)) {
continue;
}
// Hole die Maßnahme über die AggregateReference
if (appliedMeasure.getMeasure() == null) {
continue;
}
Optional<Measure> measureOpt = measureRepository.findById(
appliedMeasure.getMeasure().getId());
if (measureOpt.isEmpty()) {
continue;
}
Measure measure = measureOpt.get();
// Wir interessieren uns hauptsächlich für Third Country Duty (103)
// und Preferential Tariff (142, 143)
if (!"103".equals(measure.getMeasureCode()) &&
!"142".equals(measure.getMeasureCode()) &&
!"143".equals(measure.getMeasureCode())) {
continue;
}
// Parse den Zollsatz aus dem amount String
BigDecimal rate = parseTariffRate(appliedMeasure.getAmount());
if (rate != null && (lowestRate == null || rate.compareTo(lowestRate) < 0)) {
lowestRate = rate;
}
}
}
return lowestRate != null ? lowestRate : BigDecimal.ZERO;
}
private boolean isMeasureValid(AppliedMeasure measure, LocalDate date) {
if (measure.getStartDate() != null && measure.getStartDate().isAfter(date)) {
return false;
}
if (measure.getEndDate() != null && measure.getEndDate().isBefore(date)) {
return false;
}
return true;
}
private boolean isCountryExcluded(AppliedMeasure measure, Geo country) {
// Finde Exclusions für diese AppliedMeasure
List<MeasureExclusion> exclusions =
measureExclusionRepository.findByAppliedMeasure(
AggregateReference.to(measure.getId()));
return exclusions.stream()
.anyMatch(exc -> exc.getGeo() != null &&
exc.getGeo().getId().equals(country.getId()));
}
private BigDecimal parseTariffRate(String amount) {
if (amount == null || amount.isEmpty()) {
return null;
}
// Einfacher Parser für Prozentsätze
// Format: "12.5 %" oder "12.5% + ..." oder "12.5 % MAX ..."
Pattern pattern = Pattern.compile("^([0-9]+\\.?[0-9]*)\\s*%");
Matcher matcher = pattern.matcher(amount);
if (matcher.find()) {
try {
return new BigDecimal(matcher.group(1));
} catch (NumberFormatException e) {
log.warn("Could not parse tariff rate from: {}", amount);
}
}
return null;
}
/**
* Result-Klasse für Tarif-Abfragen
*/
public static class TariffResult {
private final boolean found;
private final BigDecimal rate;
private final String hsCode;
private final String countryCode;
private final String message;
private TariffResult(boolean found, BigDecimal rate, String hsCode,
String countryCode, String message) {
this.found = found;
this.rate = rate;
this.hsCode = hsCode;
this.countryCode = countryCode;
this.message = message;
}
public static TariffResult success(BigDecimal rate, String hsCode, String countryCode) {
return new TariffResult(true, rate, hsCode, countryCode, null);
}
public static TariffResult notFound(String message) {
return new TariffResult(false, null, null, null, message);
}
// Getters
public boolean isFound() { return found; }
public BigDecimal getRate() { return rate; }
public String getHsCode() { return hsCode; }
public String getCountryCode() { return countryCode; }
public String getMessage() { return message; }
}
}

View file

@ -0,0 +1 @@
spring.application.name=taric

View file

@ -0,0 +1,344 @@
-- meta tables, like units and certificates
create table if not exists `legal_base`
(
`id` INT NOT NULL AUTO_INCREMENT PRIMARY KEY,
`legal_base` VARCHAR(255),
`journal` VARCHAR(255),
`page` INT,
`date` DATE
);
create table if not exists `monetary_unit`
(
`id` INT NOT NULL AUTO_INCREMENT PRIMARY KEY,
`monetary_unit_code` CHAR(3)
);
create table if not exists `unit`
(
`id` INT NOT NULL AUTO_INCREMENT PRIMARY KEY,
`unit_code` CHAR(3),
`unit_qualifier` CHAR(1),
`label` TEXT
);
create table if not exists `certificate_type`
(
`id` INT NOT NULL AUTO_INCREMENT PRIMARY KEY,
`certificate_type_code` CHAR(1)
);
create table if not exists `condition_type`
(
`id` INT NOT NULL AUTO_INCREMENT PRIMARY KEY,
`condition_type_code` CHAR(2)
);
create table if not exists `certificate`
(
`id` INT NOT NULL AUTO_INCREMENT PRIMARY KEY,
`certificate_code` CHAR(4),
`certificate_type_id` INT NOT NULL,
`start_date` DATE,
`end_date` DATE,
FOREIGN KEY (certificate_type_id) REFERENCES certificate_type(id)
);
-- measure meta infos
create table if not exists `footnote`
(
id INT NOT NULL AUTO_INCREMENT PRIMARY KEY,
footnote CHAR(8),
start_date DATE,
end_date DATE
);
create table if not exists `measure_series`
(
id INT NOT NULL AUTO_INCREMENT PRIMARY KEY,
measure_series_code CHAR(1)
);
create table if not exists `measure`
(
id INT NOT NULL AUTO_INCREMENT PRIMARY KEY,
measure_series_id INT NOT NULL,
measure_code CHAR(3),
short_desc TEXT,
tm_code TINYINT,
start_date DATE,
FOREIGN KEY (measure_series_id) REFERENCES measure_series(id)
);
create table if not exists `measure_action`
(
id INT NOT NULL AUTO_INCREMENT PRIMARY KEY,
measure_action_code CHAR(2),
CONSTRAINT UC_MeasureAction UNIQUE (measure_action_code)
);
-- geo
create table if not exists `geo`
(
id INT NOT NULL AUTO_INCREMENT PRIMARY KEY,
iso_3166_code CHAR(2),
start_date DATE,
end_date DATE,
CONSTRAINT UC_IsoCode UNIQUE (iso_3166_code)
);
create table if not exists `geo_group`
(
id INT NOT NULL AUTO_INCREMENT PRIMARY KEY,
geo_group_code CHAR(4),
abbr TEXT,
start_date DATE,
end_date DATE,
CONSTRAINT UC_GroupCode UNIQUE (geo_group_code)
);
create table if not exists `geo_group_membership`
(
id INT NOT NULL AUTO_INCREMENT PRIMARY KEY,
geo_id INT NOT NULL,
geo_group_id INT NOT NULL,
start_date DATE,
end_date DATE,
FOREIGN KEY (geo_id) REFERENCES geo(id),
FOREIGN KEY (geo_group_id) REFERENCES geo_group(id),
CONSTRAINT UC_GeoGroupTuple UNIQUE (geo_id, geo_group_id)
);
-- nomenclature
create table if not exists `nomenclature`
(
id INT NOT NULL AUTO_INCREMENT PRIMARY KEY,
hscode CHAR(10),
suffix CHAR(2),
hierachy TINYINT,
indent TINYINT,
start_date DATE,
end_date DATE,
is_leaf BOOLEAN,
is_leaf_start_date DATE,
parent_id INT NULL -- TODO: for each child do: alter table nomenclature add constraint parent_nomenclature foreign key (parent_id) references nomenclature(id) on delete set null;
);
create table if not exists `nomenclature_footnote`
(
id INT NOT NULL AUTO_INCREMENT PRIMARY KEY,
footnote_id INT NOT NULL,
nomenclature_id INT NOT NULL,
FOREIGN KEY (footnote_id) REFERENCES footnote(id),
FOREIGN KEY (nomenclature_id) REFERENCES nomenclature(id)
);
create table if not exists `additional_code`
(
id INT NOT NULL AUTO_INCREMENT PRIMARY KEY,
additional_code CHAR(4),
start_date DATE,
end_date DATE,
CONSTRAINT UC_AdditionalCode UNIQUE (additional_code)
);
-- import, applied_measures
create table if not exists `import`
(
id INT NOT NULL AUTO_INCREMENT PRIMARY KEY,
nomenclature_id INT NOT NULL,
additional_code_id INT DEFAULT NULL,
geo_id INT DEFAULT NULL,
geo_group_id INT DEFAULT NULL,
FOREIGN KEY (nomenclature_id) REFERENCES nomenclature(id),
FOREIGN KEY (additional_code_id) REFERENCES additional_code(id),
FOREIGN KEY (geo_id) REFERENCES geo(id),
FOREIGN KEY (geo_group_id) REFERENCES geo_group(id)
);
create table if not exists `applied_measure`
(
id INT NOT NULL AUTO_INCREMENT PRIMARY KEY,
import_id INT NOT NULL,
measure_id INT NOT NULL,
legal_base_id INT DEFAULT NULL,
legal_base TEXT DEFAULT NULL,
start_date DATE DEFAULT NULL,
end_date DATE DEFAULT NULL,
amount TEXT DEFAULT NULL,
order_number INT DEFAULT NULL,
FOREIGN KEY (import_id) REFERENCES import(id),
FOREIGN KEY (measure_id) REFERENCES measure(id),
FOREIGN KEY (legal_base_id) REFERENCES legal_base(id)
);
create table if not exists `measure_footnote`
(
id INT NOT NULL AUTO_INCREMENT PRIMARY KEY,
footnote_id INT NOT NULL,
applied_measure_id INT NOT NULL,
FOREIGN KEY (footnote_id) REFERENCES footnote(id),
FOREIGN KEY (applied_measure_id) REFERENCES applied_measure(id)
);
create table if not exists `applied_measure_condition`
(
id INT NOT NULL AUTO_INCREMENT PRIMARY KEY,
sequence_no INT DEFAULT NULL,
applied_measure_id INT NOT NULL,
measure_action_id INT NOT NULL,
monetary_unit_id INT DEFAULT NULL,
unit_id INT DEFAULT NULL,
certificate_id INT DEFAULT NULL,
condition_type_id INT NOT NULL,
amount TEXT,
FOREIGN KEY (applied_measure_id) REFERENCES applied_measure(id),
FOREIGN KEY (measure_action_id) REFERENCES measure_action(id),
FOREIGN KEY (monetary_unit_id) REFERENCES monetary_unit(id),
FOREIGN KEY (unit_id) REFERENCES unit(id),
FOREIGN KEY (certificate_id) REFERENCES certificate(id),
FOREIGN KEY (condition_type_id) REFERENCES condition_type(id)
);
create table if not exists `measure_exclusion`
(
id INT NOT NULL AUTO_INCREMENT PRIMARY KEY,
geo_id INT NOT NULL,
applied_measure_id INT NOT NULL,
FOREIGN KEY (geo_id) REFERENCES geo(id),
FOREIGN KEY (applied_measure_id) REFERENCES applied_measure(id)
);
-- descriptions
create table if not exists `footnotes_desc`
(
id INT NOT NULL AUTO_INCREMENT PRIMARY KEY,
ref_id INT NOT NULL,
lang CHAR(2),
`desc` TEXT,
desc_start_date DATE,
FOREIGN KEY (ref_id) REFERENCES footnote(id)
);
create table if not exists `measure_desc`
(
id INT NOT NULL AUTO_INCREMENT PRIMARY KEY,
ref_id INT NOT NULL,
lang CHAR(2),
`desc` TEXT,
desc_start_date DATE,
FOREIGN KEY (ref_id) REFERENCES measure(id)
);
create table if not exists `measure_series_desc`
(
id INT NOT NULL AUTO_INCREMENT PRIMARY KEY,
ref_id INT NOT NULL,
lang CHAR(2),
`desc` TEXT,
desc_start_date DATE,
FOREIGN KEY (ref_id) REFERENCES measure_series(id)
);
create table if not exists `measure_action_desc`
(
id INT NOT NULL AUTO_INCREMENT PRIMARY KEY,
ref_id INT NOT NULL,
lang CHAR(2),
`desc` TEXT,
desc_start_date DATE,
FOREIGN KEY (ref_id) REFERENCES measure_action(id)
);
create table if not exists `geo_desc`
(
id INT NOT NULL AUTO_INCREMENT PRIMARY KEY,
ref_id INT NOT NULL,
lang CHAR(2),
`desc` TEXT,
desc_start_date DATE,
FOREIGN KEY (ref_id) REFERENCES geo(id)
);
create table if not exists `geo_group_desc`
(
id INT NOT NULL AUTO_INCREMENT PRIMARY KEY,
ref_id INT NOT NULL,
lang CHAR(2),
`desc` TEXT,
desc_start_date DATE,
FOREIGN KEY (ref_id) REFERENCES geo_group(id)
);
create table if not exists `monetary_unit_desc`
(
id INT NOT NULL AUTO_INCREMENT PRIMARY KEY,
ref_id INT NOT NULL,
lang CHAR(2),
`desc` TEXT,
desc_start_date DATE,
FOREIGN KEY (ref_id) REFERENCES monetary_unit(id)
);
create table if not exists `unit_desc`
(
id INT NOT NULL AUTO_INCREMENT PRIMARY KEY,
ref_id INT NOT NULL,
lang CHAR(2),
`desc` TEXT,
desc_start_date DATE,
FOREIGN KEY (ref_id) REFERENCES unit(id)
);
create table if not exists `certificate_desc`
(
id INT NOT NULL AUTO_INCREMENT PRIMARY KEY,
ref_id INT NOT NULL,
lang CHAR(2),
`desc` TEXT,
desc_start_date DATE,
FOREIGN KEY (ref_id) REFERENCES certificate(id)
);
create table if not exists `certificate_type_desc`
(
id INT NOT NULL AUTO_INCREMENT PRIMARY KEY,
ref_id INT NOT NULL,
lang CHAR(2),
`desc` TEXT,
desc_start_date DATE,
FOREIGN KEY (ref_id) REFERENCES certificate_type(id)
);
create table if not exists `condition_type_desc`
(
id INT NOT NULL AUTO_INCREMENT PRIMARY KEY,
ref_id INT NOT NULL,
lang CHAR(2),
`desc` TEXT,
desc_start_date DATE,
FOREIGN KEY (ref_id) REFERENCES condition_type(id)
);
create table if not exists `additional_code_desc`
(
id INT NOT NULL AUTO_INCREMENT PRIMARY KEY,
ref_id INT NOT NULL,
lang CHAR(2),
`desc` TEXT,
desc_start_date DATE,
FOREIGN KEY (ref_id) REFERENCES additional_code(id)
);
create table if not exists `nomenclature_desc`
(
id INT NOT NULL AUTO_INCREMENT PRIMARY KEY,
ref_id INT NOT NULL,
lang CHAR(2),
`desc` TEXT,
desc_start_date DATE,
FOREIGN KEY (ref_id) REFERENCES nomenclature(id)
);

File diff suppressed because one or more lines are too long

View file

@ -0,0 +1,13 @@
package de.avatic.taric;
import org.junit.jupiter.api.Test;
import org.springframework.boot.test.context.SpringBootTest;
@SpringBootTest
class TaricApplicationTests {
@Test
void contextLoads() {
}
}