From 8732b81e9aac669770ceea21f70a85ac77b02fe6 Mon Sep 17 00:00:00 2001 From: kristenhaerum Date: Tue, 28 May 2024 09:50:29 +0200 Subject: [PATCH 01/35] Add new oppdrag-service application Created a new application called oppdrag-service. This includes java-based application files, Dockerfile, Gradle build system files, and various supporting configuration files. Also added API interface descriptions in WSDL and XSD formats. A basic unit test file was added as well. --- apps/oppdrag-service/Dockerfile | 8 + apps/oppdrag-service/README.md | 19 + apps/oppdrag-service/build.gradle | 106 +++++ apps/oppdrag-service/config.yml | 61 +++ .../gradle/wrapper/gradle-wrapper.jar | Bin 0 -> 59536 bytes .../gradle/wrapper/gradle-wrapper.properties | 5 + apps/oppdrag-service/gradlew | 234 ++++++++++ apps/oppdrag-service/gradlew.bat | 89 ++++ apps/oppdrag-service/gradlewUpdate.sh | 3 + apps/oppdrag-service/settings.gradle | 17 + .../OppdragServiceApplicationStarter.java | 12 + .../config/ApplicationConfig.java | 15 + .../config/DevConfig.java | 39 ++ .../config/OpenApiConfig.java | 65 +++ .../config/SecurityConfig.java | 37 ++ .../src/main/resources/application-prod.yml | 8 + .../src/main/resources/application.yml | 45 ++ .../src/main/resources/logback-spring.xml | 40 ++ .../eksponering/oppdragServiceWSBinding.wsdl | 51 +++ .../schema/entiteter/beregningSkjema.xsd | 122 +++++ .../schema/entiteter/infomelding.xsd | 29 ++ .../schema/entiteter/oppdragSkjema.xsd | 429 ++++++++++++++++++ .../schema/entiteter/statusmelding.xsd | 41 ++ .../schema/entiteter/typer/simpleTypes.xsd | 363 +++++++++++++++ .../schema/tjenester/oppdragService/feil.xsd | 26 ++ .../oppdragServiceGrensesnitt.wsdl | 106 +++++ .../oppdragServiceServiceTypes.xsd | 112 +++++ .../ApplicationContextTest.java | 20 + settings.gradle | 1 + 29 files changed, 2103 insertions(+) create mode 100644 apps/oppdrag-service/Dockerfile create mode 100644 apps/oppdrag-service/README.md create mode 100644 apps/oppdrag-service/build.gradle create mode 100644 apps/oppdrag-service/config.yml create mode 100644 apps/oppdrag-service/gradle/wrapper/gradle-wrapper.jar create mode 100644 apps/oppdrag-service/gradle/wrapper/gradle-wrapper.properties create mode 100755 apps/oppdrag-service/gradlew create mode 100644 apps/oppdrag-service/gradlew.bat create mode 100755 apps/oppdrag-service/gradlewUpdate.sh create mode 100644 apps/oppdrag-service/settings.gradle create mode 100644 apps/oppdrag-service/src/main/java/no/nav/testnav.oppdrag.service/OppdragServiceApplicationStarter.java create mode 100644 apps/oppdrag-service/src/main/java/no/nav/testnav.oppdrag.service/config/ApplicationConfig.java create mode 100644 apps/oppdrag-service/src/main/java/no/nav/testnav.oppdrag.service/config/DevConfig.java create mode 100644 apps/oppdrag-service/src/main/java/no/nav/testnav.oppdrag.service/config/OpenApiConfig.java create mode 100644 apps/oppdrag-service/src/main/java/no/nav/testnav.oppdrag.service/config/SecurityConfig.java create mode 100644 apps/oppdrag-service/src/main/resources/application-prod.yml create mode 100644 apps/oppdrag-service/src/main/resources/application.yml create mode 100644 apps/oppdrag-service/src/main/resources/logback-spring.xml create mode 100644 apps/oppdrag-service/src/main/resources/schema/eksponering/oppdragServiceWSBinding.wsdl create mode 100644 apps/oppdrag-service/src/main/resources/schema/entiteter/beregningSkjema.xsd create mode 100644 apps/oppdrag-service/src/main/resources/schema/entiteter/infomelding.xsd create mode 100644 apps/oppdrag-service/src/main/resources/schema/entiteter/oppdragSkjema.xsd create mode 100644 apps/oppdrag-service/src/main/resources/schema/entiteter/statusmelding.xsd create mode 100644 apps/oppdrag-service/src/main/resources/schema/entiteter/typer/simpleTypes.xsd create mode 100644 apps/oppdrag-service/src/main/resources/schema/tjenester/oppdragService/feil.xsd create mode 100644 apps/oppdrag-service/src/main/resources/schema/tjenester/oppdragService/oppdragServiceGrensesnitt.wsdl create mode 100644 apps/oppdrag-service/src/main/resources/schema/tjenester/oppdragService/oppdragServiceServiceTypes.xsd create mode 100644 apps/oppdrag-service/src/test/java/no/nav/testnav.oppdrag.service/ApplicationContextTest.java diff --git a/apps/oppdrag-service/Dockerfile b/apps/oppdrag-service/Dockerfile new file mode 100644 index 00000000000..4a36f93546f --- /dev/null +++ b/apps/oppdrag-service/Dockerfile @@ -0,0 +1,8 @@ +FROM ghcr.io/navikt/baseimages/temurin:21 +LABEL maintainer="Team Dolly" + +ENV JAVA_OPTS="-Dspring.profiles.active=prod" + +ADD /build/libs/app.jar /app/app.jar + +EXPOSE 8080 diff --git a/apps/oppdrag-service/README.md b/apps/oppdrag-service/README.md new file mode 100644 index 00000000000..e5fa4e8521e --- /dev/null +++ b/apps/oppdrag-service/README.md @@ -0,0 +1,19 @@ +# Oppdrag-service +App for å sende til oppdragssystemet. + +## Swagger +Swagger finnes under [/swagger](https://miljoer-service.intern.dev.nav.no/swagger) -endepunktet til applikasjonen. + +## Lokal kjøring +Ha naisdevice kjørende og kjør OppdragServiceApplicationStarter med følgende argumenter: +``` +-Dspring.cloud.vault.token=[vault-token] +-Dspring.profiles.active=dev +``` + +### Utviklerimage +I utviklerimage brukes ikke naisdevice og du må legge til følgende ekstra argumenter: +``` +-Djavax.net.ssl.trustStore=[path til lokal truststore] +-Djavax.net.ssl.trustStorePassword=[passord til lokal truststore] +``` \ No newline at end of file diff --git a/apps/oppdrag-service/build.gradle b/apps/oppdrag-service/build.gradle new file mode 100644 index 00000000000..02a14e0dbe4 --- /dev/null +++ b/apps/oppdrag-service/build.gradle @@ -0,0 +1,106 @@ +buildscript { + repositories { + maven { + url "https://plugins.gradle.org/m2/" + } + } + dependencies { + classpath "uk.co.boothen.gradle:gradle-wsimport:0.21" + } +} + +plugins { + id 'java' + id "org.sonarqube" version "4.4.1.3373" + id 'org.springframework.boot' version "3.2.1" + id 'io.spring.dependency-management' version "1.1.4" + id "jacoco" + id "uk.co.boothen.gradle.wsimport" version "0.21" +} + +apply plugin: "uk.co.boothen.gradle.wsimport" + +sonarqube { + properties { + property "sonar.dynamicAnalysis", "reuseReports" + property "sonar.host.url", "https://sonarcloud.io" + property "sonar.java.coveragePlugin", "jacoco" + property "sonar.language", "java" + property "sonar.token", System.getenv("SONAR_TOKEN") + property "sonar.organization", "navikt" + property "sonar.project.monorepo.enabled", true + property "sonar.projectKey", "testnav-oppdrag-service" + property "sonar.projectName", "testnav-oppdrag-service" + property "sonar.sourceEncoding", "UTF-8" + } +} + +bootJar { + archiveFileName = "app.jar" + mainClass = 'no.nav.testnav.oppdrag.service.OppdragServiceApplicationStarter' + duplicatesStrategy = DuplicatesStrategy.EXCLUDE +} + +wsimport { + wsdlSourceRoot = "src/main/resources/schema/eksponering" + generatedSourceRoot = "/generated/src/wsdl/main" + generatedClassesRoot = "/classes/main" + wsdl("oppdragServiceWSBinding.wsdl") { + packageName = "no.nav.testnav.oppdrag.service" + xjcarg("-XautoNameResolution") + } + verbose = true + debug = true + target = "3.0" +} + +dependencyManagement { + applyMavenExclusions = false + imports { + mavenBom 'org.springframework.cloud:spring-cloud-dependencies:2023.0.0' + } +} + +java { + toolchain { + languageVersion = JavaLanguageVersion.of(21) + } +} + +repositories { + mavenCentral() + maven { + name = "GitHubPackages" + url = uri('https://maven.pkg.github.com/navikt/maven-release') + credentials(PasswordCredentials) { + password System.getenv("NAV_TOKEN") + username 'token' + } + } +} + +dependencies { + implementation 'jakarta.xml.bind:jakarta.xml.bind-api:4.0.0' + implementation 'org.glassfish.jaxb:jaxb-runtime:4.0.0' + + implementation 'no.nav.testnav.libs:security-core' + implementation 'no.nav.testnav.libs:reactive-core' + implementation 'no.nav.testnav.libs:reactive-security' + implementation 'no.nav.testnav.libs:data-transfer-objects' + + implementation 'org.springframework.cloud:spring-cloud-starter-vault-config' + + implementation 'net.logstash.logback:logstash-logback-encoder:7.4' + + implementation 'org.springdoc:springdoc-openapi-starter-webflux-ui:2.3.0' + implementation 'io.swagger.core.v3:swagger-annotations-jakarta:2.2.20' + implementation 'org.springframework.boot:spring-boot-starter-oauth2-client' + implementation 'org.springframework.boot:spring-boot-starter-security' + implementation 'org.springframework.boot:spring-boot-starter-validation' + + implementation 'ma.glasnost.orika:orika-core:1.5.4' + annotationProcessor 'org.projectlombok:lombok' + implementation 'org.projectlombok:lombok' + + testImplementation 'org.springframework.boot:spring-boot-starter-test' +} \ No newline at end of file diff --git a/apps/oppdrag-service/config.yml b/apps/oppdrag-service/config.yml new file mode 100644 index 00000000000..605d8dd47ac --- /dev/null +++ b/apps/oppdrag-service/config.yml @@ -0,0 +1,61 @@ +apiVersion: "nais.io/v1alpha1" +kind: "Application" +metadata: + name: testnav-oppdrag-service + namespace: dolly + labels: + team: dolly +spec: + image: "{{image}}" + port: 8080 + webproxy: true + accessPolicy: + inbound: + rules: + - application: dolly-backend + - application: dolly-backend-dev + - application: dolly-frontend + - application: dolly-frontend-dev + - application: dolly-frontend-dev-unstable + - application: dolly-idporten + - application: team-dolly-lokal-app + - application: testnav-faste-data-frontend + - application: testnav-organisasjon-forvalter + - application: testnav-orgnummer-service + - application: testnav-oversikt-frontend + - application: testnav-tps-messaging-service + tokenx: + enabled: true + azure: + application: + allowAllUsers: true + enabled: true + tenant: nav.no + replyURLs: + - "https://testnav-miljoer-service.intern.dev.nav.no/login/oauth2/code/aad" + - "http://localhost:8080/login/oauth2/code/aad" + liveness: + path: /internal/isAlive + initialDelay: 30 + periodSeconds: 30 + failureThreshold: 500 + readiness: + path: /internal/isReady + initialDelay: 30 + failureThreshold: 500 + prometheus: + enabled: true + path: /internal/metrics + replicas: + min: 1 + max: 1 + vault: + enabled: true + resources: + requests: + cpu: 100m + memory: 1024Mi + limits: + memory: 2048Mi + ingresses: + - "https://testnav-oppdrag-service.intern.dev.nav.no" diff --git a/apps/oppdrag-service/gradle/wrapper/gradle-wrapper.jar b/apps/oppdrag-service/gradle/wrapper/gradle-wrapper.jar new file mode 100644 index 0000000000000000000000000000000000000000..7454180f2ae8848c63b8b4dea2cb829da983f2fa GIT binary patch literal 59536 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 QuEJmfE|#`Dqx|px0L@K;Y5)KL literal 0 HcmV?d00001 diff --git a/apps/oppdrag-service/gradle/wrapper/gradle-wrapper.properties b/apps/oppdrag-service/gradle/wrapper/gradle-wrapper.properties new file mode 100644 index 00000000000..a5952066425 --- /dev/null +++ b/apps/oppdrag-service/gradle/wrapper/gradle-wrapper.properties @@ -0,0 +1,5 @@ +distributionBase=GRADLE_USER_HOME +distributionPath=wrapper/dists +distributionUrl=https\://services.gradle.org/distributions/gradle-8.5-bin.zip +zipStoreBase=GRADLE_USER_HOME +zipStorePath=wrapper/dists diff --git a/apps/oppdrag-service/gradlew b/apps/oppdrag-service/gradlew new file mode 100755 index 00000000000..3da45c161b0 --- /dev/null +++ b/apps/oppdrag-service/gradlew @@ -0,0 +1,234 @@ +#!/bin/sh + +# +# Copyright ? 2015-2021 the original authors. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# https://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# + +############################################################################## +# +# Gradle start up script for POSIX generated by Gradle. +# +# Important for running: +# +# (1) You need a POSIX-compliant shell to run this script. If your /bin/sh is +# noncompliant, but you have some other compliant shell such as ksh or +# bash, then to run this script, type that shell name before the whole +# command line, like: +# +# ksh Gradle +# +# Busybox and similar reduced shells will NOT work, because this script +# requires all of these POSIX shell features: +# * functions; +# * expansions ?$var?, ?${var}?, ?${var:-default}?, ?${var+SET}?, +# ?${var#prefix}?, ?${var%suffix}?, and ?$( cmd )?; +# * compound commands having a testable exit status, especially ?case?; +# * various built-in commands including ?command?, ?set?, and ?ulimit?. +# +# Important for patching: +# +# (2) This script targets any POSIX shell, so it avoids extensions provided +# by Bash, Ksh, etc; in particular arrays are avoided. +# +# The "traditional" practice of packing multiple parameters into a +# space-separated string is a well documented source of bugs and security +# problems, so this is (mostly) avoided, by progressively accumulating +# options in "$@", and eventually passing that to Java. +# +# Where the inherited environment variables (DEFAULT_JVM_OPTS, JAVA_OPTS, +# and GRADLE_OPTS) rely on word-splitting, this is performed explicitly; +# see the in-line comments for details. +# +# There are tweaks for specific operating systems such as AIX, CygWin, +# Darwin, MinGW, and NonStop. +# +# (3) This script is generated from the Groovy template +# https://github.com/gradle/gradle/blob/master/subprojects/plugins/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt +# within the Gradle project. +# +# You can find Gradle at https://github.com/gradle/gradle/. +# +############################################################################## + +# Attempt to set APP_HOME + +# Resolve links: $0 may be a link +app_path=$0 + +# Need this for daisy-chained symlinks. +while + APP_HOME=${app_path%"${app_path##*/}"} # leaves a trailing /; empty if no leading path + [ -h "$app_path" ] +do + ls=$( ls -ld "$app_path" ) + link=${ls#*' -> '} + case $link in #( + /*) app_path=$link ;; #( + *) app_path=$APP_HOME$link ;; + esac +done + +APP_HOME=$( cd "${APP_HOME:-./}" && pwd -P ) || exit + +APP_NAME="Gradle" +APP_BASE_NAME=${0##*/} + +# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. +DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"' + +# Use the maximum available, or set MAX_FD != -1 to use that value. +MAX_FD=maximum + +warn () { + echo "$*" +} >&2 + +die () { + echo + echo "$*" + echo + exit 1 +} >&2 + +# OS specific support (must be 'true' or 'false'). +cygwin=false +msys=false +darwin=false +nonstop=false +case "$( uname )" in #( + CYGWIN* ) cygwin=true ;; #( + Darwin* ) darwin=true ;; #( + MSYS* | MINGW* ) msys=true ;; #( + NONSTOP* ) nonstop=true ;; +esac + +CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar + + +# Determine the Java command to use to start the JVM. +if [ -n "$JAVA_HOME" ] ; then + if [ -x "$JAVA_HOME/jre/sh/java" ] ; then + # IBM's JDK on AIX uses strange locations for the executables + JAVACMD=$JAVA_HOME/jre/sh/java + else + JAVACMD=$JAVA_HOME/bin/java + fi + if [ ! -x "$JAVACMD" ] ; then + die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME + +Please set the JAVA_HOME variable in your environment to match the +location of your Java installation." + fi +else + JAVACMD=java + which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. + +Please set the JAVA_HOME variable in your environment to match the +location of your Java installation." +fi + +# Increase the maximum file descriptors if we can. +if ! "$cygwin" && ! "$darwin" && ! "$nonstop" ; then + case $MAX_FD in #( + max*) + MAX_FD=$( ulimit -H -n ) || + warn "Could not query maximum file descriptor limit" + esac + case $MAX_FD in #( + '' | soft) :;; #( + *) + ulimit -n "$MAX_FD" || + warn "Could not set maximum file descriptor limit to $MAX_FD" + esac +fi + +# Collect all arguments for the java command, stacking in reverse order: +# * args from the command line +# * the main class name +# * -classpath +# * -D...appname settings +# * --module-path (only if needed) +# * DEFAULT_JVM_OPTS, JAVA_OPTS, and GRADLE_OPTS environment variables. + +# For Cygwin or MSYS, switch paths to Windows format before running java +if "$cygwin" || "$msys" ; then + APP_HOME=$( cygpath --path --mixed "$APP_HOME" ) + CLASSPATH=$( cygpath --path --mixed "$CLASSPATH" ) + + JAVACMD=$( cygpath --unix "$JAVACMD" ) + + # Now convert the arguments - kludge to limit ourselves to /bin/sh + for arg do + if + case $arg in #( + -*) false ;; # don't mess with options #( + /?*) t=${arg#/} t=/${t%%/*} # looks like a POSIX filepath + [ -e "$t" ] ;; #( + *) false ;; + esac + then + arg=$( cygpath --path --ignore --mixed "$arg" ) + fi + # Roll the args list around exactly as many times as the number of + # args, so each arg winds up back in the position where it started, but + # possibly modified. + # + # NB: a `for` loop captures its iteration list before it begins, so + # changing the positional parameters here affects neither the number of + # iterations, nor the values presented in `arg`. + shift # remove old arg + set -- "$@" "$arg" # push replacement arg + done +fi + +# Collect all arguments for the java command; +# * $DEFAULT_JVM_OPTS, $JAVA_OPTS, and $GRADLE_OPTS can contain fragments of +# shell script including quotes and variable substitutions, so put them in +# double quotes to make sure that they get re-expanded; and +# * put everything else in single quotes, so that it's not re-expanded. + +set -- \ + "-Dorg.gradle.appname=$APP_BASE_NAME" \ + -classpath "$CLASSPATH" \ + org.gradle.wrapper.GradleWrapperMain \ + "$@" + +# Use "xargs" to parse quoted args. +# +# With -n1 it outputs one arg per line, with the quotes and backslashes removed. +# +# In Bash we could simply go: +# +# readarray ARGS < <( xargs -n1 <<<"$var" ) && +# set -- "${ARGS[@]}" "$@" +# +# but POSIX shell has neither arrays nor command substitution, so instead we +# post-process each arg (as a line of input to sed) to backslash-escape any +# character that might be a shell metacharacter, then use eval to reverse +# that process (while maintaining the separation between arguments), and wrap +# the whole thing up as a single "set" statement. +# +# This will of course break if any of these variables contains a newline or +# an unmatched quote. +# + +eval "set -- $( + printf '%s\n' "$DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS" | + xargs -n1 | + sed ' s~[^-[:alnum:]+,./:=@_]~\\&~g; ' | + tr '\n' ' ' + )" '"$@"' + +exec "$JAVACMD" "$@" diff --git a/apps/oppdrag-service/gradlew.bat b/apps/oppdrag-service/gradlew.bat new file mode 100644 index 00000000000..107acd32c4e --- /dev/null +++ b/apps/oppdrag-service/gradlew.bat @@ -0,0 +1,89 @@ +@rem +@rem Copyright 2015 the original author or authors. +@rem +@rem Licensed under the Apache License, Version 2.0 (the "License"); +@rem you may not use this file except in compliance with the License. +@rem You may obtain a copy of the License at +@rem +@rem https://www.apache.org/licenses/LICENSE-2.0 +@rem +@rem Unless required by applicable law or agreed to in writing, software +@rem distributed under the License is distributed on an "AS IS" BASIS, +@rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +@rem See the License for the specific language governing permissions and +@rem limitations under the License. +@rem + +@if "%DEBUG%" == "" @echo off +@rem ########################################################################## +@rem +@rem Gradle startup script for Windows +@rem +@rem ########################################################################## + +@rem Set local scope for the variables with windows NT shell +if "%OS%"=="Windows_NT" setlocal + +set DIRNAME=%~dp0 +if "%DIRNAME%" == "" set DIRNAME=. +set APP_BASE_NAME=%~n0 +set APP_HOME=%DIRNAME% + +@rem Resolve any "." and ".." in APP_HOME to make it shorter. +for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi + +@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. +set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m" + +@rem Find java.exe +if defined JAVA_HOME goto findJavaFromJavaHome + +set JAVA_EXE=java.exe +%JAVA_EXE% -version >NUL 2>&1 +if "%ERRORLEVEL%" == "0" goto execute + +echo. +echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. +echo. +echo Please set the JAVA_HOME variable in your environment to match the +echo location of your Java installation. + +goto fail + +:findJavaFromJavaHome +set JAVA_HOME=%JAVA_HOME:"=% +set JAVA_EXE=%JAVA_HOME%/bin/java.exe + +if exist "%JAVA_EXE%" goto execute + +echo. +echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% +echo. +echo Please set the JAVA_HOME variable in your environment to match the +echo location of your Java installation. + +goto fail + +:execute +@rem Setup the command line + +set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar + + +@rem Execute Gradle +"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %* + +:end +@rem End local scope for the variables with windows NT shell +if "%ERRORLEVEL%"=="0" goto mainEnd + +:fail +rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of +rem the _cmd.exe /c_ return code! +if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1 +exit /b 1 + +:mainEnd +if "%OS%"=="Windows_NT" endlocal + +:omega diff --git a/apps/oppdrag-service/gradlewUpdate.sh b/apps/oppdrag-service/gradlewUpdate.sh new file mode 100755 index 00000000000..e5ee6361152 --- /dev/null +++ b/apps/oppdrag-service/gradlewUpdate.sh @@ -0,0 +1,3 @@ +#!/bin/bash + +gradle wrapper \ No newline at end of file diff --git a/apps/oppdrag-service/settings.gradle b/apps/oppdrag-service/settings.gradle new file mode 100644 index 00000000000..8e5fe4c0910 --- /dev/null +++ b/apps/oppdrag-service/settings.gradle @@ -0,0 +1,17 @@ +plugins { + id "com.gradle.enterprise" version "3.12.3" +} + +rootProject.name = 'oppdrag-service' + +includeBuild '../../libs/security-core' +includeBuild '../../libs/reactive-core' +includeBuild '../../libs/reactive-security' +includeBuild '../../libs/data-transfer-objects' + +gradleEnterprise { + buildScan { + termsOfServiceUrl = "https://gradle.com/terms-of-service" + termsOfServiceAgree = "yes" + } +} \ No newline at end of file diff --git a/apps/oppdrag-service/src/main/java/no/nav/testnav.oppdrag.service/OppdragServiceApplicationStarter.java b/apps/oppdrag-service/src/main/java/no/nav/testnav.oppdrag.service/OppdragServiceApplicationStarter.java new file mode 100644 index 00000000000..434733c7cf1 --- /dev/null +++ b/apps/oppdrag-service/src/main/java/no/nav/testnav.oppdrag.service/OppdragServiceApplicationStarter.java @@ -0,0 +1,12 @@ +package no.nav.testnav.oppdrag.service; + +import org.springframework.boot.SpringApplication; +import org.springframework.boot.autoconfigure.SpringBootApplication; + +@SpringBootApplication +public class OppdragServiceApplicationStarter { + + public static void main(String[] args) { + SpringApplication.run(OppdragServiceApplicationStarter.class, args); + } +} \ No newline at end of file diff --git a/apps/oppdrag-service/src/main/java/no/nav/testnav.oppdrag.service/config/ApplicationConfig.java b/apps/oppdrag-service/src/main/java/no/nav/testnav.oppdrag.service/config/ApplicationConfig.java new file mode 100644 index 00000000000..44e96ea7b05 --- /dev/null +++ b/apps/oppdrag-service/src/main/java/no/nav/testnav.oppdrag.service/config/ApplicationConfig.java @@ -0,0 +1,15 @@ +package no.nav.testnav.oppdrag.service.config; + +import no.nav.testnav.libs.reactivecore.config.CoreConfig; +import no.nav.testnav.libs.reactivesecurity.config.SecureOAuth2ServerToServerConfiguration; +import org.springframework.context.annotation.Configuration; +import org.springframework.context.annotation.Import; + +@Configuration +@Import({ + CoreConfig.class, + SecureOAuth2ServerToServerConfiguration.class +}) +public class ApplicationConfig { + +} diff --git a/apps/oppdrag-service/src/main/java/no/nav/testnav.oppdrag.service/config/DevConfig.java b/apps/oppdrag-service/src/main/java/no/nav/testnav.oppdrag.service/config/DevConfig.java new file mode 100644 index 00000000000..b3ebc0f1392 --- /dev/null +++ b/apps/oppdrag-service/src/main/java/no/nav/testnav.oppdrag.service/config/DevConfig.java @@ -0,0 +1,39 @@ +package no.nav.testnav.oppdrag.service.config; + +import org.springframework.context.annotation.Configuration; +import org.springframework.context.annotation.Profile; +import org.springframework.lang.NonNull; +import org.springframework.vault.annotation.VaultPropertySource; +import org.springframework.vault.authentication.ClientAuthentication; +import org.springframework.vault.authentication.TokenAuthentication; +import org.springframework.vault.client.VaultEndpoint; +import org.springframework.vault.config.AbstractVaultConfiguration; + +import static io.micrometer.common.util.StringUtils.isBlank; + +@Configuration +@Profile("dev") +@VaultPropertySource(value = "secret/dolly/lokal", ignoreSecretNotFound = false) +public class DevConfig extends AbstractVaultConfiguration { + + private static final String VAULT_TOKEN = "spring.cloud.vault.token"; + + @Override + @NonNull + public VaultEndpoint vaultEndpoint() { + return VaultEndpoint.create("vault.adeo.no", 443); + } + + @Override + @NonNull + public ClientAuthentication clientAuthentication() { + if (System.getenv().containsKey("VAULT_TOKEN")) { + System.setProperty(VAULT_TOKEN, System.getenv("VAULT_TOKEN")); + } + var token = System.getProperty(VAULT_TOKEN); + if (isBlank(token)) { + throw new IllegalArgumentException("Påkrevet property 'spring.cloud.vault.token' er ikke satt."); + } + return new TokenAuthentication(System.getProperty(VAULT_TOKEN)); + } +} \ No newline at end of file diff --git a/apps/oppdrag-service/src/main/java/no/nav/testnav.oppdrag.service/config/OpenApiConfig.java b/apps/oppdrag-service/src/main/java/no/nav/testnav.oppdrag.service/config/OpenApiConfig.java new file mode 100644 index 00000000000..ebb238f68a9 --- /dev/null +++ b/apps/oppdrag-service/src/main/java/no/nav/testnav.oppdrag.service/config/OpenApiConfig.java @@ -0,0 +1,65 @@ +package no.nav.testnav.oppdrag.service.config; + +import io.swagger.v3.oas.models.Components; +import io.swagger.v3.oas.models.OpenAPI; +import io.swagger.v3.oas.models.info.Contact; +import io.swagger.v3.oas.models.info.Info; +import io.swagger.v3.oas.models.info.License; +import io.swagger.v3.oas.models.security.SecurityRequirement; +import io.swagger.v3.oas.models.security.SecurityScheme; +import no.nav.testnav.libs.reactivecore.config.ApplicationProperties; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.http.HttpHeaders; +import org.springframework.web.server.ServerWebExchange; +import org.springframework.web.server.WebFilter; +import org.springframework.web.server.WebFilterChain; +import reactor.core.publisher.Mono; + +import java.util.Arrays; + +@Configuration +public class OpenApiConfig implements WebFilter { + + @Bean + public OpenAPI openApi(ApplicationProperties applicationProperties) { + return new OpenAPI() + .components(new Components().addSecuritySchemes("bearer-jwt", new SecurityScheme() + .type(SecurityScheme.Type.HTTP) + .scheme("bearer") + .bearerFormat("JWT") + .in(SecurityScheme.In.HEADER) + .name(HttpHeaders.AUTHORIZATION) + )) + .addSecurityItem( + new SecurityRequirement().addList("bearer-jwt", Arrays.asList("read", "write"))) + .info(new Info() + .title(applicationProperties.getName()) + .version(applicationProperties.getVersion()) + .description(applicationProperties.getDescription()) + .termsOfService("https://nav.no") + .contact(new Contact() + .url("https://nav-it.slack.com/archives/CA3P9NGA2") + .email("dolly@nav.no") + .name("Team Dolly") + ) + .license(new License() + .name("MIT License") + .url("https://opensource.org/licenses/MIT") + ) + ); + } + + @Override + public Mono filter(ServerWebExchange exchange, WebFilterChain chain) { + if (exchange.getRequest().getURI().getPath().equals("/swagger")) { + return chain + .filter(exchange.mutate() + .request(exchange.getRequest() + .mutate().path("/swagger-ui.html").build()) + .build()); + } + + return chain.filter(exchange); + } +} \ No newline at end of file diff --git a/apps/oppdrag-service/src/main/java/no/nav/testnav.oppdrag.service/config/SecurityConfig.java b/apps/oppdrag-service/src/main/java/no/nav/testnav.oppdrag.service/config/SecurityConfig.java new file mode 100644 index 00000000000..112370f0296 --- /dev/null +++ b/apps/oppdrag-service/src/main/java/no/nav/testnav.oppdrag.service/config/SecurityConfig.java @@ -0,0 +1,37 @@ +package no.nav.testnav.oppdrag.service.config; + +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.context.annotation.Profile; +import org.springframework.security.config.Customizer; +import org.springframework.security.config.annotation.web.builders.HttpSecurity; +import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity; +import org.springframework.security.config.annotation.web.configurers.AbstractHttpConfigurer; +import org.springframework.security.config.http.SessionCreationPolicy; +import org.springframework.security.web.SecurityFilterChain; + +@EnableWebSecurity +@Configuration +@Profile({"prod", "dev"}) +public class SecurityConfig { + + @Bean + public SecurityFilterChain filterChain(HttpSecurity httpSecurity) throws Exception { + + httpSecurity.sessionManagement(sessionConfig -> sessionConfig.sessionCreationPolicy(SessionCreationPolicy.STATELESS)) + .csrf(AbstractHttpConfigurer::disable) + .authorizeHttpRequests(authorizeConfig -> authorizeConfig.requestMatchers( + "/internal/**", + "/webjars/**", + "/swagger-resources/**", + "/v3/api-docs/**", + "/swagger-ui/**", + "/swagger", + "/error", + "/swagger-ui.html" + ).permitAll().requestMatchers("/api/**").fullyAuthenticated()) + .oauth2ResourceServer(oauth2RSConfig -> oauth2RSConfig.jwt(Customizer.withDefaults())); + + return httpSecurity.build(); + } +} diff --git a/apps/oppdrag-service/src/main/resources/application-prod.yml b/apps/oppdrag-service/src/main/resources/application-prod.yml new file mode 100644 index 00000000000..0311ce578e3 --- /dev/null +++ b/apps/oppdrag-service/src/main/resources/application-prod.yml @@ -0,0 +1,8 @@ +spring: + security: + oauth2: + resourceserver: + tokenx: + issuer-uri: ${TOKEN_X_ISSUER} + jwk-set-uri: ${TOKEN_X_JWKS_URI} + accepted-audience: ${TOKEN_X_CLIENT_ID} \ No newline at end of file diff --git a/apps/oppdrag-service/src/main/resources/application.yml b/apps/oppdrag-service/src/main/resources/application.yml new file mode 100644 index 00000000000..3733587b2bc --- /dev/null +++ b/apps/oppdrag-service/src/main/resources/application.yml @@ -0,0 +1,45 @@ +AAD_ISSUER_URI: https://login.microsoftonline.com/62366534-1ec3-4962-8869-9b5535279d0b + +spring: + main: + banner-mode: off + application: + name: testnav-oppdrag-service + description: App for å sjekke hvilke miljøer i test og preprod som er tilgjengelige nå. + security: + oauth2: + resourceserver: + aad: + issuer-uri: ${AAD_ISSUER_URI}/v2.0 + jwk-set-uri: ${AAD_ISSUER_URI}/discovery/v2.0/keys + accepted-audience: ${azure.app.client.id}, api://${azure.app.client.id} + cloud: + vault: + enabled: false + +springdoc: + swagger-ui: + disable-swagger-default-url: true + url: /v3/api-docs + +management: + endpoints: + enabled-by-default: true + web: + base-path: /internal + exposure.include: prometheus,heapdump,health + path-mapping: + prometheus: metrics + endpoint: + prometheus.enabled: true + heapdump.enabled: true + prometheus: + metrics: + export: + enabled: true +server: + servlet: + encoding: + charset: UTF-8 + error: + include-message: always \ No newline at end of file diff --git a/apps/oppdrag-service/src/main/resources/logback-spring.xml b/apps/oppdrag-service/src/main/resources/logback-spring.xml new file mode 100644 index 00000000000..9583ff2d427 --- /dev/null +++ b/apps/oppdrag-service/src/main/resources/logback-spring.xml @@ -0,0 +1,40 @@ + + + + + + + true + 256 + 10280 + 20 + ^sun\.reflect\..*\.invoke + ^net\.sf\.cglib\.proxy\.MethodProxy\.invoke + java\.util\.concurrent\..* + org\.apache\.catalina\..* + org\.apache\.coyote\..* + org\.apache\.tomcat\..* + + + + + + + + + + + + + %d{HH:mm:ss.SSS} | %5p | %logger{25} | %m%n + + utf8 + + + + + + + + + \ No newline at end of file diff --git a/apps/oppdrag-service/src/main/resources/schema/eksponering/oppdragServiceWSBinding.wsdl b/apps/oppdrag-service/src/main/resources/schema/eksponering/oppdragServiceWSBinding.wsdl new file mode 100644 index 00000000000..297ecc4e999 --- /dev/null +++ b/apps/oppdrag-service/src/main/resources/schema/eksponering/oppdragServiceWSBinding.wsdl @@ -0,0 +1,51 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/apps/oppdrag-service/src/main/resources/schema/entiteter/beregningSkjema.xsd b/apps/oppdrag-service/src/main/resources/schema/entiteter/beregningSkjema.xsd new file mode 100644 index 00000000000..51d515b1c56 --- /dev/null +++ b/apps/oppdrag-service/src/main/resources/schema/entiteter/beregningSkjema.xsd @@ -0,0 +1,122 @@ + + + + + + + Beregning entiteter + For hver entitet er det lagt til en referanse ID. + Disse IDene korresponderer med entitetene som er implementert i baksystemet og kan forenkle kommunikasjon. + + + + + Entitet Beregning + Referanse ID 311 + + + + + + + Ved simuleringsberegning gjelder dette datoen beregning vil kjøres på + + + + + + + + + + + + Entitet BeregningsPeriode + Referanse ID 312 + + + + + + + + + + + + + + + Entitet BeregningStoppnivaa + Referanse ID 313 + + + + + + + + + + + + + + + + + + + + + + + Entitet BeregningStoppnivaaDetaljer + Referanse ID 314 + + + + + + + + Samensatt konkatenert felt: Hovedkontonr||Underkontonr||Formålskode||Aktivitetskode + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/apps/oppdrag-service/src/main/resources/schema/entiteter/infomelding.xsd b/apps/oppdrag-service/src/main/resources/schema/entiteter/infomelding.xsd new file mode 100644 index 00000000000..feb10cdc843 --- /dev/null +++ b/apps/oppdrag-service/src/main/resources/schema/entiteter/infomelding.xsd @@ -0,0 +1,29 @@ + + + + + Entitet for infomelding + Tilsvarende baksystemets FE469-RTV-LOGG databasetabell + + + + + Entitet for infomelding. + Brukes for å eksponere advarsler/infomelding fra tjenesten. + Informasjonsmelding hentes fra ID 469MMEL + + + + + + + + + + + + \ No newline at end of file diff --git a/apps/oppdrag-service/src/main/resources/schema/entiteter/oppdragSkjema.xsd b/apps/oppdrag-service/src/main/resources/schema/entiteter/oppdragSkjema.xsd new file mode 100644 index 00000000000..69fa839b702 --- /dev/null +++ b/apps/oppdrag-service/src/main/resources/schema/entiteter/oppdragSkjema.xsd @@ -0,0 +1,429 @@ + + + + + + + Oppdrag entiteter + For hver entitet er det lagt til en referanse ID. + Disse IDene korresponderer med entitetene som er implementert i baksystemet og kan forenkle kommunikasjon. + + + + + Entitet enhet + Referanse ID 120 dersom enhet på nivå oppdrag + Referanse ID 160 dersom enhet på nivå oppdragslinje + + + + + + + + + + + + Entitet Beløpsgrense + Referanse ID 130 + + + + + + + + + + + + + + + + + + + + + Entitet Tekst + Referanse ID 140 dersom tekst tihørende oppdrag + Referanse ID 158 dersom tekst tihørende oppdragslinje + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Entitet Grad + Referanse ID 170 + + + + + + + + + + + + + + + + + + + Entitet Attestasjon + Referanse ID 180 + + + + + + + + + + + + + + + + + + + Entitet Valuta + Referanse ID 190 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Entitet linjestatus + Referanse ID 151 + + + + + + + + + + + + + + Entitet klassifikasjon + Referanse ID 152 + + + + + + + + + + + + + + Entitet skyldner + Referanse ID 153 + + + + + + + + + + + + + + Inneholder elementene som skal være med KID + Referanse ID 154 + + + + + + + + + + + + + + Entitet Utbetales til + Referanse ID 155 + + + + + + + + + + + + + + Entitet for refusjon til et orgnr og/eller maksdato for utbetaling av ytelse + Referanse ID 156 + + + + + + + + + + + + + Entitet nøkler til bevis informasjon + Referanse ID 115 + + + + + + + + + + + + + + + + + + + + + + + + + + + Ompostering + Referanse ID 116 + + + + + + + + + + + + + + + + + + + + + + Entitet Oppdragslinje + Referanse ID 150 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Entitet Oppdrag + Referanse ID 110 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Entitet Oppdragstatus + Referanse ID 111 + + + + + + + + + + + + + + Entitet Oppdrag gjelder + Referanse ID 112 + + + + + + + + + + + + + + Entitet Bilagstype + Referanse ID 113 + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/apps/oppdrag-service/src/main/resources/schema/entiteter/statusmelding.xsd b/apps/oppdrag-service/src/main/resources/schema/entiteter/statusmelding.xsd new file mode 100644 index 00000000000..7c365d582cb --- /dev/null +++ b/apps/oppdrag-service/src/main/resources/schema/entiteter/statusmelding.xsd @@ -0,0 +1,41 @@ + + + + + Entitet for statusmelding + Tilsvarende baksystemets FE469-RTV-LOGG databasetabell + + + + + Entitet for statusmelding ang. forløp. Opp til konsument å vurdere situasjon. + Referanse ID 469MMEL + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/apps/oppdrag-service/src/main/resources/schema/entiteter/typer/simpleTypes.xsd b/apps/oppdrag-service/src/main/resources/schema/entiteter/typer/simpleTypes.xsd new file mode 100644 index 00000000000..45473051b61 --- /dev/null +++ b/apps/oppdrag-service/src/main/resources/schema/entiteter/typer/simpleTypes.xsd @@ -0,0 +1,363 @@ + + + + + Oppdrag spesifikasjon Simple Types som blir brukt i pÃ¥ attribut/felt nivÃ¥ for Oppdrag + + + + + Typen beskriver formatet og begrensningene til dato elementer. + Datoformat dd-MM-yyyy + Noen programmeringsspråk allokerer minne statisk og allokerer standard 26 tegn for hver eneste type xsd:date pga. mulighet for tidssone + For¨å forsere dato uten timezone er det benyttet string. + Både konsument og produsent må caste til felt/property av type dato. + + + + + + + + Typen beskriver formatet og begrensningene til oppdragsid. + + + + + + + + Typen beskriver formatet og begrensningene til fnr og orgnr. + + + + + + + + + Typen beskriver formatet og begrensningene til enhet (tknr evnt orgnr+avd). + + + + + + + + + Typen beskriver formatet og begrensningene til saksbehandlerId. + + + + + + + + Typen beskriver formatet og begrensningene til feilreg. + + + + + + + + Typen beskriver formatet og begrensningene til fagsystemId. + + + + + + + + Typen beskriver formatet og begrensningene til vedtakId. + + + + + + + + Typen beskriver formatet og begrensningene til utbetalingsfrekvens. + + + + + + + + + + + + Typen beskriver formatet og begrensningene til delytelseId. + + + + + + + + Typen beskriver formatet og begrensningene til beløp. + + + + + + + + + Typen beskriver formatet og begrensningene til fradragTillegg. + + + + + + + + + Typen beskriver formatet og begrensningene til grad. + + + + + + + + Typen beskriver formatet og begrensningene til kodeStatus. + + + + + + + + + + + + + + + + + + + Typen beskriver formatet og begrensningene til tidspktReg. + TidspktReg tilsvarer standard DB2 timestamp. + + + + + + + + Typen beskriver formatet og begrensningene til kodeStatusLinje. + + + + + + + + + + + Typen beskriver formatet og begrensningene til kodeKlassifik. + + + + + + + + + Typen beskriver formatet og begrensningene til KID. + + + + + + + + Typen beskriver formatet og begrensningene til kodeFagomraade. + + + + + + + + + Typen beskriver formatet og begrensningene til stonadId. + + + + + + + + Typen beskriver formatet og begrensningene til typeEnhet. + + + + + + + + + Typen beskriver formatet og begrensningene til linjeId. + + + + + + + + Typen beskriver formatet og begrensningene til sats. + + + + + + + + + Typen beskriver formatet og begrensningene til typeSats. + + + + + + + + + + + + + + Typen beskriver formatet og begrensningene til antall sats. + + + + + + + + + Typen beskriver formatet og begrensningene til brukKjoreplan. + + + + + + + + Typen beskriver formatet og begrensningene til kodeArbeidsgiver. + + + + + + + + + + Typen beskriver formatet og begrensningene til henvisning. + + + + + + + + Typen beskriver formatet og begrensningene til tekstlnr. + + + + + + + + Typen beskriver navn, typisk navn for felt som gjelderId eller utbetalesTilId. + + + + + + + + + Typen beskriver faggruppe, f.eks PEN . + + + + + + + + + Typen beskriver type bilag + + + + + + + + + Typen beskriver formatet og begrensningene til trekkVedtakId. + + + + + + Generisk type for tekstattribut lengde 1 + + + + + + + + + Type for klassekode + + + + + + + + + Type for klassekode beskrivelse + + + + + + + + + Type for type klasse + + + + + + + + + Type for type klasse beskrivelse + + + + + + + + \ No newline at end of file diff --git a/apps/oppdrag-service/src/main/resources/schema/tjenester/oppdragService/feil.xsd b/apps/oppdrag-service/src/main/resources/schema/tjenester/oppdragService/feil.xsd new file mode 100644 index 00000000000..bb797d3633e --- /dev/null +++ b/apps/oppdrag-service/src/main/resources/schema/tjenester/oppdragService/feil.xsd @@ -0,0 +1,26 @@ + + + + + + + + + + + + + + + + Feil under behandling i baksystemet + + + + + + + \ No newline at end of file diff --git a/apps/oppdrag-service/src/main/resources/schema/tjenester/oppdragService/oppdragServiceGrensesnitt.wsdl b/apps/oppdrag-service/src/main/resources/schema/tjenester/oppdragService/oppdragServiceGrensesnitt.wsdl new file mode 100644 index 00000000000..af6821eee73 --- /dev/null +++ b/apps/oppdrag-service/src/main/resources/schema/tjenester/oppdragService/oppdragServiceGrensesnitt.wsdl @@ -0,0 +1,106 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Operasjonen tilbyr innsending og registrering av ny/endret oppdrag som følge av nytt/endring på vedtak + + + + + + + + + + Operasjonen tilbyr simuleringsberegning + + + + + + + + + + \ No newline at end of file diff --git a/apps/oppdrag-service/src/main/resources/schema/tjenester/oppdragService/oppdragServiceServiceTypes.xsd b/apps/oppdrag-service/src/main/resources/schema/tjenester/oppdragService/oppdragServiceServiceTypes.xsd new file mode 100644 index 00000000000..9bb85d60310 --- /dev/null +++ b/apps/oppdrag-service/src/main/resources/schema/tjenester/oppdragService/oppdragServiceServiceTypes.xsd @@ -0,0 +1,112 @@ + + + + + + + + + + Definisjon av request og respons for tjenesten + Kan bestå av både standard (gjenbrukbare) entiteter som kan bli gjenbrukt og (komplekse)typer spesifikk for denne tjenesten + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Oppdraget for innsending. + + + + + + + + + Oppdraget som er sendt inn og videreutfylt under behandling. + + + + + Informasjonsmelding + + + + + + + + + + Oppdragetmed underelementer for simuleringsberegning. + + + + + Entitet Simulering + Referanse ID 300 + + + + + + + + + + + + + + + Simulert beregningsresultat for gitt periode + + + + + Informasjonsmelding + + + + + + \ No newline at end of file diff --git a/apps/oppdrag-service/src/test/java/no/nav/testnav.oppdrag.service/ApplicationContextTest.java b/apps/oppdrag-service/src/test/java/no/nav/testnav.oppdrag.service/ApplicationContextTest.java new file mode 100644 index 00000000000..092d7d41535 --- /dev/null +++ b/apps/oppdrag-service/src/test/java/no/nav/testnav.oppdrag.service/ApplicationContextTest.java @@ -0,0 +1,20 @@ +package no.nav.testnav.oppdrag.service; + +import org.junit.jupiter.api.Test; +import org.springframework.boot.test.context.SpringBootTest; +import org.springframework.boot.test.mock.mockito.MockBean; +import org.springframework.security.oauth2.jwt.ReactiveJwtDecoder; +import org.springframework.test.context.ActiveProfiles; + +@SpringBootTest +@ActiveProfiles("test") +class ApplicationContextTest { + + @MockBean + public ReactiveJwtDecoder reactiveJwtDecoder; + + @Test + @SuppressWarnings("java:S2699") + void load_app_context() { + } +} \ No newline at end of file diff --git a/settings.gradle b/settings.gradle index 0dac4aa7256..3a9c1eeb935 100644 --- a/settings.gradle +++ b/settings.gradle @@ -94,6 +94,7 @@ includeBuild './apps/jenkins-batch-status-service' includeBuild './apps/joark-dokument-service' includeBuild './apps/kodeverk-service' includeBuild './apps/miljoer-service' +includeBuild './apps/oppdrag-service' includeBuild './apps/oppsummeringsdokument-service' includeBuild './apps/organisasjon-bestilling-service' includeBuild './apps/organisasjon-faste-data-service' From 35be286045298dbb9109094f150f3b0ff4bba86f Mon Sep 17 00:00:00 2001 From: kristenhaerum Date: Tue, 28 May 2024 13:10:57 +0200 Subject: [PATCH 02/35] Add Oppdrag web service client and update configurations Added new OppdragClient class, related configuration, and corresponding consumer and controller. Adjusted build configurations and dependencies for SOAP-based web service compatibility. Replaced reactive-core with --- apps/oppdrag-service/build.gradle | 19 ++++++++++-- apps/oppdrag-service/settings.gradle | 4 +-- .../OppdragServiceApplicationStarter.java | 0 .../service}/config/ApplicationConfig.java | 6 ++-- .../oppdrag/service}/config/DevConfig.java | 0 .../service}/config/OpenApiConfig.java | 2 +- .../config/OppdragWsConfiguration.java | 31 +++++++++++++++++++ .../service}/config/SecurityConfig.java | 0 .../service/consumer/OppdragClient.java | 25 +++++++++++++++ .../service/consumer/OppdragConsumer.java | 7 +++++ .../service/provider/OppdragController.java | 13 ++++++++ .../src/main/resources/application.yml | 2 +- 12 files changed, 99 insertions(+), 10 deletions(-) rename apps/oppdrag-service/src/main/java/no/nav/{testnav.oppdrag.service => testnav/oppdrag/service}/OppdragServiceApplicationStarter.java (100%) rename apps/oppdrag-service/src/main/java/no/nav/{testnav.oppdrag.service => testnav/oppdrag/service}/config/ApplicationConfig.java (58%) rename apps/oppdrag-service/src/main/java/no/nav/{testnav.oppdrag.service => testnav/oppdrag/service}/config/DevConfig.java (100%) rename apps/oppdrag-service/src/main/java/no/nav/{testnav.oppdrag.service => testnav/oppdrag/service}/config/OpenApiConfig.java (97%) create mode 100644 apps/oppdrag-service/src/main/java/no/nav/testnav/oppdrag/service/config/OppdragWsConfiguration.java rename apps/oppdrag-service/src/main/java/no/nav/{testnav.oppdrag.service => testnav/oppdrag/service}/config/SecurityConfig.java (100%) create mode 100644 apps/oppdrag-service/src/main/java/no/nav/testnav/oppdrag/service/consumer/OppdragClient.java create mode 100644 apps/oppdrag-service/src/main/java/no/nav/testnav/oppdrag/service/consumer/OppdragConsumer.java create mode 100644 apps/oppdrag-service/src/main/java/no/nav/testnav/oppdrag/service/provider/OppdragController.java diff --git a/apps/oppdrag-service/build.gradle b/apps/oppdrag-service/build.gradle index 02a14e0dbe4..b9db6d98900 100644 --- a/apps/oppdrag-service/build.gradle +++ b/apps/oppdrag-service/build.gradle @@ -46,7 +46,7 @@ wsimport { generatedSourceRoot = "/generated/src/wsdl/main" generatedClassesRoot = "/classes/main" wsdl("oppdragServiceWSBinding.wsdl") { - packageName = "no.nav.testnav.oppdrag.service" + packageName = "no.nav.testnav.oppdragservice.wsdl" xjcarg("-XautoNameResolution") } verbose = true @@ -79,13 +79,23 @@ repositories { } } +configurations { + jaxws +} + dependencies { implementation 'jakarta.xml.bind:jakarta.xml.bind-api:4.0.0' implementation 'org.glassfish.jaxb:jaxb-runtime:4.0.0' + jaxws 'com.sun.xml.ws:jaxws-tools:3.0.0', + 'jakarta.xml.ws:jakarta.xml.ws-api:3.0.0', + 'jakarta.xml.bind:jakarta.xml.bind-api:3.0.0', + 'jakarta.activation:jakarta.activation-api:2.0.0', + 'com.sun.xml.ws:jaxws-rt:3.0.0' + implementation 'no.nav.testnav.libs:security-core' - implementation 'no.nav.testnav.libs:reactive-core' - implementation 'no.nav.testnav.libs:reactive-security' + implementation 'no.nav.testnav.libs:servlet-core' + implementation 'no.nav.testnav.libs:servlet-security' implementation 'no.nav.testnav.libs:data-transfer-objects' implementation 'org.springframework.cloud:spring-cloud-starter-vault-config' @@ -97,6 +107,9 @@ dependencies { implementation 'org.springframework.boot:spring-boot-starter-oauth2-client' implementation 'org.springframework.boot:spring-boot-starter-security' implementation 'org.springframework.boot:spring-boot-starter-validation' + implementation 'org.springframework.boot:spring-boot-starter-web' + implementation 'org.springframework.boot:spring-boot-starter-web-services' + implementation 'org.springframework.ws:spring-ws-security' implementation 'ma.glasnost.orika:orika-core:1.5.4' annotationProcessor 'org.projectlombok:lombok' diff --git a/apps/oppdrag-service/settings.gradle b/apps/oppdrag-service/settings.gradle index 8e5fe4c0910..6c975088f41 100644 --- a/apps/oppdrag-service/settings.gradle +++ b/apps/oppdrag-service/settings.gradle @@ -5,8 +5,8 @@ plugins { rootProject.name = 'oppdrag-service' includeBuild '../../libs/security-core' -includeBuild '../../libs/reactive-core' -includeBuild '../../libs/reactive-security' +includeBuild '../../libs/servlet-core' +includeBuild '../../libs/servlet-security' includeBuild '../../libs/data-transfer-objects' gradleEnterprise { diff --git a/apps/oppdrag-service/src/main/java/no/nav/testnav.oppdrag.service/OppdragServiceApplicationStarter.java b/apps/oppdrag-service/src/main/java/no/nav/testnav/oppdrag/service/OppdragServiceApplicationStarter.java similarity index 100% rename from apps/oppdrag-service/src/main/java/no/nav/testnav.oppdrag.service/OppdragServiceApplicationStarter.java rename to apps/oppdrag-service/src/main/java/no/nav/testnav/oppdrag/service/OppdragServiceApplicationStarter.java diff --git a/apps/oppdrag-service/src/main/java/no/nav/testnav.oppdrag.service/config/ApplicationConfig.java b/apps/oppdrag-service/src/main/java/no/nav/testnav/oppdrag/service/config/ApplicationConfig.java similarity index 58% rename from apps/oppdrag-service/src/main/java/no/nav/testnav.oppdrag.service/config/ApplicationConfig.java rename to apps/oppdrag-service/src/main/java/no/nav/testnav/oppdrag/service/config/ApplicationConfig.java index 44e96ea7b05..49d29401dca 100644 --- a/apps/oppdrag-service/src/main/java/no/nav/testnav.oppdrag.service/config/ApplicationConfig.java +++ b/apps/oppdrag-service/src/main/java/no/nav/testnav/oppdrag/service/config/ApplicationConfig.java @@ -1,13 +1,13 @@ package no.nav.testnav.oppdrag.service.config; -import no.nav.testnav.libs.reactivecore.config.CoreConfig; -import no.nav.testnav.libs.reactivesecurity.config.SecureOAuth2ServerToServerConfiguration; +import no.nav.testnav.libs.servletcore.config.ApplicationCoreConfig; +import no.nav.testnav.libs.servletsecurity.config.SecureOAuth2ServerToServerConfiguration; import org.springframework.context.annotation.Configuration; import org.springframework.context.annotation.Import; @Configuration @Import({ - CoreConfig.class, + ApplicationCoreConfig.class, SecureOAuth2ServerToServerConfiguration.class }) public class ApplicationConfig { diff --git a/apps/oppdrag-service/src/main/java/no/nav/testnav.oppdrag.service/config/DevConfig.java b/apps/oppdrag-service/src/main/java/no/nav/testnav/oppdrag/service/config/DevConfig.java similarity index 100% rename from apps/oppdrag-service/src/main/java/no/nav/testnav.oppdrag.service/config/DevConfig.java rename to apps/oppdrag-service/src/main/java/no/nav/testnav/oppdrag/service/config/DevConfig.java diff --git a/apps/oppdrag-service/src/main/java/no/nav/testnav.oppdrag.service/config/OpenApiConfig.java b/apps/oppdrag-service/src/main/java/no/nav/testnav/oppdrag/service/config/OpenApiConfig.java similarity index 97% rename from apps/oppdrag-service/src/main/java/no/nav/testnav.oppdrag.service/config/OpenApiConfig.java rename to apps/oppdrag-service/src/main/java/no/nav/testnav/oppdrag/service/config/OpenApiConfig.java index ebb238f68a9..4ad59d3759b 100644 --- a/apps/oppdrag-service/src/main/java/no/nav/testnav.oppdrag.service/config/OpenApiConfig.java +++ b/apps/oppdrag-service/src/main/java/no/nav/testnav/oppdrag/service/config/OpenApiConfig.java @@ -7,7 +7,7 @@ import io.swagger.v3.oas.models.info.License; import io.swagger.v3.oas.models.security.SecurityRequirement; import io.swagger.v3.oas.models.security.SecurityScheme; -import no.nav.testnav.libs.reactivecore.config.ApplicationProperties; +import no.nav.testnav.libs.servletcore.config.ApplicationProperties; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.http.HttpHeaders; diff --git a/apps/oppdrag-service/src/main/java/no/nav/testnav/oppdrag/service/config/OppdragWsConfiguration.java b/apps/oppdrag-service/src/main/java/no/nav/testnav/oppdrag/service/config/OppdragWsConfiguration.java new file mode 100644 index 00000000000..87314fc6872 --- /dev/null +++ b/apps/oppdrag-service/src/main/java/no/nav/testnav/oppdrag/service/config/OppdragWsConfiguration.java @@ -0,0 +1,31 @@ +package no.nav.testnav.oppdrag.service.config; + +import no.nav.testnav.oppdrag.service.consumer.OppdragClient; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.oxm.jaxb.Jaxb2Marshaller; +import org.springframework.ws.config.annotation.EnableWs; + +@EnableWs +@Configuration +public class OppdragWsConfiguration { + + @Bean + public Jaxb2Marshaller marshaller() { + Jaxb2Marshaller marshaller = new Jaxb2Marshaller(); + // this package must match the package in the specified in + // pom.xml + marshaller.setContextPath("no.nav.testnav.oppdragservice.wsdl"); + return marshaller; + } + + @Bean + public OppdragClient countryClient(Jaxb2Marshaller marshaller) { + + var client = new OppdragClient(); + client.setDefaultUri("http://localhost:8080/ws"); + client.setMarshaller(marshaller); + client.setUnmarshaller(marshaller); + return client; + } +} diff --git a/apps/oppdrag-service/src/main/java/no/nav/testnav.oppdrag.service/config/SecurityConfig.java b/apps/oppdrag-service/src/main/java/no/nav/testnav/oppdrag/service/config/SecurityConfig.java similarity index 100% rename from apps/oppdrag-service/src/main/java/no/nav/testnav.oppdrag.service/config/SecurityConfig.java rename to apps/oppdrag-service/src/main/java/no/nav/testnav/oppdrag/service/config/SecurityConfig.java diff --git a/apps/oppdrag-service/src/main/java/no/nav/testnav/oppdrag/service/consumer/OppdragClient.java b/apps/oppdrag-service/src/main/java/no/nav/testnav/oppdrag/service/consumer/OppdragClient.java new file mode 100644 index 00000000000..cf671c8d792 --- /dev/null +++ b/apps/oppdrag-service/src/main/java/no/nav/testnav/oppdrag/service/consumer/OppdragClient.java @@ -0,0 +1,25 @@ +package no.nav.testnav.oppdrag.service.consumer; + +import lombok.extern.slf4j.Slf4j; +import org.springframework.ws.client.core.support.WebServiceGatewaySupport; +import org.springframework.ws.soap.client.core.SoapActionCallback; + +@Slf4j +public class OppdragClient extends WebServiceGatewaySupport { + + public OppdragClient postOppdrag(String country) { + +// GetCountryRequest request = new GetCountryRequest(); +// request.setName(country); +// +// log.info("Requesting location for " + country); +// +// GetCountryResponse response = (GetCountryResponse) getWebServiceTemplate() +// .marshalSendAndReceive("http://localhost:8080/ws/countries", request, +// new SoapActionCallback( +// "http://spring.io/guides/gs-producing-web-service/GetCountryRequest")); +// +// return response; + return null; + } +} diff --git a/apps/oppdrag-service/src/main/java/no/nav/testnav/oppdrag/service/consumer/OppdragConsumer.java b/apps/oppdrag-service/src/main/java/no/nav/testnav/oppdrag/service/consumer/OppdragConsumer.java new file mode 100644 index 00000000000..5a15904b835 --- /dev/null +++ b/apps/oppdrag-service/src/main/java/no/nav/testnav/oppdrag/service/consumer/OppdragConsumer.java @@ -0,0 +1,7 @@ +package no.nav.testnav.oppdrag.service.consumer; + +import org.springframework.stereotype.Service; + +@Service +public class OppdragConsumer { +} diff --git a/apps/oppdrag-service/src/main/java/no/nav/testnav/oppdrag/service/provider/OppdragController.java b/apps/oppdrag-service/src/main/java/no/nav/testnav/oppdrag/service/provider/OppdragController.java new file mode 100644 index 00000000000..1bacf7e07fe --- /dev/null +++ b/apps/oppdrag-service/src/main/java/no/nav/testnav/oppdrag/service/provider/OppdragController.java @@ -0,0 +1,13 @@ +package no.nav.testnav.oppdrag.service.provider; + +import org.springframework.web.bind.annotation.PostMapping; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RestController; + +@RestController +@RequestMapping("/api/v1/oppdrag") +public class OppdragController { + + @PostMapping + public void sendOppdrag() {} +} diff --git a/apps/oppdrag-service/src/main/resources/application.yml b/apps/oppdrag-service/src/main/resources/application.yml index 3733587b2bc..e554e357d75 100644 --- a/apps/oppdrag-service/src/main/resources/application.yml +++ b/apps/oppdrag-service/src/main/resources/application.yml @@ -5,7 +5,7 @@ spring: banner-mode: off application: name: testnav-oppdrag-service - description: App for å sjekke hvilke miljøer i test og preprod som er tilgjengelige nå. + description: App for å sende oppdrag til Oppdragssystemet. security: oauth2: resourceserver: From 2cf8f2403260683150098727eabc8418ce775ece Mon Sep 17 00:00:00 2001 From: kristenhaerum Date: Tue, 28 May 2024 15:25:08 +0200 Subject: [PATCH 03/35] Add OppdragRequest DTO class A new data transfer object (DTO) class called 'OppdragRequest' is introduced. This class is suited for the Oppdrag service and is equipped with Lombok annotations for data encapsulation, builder pattern support, no-args and all-args constructors. --- .../libs/dto/oppdragservice/v1/OppdragRequest.java | 13 +++++++++++++ 1 file changed, 13 insertions(+) create mode 100644 libs/data-transfer-objects/src/main/java/no/nav/testnav/libs/dto/oppdragservice/v1/OppdragRequest.java diff --git a/libs/data-transfer-objects/src/main/java/no/nav/testnav/libs/dto/oppdragservice/v1/OppdragRequest.java b/libs/data-transfer-objects/src/main/java/no/nav/testnav/libs/dto/oppdragservice/v1/OppdragRequest.java new file mode 100644 index 00000000000..3ce9e2f8039 --- /dev/null +++ b/libs/data-transfer-objects/src/main/java/no/nav/testnav/libs/dto/oppdragservice/v1/OppdragRequest.java @@ -0,0 +1,13 @@ +package no.nav.testnav.libs.dto.oppdragservice.v1; + +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; + +@Data +@Builder +@NoArgsConstructor +@AllArgsConstructor +public class OppdragRequest { +} From 1ae4acc41411b856b1390033ec59b6ab1e09154e Mon Sep 17 00:00:00 2001 From: "Kristen.Herum" Date: Tue, 15 Oct 2024 07:38:35 +0200 Subject: [PATCH 04/35] **Refactor project structure and dependencies** Remove unnecessary DevConfig and centralize logic under oppdragservice package. Also, streamline build configuration by using dolly-apps plugin and integrating vault library for improved consistency and security management. --- apps/oppdrag-service/build.gradle | 28 +------------ apps/oppdrag-service/settings.gradle | 1 + .../oppdrag/service/config/DevConfig.java | 39 ------------------- .../OppdragServiceApplicationStarter.java | 2 +- .../config/ApplicationConfig.java | 2 +- .../oppdragservice/config/DevConfig.java | 13 +++++++ .../config/OpenApiConfig.java | 2 +- .../config/OppdragWsConfiguration.java | 4 +- .../config/SecurityConfig.java | 2 +- .../consumer/OppdragClient.java | 2 +- .../consumer/OppdragConsumer.java | 2 +- .../provider/OppdragController.java | 2 +- .../ApplicationContextTest.java | 2 +- .../dto/oppdragservice/v1/OppdragRequest.java | 1 - 14 files changed, 26 insertions(+), 76 deletions(-) delete mode 100644 apps/oppdrag-service/src/main/java/no/nav/testnav/oppdrag/service/config/DevConfig.java rename apps/oppdrag-service/src/main/java/no/nav/testnav/{oppdrag/service => oppdragservice}/OppdragServiceApplicationStarter.java (88%) rename apps/oppdrag-service/src/main/java/no/nav/testnav/{oppdrag/service => oppdragservice}/config/ApplicationConfig.java (90%) create mode 100644 apps/oppdrag-service/src/main/java/no/nav/testnav/oppdragservice/config/DevConfig.java rename apps/oppdrag-service/src/main/java/no/nav/testnav/{oppdrag/service => oppdragservice}/config/OpenApiConfig.java (98%) rename apps/oppdrag-service/src/main/java/no/nav/testnav/{oppdrag/service => oppdragservice}/config/OppdragWsConfiguration.java (89%) rename apps/oppdrag-service/src/main/java/no/nav/testnav/{oppdrag/service => oppdragservice}/config/SecurityConfig.java (97%) rename apps/oppdrag-service/src/main/java/no/nav/testnav/{oppdrag/service => oppdragservice}/consumer/OppdragClient.java (94%) rename apps/oppdrag-service/src/main/java/no/nav/testnav/{oppdrag/service => oppdragservice}/consumer/OppdragConsumer.java (65%) rename apps/oppdrag-service/src/main/java/no/nav/testnav/{oppdrag/service => oppdragservice}/provider/OppdragController.java (86%) rename apps/oppdrag-service/src/test/java/no/nav/{testnav.oppdrag.service => testnav/oppdragservice}/ApplicationContextTest.java (92%) diff --git a/apps/oppdrag-service/build.gradle b/apps/oppdrag-service/build.gradle index b9db6d98900..1c26638be91 100644 --- a/apps/oppdrag-service/build.gradle +++ b/apps/oppdrag-service/build.gradle @@ -10,11 +10,7 @@ buildscript { } plugins { - id 'java' - id "org.sonarqube" version "4.4.1.3373" - id 'org.springframework.boot' version "3.2.1" - id 'io.spring.dependency-management' version "1.1.4" - id "jacoco" + id 'dolly-apps' id "uk.co.boothen.gradle.wsimport" version "0.21" } @@ -22,16 +18,8 @@ apply plugin: "uk.co.boothen.gradle.wsimport" sonarqube { properties { - property "sonar.dynamicAnalysis", "reuseReports" - property "sonar.host.url", "https://sonarcloud.io" - property "sonar.java.coveragePlugin", "jacoco" - property "sonar.language", "java" - property "sonar.token", System.getenv("SONAR_TOKEN") - property "sonar.organization", "navikt" - property "sonar.project.monorepo.enabled", true property "sonar.projectKey", "testnav-oppdrag-service" property "sonar.projectName", "testnav-oppdrag-service" - property "sonar.sourceEncoding", "UTF-8" } } @@ -54,19 +42,6 @@ wsimport { target = "3.0" } -dependencyManagement { - applyMavenExclusions = false - imports { - mavenBom 'org.springframework.cloud:spring-cloud-dependencies:2023.0.0' - } -} - -java { - toolchain { - languageVersion = JavaLanguageVersion.of(21) - } -} - repositories { mavenCentral() maven { @@ -97,6 +72,7 @@ dependencies { implementation 'no.nav.testnav.libs:servlet-core' implementation 'no.nav.testnav.libs:servlet-security' implementation 'no.nav.testnav.libs:data-transfer-objects' + implementation "no.nav.testnav.libs:vault" implementation 'org.springframework.cloud:spring-cloud-starter-vault-config' diff --git a/apps/oppdrag-service/settings.gradle b/apps/oppdrag-service/settings.gradle index 6c975088f41..904d9306913 100644 --- a/apps/oppdrag-service/settings.gradle +++ b/apps/oppdrag-service/settings.gradle @@ -8,6 +8,7 @@ includeBuild '../../libs/security-core' includeBuild '../../libs/servlet-core' includeBuild '../../libs/servlet-security' includeBuild '../../libs/data-transfer-objects' +includeBuild '../../libs/vault' gradleEnterprise { buildScan { diff --git a/apps/oppdrag-service/src/main/java/no/nav/testnav/oppdrag/service/config/DevConfig.java b/apps/oppdrag-service/src/main/java/no/nav/testnav/oppdrag/service/config/DevConfig.java deleted file mode 100644 index b3ebc0f1392..00000000000 --- a/apps/oppdrag-service/src/main/java/no/nav/testnav/oppdrag/service/config/DevConfig.java +++ /dev/null @@ -1,39 +0,0 @@ -package no.nav.testnav.oppdrag.service.config; - -import org.springframework.context.annotation.Configuration; -import org.springframework.context.annotation.Profile; -import org.springframework.lang.NonNull; -import org.springframework.vault.annotation.VaultPropertySource; -import org.springframework.vault.authentication.ClientAuthentication; -import org.springframework.vault.authentication.TokenAuthentication; -import org.springframework.vault.client.VaultEndpoint; -import org.springframework.vault.config.AbstractVaultConfiguration; - -import static io.micrometer.common.util.StringUtils.isBlank; - -@Configuration -@Profile("dev") -@VaultPropertySource(value = "secret/dolly/lokal", ignoreSecretNotFound = false) -public class DevConfig extends AbstractVaultConfiguration { - - private static final String VAULT_TOKEN = "spring.cloud.vault.token"; - - @Override - @NonNull - public VaultEndpoint vaultEndpoint() { - return VaultEndpoint.create("vault.adeo.no", 443); - } - - @Override - @NonNull - public ClientAuthentication clientAuthentication() { - if (System.getenv().containsKey("VAULT_TOKEN")) { - System.setProperty(VAULT_TOKEN, System.getenv("VAULT_TOKEN")); - } - var token = System.getProperty(VAULT_TOKEN); - if (isBlank(token)) { - throw new IllegalArgumentException("Påkrevet property 'spring.cloud.vault.token' er ikke satt."); - } - return new TokenAuthentication(System.getProperty(VAULT_TOKEN)); - } -} \ No newline at end of file diff --git a/apps/oppdrag-service/src/main/java/no/nav/testnav/oppdrag/service/OppdragServiceApplicationStarter.java b/apps/oppdrag-service/src/main/java/no/nav/testnav/oppdragservice/OppdragServiceApplicationStarter.java similarity index 88% rename from apps/oppdrag-service/src/main/java/no/nav/testnav/oppdrag/service/OppdragServiceApplicationStarter.java rename to apps/oppdrag-service/src/main/java/no/nav/testnav/oppdragservice/OppdragServiceApplicationStarter.java index 434733c7cf1..2e8c4042fa6 100644 --- a/apps/oppdrag-service/src/main/java/no/nav/testnav/oppdrag/service/OppdragServiceApplicationStarter.java +++ b/apps/oppdrag-service/src/main/java/no/nav/testnav/oppdragservice/OppdragServiceApplicationStarter.java @@ -1,4 +1,4 @@ -package no.nav.testnav.oppdrag.service; +package no.nav.testnav.oppdragservice; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; diff --git a/apps/oppdrag-service/src/main/java/no/nav/testnav/oppdrag/service/config/ApplicationConfig.java b/apps/oppdrag-service/src/main/java/no/nav/testnav/oppdragservice/config/ApplicationConfig.java similarity index 90% rename from apps/oppdrag-service/src/main/java/no/nav/testnav/oppdrag/service/config/ApplicationConfig.java rename to apps/oppdrag-service/src/main/java/no/nav/testnav/oppdragservice/config/ApplicationConfig.java index 49d29401dca..fa45e6cc921 100644 --- a/apps/oppdrag-service/src/main/java/no/nav/testnav/oppdrag/service/config/ApplicationConfig.java +++ b/apps/oppdrag-service/src/main/java/no/nav/testnav/oppdragservice/config/ApplicationConfig.java @@ -1,4 +1,4 @@ -package no.nav.testnav.oppdrag.service.config; +package no.nav.testnav.oppdragservice.config; import no.nav.testnav.libs.servletcore.config.ApplicationCoreConfig; import no.nav.testnav.libs.servletsecurity.config.SecureOAuth2ServerToServerConfiguration; diff --git a/apps/oppdrag-service/src/main/java/no/nav/testnav/oppdragservice/config/DevConfig.java b/apps/oppdrag-service/src/main/java/no/nav/testnav/oppdragservice/config/DevConfig.java new file mode 100644 index 00000000000..a93f3cd2751 --- /dev/null +++ b/apps/oppdrag-service/src/main/java/no/nav/testnav/oppdragservice/config/DevConfig.java @@ -0,0 +1,13 @@ +package no.nav.testnav.oppdragservice.config; + +import no.nav.testnav.libs.vault.AbstractLocalVaultConfiguration; +import org.springframework.context.annotation.Configuration; +import org.springframework.context.annotation.Profile; +import org.springframework.vault.annotation.VaultPropertySource; + +@Configuration +@Profile("dev") +@VaultPropertySource(value = "secret/dolly/lokal", ignoreSecretNotFound = false) +public class DevConfig extends AbstractLocalVaultConfiguration { + +} \ No newline at end of file diff --git a/apps/oppdrag-service/src/main/java/no/nav/testnav/oppdrag/service/config/OpenApiConfig.java b/apps/oppdrag-service/src/main/java/no/nav/testnav/oppdragservice/config/OpenApiConfig.java similarity index 98% rename from apps/oppdrag-service/src/main/java/no/nav/testnav/oppdrag/service/config/OpenApiConfig.java rename to apps/oppdrag-service/src/main/java/no/nav/testnav/oppdragservice/config/OpenApiConfig.java index 4ad59d3759b..22e439651d1 100644 --- a/apps/oppdrag-service/src/main/java/no/nav/testnav/oppdrag/service/config/OpenApiConfig.java +++ b/apps/oppdrag-service/src/main/java/no/nav/testnav/oppdragservice/config/OpenApiConfig.java @@ -1,4 +1,4 @@ -package no.nav.testnav.oppdrag.service.config; +package no.nav.testnav.oppdragservice.config; import io.swagger.v3.oas.models.Components; import io.swagger.v3.oas.models.OpenAPI; diff --git a/apps/oppdrag-service/src/main/java/no/nav/testnav/oppdrag/service/config/OppdragWsConfiguration.java b/apps/oppdrag-service/src/main/java/no/nav/testnav/oppdragservice/config/OppdragWsConfiguration.java similarity index 89% rename from apps/oppdrag-service/src/main/java/no/nav/testnav/oppdrag/service/config/OppdragWsConfiguration.java rename to apps/oppdrag-service/src/main/java/no/nav/testnav/oppdragservice/config/OppdragWsConfiguration.java index 87314fc6872..1def57c64d0 100644 --- a/apps/oppdrag-service/src/main/java/no/nav/testnav/oppdrag/service/config/OppdragWsConfiguration.java +++ b/apps/oppdrag-service/src/main/java/no/nav/testnav/oppdragservice/config/OppdragWsConfiguration.java @@ -1,6 +1,6 @@ -package no.nav.testnav.oppdrag.service.config; +package no.nav.testnav.oppdragservice.config; -import no.nav.testnav.oppdrag.service.consumer.OppdragClient; +import no.nav.testnav.oppdragservice.consumer.OppdragClient; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.oxm.jaxb.Jaxb2Marshaller; diff --git a/apps/oppdrag-service/src/main/java/no/nav/testnav/oppdrag/service/config/SecurityConfig.java b/apps/oppdrag-service/src/main/java/no/nav/testnav/oppdragservice/config/SecurityConfig.java similarity index 97% rename from apps/oppdrag-service/src/main/java/no/nav/testnav/oppdrag/service/config/SecurityConfig.java rename to apps/oppdrag-service/src/main/java/no/nav/testnav/oppdragservice/config/SecurityConfig.java index 112370f0296..718c433a892 100644 --- a/apps/oppdrag-service/src/main/java/no/nav/testnav/oppdrag/service/config/SecurityConfig.java +++ b/apps/oppdrag-service/src/main/java/no/nav/testnav/oppdragservice/config/SecurityConfig.java @@ -1,4 +1,4 @@ -package no.nav.testnav.oppdrag.service.config; +package no.nav.testnav.oppdragservice.config; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; diff --git a/apps/oppdrag-service/src/main/java/no/nav/testnav/oppdrag/service/consumer/OppdragClient.java b/apps/oppdrag-service/src/main/java/no/nav/testnav/oppdragservice/consumer/OppdragClient.java similarity index 94% rename from apps/oppdrag-service/src/main/java/no/nav/testnav/oppdrag/service/consumer/OppdragClient.java rename to apps/oppdrag-service/src/main/java/no/nav/testnav/oppdragservice/consumer/OppdragClient.java index cf671c8d792..84779bd2bf0 100644 --- a/apps/oppdrag-service/src/main/java/no/nav/testnav/oppdrag/service/consumer/OppdragClient.java +++ b/apps/oppdrag-service/src/main/java/no/nav/testnav/oppdragservice/consumer/OppdragClient.java @@ -1,4 +1,4 @@ -package no.nav.testnav.oppdrag.service.consumer; +package no.nav.testnav.oppdragservice.consumer; import lombok.extern.slf4j.Slf4j; import org.springframework.ws.client.core.support.WebServiceGatewaySupport; diff --git a/apps/oppdrag-service/src/main/java/no/nav/testnav/oppdrag/service/consumer/OppdragConsumer.java b/apps/oppdrag-service/src/main/java/no/nav/testnav/oppdragservice/consumer/OppdragConsumer.java similarity index 65% rename from apps/oppdrag-service/src/main/java/no/nav/testnav/oppdrag/service/consumer/OppdragConsumer.java rename to apps/oppdrag-service/src/main/java/no/nav/testnav/oppdragservice/consumer/OppdragConsumer.java index 5a15904b835..54e01dc005b 100644 --- a/apps/oppdrag-service/src/main/java/no/nav/testnav/oppdrag/service/consumer/OppdragConsumer.java +++ b/apps/oppdrag-service/src/main/java/no/nav/testnav/oppdragservice/consumer/OppdragConsumer.java @@ -1,4 +1,4 @@ -package no.nav.testnav.oppdrag.service.consumer; +package no.nav.testnav.oppdragservice.consumer; import org.springframework.stereotype.Service; diff --git a/apps/oppdrag-service/src/main/java/no/nav/testnav/oppdrag/service/provider/OppdragController.java b/apps/oppdrag-service/src/main/java/no/nav/testnav/oppdragservice/provider/OppdragController.java similarity index 86% rename from apps/oppdrag-service/src/main/java/no/nav/testnav/oppdrag/service/provider/OppdragController.java rename to apps/oppdrag-service/src/main/java/no/nav/testnav/oppdragservice/provider/OppdragController.java index 1bacf7e07fe..3b1a068229f 100644 --- a/apps/oppdrag-service/src/main/java/no/nav/testnav/oppdrag/service/provider/OppdragController.java +++ b/apps/oppdrag-service/src/main/java/no/nav/testnav/oppdragservice/provider/OppdragController.java @@ -1,4 +1,4 @@ -package no.nav.testnav.oppdrag.service.provider; +package no.nav.testnav.oppdragservice.provider; import org.springframework.web.bind.annotation.PostMapping; import org.springframework.web.bind.annotation.RequestMapping; diff --git a/apps/oppdrag-service/src/test/java/no/nav/testnav.oppdrag.service/ApplicationContextTest.java b/apps/oppdrag-service/src/test/java/no/nav/testnav/oppdragservice/ApplicationContextTest.java similarity index 92% rename from apps/oppdrag-service/src/test/java/no/nav/testnav.oppdrag.service/ApplicationContextTest.java rename to apps/oppdrag-service/src/test/java/no/nav/testnav/oppdragservice/ApplicationContextTest.java index 092d7d41535..8f20b2bd0b2 100644 --- a/apps/oppdrag-service/src/test/java/no/nav/testnav.oppdrag.service/ApplicationContextTest.java +++ b/apps/oppdrag-service/src/test/java/no/nav/testnav/oppdragservice/ApplicationContextTest.java @@ -1,4 +1,4 @@ -package no.nav.testnav.oppdrag.service; +package no.nav.testnav.oppdragservice; import org.junit.jupiter.api.Test; import org.springframework.boot.test.context.SpringBootTest; diff --git a/libs/data-transfer-objects/src/main/java/no/nav/testnav/libs/dto/oppdragservice/v1/OppdragRequest.java b/libs/data-transfer-objects/src/main/java/no/nav/testnav/libs/dto/oppdragservice/v1/OppdragRequest.java index 3ce9e2f8039..7643dd4e942 100644 --- a/libs/data-transfer-objects/src/main/java/no/nav/testnav/libs/dto/oppdragservice/v1/OppdragRequest.java +++ b/libs/data-transfer-objects/src/main/java/no/nav/testnav/libs/dto/oppdragservice/v1/OppdragRequest.java @@ -8,6 +8,5 @@ @Data @Builder @NoArgsConstructor -@AllArgsConstructor public class OppdragRequest { } From 03b7b165f573d97adac11fb68a5b0256f1969c5b Mon Sep 17 00:00:00 2001 From: "Kristen.Herum" Date: Tue, 15 Oct 2024 10:18:39 +0200 Subject: [PATCH 05/35] Add Oppdrag service layer implementation Introduce OppdragService with a method to handle OppdragRequest and return SendInnOppdragResponse. Also, update OppdragController to integrate with the new service layer and manage incoming requests accordingly. --- .../provider/OppdragController.java | 12 +- .../service/OppdragService.java | 14 + .../dto/oppdragservice/v1/OppdragRequest.java | 342 ++++++++++++++++++ 3 files changed, 367 insertions(+), 1 deletion(-) create mode 100644 apps/oppdrag-service/src/main/java/no/nav/testnav/oppdragservice/service/OppdragService.java diff --git a/apps/oppdrag-service/src/main/java/no/nav/testnav/oppdragservice/provider/OppdragController.java b/apps/oppdrag-service/src/main/java/no/nav/testnav/oppdragservice/provider/OppdragController.java index 3b1a068229f..c99046120b8 100644 --- a/apps/oppdrag-service/src/main/java/no/nav/testnav/oppdragservice/provider/OppdragController.java +++ b/apps/oppdrag-service/src/main/java/no/nav/testnav/oppdragservice/provider/OppdragController.java @@ -1,13 +1,23 @@ package no.nav.testnav.oppdragservice.provider; +import lombok.RequiredArgsConstructor; +import no.nav.testnav.libs.dto.oppdragservice.v1.OppdragRequest; +import no.nav.testnav.oppdragservice.service.OppdragService; +import no.nav.testnav.oppdragservice.wsdl.SendInnOppdragResponse; import org.springframework.web.bind.annotation.PostMapping; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RestController; @RestController @RequestMapping("/api/v1/oppdrag") +@RequiredArgsConstructor public class OppdragController { + private final OppdragService oppdragService; + @PostMapping - public void sendOppdrag() {} + public SendInnOppdragResponse sendInnOppdrag(OppdragRequest oppdragRequest) { + + return oppdragService.sendInnOppdrag(oppdragRequest); + } } diff --git a/apps/oppdrag-service/src/main/java/no/nav/testnav/oppdragservice/service/OppdragService.java b/apps/oppdrag-service/src/main/java/no/nav/testnav/oppdragservice/service/OppdragService.java new file mode 100644 index 00000000000..0991380b21a --- /dev/null +++ b/apps/oppdrag-service/src/main/java/no/nav/testnav/oppdragservice/service/OppdragService.java @@ -0,0 +1,14 @@ +package no.nav.testnav.oppdragservice.service; + +import no.nav.testnav.libs.dto.oppdragservice.v1.OppdragRequest; +import no.nav.testnav.oppdragservice.wsdl.SendInnOppdragResponse; +import org.springframework.stereotype.Service; + +@Service +public class OppdragService { + + public SendInnOppdragResponse sendInnOppdrag(OppdragRequest oppdragRequest) { + + + } +} diff --git a/libs/data-transfer-objects/src/main/java/no/nav/testnav/libs/dto/oppdragservice/v1/OppdragRequest.java b/libs/data-transfer-objects/src/main/java/no/nav/testnav/libs/dto/oppdragservice/v1/OppdragRequest.java index 7643dd4e942..56edb93735a 100644 --- a/libs/data-transfer-objects/src/main/java/no/nav/testnav/libs/dto/oppdragservice/v1/OppdragRequest.java +++ b/libs/data-transfer-objects/src/main/java/no/nav/testnav/libs/dto/oppdragservice/v1/OppdragRequest.java @@ -1,12 +1,354 @@ package no.nav.testnav.libs.dto.oppdragservice.v1; +import io.swagger.v3.oas.annotations.media.Schema; +import jakarta.validation.constraints.NotBlank; +import jakarta.validation.constraints.Size; import lombok.AllArgsConstructor; import lombok.Builder; import lombok.Data; import lombok.NoArgsConstructor; +import java.math.BigDecimal; +import java.math.BigInteger; +import java.time.LocalDate; +import java.util.ArrayList; +import java.util.List; + +import static java.util.Objects.isNull; + @Data @Builder @NoArgsConstructor +@AllArgsConstructor public class OppdragRequest { + + @Size(min = 1, max = 4) + private List bilagstype; + private List avstemmingsnokkel; + private Ompostering ompostering; + private List oppdragslinje; + @NotBlank + private String kodeEndring; + private KodeStatus kodeStatus; + private String datoStatusFom; + @NotBlank + private String kodeFagomraade; + private String fagsystemId; + private Long oppdragsId; + private String utbetFrekvens; + private String datoForfall; + private String stonadId; + @NotBlank + @Size(min = 9, max = 11) + @Schema(description = "Fødselsnummer eller organisasjonsnummer oppdraget gjelder for") + private String oppdragGjelderId; + @NotBlank + private String datoOppdragGjelderFom; + @NotBlank + private String saksbehId; + private List enhet; + private List belopsgrense; + private List tekst; + + public List getBilagstype() { + + if (isNull(bilagstype)) { + bilagstype = new ArrayList<>(); + } + return bilagstype; + } + + public List getAvstemmingsnokkel() { + + if (isNull(avstemmingsnokkel)) { + avstemmingsnokkel = new ArrayList<>(); + } + return avstemmingsnokkel; + } + + public List getOppdragslinje() { + + if (isNull(oppdragslinje)) { + oppdragslinje = new ArrayList<>(); + } + return oppdragslinje; + } + + public List getEnhet() { + + if (isNull(enhet)) { + enhet = new ArrayList<>(); + } + return enhet; + } + + public List getBelopsgrense() { + + if (isNull(belopsgrense)) { + belopsgrense = new ArrayList<>(); + } + return belopsgrense; + } + + public List getTekst() { + + if (isNull(tekst)) { + tekst = new ArrayList<>(); + } + return tekst; + } + + @Data + @Builder + @NoArgsConstructor + @AllArgsConstructor + public static class Avstemmingsnokkel { + + @NotBlank + private String kodeKomponent; + @NotBlank + private String avstemmingsNokkel; + @NotBlank + private String tidspktReg; + } + + @Data + @Builder + @NoArgsConstructor + @AllArgsConstructor + public static class Ompostering { + + @NotBlank + private String omPostering; + private String datoOmposterFom; + private String feilreg; + @NotBlank + private String tidspktReg; + @NotBlank + private String saksbehId; + } + + @Data + @Builder + @NoArgsConstructor + @AllArgsConstructor + public static class Oppdragslinje { + + private RefusjonsInfo refusjonsInfo; + private List tekst; + @Schema(description = "Fra XSD: Referanse ID 120 dersom enhet på nivå oppdrag og " + + "Referanse ID 160 dersom enhet på nivå oppdragslinje") + private List enhet; + private List grad; + private List attestant; + private List valuta; + @NotBlank + private String kodeEndringLinje; + private KodeStatusLinje kodeStatusLinje; + private LocalDate datoStatusFom; + private String vedtakId; + private String delytelseId; + private BigInteger linjeId; + @NotBlank + private String kodeKlassifik; + private String datoKlassifikFom; + @NotBlank + private LocalDate datoVedtakFom; + private LocalDate datoVedtakTom; + @NotBlank + private BigDecimal sats; + @NotBlank + private FradragTillegg fradragTillegg; + @NotBlank + private String typeSats; + private String skyldnerId; + private LocalDate datoSkyldnerFom; + private String kravhaverId; + private LocalDate datoKravhaverFom; + private String kid; + private LocalDate datoKidFom; + private String brukKjoreplan; + @NotBlank + private String saksbehId; + @NotBlank + private String utbetalesTilId; + private LocalDate datoUtbetalesTilIdFom; + @NotBlank + private KodeArbeidsgiver kodeArbeidsgiver; + private String henvisning; + private String typeSoknad; + private String refFagsystemId; + private Long refOppdragsId; + private String refDelytelseId; + private BigInteger refLinjeId; + + public List getTekst() { + + if (isNull(tekst)) { + tekst = new ArrayList<>(); + } + return tekst; + } + + public List getEnhet() { + + if (isNull(enhet)) { + enhet = new ArrayList<>(); + } + return enhet; + } + + public List getGrad() { + + if (isNull(grad)) { + grad = new ArrayList<>(); + } + return grad; + } + + public List getAttestant() { + + if (isNull(attestant)) { + attestant = new ArrayList<>(); + } + return attestant; + } + + public List getValuta() { + + if (isNull(valuta)) { + valuta = new ArrayList<>(); + } + return valuta; + } + } + + @Data + @Builder + @NoArgsConstructor + @AllArgsConstructor + public static class RefusjonsInfo { + + private String refunderesId; + private LocalDate maksDato; + private LocalDate datoFom; + } + + @Data + @Builder + @NoArgsConstructor + @AllArgsConstructor + public static class Tekst { + + private BigInteger tekstLnr; + private String tekstKode; + private String tekst; + @NotBlank + private LocalDate datoTekstFom; + private LocalDate datoTekstTom; + private String feilreg; + } + + @Data + @Builder + @NoArgsConstructor + @AllArgsConstructor + public static class Enhet { + + @NotBlank + @Size(min = 1, max = 4) + private String typeEnhet; + @Size(min = 4, max = 13) + @Schema(description = "Enhet er tknr evt orgnr + avdeling") + private String enhet; + @NotBlank + private LocalDate datoEnhetFom; + } + + @Data + @Builder + @NoArgsConstructor + @AllArgsConstructor + public static class Grad { + + @NotBlank + protected String typeGrad; + @NotBlank + protected BigInteger grad; + } + + @Data + @Builder + @NoArgsConstructor + @AllArgsConstructor + public static class Attestant { + + @NotBlank + protected String attestantId; + protected LocalDate datoUgyldigFom; + } + + @Data + @Builder + @NoArgsConstructor + @AllArgsConstructor + public static class Valuta { + + @NotBlank + protected String typeValuta; + @NotBlank + protected String valuta; + @NotBlank + protected LocalDate datoValutaFom; + protected String feilreg; + } + + public enum KodeStatusLinje { + OPPH, + HVIL, + SPER, + REAK; + } + + public enum FradragTillegg { + F, + T; + } + + public enum KodeArbeidsgiver { + A, + S, + P; + } + + public enum KodeStatus { + NY, + LOPE, + HVIL, + SPER, + IKAT, + ATTE, + ANNU, + OPPH, + FBER, + REAK, + KORR, + FEIL; + } + + @Data + @Builder + @NoArgsConstructor + @AllArgsConstructor + public static class Belopsgrense { + + @NotBlank + private String typeGrense; + @NotBlank + private BigDecimal belopGrense; + @NotBlank + private LocalDate datoGrenseFom; + private LocalDate datoGrenseTom; + private String feilreg; + } } From 21b3d9bea88123df77e0e040fe9b0871daef62f9 Mon Sep 17 00:00:00 2001 From: "Kristen.Herum" Date: Tue, 15 Oct 2024 13:41:13 +0200 Subject: [PATCH 06/35] Refactor OppdragRequest: Change String to KodeEndring enum Changed the type of `kodeEndring` from String to a new KodeEndring enum to improve type safety and reduce potential errors. Introduced the new KodeEndring enum with values NY, ENDR, and UEND. --- .../libs/dto/oppdragservice/v1/OppdragRequest.java | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/libs/data-transfer-objects/src/main/java/no/nav/testnav/libs/dto/oppdragservice/v1/OppdragRequest.java b/libs/data-transfer-objects/src/main/java/no/nav/testnav/libs/dto/oppdragservice/v1/OppdragRequest.java index 56edb93735a..09a973c7f3d 100644 --- a/libs/data-transfer-objects/src/main/java/no/nav/testnav/libs/dto/oppdragservice/v1/OppdragRequest.java +++ b/libs/data-transfer-objects/src/main/java/no/nav/testnav/libs/dto/oppdragservice/v1/OppdragRequest.java @@ -28,7 +28,7 @@ public class OppdragRequest { private Ompostering ompostering; private List oppdragslinje; @NotBlank - private String kodeEndring; + private KodeEndring kodeEndring; private KodeStatus kodeStatus; private String datoStatusFom; @NotBlank @@ -336,6 +336,12 @@ public enum KodeStatus { FEIL; } + public enum KodeEndring { + NY, + ENDR, + UEND + } + @Data @Builder @NoArgsConstructor From bd567a1a38f341877ea5a77e802fc21eeb8f0d44 Mon Sep 17 00:00:00 2001 From: "Kristen.Herum" Date: Wed, 30 Oct 2024 13:48:54 +0100 Subject: [PATCH 07/35] Add mapping strategy and Swagger adjustments Implemented a MapperFacade configuration to handle custom mapping strategies and converters. Improved Swagger setup by refining security configurations and customizing views. Enhanced OppdragRequest DTO with additional schema information and data types for better validation and XML support. Additionally, added basic unit tests for mapping strategies and updated dependencies in the build configuration. --- apps/oppdrag-service/build.gradle | 30 ++--- apps/oppdrag-service/settings.gradle | 3 +- .../config/ApplicationConfig.java | 3 +- .../config/MapperFacadeConfig.java | 36 ++++++ .../oppdragservice/config/OpenApiConfig.java | 28 ++-- .../oppdragservice/config/SecurityConfig.java | 23 ++-- .../consumer/OppdragConsumer.java | 4 + .../mapper/MappingStrategy.java | 19 +++ .../mapper/OppdragRequestMappingStrategy.java | 43 ++++++ .../provider/OppdragController.java | 5 +- .../service/OppdragService.java | 34 ++++- .../mapper/MapperTestUtils.java | 27 ++++ .../OppdragRequestMappingStrategyTest.java | 52 ++++++++ .../dto/oppdragservice/v1/OppdragRequest.java | 122 ++++++++++++++---- 14 files changed, 345 insertions(+), 84 deletions(-) create mode 100644 apps/oppdrag-service/src/main/java/no/nav/testnav/oppdragservice/config/MapperFacadeConfig.java create mode 100644 apps/oppdrag-service/src/main/java/no/nav/testnav/oppdragservice/mapper/MappingStrategy.java create mode 100644 apps/oppdrag-service/src/main/java/no/nav/testnav/oppdragservice/mapper/OppdragRequestMappingStrategy.java create mode 100644 apps/oppdrag-service/src/test/java/no/nav/testnav/oppdragservice/mapper/MapperTestUtils.java create mode 100644 apps/oppdrag-service/src/test/java/no/nav/testnav/oppdragservice/mapper/OppdragRequestMappingStrategyTest.java diff --git a/apps/oppdrag-service/build.gradle b/apps/oppdrag-service/build.gradle index 1c26638be91..deb6b04c7fa 100644 --- a/apps/oppdrag-service/build.gradle +++ b/apps/oppdrag-service/build.gradle @@ -68,28 +68,18 @@ dependencies { 'jakarta.activation:jakarta.activation-api:2.0.0', 'com.sun.xml.ws:jaxws-rt:3.0.0' - implementation 'no.nav.testnav.libs:security-core' - implementation 'no.nav.testnav.libs:servlet-core' - implementation 'no.nav.testnav.libs:servlet-security' - implementation 'no.nav.testnav.libs:data-transfer-objects' + implementation "no.nav.testnav.libs:data-transfer-objects" + implementation "no.nav.testnav.libs:servlet-core" + implementation "no.nav.testnav.libs:servlet-security" implementation "no.nav.testnav.libs:vault" - implementation 'org.springframework.cloud:spring-cloud-starter-vault-config' + implementation "org.springframework.boot:spring-boot-starter-web" + implementation "org.springframework.boot:spring-boot-starter-security" + implementation "org.springframework.boot:spring-boot-starter-oauth2-client" + implementation "org.springframework.boot:spring-boot-starter-web-services" - implementation 'net.logstash.logback:logstash-logback-encoder:7.4' + implementation "org.springdoc:springdoc-openapi-starter-webmvc-ui:$versions.springdoc" + implementation "io.swagger.core.v3:swagger-annotations-jakarta:$versions.swagger" - implementation 'org.springdoc:springdoc-openapi-starter-webflux-ui:2.3.0' - implementation 'io.swagger.core.v3:swagger-annotations-jakarta:2.2.20' - implementation 'org.springframework.boot:spring-boot-starter-oauth2-client' - implementation 'org.springframework.boot:spring-boot-starter-security' - implementation 'org.springframework.boot:spring-boot-starter-validation' - implementation 'org.springframework.boot:spring-boot-starter-web' - implementation 'org.springframework.boot:spring-boot-starter-web-services' - implementation 'org.springframework.ws:spring-ws-security' - - implementation 'ma.glasnost.orika:orika-core:1.5.4' - annotationProcessor 'org.projectlombok:lombok' - implementation 'org.projectlombok:lombok' - - testImplementation 'org.springframework.boot:spring-boot-starter-test' + implementation "ma.glasnost.orika:orika-core:$versions.orika" } \ No newline at end of file diff --git a/apps/oppdrag-service/settings.gradle b/apps/oppdrag-service/settings.gradle index 904d9306913..1b54dd50812 100644 --- a/apps/oppdrag-service/settings.gradle +++ b/apps/oppdrag-service/settings.gradle @@ -4,10 +4,9 @@ plugins { rootProject.name = 'oppdrag-service' -includeBuild '../../libs/security-core' +includeBuild '../../libs/data-transfer-objects' includeBuild '../../libs/servlet-core' includeBuild '../../libs/servlet-security' -includeBuild '../../libs/data-transfer-objects' includeBuild '../../libs/vault' gradleEnterprise { diff --git a/apps/oppdrag-service/src/main/java/no/nav/testnav/oppdragservice/config/ApplicationConfig.java b/apps/oppdrag-service/src/main/java/no/nav/testnav/oppdragservice/config/ApplicationConfig.java index fa45e6cc921..b99613d9c20 100644 --- a/apps/oppdrag-service/src/main/java/no/nav/testnav/oppdragservice/config/ApplicationConfig.java +++ b/apps/oppdrag-service/src/main/java/no/nav/testnav/oppdragservice/config/ApplicationConfig.java @@ -6,8 +6,7 @@ import org.springframework.context.annotation.Import; @Configuration -@Import({ - ApplicationCoreConfig.class, +@Import({ApplicationCoreConfig.class, SecureOAuth2ServerToServerConfiguration.class }) public class ApplicationConfig { diff --git a/apps/oppdrag-service/src/main/java/no/nav/testnav/oppdragservice/config/MapperFacadeConfig.java b/apps/oppdrag-service/src/main/java/no/nav/testnav/oppdragservice/config/MapperFacadeConfig.java new file mode 100644 index 00000000000..8008cd59231 --- /dev/null +++ b/apps/oppdrag-service/src/main/java/no/nav/testnav/oppdragservice/config/MapperFacadeConfig.java @@ -0,0 +1,36 @@ +package no.nav.testnav.oppdragservice.config; + +import ma.glasnost.orika.CustomConverter; +import ma.glasnost.orika.MapperFacade; +import ma.glasnost.orika.impl.DefaultMapperFactory; +import no.nav.testnav.oppdragservice.mapper.MappingStrategy; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; + +import java.util.List; + +import static java.util.Objects.nonNull; + +@Configuration +@SuppressWarnings("java:S3740") +public class MapperFacadeConfig { + + @Bean + MapperFacade mapperFacade(List mappingStrategies, List customConverters) { + var mapperFactory = new DefaultMapperFactory.Builder().build(); + + if (nonNull(mappingStrategies)) { + for (var mapper : mappingStrategies) { + mapper.register(mapperFactory); + } + } + + if (nonNull(customConverters)) { + for (var converter : customConverters) { + mapperFactory.getConverterFactory().registerConverter(converter); + } + } + + return mapperFactory.getMapperFacade(); + } +} \ No newline at end of file diff --git a/apps/oppdrag-service/src/main/java/no/nav/testnav/oppdragservice/config/OpenApiConfig.java b/apps/oppdrag-service/src/main/java/no/nav/testnav/oppdragservice/config/OpenApiConfig.java index 22e439651d1..c5962d905d9 100644 --- a/apps/oppdrag-service/src/main/java/no/nav/testnav/oppdragservice/config/OpenApiConfig.java +++ b/apps/oppdrag-service/src/main/java/no/nav/testnav/oppdragservice/config/OpenApiConfig.java @@ -10,16 +10,15 @@ import no.nav.testnav.libs.servletcore.config.ApplicationProperties; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; -import org.springframework.http.HttpHeaders; -import org.springframework.web.server.ServerWebExchange; -import org.springframework.web.server.WebFilter; -import org.springframework.web.server.WebFilterChain; -import reactor.core.publisher.Mono; +import org.springframework.context.annotation.Import; +import org.springframework.web.servlet.config.annotation.ViewControllerRegistry; +import org.springframework.web.servlet.config.annotation.WebMvcConfigurer; import java.util.Arrays; @Configuration -public class OpenApiConfig implements WebFilter { +@Import(ApplicationProperties.class) +public class OpenApiConfig implements WebMvcConfigurer { @Bean public OpenAPI openApi(ApplicationProperties applicationProperties) { @@ -29,7 +28,7 @@ public OpenAPI openApi(ApplicationProperties applicationProperties) { .scheme("bearer") .bearerFormat("JWT") .in(SecurityScheme.In.HEADER) - .name(HttpHeaders.AUTHORIZATION) + .name("Authorization") )) .addSecurityItem( new SecurityRequirement().addList("bearer-jwt", Arrays.asList("read", "write"))) @@ -46,20 +45,11 @@ public OpenAPI openApi(ApplicationProperties applicationProperties) { .license(new License() .name("MIT License") .url("https://opensource.org/licenses/MIT") - ) - ); + )); } @Override - public Mono filter(ServerWebExchange exchange, WebFilterChain chain) { - if (exchange.getRequest().getURI().getPath().equals("/swagger")) { - return chain - .filter(exchange.mutate() - .request(exchange.getRequest() - .mutate().path("/swagger-ui.html").build()) - .build()); - } - - return chain.filter(exchange); + public void addViewControllers(ViewControllerRegistry registry) { + registry.addViewController("/swagger").setViewName("redirect:/swagger-ui.html"); } } \ No newline at end of file diff --git a/apps/oppdrag-service/src/main/java/no/nav/testnav/oppdragservice/config/SecurityConfig.java b/apps/oppdrag-service/src/main/java/no/nav/testnav/oppdragservice/config/SecurityConfig.java index 718c433a892..28452a02141 100644 --- a/apps/oppdrag-service/src/main/java/no/nav/testnav/oppdragservice/config/SecurityConfig.java +++ b/apps/oppdrag-service/src/main/java/no/nav/testnav/oppdragservice/config/SecurityConfig.java @@ -2,36 +2,31 @@ import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; -import org.springframework.context.annotation.Profile; import org.springframework.security.config.Customizer; import org.springframework.security.config.annotation.web.builders.HttpSecurity; import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity; import org.springframework.security.config.annotation.web.configurers.AbstractHttpConfigurer; import org.springframework.security.config.http.SessionCreationPolicy; import org.springframework.security.web.SecurityFilterChain; +import org.springframework.security.web.servlet.util.matcher.MvcRequestMatcher; +import org.springframework.web.servlet.handler.HandlerMappingIntrospector; @EnableWebSecurity @Configuration -@Profile({"prod", "dev"}) public class SecurityConfig { @Bean - public SecurityFilterChain filterChain(HttpSecurity httpSecurity) throws Exception { + public SecurityFilterChain filterChain(HttpSecurity httpSecurity, HandlerMappingIntrospector introspector) throws Exception { + + MvcRequestMatcher.Builder mvcMatcherBuilder = new MvcRequestMatcher.Builder(introspector); httpSecurity.sessionManagement(sessionConfig -> sessionConfig.sessionCreationPolicy(SessionCreationPolicy.STATELESS)) .csrf(AbstractHttpConfigurer::disable) - .authorizeHttpRequests(authorizeConfig -> authorizeConfig.requestMatchers( - "/internal/**", - "/webjars/**", - "/swagger-resources/**", - "/v3/api-docs/**", - "/swagger-ui/**", - "/swagger", - "/error", - "/swagger-ui.html" - ).permitAll().requestMatchers("/api/**").fullyAuthenticated()) + .authorizeHttpRequests(authorizeConfig -> authorizeConfig + .requestMatchers(mvcMatcherBuilder.pattern("/api/**")).fullyAuthenticated() + .anyRequest().permitAll()) .oauth2ResourceServer(oauth2RSConfig -> oauth2RSConfig.jwt(Customizer.withDefaults())); return httpSecurity.build(); } -} +} \ No newline at end of file diff --git a/apps/oppdrag-service/src/main/java/no/nav/testnav/oppdragservice/consumer/OppdragConsumer.java b/apps/oppdrag-service/src/main/java/no/nav/testnav/oppdragservice/consumer/OppdragConsumer.java index 54e01dc005b..67cfde505c6 100644 --- a/apps/oppdrag-service/src/main/java/no/nav/testnav/oppdragservice/consumer/OppdragConsumer.java +++ b/apps/oppdrag-service/src/main/java/no/nav/testnav/oppdragservice/consumer/OppdragConsumer.java @@ -4,4 +4,8 @@ @Service public class OppdragConsumer { + + public void sendOppdrag(String xmlPayload) { + + } } diff --git a/apps/oppdrag-service/src/main/java/no/nav/testnav/oppdragservice/mapper/MappingStrategy.java b/apps/oppdrag-service/src/main/java/no/nav/testnav/oppdragservice/mapper/MappingStrategy.java new file mode 100644 index 00000000000..fb400014104 --- /dev/null +++ b/apps/oppdrag-service/src/main/java/no/nav/testnav/oppdragservice/mapper/MappingStrategy.java @@ -0,0 +1,19 @@ +package no.nav.testnav.oppdragservice.mapper; + +import ma.glasnost.orika.MapperFactory; + +@FunctionalInterface +public interface MappingStrategy { + + /** + * A callback for registering criteria on the provided {@link MapperFactory}. + *

+ *

{@code
+     *
+     * @Override public void register(MapperFactory factory) {
+     * factory.registerMapper(arbeidsfordelingToRestArbeidsfordeling());
+     * }
+     * }
+ */ + void register(MapperFactory factory); +} diff --git a/apps/oppdrag-service/src/main/java/no/nav/testnav/oppdragservice/mapper/OppdragRequestMappingStrategy.java b/apps/oppdrag-service/src/main/java/no/nav/testnav/oppdragservice/mapper/OppdragRequestMappingStrategy.java new file mode 100644 index 00000000000..f03eff9b29a --- /dev/null +++ b/apps/oppdrag-service/src/main/java/no/nav/testnav/oppdragservice/mapper/OppdragRequestMappingStrategy.java @@ -0,0 +1,43 @@ +package no.nav.testnav.oppdragservice.mapper; + +import ma.glasnost.orika.CustomMapper; +import ma.glasnost.orika.MapperFactory; +import ma.glasnost.orika.MappingContext; +import no.nav.testnav.libs.dto.oppdragservice.v1.OppdragRequest; +import no.nav.testnav.oppdragservice.wsdl.Oppdrag; +import no.nav.testnav.oppdragservice.wsdl.SendInnOppdragRequest; +import no.nav.testnav.oppdragservice.wsdl.SendInnOppdragRequest2; +import org.springframework.stereotype.Component; + +@Component +public class OppdragRequestMappingStrategy implements MappingStrategy{ + + @Override + public void register(MapperFactory factory) { + + factory.classMap(OppdragRequest.class, SendInnOppdragRequest.class) + .customize(new CustomMapper<>() { + @Override + public void mapAtoB(OppdragRequest source, + SendInnOppdragRequest destination, + MappingContext context) { + + destination.setRequest(mapperFacade.map(source, SendInnOppdragRequest2.class, context)); + } + }) + .register(); + + factory.classMap(OppdragRequest.class, Oppdrag.class) + .customize(new CustomMapper<>() { + @Override + public void mapAtoB(OppdragRequest source, + Oppdrag destination, + MappingContext context) { + + + } + }) + .byDefault() + .register(); + } +} diff --git a/apps/oppdrag-service/src/main/java/no/nav/testnav/oppdragservice/provider/OppdragController.java b/apps/oppdrag-service/src/main/java/no/nav/testnav/oppdragservice/provider/OppdragController.java index c99046120b8..4a7697437fd 100644 --- a/apps/oppdrag-service/src/main/java/no/nav/testnav/oppdragservice/provider/OppdragController.java +++ b/apps/oppdrag-service/src/main/java/no/nav/testnav/oppdragservice/provider/OppdragController.java @@ -1,10 +1,12 @@ package no.nav.testnav.oppdragservice.provider; +import io.swagger.v3.oas.annotations.Operation; import lombok.RequiredArgsConstructor; import no.nav.testnav.libs.dto.oppdragservice.v1.OppdragRequest; import no.nav.testnav.oppdragservice.service.OppdragService; import no.nav.testnav.oppdragservice.wsdl.SendInnOppdragResponse; import org.springframework.web.bind.annotation.PostMapping; +import org.springframework.web.bind.annotation.RequestBody; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RestController; @@ -16,7 +18,8 @@ public class OppdragController { private final OppdragService oppdragService; @PostMapping - public SendInnOppdragResponse sendInnOppdrag(OppdragRequest oppdragRequest) { + @Operation(summary = "Send inn oppdrag") + public SendInnOppdragResponse sendInnOppdrag(@RequestBody OppdragRequest oppdragRequest) { return oppdragService.sendInnOppdrag(oppdragRequest); } diff --git a/apps/oppdrag-service/src/main/java/no/nav/testnav/oppdragservice/service/OppdragService.java b/apps/oppdrag-service/src/main/java/no/nav/testnav/oppdragservice/service/OppdragService.java index 0991380b21a..109fba28866 100644 --- a/apps/oppdrag-service/src/main/java/no/nav/testnav/oppdragservice/service/OppdragService.java +++ b/apps/oppdrag-service/src/main/java/no/nav/testnav/oppdragservice/service/OppdragService.java @@ -1,14 +1,46 @@ package no.nav.testnav.oppdragservice.service; +import jakarta.xml.bind.JAXBContext; +import jakarta.xml.bind.JAXBException; +import lombok.SneakyThrows; +import ma.glasnost.orika.MapperFacade; import no.nav.testnav.libs.dto.oppdragservice.v1.OppdragRequest; +import no.nav.testnav.oppdragservice.consumer.OppdragConsumer; +import no.nav.testnav.oppdragservice.wsdl.SendInnOppdragRequest; import no.nav.testnav.oppdragservice.wsdl.SendInnOppdragResponse; import org.springframework.stereotype.Service; +import java.io.StringWriter; + @Service public class OppdragService { + private final JAXBContext jaxbContext; + private final OppdragConsumer oppdragConsumer; + private final MapperFacade mapperFacade; + + public OppdragService(OppdragConsumer oppdragConsumer, MapperFacade mapperFacade) throws JAXBException { + this.oppdragConsumer = oppdragConsumer; + this.mapperFacade = mapperFacade; + this.jaxbContext = JAXBContext.newInstance(SendInnOppdragRequest.class); + } + public SendInnOppdragResponse sendInnOppdrag(OppdragRequest oppdragRequest) { + var request = mapperFacade.map(oppdragRequest, SendInnOppdragRequest.class); + var xmlRequest = marshallToXml(request); + + oppdragConsumer.sendOppdrag(xmlRequest); + return null; + } + + @SneakyThrows + private String marshallToXml(SendInnOppdragRequest melding) { + + var marshaller = jaxbContext.createMarshaller(); + var writer = new StringWriter(); + marshaller.marshal(melding, writer); + return writer.toString(); } -} +} \ No newline at end of file diff --git a/apps/oppdrag-service/src/test/java/no/nav/testnav/oppdragservice/mapper/MapperTestUtils.java b/apps/oppdrag-service/src/test/java/no/nav/testnav/oppdragservice/mapper/MapperTestUtils.java new file mode 100644 index 00000000000..75c1e65a947 --- /dev/null +++ b/apps/oppdrag-service/src/test/java/no/nav/testnav/oppdragservice/mapper/MapperTestUtils.java @@ -0,0 +1,27 @@ +package no.nav.testnav.oppdragservice.mapper; + +import ma.glasnost.orika.CustomConverter; +import ma.glasnost.orika.MapperFacade; +import ma.glasnost.orika.impl.DefaultMapperFactory; + +import static java.util.Objects.nonNull; + +public class MapperTestUtils { + + public static MapperFacade createMapperFacadeForMappingStrategy(MappingStrategy... strategies) { + return createMapperFacadeForMappingStrategy(null, strategies); + } + + public static MapperFacade createMapperFacadeForMappingStrategy(CustomConverter converter, MappingStrategy... strategies) { + DefaultMapperFactory mapperFactory = new DefaultMapperFactory.Builder().build(); + + for (MappingStrategy strategy : strategies) { + strategy.register(mapperFactory); + } + + if (nonNull(converter)) { + mapperFactory.getConverterFactory().registerConverter(converter); + } + return mapperFactory.getMapperFacade(); + } +} \ No newline at end of file diff --git a/apps/oppdrag-service/src/test/java/no/nav/testnav/oppdragservice/mapper/OppdragRequestMappingStrategyTest.java b/apps/oppdrag-service/src/test/java/no/nav/testnav/oppdragservice/mapper/OppdragRequestMappingStrategyTest.java new file mode 100644 index 00000000000..d96c6b711b5 --- /dev/null +++ b/apps/oppdrag-service/src/test/java/no/nav/testnav/oppdragservice/mapper/OppdragRequestMappingStrategyTest.java @@ -0,0 +1,52 @@ +package no.nav.testnav.oppdragservice.mapper; + +import ma.glasnost.orika.MapperFacade; +import no.nav.testnav.libs.dto.oppdragservice.v1.OppdragRequest; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.ExtendWith; +import org.mockito.junit.jupiter.MockitoExtension; + +import java.util.List; + +@ExtendWith(MockitoExtension.class) +class OppdragRequestMappingStrategyTest { + + private MapperFacade mapperFacade; + + @BeforeEach + void setup() { + mapperFacade = MapperTestUtils.createMapperFacadeForMappingStrategy(new OppdragRequestMappingStrategy()); + } + + @Test + void mapOrdreOK() { + +// mapperFacade.map() + } + + private static OppdragRequest buildOppdragRequest() { + + return OppdragRequest.builder() + .bilagstype(List.of(OppdragRequest.Bilagstype.builder().typeBilag("12").build())) +// .avstemmingsnokkel() +// .ompostering() +// .oppdragslinje() +// .kodeEndring() +// .kodeStatus() +// .datoStatusFom() +// .kodeFagomraade() +// .fagsystemId() +// .oppdragsId() +// .utbetFrekvens() +// .datoForfall() +// .stonadId() +// .oppdragGjelderId() +// .datoOppdragGjelderFom() +// .saksbehId() +// .enhet() +// .belopsgrense() +// .tekst() + .build(); + } +} \ No newline at end of file diff --git a/libs/data-transfer-objects/src/main/java/no/nav/testnav/libs/dto/oppdragservice/v1/OppdragRequest.java b/libs/data-transfer-objects/src/main/java/no/nav/testnav/libs/dto/oppdragservice/v1/OppdragRequest.java index 09a973c7f3d..52afa4e35f4 100644 --- a/libs/data-transfer-objects/src/main/java/no/nav/testnav/libs/dto/oppdragservice/v1/OppdragRequest.java +++ b/libs/data-transfer-objects/src/main/java/no/nav/testnav/libs/dto/oppdragservice/v1/OppdragRequest.java @@ -11,6 +11,7 @@ import java.math.BigDecimal; import java.math.BigInteger; import java.time.LocalDate; +import java.time.LocalDateTime; import java.util.ArrayList; import java.util.List; @@ -20,37 +21,43 @@ @Builder @NoArgsConstructor @AllArgsConstructor +@Schema(description = "Entitet Oppdrag, Referanse ID 110") public class OppdragRequest { - @Size(min = 1, max = 4) - private List bilagstype; + private List bilagstype; private List avstemmingsnokkel; private Ompostering ompostering; private List oppdragslinje; + @NotBlank private KodeEndring kodeEndring; private KodeStatus kodeStatus; private String datoStatusFom; @NotBlank + @Schema(minLength = 1, maxLength = 8) private String kodeFagomraade; + @Schema(maxLength = 30) private String fagsystemId; + @Schema(maxLength = 10) private Long oppdragsId; - private String utbetFrekvens; - private String datoForfall; + private UtbetalingFrekvensType utbetFrekvens; + private LocalDate datoForfall; + @Schema(maxLength = 10) private String stonadId; @NotBlank - @Size(min = 9, max = 11) - @Schema(description = "Fødselsnummer eller organisasjonsnummer oppdraget gjelder for") + @Schema(description = "Angir fødselsnummer eller organisasjonsnummer oppdraget gjelder for", minLength = 9, maxLength = 11) private String oppdragGjelderId; @NotBlank - private String datoOppdragGjelderFom; + private LocalDate datoOppdragGjelderFom; @NotBlank + @Schema(maxLength = 8) private String saksbehId; + private List enhet; private List belopsgrense; private List tekst; - public List getBilagstype() { + public List getBilagstype() { if (isNull(bilagstype)) { bilagstype = new ArrayList<>(); @@ -102,29 +109,46 @@ public List getTekst() { @Builder @NoArgsConstructor @AllArgsConstructor + @Schema(description = "Bilagstype, Referanse ID 113") + public static class Bilagstype { + + @Schema(description = "Kode for type av bilag", minLength = 1, maxLength = 2) + private String typeBilag; + } + + @Data + @Builder + @NoArgsConstructor + @AllArgsConstructor + @Schema(description = "Entitet nøkler til bevis informasjon, Referanse ID 115") public static class Avstemmingsnokkel { @NotBlank + @Schema(minLength = 1, maxLength = 8) private String kodeKomponent; @NotBlank + @Schema(minLength = 1, maxLength = 8) private String avstemmingsNokkel; @NotBlank - private String tidspktReg; + private LocalDateTime tidspktReg; } @Data @Builder @NoArgsConstructor @AllArgsConstructor + @Schema(description = "Ompostering, Referanse ID 116") public static class Ompostering { @NotBlank - private String omPostering; - private String datoOmposterFom; + private JaNei omPostering; + private LocalDate datoOmposterFom; + @Schema(description = "Kode for beskrivelse av feil", minLength = 0, maxLength = 1) private String feilreg; @NotBlank - private String tidspktReg; + private LocalDateTime tidspktReg; @NotBlank + @Schema(maxLength = 8) private String saksbehId; } @@ -132,55 +156,73 @@ public static class Ompostering { @Builder @NoArgsConstructor @AllArgsConstructor + @Schema(description = "Oppdragslinje, Referanse ID 115") public static class Oppdragslinje { - private RefusjonsInfo refusjonsInfo; - private List tekst; - @Schema(description = "Fra XSD: Referanse ID 120 dersom enhet på nivå oppdrag og " + - "Referanse ID 160 dersom enhet på nivå oppdragslinje") - private List enhet; - private List grad; - private List attestant; - private List valuta; @NotBlank - private String kodeEndringLinje; + private KodeEndringType kodeEndringLinje; private KodeStatusLinje kodeStatusLinje; private LocalDate datoStatusFom; + @Schema(maxLength = 10) private String vedtakId; + @Schema(maxLength = 30) private String delytelseId; - private BigInteger linjeId; + @Schema(maxLength = 5) + private Integer linjeId; @NotBlank + @Schema(minLength = 1, maxLength = 50) private String kodeKlassifik; - private String datoKlassifikFom; + private LocalDate datoKlassifikFom; @NotBlank private LocalDate datoVedtakFom; private LocalDate datoVedtakTom; @NotBlank + @Schema(description = "maximal toal lengde = 13, antall desimaler = 2") private BigDecimal sats; @NotBlank private FradragTillegg fradragTillegg; @NotBlank - private String typeSats; + private SatsType typeSats; + @Schema(description = "Angir fødselsnummer eller organisasjonsnummer på skyldneren", minLength = 9, maxLength = 11) private String skyldnerId; private LocalDate datoSkyldnerFom; + @Schema(description = "Angir fødselsnummer eller organisasjonsnummer på kravhaver", minLength = 9, maxLength = 11) private String kravhaverId; private LocalDate datoKravhaverFom; + @Schema(maxLength = 26) private String kid; private LocalDate datoKidFom; + @Schema(maxLength = 1) private String brukKjoreplan; @NotBlank + @Schema(maxLength = 8) private String saksbehId; @NotBlank + @Schema(description = "Angir fødselsnummer eller organisasjonsnummer på kravhaver", minLength = 9, maxLength = 11) private String utbetalesTilId; private LocalDate datoUtbetalesTilIdFom; @NotBlank private KodeArbeidsgiver kodeArbeidsgiver; + @Schema(maxLength = 30) private String henvisning; + @Schema(maxLength = 10) private String typeSoknad; + @Schema(maxLength = 30) private String refFagsystemId; + @Schema(maxLength = 10) private Long refOppdragsId; + @Schema(maxLength = 30) private String refDelytelseId; - private BigInteger refLinjeId; + @Schema(maxLength = 5) + private Integer refLinjeId; + private RefusjonsInfo refusjonsInfo; + private List tekst; + @Schema(description = "Fra XSD: Referanse ID 120 dersom enhet på nivå oppdrag og " + + "Referanse ID 160 dersom enhet på nivå oppdragslinje") + private List enhet; + private List grad; + private List attestant; + private List valuta; public List getTekst() { @@ -303,6 +345,11 @@ public static class Valuta { protected String feilreg; } + public enum JaNei { + J, + N; + } + public enum KodeStatusLinje { OPPH, HVIL, @@ -342,6 +389,31 @@ public enum KodeEndring { UEND } + public enum KodeEndringType { + NY, + ENDR + } + + public enum SatsType { + + DAG, + UKE, + _14DB, + MND, + AAR, + ENG, + AKTO + } + + public enum UtbetalingFrekvensType { + + DAG, + UKE, + MND, + _14DG, + ENG + } + @Data @Builder @NoArgsConstructor From 83ee526da4b0e8713992ad4f8cdaa95201b06c19 Mon Sep 17 00:00:00 2001 From: "Kristen.Herum" Date: Wed, 30 Oct 2024 15:09:54 +0100 Subject: [PATCH 08/35] Enhance DTO schemas and validation Removed unnecessary import, added detailed `@Schema` descriptions, and improved validation constraints for multiple fields within the `OppdragRequest` class. Introduced `ValuteType` enum to streamline currency handling. --- .../dto/oppdragservice/v1/OppdragRequest.java | 51 +++++++++++++++---- 1 file changed, 40 insertions(+), 11 deletions(-) diff --git a/libs/data-transfer-objects/src/main/java/no/nav/testnav/libs/dto/oppdragservice/v1/OppdragRequest.java b/libs/data-transfer-objects/src/main/java/no/nav/testnav/libs/dto/oppdragservice/v1/OppdragRequest.java index 52afa4e35f4..ca82bf5708d 100644 --- a/libs/data-transfer-objects/src/main/java/no/nav/testnav/libs/dto/oppdragservice/v1/OppdragRequest.java +++ b/libs/data-transfer-objects/src/main/java/no/nav/testnav/libs/dto/oppdragservice/v1/OppdragRequest.java @@ -9,7 +9,6 @@ import lombok.NoArgsConstructor; import java.math.BigDecimal; -import java.math.BigInteger; import java.time.LocalDate; import java.time.LocalDateTime; import java.util.ArrayList; @@ -215,10 +214,10 @@ public static class Oppdragslinje { private String refDelytelseId; @Schema(maxLength = 5) private Integer refLinjeId; + private RefusjonsInfo refusjonsInfo; private List tekst; - @Schema(description = "Fra XSD: Referanse ID 120 dersom enhet på nivå oppdrag og " + - "Referanse ID 160 dersom enhet på nivå oppdragslinje") + private List enhet; private List grad; private List attestant; @@ -269,8 +268,10 @@ public List getValuta() { @Builder @NoArgsConstructor @AllArgsConstructor + @Schema(description = "Entitet for refusjon til et orgnr og/eller maksdato for utbetaling av ytelse, Referanse ID 156") public static class RefusjonsInfo { + @Schema(description = "Angir fødselsnummer eller organisasjonsnummer på kravhaver", minLength = 9, maxLength = 11) private String refunderesId; private LocalDate maksDato; private LocalDate datoFom; @@ -280,14 +281,21 @@ public static class RefusjonsInfo { @Builder @NoArgsConstructor @AllArgsConstructor + @Schema(description = "Entitet Tekst, Referanse ID 140 dersom tekst er tilhørende oppdrag, " + + "Referanse ID 158 dersom tekst er tilhørende oppdragslinje") public static class Tekst { - private BigInteger tekstLnr; + @NotBlank + @Schema(minLength = 1, maxLength = 2) + private Integer tekstLnr; + @Schema(maxLength = 4) private String tekstKode; + @Schema private String tekst; @NotBlank private LocalDate datoTekstFom; private LocalDate datoTekstTom; + @Schema(description = "Kode for beskrivelse av feil", minLength = 0, maxLength = 1) private String feilreg; } @@ -295,6 +303,8 @@ public static class Tekst { @Builder @NoArgsConstructor @AllArgsConstructor + @Schema(description = "Entitet enhet, Referanse ID 120 dersom enhet er på nivå oppdrag, " + + "Referanse ID 160 dersom enhet er på nivå oppdragslinje") public static class Enhet { @NotBlank @@ -311,21 +321,26 @@ public static class Enhet { @Builder @NoArgsConstructor @AllArgsConstructor + @Schema(description = "Entitet Grad, Referanse ID 170") public static class Grad { @NotBlank + @Schema(minLength = 1, maxLength = 4) protected String typeGrad; @NotBlank - protected BigInteger grad; + @Schema(description = "Prosentgrad, maks 100") + protected Integer grad; } @Data @Builder @NoArgsConstructor @AllArgsConstructor + @Schema(description = "Entitet Attestasjon, Referanse ID 180") public static class Attestant { @NotBlank + @Schema(minLength = 1, maxLength = 8) protected String attestantId; protected LocalDate datoUgyldigFom; } @@ -334,38 +349,41 @@ public static class Attestant { @Builder @NoArgsConstructor @AllArgsConstructor + @Schema(description = "Entitet Valuta, Referanse ID 190") public static class Valuta { @NotBlank - protected String typeValuta; + protected ValuteType typeValuta; @NotBlank + @Schema(minLength = 1, maxLength = 3) protected String valuta; @NotBlank protected LocalDate datoValutaFom; + @Schema(description = "Kode for beskrivelse av feil", minLength = 0, maxLength = 1) protected String feilreg; } public enum JaNei { J, - N; + N } public enum KodeStatusLinje { OPPH, HVIL, SPER, - REAK; + REAK } public enum FradragTillegg { F, - T; + T } public enum KodeArbeidsgiver { A, S, - P; + P } public enum KodeStatus { @@ -380,7 +398,7 @@ public enum KodeStatus { FBER, REAK, KORR, - FEIL; + FEIL } public enum KodeEndring { @@ -414,19 +432,30 @@ public enum UtbetalingFrekvensType { ENG } + public enum ValuteType { + + FAKT, + FRAM, + UTB + } + @Data @Builder @NoArgsConstructor @AllArgsConstructor + @Schema(description = "Entitet Beløpsgrense, Referanse ID 130") public static class Belopsgrense { @NotBlank + @Schema(minLength = 1, maxLength = 4) private String typeGrense; @NotBlank + @Schema(description = "Typen beskriver formatet og begrensningene til beløp, maks totalt antall sifre=11, desimaler=2") private BigDecimal belopGrense; @NotBlank private LocalDate datoGrenseFom; private LocalDate datoGrenseTom; + @Schema(description = "Kode for beskrivelse av feil", minLength = 0, maxLength = 1) private String feilreg; } } From 20998004eeb2a6240562a6c13b72ce1cf70898f5 Mon Sep 17 00:00:00 2001 From: "Kristen.Herum" Date: Thu, 31 Oct 2024 12:46:46 +0100 Subject: [PATCH 09/35] Add custom mappings for LocalDate and LocalDateTime Introduced new classes LocalDateCustomMapping and LocalDateTimeCustomMapping to handle custom conversion formats. Updated OppdragRequest and related mapping strategies to use these custom converters. Added unit tests to verify the new mapping logic. --- .../mapper/LocalDateCustomMapping.java | 23 ++ .../mapper/LocalDateTimeCustomMapping.java | 23 ++ .../mapper/OppdragRequestMappingStrategy.java | 26 +- .../mapper/MapperTestUtils.java | 9 +- .../OppdragRequestMappingStrategyTest.java | 274 ++++++++++++++++-- .../dto/oppdragservice/v1/OppdragRequest.java | 2 +- 6 files changed, 329 insertions(+), 28 deletions(-) create mode 100644 apps/oppdrag-service/src/main/java/no/nav/testnav/oppdragservice/mapper/LocalDateCustomMapping.java create mode 100644 apps/oppdrag-service/src/main/java/no/nav/testnav/oppdragservice/mapper/LocalDateTimeCustomMapping.java diff --git a/apps/oppdrag-service/src/main/java/no/nav/testnav/oppdragservice/mapper/LocalDateCustomMapping.java b/apps/oppdrag-service/src/main/java/no/nav/testnav/oppdragservice/mapper/LocalDateCustomMapping.java new file mode 100644 index 00000000000..75f3667c028 --- /dev/null +++ b/apps/oppdrag-service/src/main/java/no/nav/testnav/oppdragservice/mapper/LocalDateCustomMapping.java @@ -0,0 +1,23 @@ +package no.nav.testnav.oppdragservice.mapper; + +import lombok.extern.slf4j.Slf4j; +import ma.glasnost.orika.CustomConverter; +import ma.glasnost.orika.MappingContext; +import ma.glasnost.orika.metadata.Type; +import org.springframework.stereotype.Component; + +import java.time.LocalDate; +import java.time.format.DateTimeFormatter; + +@Slf4j +@Component +public class LocalDateCustomMapping extends CustomConverter { + + private static final DateTimeFormatter FORMATTER = DateTimeFormatter.ofPattern("dd-MM-yyyy"); + + @Override + public String convert(LocalDate localDate, Type type, MappingContext mappingContext) { + + return FORMATTER.format(localDate); + } +} \ No newline at end of file diff --git a/apps/oppdrag-service/src/main/java/no/nav/testnav/oppdragservice/mapper/LocalDateTimeCustomMapping.java b/apps/oppdrag-service/src/main/java/no/nav/testnav/oppdragservice/mapper/LocalDateTimeCustomMapping.java new file mode 100644 index 00000000000..57ec944d51a --- /dev/null +++ b/apps/oppdrag-service/src/main/java/no/nav/testnav/oppdragservice/mapper/LocalDateTimeCustomMapping.java @@ -0,0 +1,23 @@ +package no.nav.testnav.oppdragservice.mapper; + +import lombok.extern.slf4j.Slf4j; +import ma.glasnost.orika.CustomConverter; +import ma.glasnost.orika.MappingContext; +import ma.glasnost.orika.metadata.Type; +import org.springframework.stereotype.Component; + +import java.time.LocalDateTime; +import java.time.format.DateTimeFormatter; + +@Slf4j +@Component +public class LocalDateTimeCustomMapping extends CustomConverter { + + private static final DateTimeFormatter FORMATTER = DateTimeFormatter.ofPattern("yyyy-MM-dd-HH.mm.ss.SSSSSS"); + + @Override + public String convert(LocalDateTime localDateTime, Type type, MappingContext mappingContext) { + + return FORMATTER.format(localDateTime); + } +} \ No newline at end of file diff --git a/apps/oppdrag-service/src/main/java/no/nav/testnav/oppdragservice/mapper/OppdragRequestMappingStrategy.java b/apps/oppdrag-service/src/main/java/no/nav/testnav/oppdragservice/mapper/OppdragRequestMappingStrategy.java index f03eff9b29a..20d440c4423 100644 --- a/apps/oppdrag-service/src/main/java/no/nav/testnav/oppdragservice/mapper/OppdragRequestMappingStrategy.java +++ b/apps/oppdrag-service/src/main/java/no/nav/testnav/oppdragservice/mapper/OppdragRequestMappingStrategy.java @@ -5,10 +5,13 @@ import ma.glasnost.orika.MappingContext; import no.nav.testnav.libs.dto.oppdragservice.v1.OppdragRequest; import no.nav.testnav.oppdragservice.wsdl.Oppdrag; +import no.nav.testnav.oppdragservice.wsdl.Oppdragslinje; import no.nav.testnav.oppdragservice.wsdl.SendInnOppdragRequest; import no.nav.testnav.oppdragservice.wsdl.SendInnOppdragRequest2; import org.springframework.stereotype.Component; +import static java.util.Objects.nonNull; + @Component public class OppdragRequestMappingStrategy implements MappingStrategy{ @@ -22,7 +25,9 @@ public void mapAtoB(OppdragRequest source, SendInnOppdragRequest destination, MappingContext context) { - destination.setRequest(mapperFacade.map(source, SendInnOppdragRequest2.class, context)); + var oppdragRequest = new SendInnOppdragRequest2(); + oppdragRequest.setOppdrag(mapperFacade.map(source, Oppdrag.class, context)); + destination.setRequest(oppdragRequest); } }) .register(); @@ -34,7 +39,26 @@ public void mapAtoB(OppdragRequest source, Oppdrag destination, MappingContext context) { + if (nonNull(source.getUtbetFrekvens())) { + destination.setUtbetFrekvens(destination.getUtbetFrekvens() + .replace("_","")); + } + } + }) + .byDefault() + .register(); + + factory.classMap(OppdragRequest.Oppdragslinje.class, Oppdragslinje.class) + .customize(new CustomMapper<>() { + @Override + public void mapAtoB(OppdragRequest.Oppdragslinje source, + Oppdragslinje destination, + MappingContext context) { + if (nonNull(source.getTypeSats())) { + destination.setTypeSats(destination.getTypeSats() + .replace("_","")); + } } }) .byDefault() diff --git a/apps/oppdrag-service/src/test/java/no/nav/testnav/oppdragservice/mapper/MapperTestUtils.java b/apps/oppdrag-service/src/test/java/no/nav/testnav/oppdragservice/mapper/MapperTestUtils.java index 75c1e65a947..2d2620596be 100644 --- a/apps/oppdrag-service/src/test/java/no/nav/testnav/oppdragservice/mapper/MapperTestUtils.java +++ b/apps/oppdrag-service/src/test/java/no/nav/testnav/oppdragservice/mapper/MapperTestUtils.java @@ -4,6 +4,8 @@ import ma.glasnost.orika.MapperFacade; import ma.glasnost.orika.impl.DefaultMapperFactory; +import java.util.List; + import static java.util.Objects.nonNull; public class MapperTestUtils { @@ -12,15 +14,16 @@ public static MapperFacade createMapperFacadeForMappingStrategy(MappingStrategy. return createMapperFacadeForMappingStrategy(null, strategies); } - public static MapperFacade createMapperFacadeForMappingStrategy(CustomConverter converter, MappingStrategy... strategies) { + public static MapperFacade createMapperFacadeForMappingStrategy(List converters, MappingStrategy... strategies) { DefaultMapperFactory mapperFactory = new DefaultMapperFactory.Builder().build(); for (MappingStrategy strategy : strategies) { strategy.register(mapperFactory); } - if (nonNull(converter)) { - mapperFactory.getConverterFactory().registerConverter(converter); + if (nonNull(converters)) { + converters + .forEach(converter -> mapperFactory.getConverterFactory().registerConverter(converter)); } return mapperFactory.getMapperFacade(); } diff --git a/apps/oppdrag-service/src/test/java/no/nav/testnav/oppdragservice/mapper/OppdragRequestMappingStrategyTest.java b/apps/oppdrag-service/src/test/java/no/nav/testnav/oppdragservice/mapper/OppdragRequestMappingStrategyTest.java index d96c6b711b5..7c2ead7ecbe 100644 --- a/apps/oppdrag-service/src/test/java/no/nav/testnav/oppdragservice/mapper/OppdragRequestMappingStrategyTest.java +++ b/apps/oppdrag-service/src/test/java/no/nav/testnav/oppdragservice/mapper/OppdragRequestMappingStrategyTest.java @@ -2,51 +2,279 @@ import ma.glasnost.orika.MapperFacade; import no.nav.testnav.libs.dto.oppdragservice.v1.OppdragRequest; +import no.nav.testnav.libs.dto.oppdragservice.v1.OppdragRequest.SatsType; +import no.nav.testnav.libs.dto.oppdragservice.v1.OppdragRequest.ValuteType; +import no.nav.testnav.oppdragservice.wsdl.FradragTillegg; +import no.nav.testnav.oppdragservice.wsdl.KodeArbeidsgiver; +import no.nav.testnav.oppdragservice.wsdl.KodeStatus; +import no.nav.testnav.oppdragservice.wsdl.KodeStatusLinje; +import no.nav.testnav.oppdragservice.wsdl.SendInnOppdragRequest; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; import org.junit.jupiter.api.extension.ExtendWith; import org.mockito.junit.jupiter.MockitoExtension; +import java.math.BigDecimal; +import java.math.BigInteger; +import java.time.LocalDate; +import java.time.LocalDateTime; +import java.time.format.DateTimeFormatter; import java.util.List; +import static org.hamcrest.CoreMatchers.equalTo; +import static org.hamcrest.CoreMatchers.is; +import static org.hamcrest.MatcherAssert.assertThat; +import static org.hamcrest.Matchers.allOf; +import static org.hamcrest.Matchers.contains; +import static org.hamcrest.Matchers.hasProperty; + @ExtendWith(MockitoExtension.class) class OppdragRequestMappingStrategyTest { + private static final LocalDate LOCAL_DATE = LocalDate.now(); + private static final LocalDateTime LOCAL_DATE_TIME = LocalDateTime.now(); + + private static final String TARGET_DATE_FORMAT = DateTimeFormatter + .ofPattern("dd-MM-yyyy").format(LOCAL_DATE); + private static final String DB2_DATE_TIME_FORMAT = DateTimeFormatter + .ofPattern("yyyy-MM-dd-HH.mm.ss.SSSSSS").format(LOCAL_DATE_TIME); + + private static final String TEXT_VALUE = "tekst"; + private static final Integer NUMBER_VALUE = 123; + private static final Long LONG_VALUE = 456L; + private static final String NOM = "Z123456"; + private static final BigDecimal BELOP_GRENSE = new java.math.BigDecimal("12332.34"); + private static final BigInteger TARGET_NUMBER_VALUE = new BigInteger(NUMBER_VALUE.toString()); + private MapperFacade mapperFacade; @BeforeEach void setup() { - mapperFacade = MapperTestUtils.createMapperFacadeForMappingStrategy(new OppdragRequestMappingStrategy()); + mapperFacade = MapperTestUtils.createMapperFacadeForMappingStrategy( + List.of(new LocalDateCustomMapping(), + new LocalDateTimeCustomMapping()), + new OppdragRequestMappingStrategy()); + } + + @Test + void mapOppdrag_OK() { + + var oppdragRequest = buildOppdragRequest(); + + var target = mapperFacade.map(oppdragRequest, SendInnOppdragRequest.class) + .getRequest().getOppdrag(); + + assertThat(target.getOppdragsId(), is(equalTo(LONG_VALUE))); + assertThat(target.getBilagstype(), contains(hasProperty("typeBilag", is(equalTo(TEXT_VALUE))))); + assertThat(target.getAvstemmingsnokkel(), contains(allOf( + hasProperty("kodeKomponent", is(equalTo(TEXT_VALUE))), + hasProperty("avstemmingsNokkel", is(equalTo(TEXT_VALUE))), + hasProperty("tidspktReg", is(equalTo(DB2_DATE_TIME_FORMAT)))))); + assertThat(target.getOmpostering(), allOf( + hasProperty("datoOmposterFom", is(equalTo(TARGET_DATE_FORMAT))), + hasProperty("tidspktReg", is(equalTo(DB2_DATE_TIME_FORMAT))), + hasProperty("omPostering", is(equalTo("J"))), + hasProperty("saksbehId", is(equalTo(TEXT_VALUE))))); + assertThat(target.getKodeEndring(), is(equalTo(OppdragRequest.KodeEndring.NY.toString()))); + assertThat(target.getKodeStatus(), is(equalTo(KodeStatus.ATTE))); + assertThat(target.getDatoStatusFom(), is(equalTo(TARGET_DATE_FORMAT))); + assertThat(target.getKodeFagomraade(), is(equalTo(TEXT_VALUE))); + assertThat(target.getFagsystemId(), is(equalTo(TEXT_VALUE))); + assertThat(target.getOppdragsId(), is(equalTo(LONG_VALUE))); + assertThat(target.getUtbetFrekvens(), is(equalTo("14DG"))); + assertThat(target.getDatoForfall(), is(equalTo(TARGET_DATE_FORMAT))); + assertThat(target.getStonadId(), is(equalTo(TEXT_VALUE))); + assertThat(target.getOppdragGjelderId(), is(equalTo(TEXT_VALUE))); + assertThat(target.getDatoOppdragGjelderFom(), is(equalTo(TARGET_DATE_FORMAT))); + assertThat(target.getSaksbehId(), is(equalTo(NOM))); + assertThat(target.getEnhet(), contains(allOf( + hasProperty("typeEnhet", is(equalTo(TEXT_VALUE))), + hasProperty("enhet", is(equalTo(TEXT_VALUE))), + hasProperty("datoEnhetFom", is(equalTo(TARGET_DATE_FORMAT)))))); + assertThat(target.getBelopsgrense(), contains(allOf( + hasProperty("belopGrense", is(equalTo(BELOP_GRENSE))), + hasProperty("datoGrenseFom", is(equalTo(TARGET_DATE_FORMAT))), + hasProperty("datoGrenseTom", is(equalTo(TARGET_DATE_FORMAT))), + hasProperty("typeGrense", is(equalTo(TEXT_VALUE))), + hasProperty("feilreg", is(equalTo(TEXT_VALUE)))))); + assertThat(target.getTekst(), contains(allOf( + hasProperty("tekst", is(equalTo(TEXT_VALUE))), + hasProperty("tekstLnr", is(equalTo(TARGET_NUMBER_VALUE))), + hasProperty("datoTekstFom", is(equalTo(TARGET_DATE_FORMAT))), + hasProperty("datoTekstTom", is(equalTo(TARGET_DATE_FORMAT))), + hasProperty("tekstKode", is(equalTo(TEXT_VALUE))), + hasProperty("feilreg", is(equalTo(TEXT_VALUE)))))); } @Test - void mapOrdreOK() { + void mapOppdragsLinje_OK() { + + var oppdragRequest = buildOppdragsLinje(); + + var target = mapperFacade.map(oppdragRequest, SendInnOppdragRequest.class) + .getRequest().getOppdrag(); -// mapperFacade.map() + assertThat(target.getOppdragslinje(), contains(allOf( + hasProperty("kodeEndringLinje", is(equalTo("NY"))), + hasProperty("kodeStatusLinje", is(equalTo(KodeStatusLinje.OPPH))), + hasProperty("datoStatusFom", is(equalTo(TARGET_DATE_FORMAT))), + hasProperty("vedtakId", is(equalTo(TEXT_VALUE))), + hasProperty("delytelseId", is(equalTo(TEXT_VALUE))), + hasProperty("linjeId", is(equalTo(TARGET_NUMBER_VALUE))), + hasProperty("kodeKlassifik", is(equalTo(TEXT_VALUE))), + hasProperty("datoKlassifikFom", is(equalTo(TARGET_DATE_FORMAT))), + hasProperty("datoVedtakFom", is(equalTo(TARGET_DATE_FORMAT))), + hasProperty("datoVedtakTom", is(equalTo(TARGET_DATE_FORMAT))), + hasProperty("sats", is(equalTo(BELOP_GRENSE))), + hasProperty("fradragTillegg", is(equalTo(FradragTillegg.F))), + hasProperty("typeSats", is(equalTo("14DB"))), + hasProperty("skyldnerId", is(equalTo(TEXT_VALUE))), + hasProperty("datoSkyldnerFom", is(equalTo(TARGET_DATE_FORMAT))), + hasProperty("kravhaverId", is(equalTo(TEXT_VALUE))), + hasProperty("datoKravhaverFom", is(equalTo(TARGET_DATE_FORMAT))), + hasProperty("kid", is(equalTo(TEXT_VALUE))), + hasProperty("datoKidFom", is(equalTo(TARGET_DATE_FORMAT))), + hasProperty("brukKjoreplan", is(equalTo(TEXT_VALUE))), + hasProperty("saksbehId", is(equalTo(NOM))), + hasProperty("utbetalesTilId", is(equalTo(TEXT_VALUE))), + hasProperty("datoUtbetalesTilIdFom", is(equalTo(TARGET_DATE_FORMAT))), + hasProperty("kodeArbeidsgiver", is(equalTo(KodeArbeidsgiver.A))), + hasProperty("henvisning", is(equalTo(TEXT_VALUE))), + hasProperty("typeSoknad", is(equalTo(TEXT_VALUE))), + hasProperty("refFagsystemId", is(equalTo(TEXT_VALUE))), + hasProperty("refOppdragsId", is(equalTo(LONG_VALUE))), + hasProperty("refDelytelseId", is(equalTo(TEXT_VALUE))), + hasProperty("refLinjeId", is(equalTo(TARGET_NUMBER_VALUE))), + hasProperty("refusjonsInfo", allOf( + hasProperty("refunderesId", is(equalTo(TEXT_VALUE))), + hasProperty("maksDato", is(equalTo(TARGET_DATE_FORMAT))), + hasProperty("datoFom", is(equalTo(TARGET_DATE_FORMAT))))), + hasProperty("tekst", contains(allOf( + hasProperty("tekst", is(equalTo(TEXT_VALUE))), + hasProperty("tekstLnr", is(equalTo(TARGET_NUMBER_VALUE))), + hasProperty("datoTekstFom", is(equalTo(TARGET_DATE_FORMAT)))))), + hasProperty("enhet", contains(allOf( + hasProperty("typeEnhet", is(equalTo(TEXT_VALUE))), + hasProperty("enhet", is(equalTo(TEXT_VALUE))), + hasProperty("datoEnhetFom", is(equalTo(TARGET_DATE_FORMAT)))))), + hasProperty("grad", contains(allOf( + hasProperty("typeGrad", is(equalTo(TEXT_VALUE))), + hasProperty("grad", is(equalTo(TARGET_NUMBER_VALUE)))))), + hasProperty("attestant", contains(allOf( + hasProperty("attestantId", is(equalTo(TEXT_VALUE))), + hasProperty("datoUgyldigFom", is(equalTo(TARGET_DATE_FORMAT)))))), + hasProperty("valuta", contains(allOf( + hasProperty("typeValuta", is(equalTo(ValuteType.FAKT.toString()))), + hasProperty("valuta", is(equalTo(TEXT_VALUE))), + hasProperty("datoValutaFom", is(equalTo(TARGET_DATE_FORMAT))), + hasProperty("feilreg", is(equalTo(TEXT_VALUE)))))) + ))); } private static OppdragRequest buildOppdragRequest() { return OppdragRequest.builder() - .bilagstype(List.of(OppdragRequest.Bilagstype.builder().typeBilag("12").build())) -// .avstemmingsnokkel() -// .ompostering() -// .oppdragslinje() -// .kodeEndring() -// .kodeStatus() -// .datoStatusFom() -// .kodeFagomraade() -// .fagsystemId() -// .oppdragsId() -// .utbetFrekvens() -// .datoForfall() -// .stonadId() -// .oppdragGjelderId() -// .datoOppdragGjelderFom() -// .saksbehId() -// .enhet() -// .belopsgrense() -// .tekst() - .build(); + .oppdragsId(LONG_VALUE) + .bilagstype(List.of(OppdragRequest.Bilagstype.builder() + .typeBilag(TEXT_VALUE).build())) + .avstemmingsnokkel(List.of(OppdragRequest.Avstemmingsnokkel + .builder().kodeKomponent(TEXT_VALUE) + .avstemmingsNokkel(TEXT_VALUE) + .tidspktReg(LOCAL_DATE_TIME).build())) + .ompostering(OppdragRequest.Ompostering.builder() + .datoOmposterFom(LOCAL_DATE) + .tidspktReg(LOCAL_DATE_TIME) + .omPostering(OppdragRequest.JaNei.J) + .saksbehId(TEXT_VALUE).build()) + .kodeEndring(OppdragRequest.KodeEndring.NY) + .kodeStatus(OppdragRequest.KodeStatus.ATTE) + .datoStatusFom(LOCAL_DATE) + .kodeFagomraade(TEXT_VALUE) + .fagsystemId(TEXT_VALUE) + .oppdragsId(LONG_VALUE) + .utbetFrekvens(OppdragRequest.UtbetalingFrekvensType._14DG) + .datoForfall(LOCAL_DATE) + .stonadId(TEXT_VALUE) + .oppdragGjelderId(TEXT_VALUE) + .datoOppdragGjelderFom(LOCAL_DATE) + .saksbehId(NOM) + .enhet(List.of(OppdragRequest.Enhet.builder().typeEnhet(TEXT_VALUE) + .enhet(TEXT_VALUE).datoEnhetFom(LOCAL_DATE).build())) + .belopsgrense(List.of(OppdragRequest.Belopsgrense.builder() + .belopGrense(BELOP_GRENSE).datoGrenseFom(LOCAL_DATE) + .datoGrenseTom(LOCAL_DATE).typeGrense(TEXT_VALUE) + .feilreg(TEXT_VALUE).build())) + .tekst(List.of(OppdragRequest.Tekst.builder().tekst(TEXT_VALUE) + .tekstLnr(NUMBER_VALUE).datoTekstFom(LOCAL_DATE) + .datoTekstTom(LOCAL_DATE).tekstKode(TEXT_VALUE) + .feilreg(TEXT_VALUE).build())) + .build(); + } + + private static OppdragRequest buildOppdragsLinje() { + + return OppdragRequest.builder() + .oppdragslinje(List.of(OppdragRequest.Oppdragslinje.builder() + .kodeEndringLinje(OppdragRequest.KodeEndringType.NY) + .kodeStatusLinje(OppdragRequest.KodeStatusLinje.OPPH) + .datoStatusFom(LOCAL_DATE) + .vedtakId(TEXT_VALUE) + .delytelseId(TEXT_VALUE) + .linjeId(NUMBER_VALUE) + .kodeKlassifik(TEXT_VALUE) + .datoKlassifikFom(LOCAL_DATE) + .datoVedtakFom(LOCAL_DATE) + .datoVedtakTom(LOCAL_DATE) + .sats(BELOP_GRENSE) + .fradragTillegg(OppdragRequest.FradragTillegg.F) + .typeSats(SatsType._14DB) + .skyldnerId(TEXT_VALUE) + .datoSkyldnerFom(LOCAL_DATE) + .kravhaverId(TEXT_VALUE) + .datoKravhaverFom(LOCAL_DATE) + .kid(TEXT_VALUE) + .datoKidFom(LOCAL_DATE) + .brukKjoreplan(TEXT_VALUE) + .saksbehId(NOM) + .utbetalesTilId(TEXT_VALUE) + .datoUtbetalesTilIdFom(LOCAL_DATE) + .kodeArbeidsgiver(OppdragRequest.KodeArbeidsgiver.A) + .henvisning(TEXT_VALUE) + .typeSoknad(TEXT_VALUE) + .refFagsystemId(TEXT_VALUE) + .refOppdragsId(LONG_VALUE) + .refDelytelseId(TEXT_VALUE) + .refLinjeId(NUMBER_VALUE) + .refusjonsInfo(OppdragRequest.RefusjonsInfo.builder() + .refunderesId(TEXT_VALUE) + .maksDato(LOCAL_DATE) + .datoFom(LOCAL_DATE) + .build()) + .tekst(List.of(OppdragRequest.Tekst.builder() + .tekst(TEXT_VALUE) + .tekstLnr(NUMBER_VALUE) + .datoTekstFom(LOCAL_DATE) + .build())) + .enhet(List.of(OppdragRequest.Enhet.builder() + .typeEnhet(TEXT_VALUE) + .enhet(TEXT_VALUE) + .datoEnhetFom(LOCAL_DATE) + .build())) + .grad(List.of(OppdragRequest.Grad.builder() + .typeGrad(TEXT_VALUE) + .grad(NUMBER_VALUE) + .build())) + .attestant(List.of(OppdragRequest.Attestant.builder() + .attestantId(TEXT_VALUE) + .datoUgyldigFom(LOCAL_DATE) + .build())) + .valuta(List.of(OppdragRequest.Valuta.builder() + .typeValuta(ValuteType.FAKT) + .valuta(TEXT_VALUE) + .datoValutaFom(LOCAL_DATE) + .feilreg(TEXT_VALUE) + .build())) + .build())) + .build(); } } \ No newline at end of file diff --git a/libs/data-transfer-objects/src/main/java/no/nav/testnav/libs/dto/oppdragservice/v1/OppdragRequest.java b/libs/data-transfer-objects/src/main/java/no/nav/testnav/libs/dto/oppdragservice/v1/OppdragRequest.java index ca82bf5708d..4fef56f644e 100644 --- a/libs/data-transfer-objects/src/main/java/no/nav/testnav/libs/dto/oppdragservice/v1/OppdragRequest.java +++ b/libs/data-transfer-objects/src/main/java/no/nav/testnav/libs/dto/oppdragservice/v1/OppdragRequest.java @@ -31,7 +31,7 @@ public class OppdragRequest { @NotBlank private KodeEndring kodeEndring; private KodeStatus kodeStatus; - private String datoStatusFom; + private LocalDate datoStatusFom; @NotBlank @Schema(minLength = 1, maxLength = 8) private String kodeFagomraade; From 7d1b54df92aa55d75543650b4f83c1aca3e87bb4 Mon Sep 17 00:00:00 2001 From: "Kristen.Herum" Date: Fri, 1 Nov 2024 10:56:13 +0100 Subject: [PATCH 10/35] Add TestConfig and Oppdragsdata utility classes Added TestConfig.java to provide Spring test configuration, including beans for OppdragService, OppdragConsumer, and MapperFacade. Created Oppdragsdata.java in utility package to facilitate the construction of OppdragRequest and SendInnOppdragResponse objects, enhancing the testing structure. --- .../config/OppdragWsConfiguration.java | 7 +- .../consumer/OppdragConsumer.java | 12 +- .../mapper/LocalDateCustomMapping.java | 12 +- .../mapper/LocalDateTimeCustomMapping.java | 12 +- .../mapper/OppdragRequestMappingStrategy.java | 14 +- .../OppdragResponseMappingStrategy.java | 43 ++ .../service/OppdragService.java | 2 +- .../oppdragservice/config/TestConfig.java | 37 ++ .../OppdragRequestMappingStrategyTest.java | 150 +----- .../OppdragResponseMappingStrategyTest.java | 156 ++++++ .../service/OppdragServiceTest.java | 37 ++ .../oppdragservice/utilty/Oppdragsdata.java | 294 +++++++++++ .../libs/dto/oppdragservice/v1/Oppdrag.java | 460 ++++++++++++++++++ .../dto/oppdragservice/v1/OppdragRequest.java | 446 +---------------- .../oppdragservice/v1/OppdragResponse.java | 25 + 15 files changed, 1108 insertions(+), 599 deletions(-) create mode 100644 apps/oppdrag-service/src/main/java/no/nav/testnav/oppdragservice/mapper/OppdragResponseMappingStrategy.java create mode 100644 apps/oppdrag-service/src/test/java/no/nav/testnav/oppdragservice/config/TestConfig.java create mode 100644 apps/oppdrag-service/src/test/java/no/nav/testnav/oppdragservice/mapper/OppdragResponseMappingStrategyTest.java create mode 100644 apps/oppdrag-service/src/test/java/no/nav/testnav/oppdragservice/service/OppdragServiceTest.java create mode 100644 apps/oppdrag-service/src/test/java/no/nav/testnav/oppdragservice/utilty/Oppdragsdata.java create mode 100644 libs/data-transfer-objects/src/main/java/no/nav/testnav/libs/dto/oppdragservice/v1/Oppdrag.java create mode 100644 libs/data-transfer-objects/src/main/java/no/nav/testnav/libs/dto/oppdragservice/v1/OppdragResponse.java diff --git a/apps/oppdrag-service/src/main/java/no/nav/testnav/oppdragservice/config/OppdragWsConfiguration.java b/apps/oppdrag-service/src/main/java/no/nav/testnav/oppdragservice/config/OppdragWsConfiguration.java index 1def57c64d0..2cead073f8d 100644 --- a/apps/oppdrag-service/src/main/java/no/nav/testnav/oppdragservice/config/OppdragWsConfiguration.java +++ b/apps/oppdrag-service/src/main/java/no/nav/testnav/oppdragservice/config/OppdragWsConfiguration.java @@ -5,22 +5,23 @@ import org.springframework.context.annotation.Configuration; import org.springframework.oxm.jaxb.Jaxb2Marshaller; import org.springframework.ws.config.annotation.EnableWs; +import org.springframework.ws.config.annotation.WsConfigurerAdapter; @EnableWs @Configuration -public class OppdragWsConfiguration { +public class OppdragWsConfiguration extends WsConfigurerAdapter { @Bean public Jaxb2Marshaller marshaller() { Jaxb2Marshaller marshaller = new Jaxb2Marshaller(); // this package must match the package in the specified in - // pom.xml + // build.gradle marshaller.setContextPath("no.nav.testnav.oppdragservice.wsdl"); return marshaller; } @Bean - public OppdragClient countryClient(Jaxb2Marshaller marshaller) { + public OppdragClient oppdragClient(Jaxb2Marshaller marshaller) { var client = new OppdragClient(); client.setDefaultUri("http://localhost:8080/ws"); diff --git a/apps/oppdrag-service/src/main/java/no/nav/testnav/oppdragservice/consumer/OppdragConsumer.java b/apps/oppdrag-service/src/main/java/no/nav/testnav/oppdragservice/consumer/OppdragConsumer.java index 67cfde505c6..44135515485 100644 --- a/apps/oppdrag-service/src/main/java/no/nav/testnav/oppdragservice/consumer/OppdragConsumer.java +++ b/apps/oppdrag-service/src/main/java/no/nav/testnav/oppdragservice/consumer/OppdragConsumer.java @@ -1,11 +1,19 @@ package no.nav.testnav.oppdragservice.consumer; +import lombok.extern.slf4j.Slf4j; +import no.nav.testnav.oppdragservice.wsdl.SendInnOppdragRequest; +import no.nav.testnav.oppdragservice.wsdl.SendInnOppdragResponse; import org.springframework.stereotype.Service; +import org.springframework.ws.client.core.support.WebServiceGatewaySupport; +import org.springframework.ws.soap.client.core.SoapActionCallback; +@Slf4j @Service -public class OppdragConsumer { +public class OppdragConsumer extends WebServiceGatewaySupport { - public void sendOppdrag(String xmlPayload) { + public SendInnOppdragResponse sendOppdrag(SendInnOppdragRequest melding) { + return (SendInnOppdragResponse) getWebServiceTemplate().marshalSendAndReceive("", melding, + new SoapActionCallback("no.nav.testnav.oppdragservice.wsdl.SendInnOppdragResponse")); } } diff --git a/apps/oppdrag-service/src/main/java/no/nav/testnav/oppdragservice/mapper/LocalDateCustomMapping.java b/apps/oppdrag-service/src/main/java/no/nav/testnav/oppdragservice/mapper/LocalDateCustomMapping.java index 75f3667c028..cbdb8035f74 100644 --- a/apps/oppdrag-service/src/main/java/no/nav/testnav/oppdragservice/mapper/LocalDateCustomMapping.java +++ b/apps/oppdrag-service/src/main/java/no/nav/testnav/oppdragservice/mapper/LocalDateCustomMapping.java @@ -1,8 +1,8 @@ package no.nav.testnav.oppdragservice.mapper; import lombok.extern.slf4j.Slf4j; -import ma.glasnost.orika.CustomConverter; import ma.glasnost.orika.MappingContext; +import ma.glasnost.orika.converter.BidirectionalConverter; import ma.glasnost.orika.metadata.Type; import org.springframework.stereotype.Component; @@ -11,13 +11,19 @@ @Slf4j @Component -public class LocalDateCustomMapping extends CustomConverter { +public class LocalDateCustomMapping extends BidirectionalConverter { private static final DateTimeFormatter FORMATTER = DateTimeFormatter.ofPattern("dd-MM-yyyy"); @Override - public String convert(LocalDate localDate, Type type, MappingContext mappingContext) { + public String convertTo(LocalDate localDate, Type type, MappingContext mappingContext) { return FORMATTER.format(localDate); } + + @Override + public LocalDate convertFrom(String s, Type type, MappingContext mappingContext) { + + return LocalDate.from(FORMATTER.parse(s)); + } } \ No newline at end of file diff --git a/apps/oppdrag-service/src/main/java/no/nav/testnav/oppdragservice/mapper/LocalDateTimeCustomMapping.java b/apps/oppdrag-service/src/main/java/no/nav/testnav/oppdragservice/mapper/LocalDateTimeCustomMapping.java index 57ec944d51a..9cb6743313a 100644 --- a/apps/oppdrag-service/src/main/java/no/nav/testnav/oppdragservice/mapper/LocalDateTimeCustomMapping.java +++ b/apps/oppdrag-service/src/main/java/no/nav/testnav/oppdragservice/mapper/LocalDateTimeCustomMapping.java @@ -1,8 +1,8 @@ package no.nav.testnav.oppdragservice.mapper; import lombok.extern.slf4j.Slf4j; -import ma.glasnost.orika.CustomConverter; import ma.glasnost.orika.MappingContext; +import ma.glasnost.orika.converter.BidirectionalConverter; import ma.glasnost.orika.metadata.Type; import org.springframework.stereotype.Component; @@ -11,13 +11,19 @@ @Slf4j @Component -public class LocalDateTimeCustomMapping extends CustomConverter { +public class LocalDateTimeCustomMapping extends BidirectionalConverter { private static final DateTimeFormatter FORMATTER = DateTimeFormatter.ofPattern("yyyy-MM-dd-HH.mm.ss.SSSSSS"); @Override - public String convert(LocalDateTime localDateTime, Type type, MappingContext mappingContext) { + public String convertTo(LocalDateTime localDateTime, Type type, MappingContext mappingContext) { return FORMATTER.format(localDateTime); } + + @Override + public LocalDateTime convertFrom(String s, Type type, MappingContext mappingContext) { + + return LocalDateTime.from(FORMATTER.parse(s)); + } } \ No newline at end of file diff --git a/apps/oppdrag-service/src/main/java/no/nav/testnav/oppdragservice/mapper/OppdragRequestMappingStrategy.java b/apps/oppdrag-service/src/main/java/no/nav/testnav/oppdragservice/mapper/OppdragRequestMappingStrategy.java index 20d440c4423..316d683b523 100644 --- a/apps/oppdrag-service/src/main/java/no/nav/testnav/oppdragservice/mapper/OppdragRequestMappingStrategy.java +++ b/apps/oppdrag-service/src/main/java/no/nav/testnav/oppdragservice/mapper/OppdragRequestMappingStrategy.java @@ -3,8 +3,8 @@ import ma.glasnost.orika.CustomMapper; import ma.glasnost.orika.MapperFactory; import ma.glasnost.orika.MappingContext; +import no.nav.testnav.libs.dto.oppdragservice.v1.Oppdrag; import no.nav.testnav.libs.dto.oppdragservice.v1.OppdragRequest; -import no.nav.testnav.oppdragservice.wsdl.Oppdrag; import no.nav.testnav.oppdragservice.wsdl.Oppdragslinje; import no.nav.testnav.oppdragservice.wsdl.SendInnOppdragRequest; import no.nav.testnav.oppdragservice.wsdl.SendInnOppdragRequest2; @@ -26,17 +26,17 @@ public void mapAtoB(OppdragRequest source, MappingContext context) { var oppdragRequest = new SendInnOppdragRequest2(); - oppdragRequest.setOppdrag(mapperFacade.map(source, Oppdrag.class, context)); + oppdragRequest.setOppdrag(mapperFacade.map(source.getOppdrag(), no.nav.testnav.oppdragservice.wsdl.Oppdrag.class, context)); destination.setRequest(oppdragRequest); } }) .register(); - factory.classMap(OppdragRequest.class, Oppdrag.class) + factory.classMap(Oppdrag.class, no.nav.testnav.oppdragservice.wsdl.Oppdrag.class) .customize(new CustomMapper<>() { @Override - public void mapAtoB(OppdragRequest source, - Oppdrag destination, + public void mapAtoB(Oppdrag source, + no.nav.testnav.oppdragservice.wsdl.Oppdrag destination, MappingContext context) { if (nonNull(source.getUtbetFrekvens())) { @@ -48,10 +48,10 @@ public void mapAtoB(OppdragRequest source, .byDefault() .register(); - factory.classMap(OppdragRequest.Oppdragslinje.class, Oppdragslinje.class) + factory.classMap(Oppdrag.Oppdragslinje.class, Oppdragslinje.class) .customize(new CustomMapper<>() { @Override - public void mapAtoB(OppdragRequest.Oppdragslinje source, + public void mapAtoB(Oppdrag.Oppdragslinje source, Oppdragslinje destination, MappingContext context) { diff --git a/apps/oppdrag-service/src/main/java/no/nav/testnav/oppdragservice/mapper/OppdragResponseMappingStrategy.java b/apps/oppdrag-service/src/main/java/no/nav/testnav/oppdragservice/mapper/OppdragResponseMappingStrategy.java new file mode 100644 index 00000000000..a6b74cef50f --- /dev/null +++ b/apps/oppdrag-service/src/main/java/no/nav/testnav/oppdragservice/mapper/OppdragResponseMappingStrategy.java @@ -0,0 +1,43 @@ +package no.nav.testnav.oppdragservice.mapper; + +import ma.glasnost.orika.CustomMapper; +import ma.glasnost.orika.MapperFactory; +import ma.glasnost.orika.MappingContext; +import no.nav.testnav.libs.dto.oppdragservice.v1.Oppdrag; +import no.nav.testnav.libs.dto.oppdragservice.v1.OppdragResponse; +import no.nav.testnav.oppdragservice.wsdl.SendInnOppdragResponse; +import org.springframework.stereotype.Component; + +import static java.util.Objects.nonNull; + +@Component +public class OppdragResponseMappingStrategy implements MappingStrategy{ + + @Override + public void register(MapperFactory factory) { + + factory.classMap(SendInnOppdragResponse.class, OppdragResponse.class) + .customize(new CustomMapper<>() { + @Override + public void mapAtoB(SendInnOppdragResponse source, + OppdragResponse destination, + MappingContext context) { + + var oppdrag = source.getResponse().getOppdrag(); + if (nonNull(oppdrag.getUtbetFrekvens())) { + oppdrag.setUtbetFrekvens(oppdrag.getUtbetFrekvens() + .replace("14DG", "_14DG")); + } + + oppdrag.getOppdragslinje().stream() + .filter(oppdragslinje -> nonNull(oppdragslinje.getTypeSats())) + .forEach(oppdragslinje -> + oppdragslinje.setTypeSats(oppdragslinje.getTypeSats() + .replace("14DB","_14DB"))); + + destination.setOppdrag(mapperFacade.map(oppdrag, Oppdrag.class, context)); + } + }) + .register(); + } +} diff --git a/apps/oppdrag-service/src/main/java/no/nav/testnav/oppdragservice/service/OppdragService.java b/apps/oppdrag-service/src/main/java/no/nav/testnav/oppdragservice/service/OppdragService.java index 109fba28866..ac8a4c8b888 100644 --- a/apps/oppdrag-service/src/main/java/no/nav/testnav/oppdragservice/service/OppdragService.java +++ b/apps/oppdrag-service/src/main/java/no/nav/testnav/oppdragservice/service/OppdragService.java @@ -30,7 +30,7 @@ public SendInnOppdragResponse sendInnOppdrag(OppdragRequest oppdragRequest) { var request = mapperFacade.map(oppdragRequest, SendInnOppdragRequest.class); var xmlRequest = marshallToXml(request); - oppdragConsumer.sendOppdrag(xmlRequest); + var response = oppdragConsumer.sendOppdrag(request); return null; } diff --git a/apps/oppdrag-service/src/test/java/no/nav/testnav/oppdragservice/config/TestConfig.java b/apps/oppdrag-service/src/test/java/no/nav/testnav/oppdragservice/config/TestConfig.java new file mode 100644 index 00000000000..924f952d4e6 --- /dev/null +++ b/apps/oppdrag-service/src/test/java/no/nav/testnav/oppdragservice/config/TestConfig.java @@ -0,0 +1,37 @@ +package no.nav.testnav.oppdragservice.config; + +import jakarta.xml.bind.JAXBException; +import ma.glasnost.orika.MapperFacade; +import no.nav.testnav.oppdragservice.consumer.OppdragConsumer; +import no.nav.testnav.oppdragservice.mapper.LocalDateCustomMapping; +import no.nav.testnav.oppdragservice.mapper.LocalDateTimeCustomMapping; +import no.nav.testnav.oppdragservice.mapper.MapperTestUtils; +import no.nav.testnav.oppdragservice.mapper.OppdragRequestMappingStrategy; +import no.nav.testnav.oppdragservice.service.OppdragService; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; + +import java.util.List; + +@Configuration +public class TestConfig { + + @Bean + public OppdragService oppdragService() throws JAXBException { + return new OppdragService(oppdragConsumer(), mapperFacade()); + } + + @Bean + public OppdragConsumer oppdragConsumer() { + return new OppdragConsumer(); + } + + @Bean + public MapperFacade mapperFacade() { + + return MapperTestUtils.createMapperFacadeForMappingStrategy( + List.of(new LocalDateCustomMapping(), + new LocalDateTimeCustomMapping()), + new OppdragRequestMappingStrategy()); + } +} \ No newline at end of file diff --git a/apps/oppdrag-service/src/test/java/no/nav/testnav/oppdragservice/mapper/OppdragRequestMappingStrategyTest.java b/apps/oppdrag-service/src/test/java/no/nav/testnav/oppdragservice/mapper/OppdragRequestMappingStrategyTest.java index 7c2ead7ecbe..a4cb5be2280 100644 --- a/apps/oppdrag-service/src/test/java/no/nav/testnav/oppdragservice/mapper/OppdragRequestMappingStrategyTest.java +++ b/apps/oppdrag-service/src/test/java/no/nav/testnav/oppdragservice/mapper/OppdragRequestMappingStrategyTest.java @@ -1,9 +1,9 @@ package no.nav.testnav.oppdragservice.mapper; import ma.glasnost.orika.MapperFacade; -import no.nav.testnav.libs.dto.oppdragservice.v1.OppdragRequest; -import no.nav.testnav.libs.dto.oppdragservice.v1.OppdragRequest.SatsType; -import no.nav.testnav.libs.dto.oppdragservice.v1.OppdragRequest.ValuteType; +import no.nav.testnav.libs.dto.oppdragservice.v1.Oppdrag; +import no.nav.testnav.libs.dto.oppdragservice.v1.Oppdrag.ValuteType; +import no.nav.testnav.oppdragservice.utilty.Oppdragsdata; import no.nav.testnav.oppdragservice.wsdl.FradragTillegg; import no.nav.testnav.oppdragservice.wsdl.KodeArbeidsgiver; import no.nav.testnav.oppdragservice.wsdl.KodeStatus; @@ -14,13 +14,15 @@ import org.junit.jupiter.api.extension.ExtendWith; import org.mockito.junit.jupiter.MockitoExtension; -import java.math.BigDecimal; -import java.math.BigInteger; -import java.time.LocalDate; -import java.time.LocalDateTime; -import java.time.format.DateTimeFormatter; import java.util.List; +import static no.nav.testnav.oppdragservice.utilty.Oppdragsdata.BELOP_GRENSE; +import static no.nav.testnav.oppdragservice.utilty.Oppdragsdata.DB2_DATE_TIME_FORMAT; +import static no.nav.testnav.oppdragservice.utilty.Oppdragsdata.LONG_VALUE; +import static no.nav.testnav.oppdragservice.utilty.Oppdragsdata.NOM; +import static no.nav.testnav.oppdragservice.utilty.Oppdragsdata.TARGET_DATE_FORMAT; +import static no.nav.testnav.oppdragservice.utilty.Oppdragsdata.TARGET_NUMBER_VALUE; +import static no.nav.testnav.oppdragservice.utilty.Oppdragsdata.TEXT_VALUE; import static org.hamcrest.CoreMatchers.equalTo; import static org.hamcrest.CoreMatchers.is; import static org.hamcrest.MatcherAssert.assertThat; @@ -31,21 +33,6 @@ @ExtendWith(MockitoExtension.class) class OppdragRequestMappingStrategyTest { - private static final LocalDate LOCAL_DATE = LocalDate.now(); - private static final LocalDateTime LOCAL_DATE_TIME = LocalDateTime.now(); - - private static final String TARGET_DATE_FORMAT = DateTimeFormatter - .ofPattern("dd-MM-yyyy").format(LOCAL_DATE); - private static final String DB2_DATE_TIME_FORMAT = DateTimeFormatter - .ofPattern("yyyy-MM-dd-HH.mm.ss.SSSSSS").format(LOCAL_DATE_TIME); - - private static final String TEXT_VALUE = "tekst"; - private static final Integer NUMBER_VALUE = 123; - private static final Long LONG_VALUE = 456L; - private static final String NOM = "Z123456"; - private static final BigDecimal BELOP_GRENSE = new java.math.BigDecimal("12332.34"); - private static final BigInteger TARGET_NUMBER_VALUE = new BigInteger(NUMBER_VALUE.toString()); - private MapperFacade mapperFacade; @BeforeEach @@ -57,9 +44,9 @@ void setup() { } @Test - void mapOppdrag_OK() { + void mapOppdragRequest_OK() { - var oppdragRequest = buildOppdragRequest(); + var oppdragRequest = Oppdragsdata.buildOppdragRequest(); var target = mapperFacade.map(oppdragRequest, SendInnOppdragRequest.class) .getRequest().getOppdrag(); @@ -75,7 +62,7 @@ void mapOppdrag_OK() { hasProperty("tidspktReg", is(equalTo(DB2_DATE_TIME_FORMAT))), hasProperty("omPostering", is(equalTo("J"))), hasProperty("saksbehId", is(equalTo(TEXT_VALUE))))); - assertThat(target.getKodeEndring(), is(equalTo(OppdragRequest.KodeEndring.NY.toString()))); + assertThat(target.getKodeEndring(), is(equalTo(Oppdrag.KodeEndring.NY.toString()))); assertThat(target.getKodeStatus(), is(equalTo(KodeStatus.ATTE))); assertThat(target.getDatoStatusFom(), is(equalTo(TARGET_DATE_FORMAT))); assertThat(target.getKodeFagomraade(), is(equalTo(TEXT_VALUE))); @@ -107,9 +94,9 @@ void mapOppdrag_OK() { } @Test - void mapOppdragsLinje_OK() { + void mapOppdragsLinjeRequest_OK() { - var oppdragRequest = buildOppdragsLinje(); + var oppdragRequest = Oppdragsdata.buildOppdragsLinjeRequest(); var target = mapperFacade.map(oppdragRequest, SendInnOppdragRequest.class) .getRequest().getOppdrag(); @@ -170,111 +157,4 @@ void mapOppdragsLinje_OK() { hasProperty("feilreg", is(equalTo(TEXT_VALUE)))))) ))); } - - private static OppdragRequest buildOppdragRequest() { - - return OppdragRequest.builder() - .oppdragsId(LONG_VALUE) - .bilagstype(List.of(OppdragRequest.Bilagstype.builder() - .typeBilag(TEXT_VALUE).build())) - .avstemmingsnokkel(List.of(OppdragRequest.Avstemmingsnokkel - .builder().kodeKomponent(TEXT_VALUE) - .avstemmingsNokkel(TEXT_VALUE) - .tidspktReg(LOCAL_DATE_TIME).build())) - .ompostering(OppdragRequest.Ompostering.builder() - .datoOmposterFom(LOCAL_DATE) - .tidspktReg(LOCAL_DATE_TIME) - .omPostering(OppdragRequest.JaNei.J) - .saksbehId(TEXT_VALUE).build()) - .kodeEndring(OppdragRequest.KodeEndring.NY) - .kodeStatus(OppdragRequest.KodeStatus.ATTE) - .datoStatusFom(LOCAL_DATE) - .kodeFagomraade(TEXT_VALUE) - .fagsystemId(TEXT_VALUE) - .oppdragsId(LONG_VALUE) - .utbetFrekvens(OppdragRequest.UtbetalingFrekvensType._14DG) - .datoForfall(LOCAL_DATE) - .stonadId(TEXT_VALUE) - .oppdragGjelderId(TEXT_VALUE) - .datoOppdragGjelderFom(LOCAL_DATE) - .saksbehId(NOM) - .enhet(List.of(OppdragRequest.Enhet.builder().typeEnhet(TEXT_VALUE) - .enhet(TEXT_VALUE).datoEnhetFom(LOCAL_DATE).build())) - .belopsgrense(List.of(OppdragRequest.Belopsgrense.builder() - .belopGrense(BELOP_GRENSE).datoGrenseFom(LOCAL_DATE) - .datoGrenseTom(LOCAL_DATE).typeGrense(TEXT_VALUE) - .feilreg(TEXT_VALUE).build())) - .tekst(List.of(OppdragRequest.Tekst.builder().tekst(TEXT_VALUE) - .tekstLnr(NUMBER_VALUE).datoTekstFom(LOCAL_DATE) - .datoTekstTom(LOCAL_DATE).tekstKode(TEXT_VALUE) - .feilreg(TEXT_VALUE).build())) - .build(); - } - - private static OppdragRequest buildOppdragsLinje() { - - return OppdragRequest.builder() - .oppdragslinje(List.of(OppdragRequest.Oppdragslinje.builder() - .kodeEndringLinje(OppdragRequest.KodeEndringType.NY) - .kodeStatusLinje(OppdragRequest.KodeStatusLinje.OPPH) - .datoStatusFom(LOCAL_DATE) - .vedtakId(TEXT_VALUE) - .delytelseId(TEXT_VALUE) - .linjeId(NUMBER_VALUE) - .kodeKlassifik(TEXT_VALUE) - .datoKlassifikFom(LOCAL_DATE) - .datoVedtakFom(LOCAL_DATE) - .datoVedtakTom(LOCAL_DATE) - .sats(BELOP_GRENSE) - .fradragTillegg(OppdragRequest.FradragTillegg.F) - .typeSats(SatsType._14DB) - .skyldnerId(TEXT_VALUE) - .datoSkyldnerFom(LOCAL_DATE) - .kravhaverId(TEXT_VALUE) - .datoKravhaverFom(LOCAL_DATE) - .kid(TEXT_VALUE) - .datoKidFom(LOCAL_DATE) - .brukKjoreplan(TEXT_VALUE) - .saksbehId(NOM) - .utbetalesTilId(TEXT_VALUE) - .datoUtbetalesTilIdFom(LOCAL_DATE) - .kodeArbeidsgiver(OppdragRequest.KodeArbeidsgiver.A) - .henvisning(TEXT_VALUE) - .typeSoknad(TEXT_VALUE) - .refFagsystemId(TEXT_VALUE) - .refOppdragsId(LONG_VALUE) - .refDelytelseId(TEXT_VALUE) - .refLinjeId(NUMBER_VALUE) - .refusjonsInfo(OppdragRequest.RefusjonsInfo.builder() - .refunderesId(TEXT_VALUE) - .maksDato(LOCAL_DATE) - .datoFom(LOCAL_DATE) - .build()) - .tekst(List.of(OppdragRequest.Tekst.builder() - .tekst(TEXT_VALUE) - .tekstLnr(NUMBER_VALUE) - .datoTekstFom(LOCAL_DATE) - .build())) - .enhet(List.of(OppdragRequest.Enhet.builder() - .typeEnhet(TEXT_VALUE) - .enhet(TEXT_VALUE) - .datoEnhetFom(LOCAL_DATE) - .build())) - .grad(List.of(OppdragRequest.Grad.builder() - .typeGrad(TEXT_VALUE) - .grad(NUMBER_VALUE) - .build())) - .attestant(List.of(OppdragRequest.Attestant.builder() - .attestantId(TEXT_VALUE) - .datoUgyldigFom(LOCAL_DATE) - .build())) - .valuta(List.of(OppdragRequest.Valuta.builder() - .typeValuta(ValuteType.FAKT) - .valuta(TEXT_VALUE) - .datoValutaFom(LOCAL_DATE) - .feilreg(TEXT_VALUE) - .build())) - .build())) - .build(); - } } \ No newline at end of file diff --git a/apps/oppdrag-service/src/test/java/no/nav/testnav/oppdragservice/mapper/OppdragResponseMappingStrategyTest.java b/apps/oppdrag-service/src/test/java/no/nav/testnav/oppdragservice/mapper/OppdragResponseMappingStrategyTest.java new file mode 100644 index 00000000000..6d644fc7a83 --- /dev/null +++ b/apps/oppdrag-service/src/test/java/no/nav/testnav/oppdragservice/mapper/OppdragResponseMappingStrategyTest.java @@ -0,0 +1,156 @@ +package no.nav.testnav.oppdragservice.mapper; + +import ma.glasnost.orika.MapperFacade; +import no.nav.testnav.libs.dto.oppdragservice.v1.Oppdrag; +import no.nav.testnav.libs.dto.oppdragservice.v1.Oppdrag.JaNei; +import no.nav.testnav.libs.dto.oppdragservice.v1.OppdragResponse; +import no.nav.testnav.oppdragservice.utilty.Oppdragsdata; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.ExtendWith; +import org.mockito.junit.jupiter.MockitoExtension; + +import java.util.List; + +import static no.nav.testnav.oppdragservice.utilty.Oppdragsdata.BELOP_GRENSE; +import static no.nav.testnav.oppdragservice.utilty.Oppdragsdata.LOCAL_DATE; +import static no.nav.testnav.oppdragservice.utilty.Oppdragsdata.LOCAL_DATE_TIME; +import static no.nav.testnav.oppdragservice.utilty.Oppdragsdata.LONG_VALUE; +import static no.nav.testnav.oppdragservice.utilty.Oppdragsdata.NOM; +import static no.nav.testnav.oppdragservice.utilty.Oppdragsdata.NUMBER_VALUE; +import static no.nav.testnav.oppdragservice.utilty.Oppdragsdata.TEXT_VALUE; +import static org.hamcrest.CoreMatchers.equalTo; +import static org.hamcrest.CoreMatchers.is; +import static org.hamcrest.MatcherAssert.assertThat; +import static org.hamcrest.Matchers.allOf; +import static org.hamcrest.Matchers.contains; +import static org.hamcrest.Matchers.hasProperty; + +@ExtendWith(MockitoExtension.class) +class OppdragResponseMappingStrategyTest { + + private MapperFacade mapperFacade; + + @BeforeEach + void setup() { + + mapperFacade = MapperTestUtils.createMapperFacadeForMappingStrategy( + List.of(new LocalDateCustomMapping(), new LocalDateTimeCustomMapping()), + new OppdragResponseMappingStrategy()); + } + + @Test + void mapOppdragResponse_OK() { + + var oppdragResponse = Oppdragsdata.buildOppdragResponse(); + + var response = mapperFacade.map(oppdragResponse, OppdragResponse.class); + var target = response.getOppdrag(); + + assertThat(target.getOppdragsId(), is(equalTo(LONG_VALUE))); + assertThat(target.getBilagstype(), contains(hasProperty("typeBilag", is(equalTo(TEXT_VALUE))))); + assertThat(target.getAvstemmingsnokkel(), contains(allOf( + hasProperty("kodeKomponent", is(equalTo(TEXT_VALUE))), + hasProperty("avstemmingsNokkel", is(equalTo(TEXT_VALUE))), + hasProperty("tidspktReg", is(equalTo(LOCAL_DATE_TIME)))))); + assertThat(target.getOmpostering(), allOf( + hasProperty("datoOmposterFom", is(equalTo(LOCAL_DATE))), + hasProperty("tidspktReg", is(equalTo(LOCAL_DATE_TIME))), + hasProperty("omPostering", is(equalTo(JaNei.J))), + hasProperty("saksbehId", is(equalTo(TEXT_VALUE))))); + assertThat(target.getKodeEndring(), is(equalTo(Oppdrag.KodeEndring.NY))); + assertThat(target.getKodeStatus(), is(equalTo(Oppdrag.KodeStatus.ATTE))); + assertThat(target.getDatoStatusFom(), is(equalTo(LOCAL_DATE))); + assertThat(target.getKodeFagomraade(), is(equalTo(TEXT_VALUE))); + assertThat(target.getFagsystemId(), is(equalTo(TEXT_VALUE))); + assertThat(target.getOppdragsId(), is(equalTo(LONG_VALUE))); + assertThat(target.getUtbetFrekvens(), is(equalTo(Oppdrag.UtbetalingFrekvensType._14DG))); + assertThat(target.getDatoForfall(), is(equalTo(LOCAL_DATE))); + assertThat(target.getStonadId(), is(equalTo(TEXT_VALUE))); + assertThat(target.getOppdragGjelderId(), is(equalTo(TEXT_VALUE))); + assertThat(target.getDatoOppdragGjelderFom(), is(equalTo(LOCAL_DATE))); + assertThat(target.getSaksbehId(), is(equalTo(NOM))); + assertThat(target.getEnhet(), contains(allOf( + hasProperty("typeEnhet", is(equalTo(TEXT_VALUE))), + hasProperty("enhet", is(equalTo(TEXT_VALUE))), + hasProperty("datoEnhetFom", is(equalTo(LOCAL_DATE)))))); + assertThat(target.getBelopsgrense(), contains(allOf( + hasProperty("belopGrense", is(equalTo(BELOP_GRENSE))), + hasProperty("datoGrenseFom", is(equalTo(LOCAL_DATE))), + hasProperty("datoGrenseTom", is(equalTo(LOCAL_DATE))), + hasProperty("typeGrense", is(equalTo(TEXT_VALUE))), + hasProperty("feilreg", is(equalTo(TEXT_VALUE)))))); + assertThat(target.getTekst(), contains(allOf( + hasProperty("tekst", is(equalTo(TEXT_VALUE))), + hasProperty("tekstLnr", is(equalTo(NUMBER_VALUE))), + hasProperty("datoTekstFom", is(equalTo(LOCAL_DATE))), + hasProperty("datoTekstTom", is(equalTo(LOCAL_DATE))), + hasProperty("tekstKode", is(equalTo(TEXT_VALUE))), + hasProperty("feilreg", is(equalTo(TEXT_VALUE)))))); + } + + @Test + void mapOppdragsLinjeResponse_OK() { + + var oppdragResponse = Oppdragsdata.buildOppdragslinjeResponse(); + + var response = mapperFacade.map(oppdragResponse, OppdragResponse.class); + var target = response.getOppdrag(); + + assertThat(target.getOppdragslinje(), contains(allOf( + hasProperty("kodeEndringLinje", is(equalTo(Oppdrag.KodeEndringType.NY))), + hasProperty("kodeStatusLinje", is(equalTo(Oppdrag.KodeStatusLinje.OPPH))), + hasProperty("datoStatusFom", is(equalTo(LOCAL_DATE))), + hasProperty("vedtakId", is(equalTo(TEXT_VALUE))), + hasProperty("delytelseId", is(equalTo(TEXT_VALUE))), + hasProperty("linjeId", is(equalTo(NUMBER_VALUE))), + hasProperty("kodeKlassifik", is(equalTo(TEXT_VALUE))), + hasProperty("datoKlassifikFom", is(equalTo(LOCAL_DATE))), + hasProperty("datoVedtakFom", is(equalTo(LOCAL_DATE))), + hasProperty("datoVedtakTom", is(equalTo(LOCAL_DATE))), + hasProperty("sats", is(equalTo(BELOP_GRENSE))), + hasProperty("fradragTillegg", is(equalTo(Oppdrag.FradragTillegg.F))), + hasProperty("typeSats", is(equalTo(Oppdrag.SatsType._14DB))), + hasProperty("skyldnerId", is(equalTo(TEXT_VALUE))), + hasProperty("datoSkyldnerFom", is(equalTo(LOCAL_DATE))), + hasProperty("kravhaverId", is(equalTo(TEXT_VALUE))), + hasProperty("datoKravhaverFom", is(equalTo(LOCAL_DATE))), + hasProperty("kid", is(equalTo(TEXT_VALUE))), + hasProperty("datoKidFom", is(equalTo(LOCAL_DATE))), + hasProperty("brukKjoreplan", is(equalTo(TEXT_VALUE))), + hasProperty("saksbehId", is(equalTo(NOM))), + hasProperty("utbetalesTilId", is(equalTo(TEXT_VALUE))), + hasProperty("datoUtbetalesTilIdFom", is(equalTo(LOCAL_DATE))), + hasProperty("kodeArbeidsgiver", is(equalTo(Oppdrag.KodeArbeidsgiver.A))), + hasProperty("henvisning", is(equalTo(TEXT_VALUE))), + hasProperty("typeSoknad", is(equalTo(TEXT_VALUE))), + hasProperty("refFagsystemId", is(equalTo(TEXT_VALUE))), + hasProperty("refOppdragsId", is(equalTo(LONG_VALUE))), + hasProperty("refDelytelseId", is(equalTo(TEXT_VALUE))), + hasProperty("refLinjeId", is(equalTo(NUMBER_VALUE))), + hasProperty("refusjonsInfo", allOf( + hasProperty("refunderesId", is(equalTo(TEXT_VALUE))), + hasProperty("maksDato", is(equalTo(LOCAL_DATE))), + hasProperty("datoFom", is(equalTo(LOCAL_DATE))))), + hasProperty("tekst", contains(allOf( + hasProperty("tekst", is(equalTo(TEXT_VALUE))), + hasProperty("tekstLnr", is(equalTo(NUMBER_VALUE))), + hasProperty("datoTekstFom", is(equalTo(LOCAL_DATE)))))), + hasProperty("enhet", contains(allOf( + hasProperty("typeEnhet", is(equalTo(TEXT_VALUE))), + hasProperty("enhet", is(equalTo(TEXT_VALUE))), + hasProperty("datoEnhetFom", is(equalTo(LOCAL_DATE)))))), + hasProperty("grad", contains(allOf( + hasProperty("typeGrad", is(equalTo(TEXT_VALUE))), + hasProperty("grad", is(equalTo(NUMBER_VALUE)))))), + hasProperty("attestant", contains(allOf( + hasProperty("attestantId", is(equalTo(TEXT_VALUE))), + hasProperty("datoUgyldigFom", is(equalTo(LOCAL_DATE)))))), + hasProperty("valuta", contains(allOf( + hasProperty("typeValuta", is(equalTo(Oppdrag.ValuteType.FAKT))), + hasProperty("valuta", is(equalTo(TEXT_VALUE))), + hasProperty("datoValutaFom", is(equalTo(LOCAL_DATE))), + hasProperty("feilreg", is(equalTo(TEXT_VALUE)))))) + ))); + } +} \ No newline at end of file diff --git a/apps/oppdrag-service/src/test/java/no/nav/testnav/oppdragservice/service/OppdragServiceTest.java b/apps/oppdrag-service/src/test/java/no/nav/testnav/oppdragservice/service/OppdragServiceTest.java new file mode 100644 index 00000000000..9040b9c9dd3 --- /dev/null +++ b/apps/oppdrag-service/src/test/java/no/nav/testnav/oppdragservice/service/OppdragServiceTest.java @@ -0,0 +1,37 @@ +package no.nav.testnav.oppdragservice.service; + +import ma.glasnost.orika.MapperFacade; +import no.nav.testnav.oppdragservice.config.TestConfig; +import no.nav.testnav.oppdragservice.consumer.OppdragConsumer; +import no.nav.testnav.oppdragservice.utilty.Oppdragsdata; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.ExtendWith; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.test.context.SpringBootTest; +import org.springframework.boot.test.mock.mockito.MockBean; +import org.springframework.test.context.ContextConfiguration; +import org.springframework.test.context.junit.jupiter.SpringExtension; + +@ExtendWith(SpringExtension.class) +@SpringBootTest() +@ContextConfiguration(classes = TestConfig.class) +class OppdragServiceTest { + + @MockBean + private OppdragConsumer oppdragConsumer; + + @Autowired + private MapperFacade mapperFacade; + + @Autowired + private OppdragService oppdragService; + + @Test + void execService_OK() { + + var request = Oppdragsdata.buildOppdragRequest(); + var test = oppdragService.sendInnOppdrag(request); + + System.out.println(test); + } + } \ No newline at end of file diff --git a/apps/oppdrag-service/src/test/java/no/nav/testnav/oppdragservice/utilty/Oppdragsdata.java b/apps/oppdrag-service/src/test/java/no/nav/testnav/oppdragservice/utilty/Oppdragsdata.java new file mode 100644 index 00000000000..b68e5c21a64 --- /dev/null +++ b/apps/oppdrag-service/src/test/java/no/nav/testnav/oppdragservice/utilty/Oppdragsdata.java @@ -0,0 +1,294 @@ +package no.nav.testnav.oppdragservice.utilty; + +import lombok.experimental.UtilityClass; +import no.nav.testnav.libs.dto.oppdragservice.v1.Oppdrag; +import no.nav.testnav.libs.dto.oppdragservice.v1.OppdragRequest; +import no.nav.testnav.oppdragservice.wsdl.Bilagstype; +import no.nav.testnav.oppdragservice.wsdl.FradragTillegg; +import no.nav.testnav.oppdragservice.wsdl.KodeArbeidsgiver; +import no.nav.testnav.oppdragservice.wsdl.KodeStatus; +import no.nav.testnav.oppdragservice.wsdl.KodeStatusLinje; +import no.nav.testnav.oppdragservice.wsdl.SendInnOppdragResponse; +import no.nav.testnav.oppdragservice.wsdl.SendInnOppdragResponse2; + +import java.math.BigDecimal; +import java.math.BigInteger; +import java.time.LocalDate; +import java.time.LocalDateTime; +import java.time.format.DateTimeFormatter; +import java.util.List; + +@UtilityClass +public class Oppdragsdata { + + public static final LocalDate LOCAL_DATE = LocalDate.now(); + public static final LocalDateTime LOCAL_DATE_TIME = LocalDateTime.now(); + + public static final String TARGET_DATE_FORMAT = DateTimeFormatter + .ofPattern("dd-MM-yyyy").format(LOCAL_DATE); + public static final String DB2_DATE_TIME_FORMAT = DateTimeFormatter + .ofPattern("yyyy-MM-dd-HH.mm.ss.SSSSSS").format(LOCAL_DATE_TIME); + + public static final String TEXT_VALUE = "tekst"; + public static final Integer NUMBER_VALUE = 123; + public static final Long LONG_VALUE = 456L; + public static final String NOM = "Z123456"; + public static final BigDecimal BELOP_GRENSE = new java.math.BigDecimal("12332.34"); + public static final BigInteger TARGET_NUMBER_VALUE = new BigInteger(NUMBER_VALUE.toString()); + + public static OppdragRequest buildOppdragRequest() { + + return OppdragRequest.builder() + .oppdrag(Oppdrag.builder() + .oppdragsId(LONG_VALUE) + .bilagstype(List.of(Oppdrag.Bilagstype.builder() + .typeBilag(TEXT_VALUE).build())) + .avstemmingsnokkel(List.of(Oppdrag.Avstemmingsnokkel + .builder().kodeKomponent(TEXT_VALUE) + .avstemmingsNokkel(TEXT_VALUE) + .tidspktReg(LOCAL_DATE_TIME).build())) + .ompostering(Oppdrag.Ompostering.builder() + .datoOmposterFom(LOCAL_DATE) + .tidspktReg(LOCAL_DATE_TIME) + .omPostering(Oppdrag.JaNei.J) + .saksbehId(TEXT_VALUE).build()) + .kodeEndring(Oppdrag.KodeEndring.NY) + .kodeStatus(Oppdrag.KodeStatus.ATTE) + .datoStatusFom(LOCAL_DATE) + .kodeFagomraade(TEXT_VALUE) + .fagsystemId(TEXT_VALUE) + .oppdragsId(LONG_VALUE) + .utbetFrekvens(Oppdrag.UtbetalingFrekvensType._14DG) + .datoForfall(LOCAL_DATE) + .stonadId(TEXT_VALUE) + .oppdragGjelderId(TEXT_VALUE) + .datoOppdragGjelderFom(LOCAL_DATE) + .saksbehId(NOM) + .enhet(List.of(Oppdrag.Enhet.builder().typeEnhet(TEXT_VALUE) + .enhet(TEXT_VALUE).datoEnhetFom(LOCAL_DATE).build())) + .belopsgrense(List.of(Oppdrag.Belopsgrense.builder() + .belopGrense(BELOP_GRENSE).datoGrenseFom(LOCAL_DATE) + .datoGrenseTom(LOCAL_DATE).typeGrense(TEXT_VALUE) + .feilreg(TEXT_VALUE).build())) + .tekst(List.of(Oppdrag.Tekst.builder().tekst(TEXT_VALUE) + .tekstLnr(NUMBER_VALUE).datoTekstFom(LOCAL_DATE) + .datoTekstTom(LOCAL_DATE).tekstKode(TEXT_VALUE) + .feilreg(TEXT_VALUE).build())) + .build()) + .build(); + } + + public static OppdragRequest buildOppdragsLinjeRequest() { + + return OppdragRequest.builder() + .oppdrag(Oppdrag.builder() + .oppdragslinje(List.of(Oppdrag.Oppdragslinje.builder() + .kodeEndringLinje(Oppdrag.KodeEndringType.NY) + .kodeStatusLinje(Oppdrag.KodeStatusLinje.OPPH) + .datoStatusFom(LOCAL_DATE) + .vedtakId(TEXT_VALUE) + .delytelseId(TEXT_VALUE) + .linjeId(NUMBER_VALUE) + .kodeKlassifik(TEXT_VALUE) + .datoKlassifikFom(LOCAL_DATE) + .datoVedtakFom(LOCAL_DATE) + .datoVedtakTom(LOCAL_DATE) + .sats(BELOP_GRENSE) + .fradragTillegg(Oppdrag.FradragTillegg.F) + .typeSats(Oppdrag.SatsType._14DB) + .skyldnerId(TEXT_VALUE) + .datoSkyldnerFom(LOCAL_DATE) + .kravhaverId(TEXT_VALUE) + .datoKravhaverFom(LOCAL_DATE) + .kid(TEXT_VALUE) + .datoKidFom(LOCAL_DATE) + .brukKjoreplan(TEXT_VALUE) + .saksbehId(NOM) + .utbetalesTilId(TEXT_VALUE) + .datoUtbetalesTilIdFom(LOCAL_DATE) + .kodeArbeidsgiver(Oppdrag.KodeArbeidsgiver.A) + .henvisning(TEXT_VALUE) + .typeSoknad(TEXT_VALUE) + .refFagsystemId(TEXT_VALUE) + .refOppdragsId(LONG_VALUE) + .refDelytelseId(TEXT_VALUE) + .refLinjeId(NUMBER_VALUE) + .refusjonsInfo(Oppdrag.RefusjonsInfo.builder() + .refunderesId(TEXT_VALUE) + .maksDato(LOCAL_DATE) + .datoFom(LOCAL_DATE) + .build()) + .tekst(List.of(Oppdrag.Tekst.builder() + .tekst(TEXT_VALUE) + .tekstLnr(NUMBER_VALUE) + .datoTekstFom(LOCAL_DATE) + .build())) + .enhet(List.of(Oppdrag.Enhet.builder() + .typeEnhet(TEXT_VALUE) + .enhet(TEXT_VALUE) + .datoEnhetFom(LOCAL_DATE) + .build())) + .grad(List.of(Oppdrag.Grad.builder() + .typeGrad(TEXT_VALUE) + .grad(NUMBER_VALUE) + .build())) + .attestant(List.of(Oppdrag.Attestant.builder() + .attestantId(TEXT_VALUE) + .datoUgyldigFom(LOCAL_DATE) + .build())) + .valuta(List.of(Oppdrag.Valuta.builder() + .typeValuta(Oppdrag.ValuteType.FAKT) + .valuta(TEXT_VALUE) + .datoValutaFom(LOCAL_DATE) + .feilreg(TEXT_VALUE) + .build())) + .build())) + .build()) + .build(); + } + + public static SendInnOppdragResponse buildOppdragResponse() { + + var response = new SendInnOppdragResponse(); + response.setResponse(new SendInnOppdragResponse2()); + + var oppdrag = new no.nav.testnav.oppdragservice.wsdl.Oppdrag(); + oppdrag.setOppdragsId(LONG_VALUE); + response.getResponse().setOppdrag(oppdrag); + + var bilagstype = new Bilagstype(); + bilagstype.setTypeBilag(TEXT_VALUE); + oppdrag.getBilagstype().add(bilagstype); + + var avstemmingsnokkel = new no.nav.testnav.oppdragservice.wsdl.Avstemmingsnokkel(); + avstemmingsnokkel.setKodeKomponent(TEXT_VALUE); + avstemmingsnokkel.setAvstemmingsNokkel(TEXT_VALUE); + avstemmingsnokkel.setTidspktReg(DB2_DATE_TIME_FORMAT); + oppdrag.getAvstemmingsnokkel().add(avstemmingsnokkel); + + var ompostering = new no.nav.testnav.oppdragservice.wsdl.Ompostering(); + ompostering.setDatoOmposterFom(TARGET_DATE_FORMAT); + ompostering.setTidspktReg(DB2_DATE_TIME_FORMAT); + ompostering.setOmPostering(Oppdrag.JaNei.J.toString()); + ompostering.setSaksbehId(TEXT_VALUE); + oppdrag.setOmpostering(ompostering); + + oppdrag.setKodeEndring(Oppdrag.KodeEndring.NY.toString()); + oppdrag.setKodeStatus(KodeStatus.ATTE); + oppdrag.setDatoStatusFom(TARGET_DATE_FORMAT); + oppdrag.setKodeFagomraade(TEXT_VALUE); + oppdrag.setFagsystemId(TEXT_VALUE); + oppdrag.setOppdragsId(LONG_VALUE); + oppdrag.setUtbetFrekvens("14DG"); + oppdrag.setDatoForfall(TARGET_DATE_FORMAT); + oppdrag.setStonadId(TEXT_VALUE); + oppdrag.setOppdragGjelderId(TEXT_VALUE); + oppdrag.setDatoOppdragGjelderFom(TARGET_DATE_FORMAT); + oppdrag.setSaksbehId(NOM); + + var enhet = new no.nav.testnav.oppdragservice.wsdl.Enhet(); + enhet.setTypeEnhet(TEXT_VALUE); + enhet.setEnhet(TEXT_VALUE); + enhet.setDatoEnhetFom(TARGET_DATE_FORMAT); + oppdrag.getEnhet().add(enhet); + + var belopsgrense = new no.nav.testnav.oppdragservice.wsdl.Belopsgrense(); + belopsgrense.setBelopGrense(BELOP_GRENSE); + belopsgrense.setDatoGrenseFom(TARGET_DATE_FORMAT); + belopsgrense.setDatoGrenseTom(TARGET_DATE_FORMAT); + belopsgrense.setTypeGrense(TEXT_VALUE); + belopsgrense.setFeilreg(TEXT_VALUE); + oppdrag.getBelopsgrense().add(belopsgrense); + + var tekst = new no.nav.testnav.oppdragservice.wsdl.Tekst(); + tekst.setTekst(TEXT_VALUE); + tekst.setTekstLnr(TARGET_NUMBER_VALUE); + tekst.setDatoTekstFom(TARGET_DATE_FORMAT); + tekst.setDatoTekstTom(TARGET_DATE_FORMAT); + tekst.setTekstKode(TEXT_VALUE); + tekst.setFeilreg(TEXT_VALUE); + oppdrag.getTekst().add(tekst); + + return response; + } + + public static SendInnOppdragResponse buildOppdragslinjeResponse() { + + var response = new SendInnOppdragResponse(); + response.setResponse(new SendInnOppdragResponse2()); + + var oppdrag = new no.nav.testnav.oppdragservice.wsdl.Oppdrag(); + response.getResponse().setOppdrag(oppdrag); + + var oppdragslinje = new no.nav.testnav.oppdragservice.wsdl.Oppdragslinje(); + oppdrag.getOppdragslinje().add(oppdragslinje); + + oppdragslinje.setKodeEndringLinje(Oppdrag.KodeEndringType.NY.toString()); + oppdragslinje.setKodeStatusLinje(KodeStatusLinje.OPPH); + oppdragslinje.setDatoStatusFom(TARGET_DATE_FORMAT); + oppdragslinje.setVedtakId(TEXT_VALUE); + oppdragslinje.setDelytelseId(TEXT_VALUE); + oppdragslinje.setLinjeId(TARGET_NUMBER_VALUE); + oppdragslinje.setKodeKlassifik(TEXT_VALUE); + oppdragslinje.setDatoKlassifikFom(TARGET_DATE_FORMAT); + oppdragslinje.setDatoVedtakFom(TARGET_DATE_FORMAT); + oppdragslinje.setDatoVedtakTom(TARGET_DATE_FORMAT); + oppdragslinje.setSats(BELOP_GRENSE); + oppdragslinje.setFradragTillegg(FradragTillegg.F); + oppdragslinje.setTypeSats("14DB"); + oppdragslinje.setSkyldnerId(TEXT_VALUE); + oppdragslinje.setDatoSkyldnerFom(TARGET_DATE_FORMAT); + oppdragslinje.setKravhaverId(TEXT_VALUE); + oppdragslinje.setDatoKravhaverFom(TARGET_DATE_FORMAT); + oppdragslinje.setKid(TEXT_VALUE); + oppdragslinje.setDatoKidFom(TARGET_DATE_FORMAT); + oppdragslinje.setBrukKjoreplan(TEXT_VALUE); + oppdragslinje.setSaksbehId(NOM); + oppdragslinje.setUtbetalesTilId(TEXT_VALUE); + oppdragslinje.setDatoUtbetalesTilIdFom(TARGET_DATE_FORMAT); + oppdragslinje.setKodeArbeidsgiver(KodeArbeidsgiver.A); + oppdragslinje.setHenvisning(TEXT_VALUE); + oppdragslinje.setTypeSoknad(TEXT_VALUE); + oppdragslinje.setRefFagsystemId(TEXT_VALUE); + oppdragslinje.setRefOppdragsId(LONG_VALUE); + oppdragslinje.setRefDelytelseId(TEXT_VALUE); + oppdragslinje.setRefLinjeId(TARGET_NUMBER_VALUE); + + var refusjonsInfo = new no.nav.testnav.oppdragservice.wsdl.RefusjonsInfo(); + refusjonsInfo.setRefunderesId(TEXT_VALUE); + refusjonsInfo.setMaksDato(TARGET_DATE_FORMAT); + refusjonsInfo.setDatoFom(TARGET_DATE_FORMAT); + oppdragslinje.setRefusjonsInfo(refusjonsInfo); + + var tekst = new no.nav.testnav.oppdragservice.wsdl.Tekst(); + tekst.setTekst(TEXT_VALUE); + tekst.setTekstLnr(TARGET_NUMBER_VALUE); + tekst.setDatoTekstFom(TARGET_DATE_FORMAT); + oppdragslinje.getTekst().add(tekst); + + var enhet = new no.nav.testnav.oppdragservice.wsdl.Enhet(); + enhet.setTypeEnhet(TEXT_VALUE); + enhet.setEnhet(TEXT_VALUE); + enhet.setDatoEnhetFom(TARGET_DATE_FORMAT); + oppdragslinje.getEnhet().add(enhet); + + var grad = new no.nav.testnav.oppdragservice.wsdl.Grad(); + grad.setTypeGrad(TEXT_VALUE); + grad.setGrad(TARGET_NUMBER_VALUE); + oppdragslinje.getGrad().add(grad); + + var attestant = new no.nav.testnav.oppdragservice.wsdl.Attestant(); + attestant.setAttestantId(TEXT_VALUE); + attestant.setDatoUgyldigFom(TARGET_DATE_FORMAT); + oppdragslinje.getAttestant().add(attestant); + + var valuta = new no.nav.testnav.oppdragservice.wsdl.Valuta(); + valuta.setTypeValuta(Oppdrag.ValuteType.FAKT.toString()); + valuta.setValuta(TEXT_VALUE); + valuta.setDatoValutaFom(TARGET_DATE_FORMAT); + valuta.setFeilreg(TEXT_VALUE); + oppdragslinje.getValuta().add(valuta); + + return response; + } +} diff --git a/libs/data-transfer-objects/src/main/java/no/nav/testnav/libs/dto/oppdragservice/v1/Oppdrag.java b/libs/data-transfer-objects/src/main/java/no/nav/testnav/libs/dto/oppdragservice/v1/Oppdrag.java new file mode 100644 index 00000000000..1954544ee2b --- /dev/null +++ b/libs/data-transfer-objects/src/main/java/no/nav/testnav/libs/dto/oppdragservice/v1/Oppdrag.java @@ -0,0 +1,460 @@ +package no.nav.testnav.libs.dto.oppdragservice.v1; + +import io.swagger.v3.oas.annotations.media.Schema; +import jakarta.validation.constraints.NotBlank; +import jakarta.validation.constraints.Size; +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; + +import java.math.BigDecimal; +import java.time.LocalDate; +import java.time.LocalDateTime; +import java.util.ArrayList; +import java.util.List; + +import static java.util.Objects.isNull; + +@Data +@Builder +@NoArgsConstructor +@AllArgsConstructor +public class Oppdrag { + + private List bilagstype; + private List avstemmingsnokkel; + private Ompostering ompostering; + private List oppdragslinje; + + @NotBlank + private KodeEndring kodeEndring; + private KodeStatus kodeStatus; + private LocalDate datoStatusFom; + @NotBlank + @Schema(minLength = 1, maxLength = 8) + private String kodeFagomraade; + @Schema(maxLength = 30) + private String fagsystemId; + @Schema(maxLength = 10) + private Long oppdragsId; + private UtbetalingFrekvensType utbetFrekvens; + private LocalDate datoForfall; + @Schema(maxLength = 10) + private String stonadId; + @NotBlank + @Schema(description = "Angir fødselsnummer eller organisasjonsnummer oppdraget gjelder for", minLength = 9, maxLength = 11) + private String oppdragGjelderId; + @NotBlank + private LocalDate datoOppdragGjelderFom; + @NotBlank + @Schema(maxLength = 8) + private String saksbehId; + + private List enhet; + private List belopsgrense; + private List tekst; + + public List getBilagstype() { + + if (isNull(bilagstype)) { + bilagstype = new ArrayList<>(); + } + return bilagstype; + } + + public List getAvstemmingsnokkel() { + + if (isNull(avstemmingsnokkel)) { + avstemmingsnokkel = new ArrayList<>(); + } + return avstemmingsnokkel; + } + + public List getOppdragslinje() { + + if (isNull(oppdragslinje)) { + oppdragslinje = new ArrayList<>(); + } + return oppdragslinje; + } + + public List getEnhet() { + + if (isNull(enhet)) { + enhet = new ArrayList<>(); + } + return enhet; + } + + public List getBelopsgrense() { + + if (isNull(belopsgrense)) { + belopsgrense = new ArrayList<>(); + } + return belopsgrense; + } + + public List getTekst() { + + if (isNull(tekst)) { + tekst = new ArrayList<>(); + } + return tekst; + } + + @Data + @Builder + @NoArgsConstructor + @AllArgsConstructor + @Schema(description = "Bilagstype, Referanse ID 113") + public static class Bilagstype { + + @Schema(description = "Kode for type av bilag", minLength = 1, maxLength = 2) + private String typeBilag; + } + + @Data + @Builder + @NoArgsConstructor + @AllArgsConstructor + @Schema(description = "Entitet nøkler til bevis informasjon, Referanse ID 115") + public static class Avstemmingsnokkel { + + @NotBlank + @Schema(minLength = 1, maxLength = 8) + private String kodeKomponent; + @NotBlank + @Schema(minLength = 1, maxLength = 8) + private String avstemmingsNokkel; + @NotBlank + private LocalDateTime tidspktReg; + } + + @Data + @Builder + @NoArgsConstructor + @AllArgsConstructor + @Schema(description = "Ompostering, Referanse ID 116") + public static class Ompostering { + + @NotBlank + private JaNei omPostering; + private LocalDate datoOmposterFom; + @Schema(description = "Kode for beskrivelse av feil", minLength = 0, maxLength = 1) + private String feilreg; + @NotBlank + private LocalDateTime tidspktReg; + @NotBlank + @Schema(maxLength = 8) + private String saksbehId; + } + + @Data + @Builder + @NoArgsConstructor + @AllArgsConstructor + @Schema(description = "Oppdragslinje, Referanse ID 115") + public static class Oppdragslinje { + + @NotBlank + private KodeEndringType kodeEndringLinje; + private KodeStatusLinje kodeStatusLinje; + private LocalDate datoStatusFom; + @Schema(maxLength = 10) + private String vedtakId; + @Schema(maxLength = 30) + private String delytelseId; + @Schema(maxLength = 5) + private Integer linjeId; + @NotBlank + @Schema(minLength = 1, maxLength = 50) + private String kodeKlassifik; + private LocalDate datoKlassifikFom; + @NotBlank + private LocalDate datoVedtakFom; + private LocalDate datoVedtakTom; + @NotBlank + @Schema(description = "maximal toal lengde = 13, antall desimaler = 2") + private BigDecimal sats; + @NotBlank + private FradragTillegg fradragTillegg; + @NotBlank + private SatsType typeSats; + @Schema(description = "Angir fødselsnummer eller organisasjonsnummer på skyldneren", minLength = 9, maxLength = 11) + private String skyldnerId; + private LocalDate datoSkyldnerFom; + @Schema(description = "Angir fødselsnummer eller organisasjonsnummer på kravhaver", minLength = 9, maxLength = 11) + private String kravhaverId; + private LocalDate datoKravhaverFom; + @Schema(maxLength = 26) + private String kid; + private LocalDate datoKidFom; + @Schema(maxLength = 1) + private String brukKjoreplan; + @NotBlank + @Schema(maxLength = 8) + private String saksbehId; + @NotBlank + @Schema(description = "Angir fødselsnummer eller organisasjonsnummer på kravhaver", minLength = 9, maxLength = 11) + private String utbetalesTilId; + private LocalDate datoUtbetalesTilIdFom; + @NotBlank + private KodeArbeidsgiver kodeArbeidsgiver; + @Schema(maxLength = 30) + private String henvisning; + @Schema(maxLength = 10) + private String typeSoknad; + @Schema(maxLength = 30) + private String refFagsystemId; + @Schema(maxLength = 10) + private Long refOppdragsId; + @Schema(maxLength = 30) + private String refDelytelseId; + @Schema(maxLength = 5) + private Integer refLinjeId; + + private RefusjonsInfo refusjonsInfo; + private List tekst; + + private List enhet; + private List grad; + private List attestant; + private List valuta; + + public List getTekst() { + + if (isNull(tekst)) { + tekst = new ArrayList<>(); + } + return tekst; + } + + public List getEnhet() { + + if (isNull(enhet)) { + enhet = new ArrayList<>(); + } + return enhet; + } + + public List getGrad() { + + if (isNull(grad)) { + grad = new ArrayList<>(); + } + return grad; + } + + public List getAttestant() { + + if (isNull(attestant)) { + attestant = new ArrayList<>(); + } + return attestant; + } + + public List getValuta() { + + if (isNull(valuta)) { + valuta = new ArrayList<>(); + } + return valuta; + } + } + + @Data + @Builder + @NoArgsConstructor + @AllArgsConstructor + @Schema(description = "Entitet for refusjon til et orgnr og/eller maksdato for utbetaling av ytelse, Referanse ID 156") + public static class RefusjonsInfo { + + @Schema(description = "Angir fødselsnummer eller organisasjonsnummer på kravhaver", minLength = 9, maxLength = 11) + private String refunderesId; + private LocalDate maksDato; + private LocalDate datoFom; + } + + @Data + @Builder + @NoArgsConstructor + @AllArgsConstructor + @Schema(description = "Entitet Tekst, Referanse ID 140 dersom tekst er tilhørende oppdrag, " + + "Referanse ID 158 dersom tekst er tilhørende oppdragslinje") + public static class Tekst { + + @NotBlank + @Schema(minLength = 1, maxLength = 2) + private Integer tekstLnr; + @Schema(maxLength = 4) + private String tekstKode; + @Schema + private String tekst; + @NotBlank + private LocalDate datoTekstFom; + private LocalDate datoTekstTom; + @Schema(description = "Kode for beskrivelse av feil", minLength = 0, maxLength = 1) + private String feilreg; + } + + @Data + @Builder + @NoArgsConstructor + @AllArgsConstructor + @Schema(description = "Entitet enhet, Referanse ID 120 dersom enhet er på nivå oppdrag, " + + "Referanse ID 160 dersom enhet er på nivå oppdragslinje") + public static class Enhet { + + @NotBlank + @Size(min = 1, max = 4) + private String typeEnhet; + @Size(min = 4, max = 13) + @Schema(description = "Enhet er tknr evt orgnr + avdeling") + private String enhet; + @NotBlank + private LocalDate datoEnhetFom; + } + + @Data + @Builder + @NoArgsConstructor + @AllArgsConstructor + @Schema(description = "Entitet Grad, Referanse ID 170") + public static class Grad { + + @NotBlank + @Schema(minLength = 1, maxLength = 4) + protected String typeGrad; + @NotBlank + @Schema(description = "Prosentgrad, maks 100") + protected Integer grad; + } + + @Data + @Builder + @NoArgsConstructor + @AllArgsConstructor + @Schema(description = "Entitet Attestasjon, Referanse ID 180") + public static class Attestant { + + @NotBlank + @Schema(minLength = 1, maxLength = 8) + protected String attestantId; + protected LocalDate datoUgyldigFom; + } + + @Data + @Builder + @NoArgsConstructor + @AllArgsConstructor + @Schema(description = "Entitet Valuta, Referanse ID 190") + public static class Valuta { + + @NotBlank + protected ValuteType typeValuta; + @NotBlank + @Schema(minLength = 1, maxLength = 3) + protected String valuta; + @NotBlank + protected LocalDate datoValutaFom; + @Schema(description = "Kode for beskrivelse av feil", minLength = 0, maxLength = 1) + protected String feilreg; + } + + public enum JaNei { + J, + N + } + + public enum KodeStatusLinje { + OPPH, + HVIL, + SPER, + REAK + } + + public enum FradragTillegg { + F, + T + } + + public enum KodeArbeidsgiver { + A, + S, + P + } + + public enum KodeStatus { + NY, + LOPE, + HVIL, + SPER, + IKAT, + ATTE, + ANNU, + OPPH, + FBER, + REAK, + KORR, + FEIL + } + + public enum KodeEndring { + NY, + ENDR, + UEND + } + + public enum KodeEndringType { + NY, + ENDR + } + + public enum SatsType { + + DAG, + UKE, + _14DB, + MND, + AAR, + ENG, + AKTO + } + + public enum UtbetalingFrekvensType { + + DAG, + UKE, + MND, + _14DG, + ENG + } + + public enum ValuteType { + + FAKT, + FRAM, + UTB + } + + @Data + @Builder + @NoArgsConstructor + @AllArgsConstructor + @Schema(description = "Entitet Beløpsgrense, Referanse ID 130") + public static class Belopsgrense { + + @NotBlank + @Schema(minLength = 1, maxLength = 4) + private String typeGrense; + @NotBlank + @Schema(description = "Typen beskriver formatet og begrensningene til beløp, maks totalt antall sifre=11, desimaler=2") + private BigDecimal belopGrense; + @NotBlank + private LocalDate datoGrenseFom; + private LocalDate datoGrenseTom; + @Schema(description = "Kode for beskrivelse av feil", minLength = 0, maxLength = 1) + private String feilreg; + } +} diff --git a/libs/data-transfer-objects/src/main/java/no/nav/testnav/libs/dto/oppdragservice/v1/OppdragRequest.java b/libs/data-transfer-objects/src/main/java/no/nav/testnav/libs/dto/oppdragservice/v1/OppdragRequest.java index 4fef56f644e..228ff35b00e 100644 --- a/libs/data-transfer-objects/src/main/java/no/nav/testnav/libs/dto/oppdragservice/v1/OppdragRequest.java +++ b/libs/data-transfer-objects/src/main/java/no/nav/testnav/libs/dto/oppdragservice/v1/OppdragRequest.java @@ -1,21 +1,11 @@ package no.nav.testnav.libs.dto.oppdragservice.v1; import io.swagger.v3.oas.annotations.media.Schema; -import jakarta.validation.constraints.NotBlank; -import jakarta.validation.constraints.Size; import lombok.AllArgsConstructor; import lombok.Builder; import lombok.Data; import lombok.NoArgsConstructor; -import java.math.BigDecimal; -import java.time.LocalDate; -import java.time.LocalDateTime; -import java.util.ArrayList; -import java.util.List; - -import static java.util.Objects.isNull; - @Data @Builder @NoArgsConstructor @@ -23,439 +13,5 @@ @Schema(description = "Entitet Oppdrag, Referanse ID 110") public class OppdragRequest { - private List bilagstype; - private List avstemmingsnokkel; - private Ompostering ompostering; - private List oppdragslinje; - - @NotBlank - private KodeEndring kodeEndring; - private KodeStatus kodeStatus; - private LocalDate datoStatusFom; - @NotBlank - @Schema(minLength = 1, maxLength = 8) - private String kodeFagomraade; - @Schema(maxLength = 30) - private String fagsystemId; - @Schema(maxLength = 10) - private Long oppdragsId; - private UtbetalingFrekvensType utbetFrekvens; - private LocalDate datoForfall; - @Schema(maxLength = 10) - private String stonadId; - @NotBlank - @Schema(description = "Angir fødselsnummer eller organisasjonsnummer oppdraget gjelder for", minLength = 9, maxLength = 11) - private String oppdragGjelderId; - @NotBlank - private LocalDate datoOppdragGjelderFom; - @NotBlank - @Schema(maxLength = 8) - private String saksbehId; - - private List enhet; - private List belopsgrense; - private List tekst; - - public List getBilagstype() { - - if (isNull(bilagstype)) { - bilagstype = new ArrayList<>(); - } - return bilagstype; - } - - public List getAvstemmingsnokkel() { - - if (isNull(avstemmingsnokkel)) { - avstemmingsnokkel = new ArrayList<>(); - } - return avstemmingsnokkel; - } - - public List getOppdragslinje() { - - if (isNull(oppdragslinje)) { - oppdragslinje = new ArrayList<>(); - } - return oppdragslinje; - } - - public List getEnhet() { - - if (isNull(enhet)) { - enhet = new ArrayList<>(); - } - return enhet; - } - - public List getBelopsgrense() { - - if (isNull(belopsgrense)) { - belopsgrense = new ArrayList<>(); - } - return belopsgrense; - } - - public List getTekst() { - - if (isNull(tekst)) { - tekst = new ArrayList<>(); - } - return tekst; - } - - @Data - @Builder - @NoArgsConstructor - @AllArgsConstructor - @Schema(description = "Bilagstype, Referanse ID 113") - public static class Bilagstype { - - @Schema(description = "Kode for type av bilag", minLength = 1, maxLength = 2) - private String typeBilag; - } - - @Data - @Builder - @NoArgsConstructor - @AllArgsConstructor - @Schema(description = "Entitet nøkler til bevis informasjon, Referanse ID 115") - public static class Avstemmingsnokkel { - - @NotBlank - @Schema(minLength = 1, maxLength = 8) - private String kodeKomponent; - @NotBlank - @Schema(minLength = 1, maxLength = 8) - private String avstemmingsNokkel; - @NotBlank - private LocalDateTime tidspktReg; - } - - @Data - @Builder - @NoArgsConstructor - @AllArgsConstructor - @Schema(description = "Ompostering, Referanse ID 116") - public static class Ompostering { - - @NotBlank - private JaNei omPostering; - private LocalDate datoOmposterFom; - @Schema(description = "Kode for beskrivelse av feil", minLength = 0, maxLength = 1) - private String feilreg; - @NotBlank - private LocalDateTime tidspktReg; - @NotBlank - @Schema(maxLength = 8) - private String saksbehId; - } - - @Data - @Builder - @NoArgsConstructor - @AllArgsConstructor - @Schema(description = "Oppdragslinje, Referanse ID 115") - public static class Oppdragslinje { - - @NotBlank - private KodeEndringType kodeEndringLinje; - private KodeStatusLinje kodeStatusLinje; - private LocalDate datoStatusFom; - @Schema(maxLength = 10) - private String vedtakId; - @Schema(maxLength = 30) - private String delytelseId; - @Schema(maxLength = 5) - private Integer linjeId; - @NotBlank - @Schema(minLength = 1, maxLength = 50) - private String kodeKlassifik; - private LocalDate datoKlassifikFom; - @NotBlank - private LocalDate datoVedtakFom; - private LocalDate datoVedtakTom; - @NotBlank - @Schema(description = "maximal toal lengde = 13, antall desimaler = 2") - private BigDecimal sats; - @NotBlank - private FradragTillegg fradragTillegg; - @NotBlank - private SatsType typeSats; - @Schema(description = "Angir fødselsnummer eller organisasjonsnummer på skyldneren", minLength = 9, maxLength = 11) - private String skyldnerId; - private LocalDate datoSkyldnerFom; - @Schema(description = "Angir fødselsnummer eller organisasjonsnummer på kravhaver", minLength = 9, maxLength = 11) - private String kravhaverId; - private LocalDate datoKravhaverFom; - @Schema(maxLength = 26) - private String kid; - private LocalDate datoKidFom; - @Schema(maxLength = 1) - private String brukKjoreplan; - @NotBlank - @Schema(maxLength = 8) - private String saksbehId; - @NotBlank - @Schema(description = "Angir fødselsnummer eller organisasjonsnummer på kravhaver", minLength = 9, maxLength = 11) - private String utbetalesTilId; - private LocalDate datoUtbetalesTilIdFom; - @NotBlank - private KodeArbeidsgiver kodeArbeidsgiver; - @Schema(maxLength = 30) - private String henvisning; - @Schema(maxLength = 10) - private String typeSoknad; - @Schema(maxLength = 30) - private String refFagsystemId; - @Schema(maxLength = 10) - private Long refOppdragsId; - @Schema(maxLength = 30) - private String refDelytelseId; - @Schema(maxLength = 5) - private Integer refLinjeId; - - private RefusjonsInfo refusjonsInfo; - private List tekst; - - private List enhet; - private List grad; - private List attestant; - private List valuta; - - public List getTekst() { - - if (isNull(tekst)) { - tekst = new ArrayList<>(); - } - return tekst; - } - - public List getEnhet() { - - if (isNull(enhet)) { - enhet = new ArrayList<>(); - } - return enhet; - } - - public List getGrad() { - - if (isNull(grad)) { - grad = new ArrayList<>(); - } - return grad; - } - - public List getAttestant() { - - if (isNull(attestant)) { - attestant = new ArrayList<>(); - } - return attestant; - } - - public List getValuta() { - - if (isNull(valuta)) { - valuta = new ArrayList<>(); - } - return valuta; - } - } - - @Data - @Builder - @NoArgsConstructor - @AllArgsConstructor - @Schema(description = "Entitet for refusjon til et orgnr og/eller maksdato for utbetaling av ytelse, Referanse ID 156") - public static class RefusjonsInfo { - - @Schema(description = "Angir fødselsnummer eller organisasjonsnummer på kravhaver", minLength = 9, maxLength = 11) - private String refunderesId; - private LocalDate maksDato; - private LocalDate datoFom; - } - - @Data - @Builder - @NoArgsConstructor - @AllArgsConstructor - @Schema(description = "Entitet Tekst, Referanse ID 140 dersom tekst er tilhørende oppdrag, " + - "Referanse ID 158 dersom tekst er tilhørende oppdragslinje") - public static class Tekst { - - @NotBlank - @Schema(minLength = 1, maxLength = 2) - private Integer tekstLnr; - @Schema(maxLength = 4) - private String tekstKode; - @Schema - private String tekst; - @NotBlank - private LocalDate datoTekstFom; - private LocalDate datoTekstTom; - @Schema(description = "Kode for beskrivelse av feil", minLength = 0, maxLength = 1) - private String feilreg; - } - - @Data - @Builder - @NoArgsConstructor - @AllArgsConstructor - @Schema(description = "Entitet enhet, Referanse ID 120 dersom enhet er på nivå oppdrag, " + - "Referanse ID 160 dersom enhet er på nivå oppdragslinje") - public static class Enhet { - - @NotBlank - @Size(min = 1, max = 4) - private String typeEnhet; - @Size(min = 4, max = 13) - @Schema(description = "Enhet er tknr evt orgnr + avdeling") - private String enhet; - @NotBlank - private LocalDate datoEnhetFom; - } - - @Data - @Builder - @NoArgsConstructor - @AllArgsConstructor - @Schema(description = "Entitet Grad, Referanse ID 170") - public static class Grad { - - @NotBlank - @Schema(minLength = 1, maxLength = 4) - protected String typeGrad; - @NotBlank - @Schema(description = "Prosentgrad, maks 100") - protected Integer grad; - } - - @Data - @Builder - @NoArgsConstructor - @AllArgsConstructor - @Schema(description = "Entitet Attestasjon, Referanse ID 180") - public static class Attestant { - - @NotBlank - @Schema(minLength = 1, maxLength = 8) - protected String attestantId; - protected LocalDate datoUgyldigFom; - } - - @Data - @Builder - @NoArgsConstructor - @AllArgsConstructor - @Schema(description = "Entitet Valuta, Referanse ID 190") - public static class Valuta { - - @NotBlank - protected ValuteType typeValuta; - @NotBlank - @Schema(minLength = 1, maxLength = 3) - protected String valuta; - @NotBlank - protected LocalDate datoValutaFom; - @Schema(description = "Kode for beskrivelse av feil", minLength = 0, maxLength = 1) - protected String feilreg; - } - - public enum JaNei { - J, - N - } - - public enum KodeStatusLinje { - OPPH, - HVIL, - SPER, - REAK - } - - public enum FradragTillegg { - F, - T - } - - public enum KodeArbeidsgiver { - A, - S, - P - } - - public enum KodeStatus { - NY, - LOPE, - HVIL, - SPER, - IKAT, - ATTE, - ANNU, - OPPH, - FBER, - REAK, - KORR, - FEIL - } - - public enum KodeEndring { - NY, - ENDR, - UEND - } - - public enum KodeEndringType { - NY, - ENDR - } - - public enum SatsType { - - DAG, - UKE, - _14DB, - MND, - AAR, - ENG, - AKTO - } - - public enum UtbetalingFrekvensType { - - DAG, - UKE, - MND, - _14DG, - ENG - } - - public enum ValuteType { - - FAKT, - FRAM, - UTB - } - - @Data - @Builder - @NoArgsConstructor - @AllArgsConstructor - @Schema(description = "Entitet Beløpsgrense, Referanse ID 130") - public static class Belopsgrense { - - @NotBlank - @Schema(minLength = 1, maxLength = 4) - private String typeGrense; - @NotBlank - @Schema(description = "Typen beskriver formatet og begrensningene til beløp, maks totalt antall sifre=11, desimaler=2") - private BigDecimal belopGrense; - @NotBlank - private LocalDate datoGrenseFom; - private LocalDate datoGrenseTom; - @Schema(description = "Kode for beskrivelse av feil", minLength = 0, maxLength = 1) - private String feilreg; - } + private Oppdrag oppdrag; } diff --git a/libs/data-transfer-objects/src/main/java/no/nav/testnav/libs/dto/oppdragservice/v1/OppdragResponse.java b/libs/data-transfer-objects/src/main/java/no/nav/testnav/libs/dto/oppdragservice/v1/OppdragResponse.java new file mode 100644 index 00000000000..f0cde26ef67 --- /dev/null +++ b/libs/data-transfer-objects/src/main/java/no/nav/testnav/libs/dto/oppdragservice/v1/OppdragResponse.java @@ -0,0 +1,25 @@ +package no.nav.testnav.libs.dto.oppdragservice.v1; + +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; + +@Data +@Builder +@NoArgsConstructor +@AllArgsConstructor +public class OppdragResponse { + + private Oppdrag oppdrag; + private Infomelding infomelding; + + @Data + @Builder + @NoArgsConstructor + @AllArgsConstructor + public static class Infomelding { + + private String beskrMelding; + } +} From 01276b76b6aa0d3195a97f51f0f22b258d617e4f Mon Sep 17 00:00:00 2001 From: "Kristen.Herum" Date: Fri, 1 Nov 2024 13:03:42 +0100 Subject: [PATCH 11/35] Refactor OppdragService to use new OppdragResponse DTO Removed TestConfig and updated related test cases to directly use mocks. Modified OppdragService to return and map OppdragResponse instead of SendInnOppdragResponse, enhancing the consistency and maintainability of the service. --- .../OppdragResponseMappingStrategy.java | 2 + .../provider/OppdragController.java | 4 +- .../service/OppdragService.java | 10 +-- .../oppdragservice/config/TestConfig.java | 37 ----------- .../OppdragRequestMappingStrategyTest.java | 3 +- .../OppdragResponseMappingStrategyTest.java | 9 ++- .../service/OppdragServiceTest.java | 62 ++++++++++++++----- .../oppdragservice/utilty/Oppdragsdata.java | 14 ++++- 8 files changed, 77 insertions(+), 64 deletions(-) delete mode 100644 apps/oppdrag-service/src/test/java/no/nav/testnav/oppdragservice/config/TestConfig.java diff --git a/apps/oppdrag-service/src/main/java/no/nav/testnav/oppdragservice/mapper/OppdragResponseMappingStrategy.java b/apps/oppdrag-service/src/main/java/no/nav/testnav/oppdragservice/mapper/OppdragResponseMappingStrategy.java index a6b74cef50f..7b6d19bc2ca 100644 --- a/apps/oppdrag-service/src/main/java/no/nav/testnav/oppdragservice/mapper/OppdragResponseMappingStrategy.java +++ b/apps/oppdrag-service/src/main/java/no/nav/testnav/oppdragservice/mapper/OppdragResponseMappingStrategy.java @@ -5,6 +5,7 @@ import ma.glasnost.orika.MappingContext; import no.nav.testnav.libs.dto.oppdragservice.v1.Oppdrag; import no.nav.testnav.libs.dto.oppdragservice.v1.OppdragResponse; +import no.nav.testnav.libs.dto.oppdragservice.v1.OppdragResponse.Infomelding; import no.nav.testnav.oppdragservice.wsdl.SendInnOppdragResponse; import org.springframework.stereotype.Component; @@ -36,6 +37,7 @@ public void mapAtoB(SendInnOppdragResponse source, .replace("14DB","_14DB"))); destination.setOppdrag(mapperFacade.map(oppdrag, Oppdrag.class, context)); + destination.setInfomelding(mapperFacade.map(source.getResponse().getInfomelding(), Infomelding.class)); } }) .register(); diff --git a/apps/oppdrag-service/src/main/java/no/nav/testnav/oppdragservice/provider/OppdragController.java b/apps/oppdrag-service/src/main/java/no/nav/testnav/oppdragservice/provider/OppdragController.java index 4a7697437fd..17e07ffbdce 100644 --- a/apps/oppdrag-service/src/main/java/no/nav/testnav/oppdragservice/provider/OppdragController.java +++ b/apps/oppdrag-service/src/main/java/no/nav/testnav/oppdragservice/provider/OppdragController.java @@ -3,8 +3,8 @@ import io.swagger.v3.oas.annotations.Operation; import lombok.RequiredArgsConstructor; import no.nav.testnav.libs.dto.oppdragservice.v1.OppdragRequest; +import no.nav.testnav.libs.dto.oppdragservice.v1.OppdragResponse; import no.nav.testnav.oppdragservice.service.OppdragService; -import no.nav.testnav.oppdragservice.wsdl.SendInnOppdragResponse; import org.springframework.web.bind.annotation.PostMapping; import org.springframework.web.bind.annotation.RequestBody; import org.springframework.web.bind.annotation.RequestMapping; @@ -19,7 +19,7 @@ public class OppdragController { @PostMapping @Operation(summary = "Send inn oppdrag") - public SendInnOppdragResponse sendInnOppdrag(@RequestBody OppdragRequest oppdragRequest) { + public OppdragResponse sendInnOppdrag(@RequestBody OppdragRequest oppdragRequest) { return oppdragService.sendInnOppdrag(oppdragRequest); } diff --git a/apps/oppdrag-service/src/main/java/no/nav/testnav/oppdragservice/service/OppdragService.java b/apps/oppdrag-service/src/main/java/no/nav/testnav/oppdragservice/service/OppdragService.java index ac8a4c8b888..e3ed0315701 100644 --- a/apps/oppdrag-service/src/main/java/no/nav/testnav/oppdragservice/service/OppdragService.java +++ b/apps/oppdrag-service/src/main/java/no/nav/testnav/oppdragservice/service/OppdragService.java @@ -5,9 +5,9 @@ import lombok.SneakyThrows; import ma.glasnost.orika.MapperFacade; import no.nav.testnav.libs.dto.oppdragservice.v1.OppdragRequest; +import no.nav.testnav.libs.dto.oppdragservice.v1.OppdragResponse; import no.nav.testnav.oppdragservice.consumer.OppdragConsumer; import no.nav.testnav.oppdragservice.wsdl.SendInnOppdragRequest; -import no.nav.testnav.oppdragservice.wsdl.SendInnOppdragResponse; import org.springframework.stereotype.Service; import java.io.StringWriter; @@ -25,13 +25,13 @@ public OppdragService(OppdragConsumer oppdragConsumer, MapperFacade mapperFacade this.jaxbContext = JAXBContext.newInstance(SendInnOppdragRequest.class); } - public SendInnOppdragResponse sendInnOppdrag(OppdragRequest oppdragRequest) { + public OppdragResponse sendInnOppdrag(OppdragRequest oppdragRequest) { var request = mapperFacade.map(oppdragRequest, SendInnOppdragRequest.class); - var xmlRequest = marshallToXml(request); - var response = oppdragConsumer.sendOppdrag(request); - return null; + var oppdragResponse = oppdragConsumer.sendOppdrag(request); + + return mapperFacade.map(oppdragResponse, OppdragResponse.class); } @SneakyThrows diff --git a/apps/oppdrag-service/src/test/java/no/nav/testnav/oppdragservice/config/TestConfig.java b/apps/oppdrag-service/src/test/java/no/nav/testnav/oppdragservice/config/TestConfig.java deleted file mode 100644 index 924f952d4e6..00000000000 --- a/apps/oppdrag-service/src/test/java/no/nav/testnav/oppdragservice/config/TestConfig.java +++ /dev/null @@ -1,37 +0,0 @@ -package no.nav.testnav.oppdragservice.config; - -import jakarta.xml.bind.JAXBException; -import ma.glasnost.orika.MapperFacade; -import no.nav.testnav.oppdragservice.consumer.OppdragConsumer; -import no.nav.testnav.oppdragservice.mapper.LocalDateCustomMapping; -import no.nav.testnav.oppdragservice.mapper.LocalDateTimeCustomMapping; -import no.nav.testnav.oppdragservice.mapper.MapperTestUtils; -import no.nav.testnav.oppdragservice.mapper.OppdragRequestMappingStrategy; -import no.nav.testnav.oppdragservice.service.OppdragService; -import org.springframework.context.annotation.Bean; -import org.springframework.context.annotation.Configuration; - -import java.util.List; - -@Configuration -public class TestConfig { - - @Bean - public OppdragService oppdragService() throws JAXBException { - return new OppdragService(oppdragConsumer(), mapperFacade()); - } - - @Bean - public OppdragConsumer oppdragConsumer() { - return new OppdragConsumer(); - } - - @Bean - public MapperFacade mapperFacade() { - - return MapperTestUtils.createMapperFacadeForMappingStrategy( - List.of(new LocalDateCustomMapping(), - new LocalDateTimeCustomMapping()), - new OppdragRequestMappingStrategy()); - } -} \ No newline at end of file diff --git a/apps/oppdrag-service/src/test/java/no/nav/testnav/oppdragservice/mapper/OppdragRequestMappingStrategyTest.java b/apps/oppdrag-service/src/test/java/no/nav/testnav/oppdragservice/mapper/OppdragRequestMappingStrategyTest.java index a4cb5be2280..daed158f05b 100644 --- a/apps/oppdrag-service/src/test/java/no/nav/testnav/oppdragservice/mapper/OppdragRequestMappingStrategyTest.java +++ b/apps/oppdrag-service/src/test/java/no/nav/testnav/oppdragservice/mapper/OppdragRequestMappingStrategyTest.java @@ -61,7 +61,8 @@ void mapOppdragRequest_OK() { hasProperty("datoOmposterFom", is(equalTo(TARGET_DATE_FORMAT))), hasProperty("tidspktReg", is(equalTo(DB2_DATE_TIME_FORMAT))), hasProperty("omPostering", is(equalTo("J"))), - hasProperty("saksbehId", is(equalTo(TEXT_VALUE))))); + hasProperty("saksbehId", is(equalTo(TEXT_VALUE))), + hasProperty("feilreg", is(equalTo(TEXT_VALUE))))); assertThat(target.getKodeEndring(), is(equalTo(Oppdrag.KodeEndring.NY.toString()))); assertThat(target.getKodeStatus(), is(equalTo(KodeStatus.ATTE))); assertThat(target.getDatoStatusFom(), is(equalTo(TARGET_DATE_FORMAT))); diff --git a/apps/oppdrag-service/src/test/java/no/nav/testnav/oppdragservice/mapper/OppdragResponseMappingStrategyTest.java b/apps/oppdrag-service/src/test/java/no/nav/testnav/oppdragservice/mapper/OppdragResponseMappingStrategyTest.java index 6d644fc7a83..e14c507b243 100644 --- a/apps/oppdrag-service/src/test/java/no/nav/testnav/oppdragservice/mapper/OppdragResponseMappingStrategyTest.java +++ b/apps/oppdrag-service/src/test/java/no/nav/testnav/oppdragservice/mapper/OppdragResponseMappingStrategyTest.java @@ -45,6 +45,9 @@ void mapOppdragResponse_OK() { var oppdragResponse = Oppdragsdata.buildOppdragResponse(); var response = mapperFacade.map(oppdragResponse, OppdragResponse.class); + + assertThat(response.getInfomelding().getBeskrMelding(), is(equalTo(TEXT_VALUE))); + var target = response.getOppdrag(); assertThat(target.getOppdragsId(), is(equalTo(LONG_VALUE))); @@ -57,7 +60,8 @@ void mapOppdragResponse_OK() { hasProperty("datoOmposterFom", is(equalTo(LOCAL_DATE))), hasProperty("tidspktReg", is(equalTo(LOCAL_DATE_TIME))), hasProperty("omPostering", is(equalTo(JaNei.J))), - hasProperty("saksbehId", is(equalTo(TEXT_VALUE))))); + hasProperty("saksbehId", is(equalTo(TEXT_VALUE))), + hasProperty("feilreg", is(equalTo(TEXT_VALUE))))); assertThat(target.getKodeEndring(), is(equalTo(Oppdrag.KodeEndring.NY))); assertThat(target.getKodeStatus(), is(equalTo(Oppdrag.KodeStatus.ATTE))); assertThat(target.getDatoStatusFom(), is(equalTo(LOCAL_DATE))); @@ -95,6 +99,9 @@ void mapOppdragsLinjeResponse_OK() { var oppdragResponse = Oppdragsdata.buildOppdragslinjeResponse(); var response = mapperFacade.map(oppdragResponse, OppdragResponse.class); + + assertThat(response.getInfomelding().getBeskrMelding(), is(equalTo(TEXT_VALUE))); + var target = response.getOppdrag(); assertThat(target.getOppdragslinje(), contains(allOf( diff --git a/apps/oppdrag-service/src/test/java/no/nav/testnav/oppdragservice/service/OppdragServiceTest.java b/apps/oppdrag-service/src/test/java/no/nav/testnav/oppdragservice/service/OppdragServiceTest.java index 9040b9c9dd3..bebbf13318e 100644 --- a/apps/oppdrag-service/src/test/java/no/nav/testnav/oppdragservice/service/OppdragServiceTest.java +++ b/apps/oppdrag-service/src/test/java/no/nav/testnav/oppdragservice/service/OppdragServiceTest.java @@ -1,37 +1,65 @@ package no.nav.testnav.oppdragservice.service; import ma.glasnost.orika.MapperFacade; -import no.nav.testnav.oppdragservice.config.TestConfig; import no.nav.testnav.oppdragservice.consumer.OppdragConsumer; +import no.nav.testnav.oppdragservice.mapper.LocalDateCustomMapping; +import no.nav.testnav.oppdragservice.mapper.LocalDateTimeCustomMapping; +import no.nav.testnav.oppdragservice.mapper.MapperTestUtils; +import no.nav.testnav.oppdragservice.mapper.OppdragRequestMappingStrategy; +import no.nav.testnav.oppdragservice.mapper.OppdragResponseMappingStrategy; import no.nav.testnav.oppdragservice.utilty.Oppdragsdata; +import no.nav.testnav.oppdragservice.wsdl.SendInnOppdragRequest; import org.junit.jupiter.api.Test; import org.junit.jupiter.api.extension.ExtendWith; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.boot.test.context.SpringBootTest; -import org.springframework.boot.test.mock.mockito.MockBean; -import org.springframework.test.context.ContextConfiguration; -import org.springframework.test.context.junit.jupiter.SpringExtension; - -@ExtendWith(SpringExtension.class) -@SpringBootTest() -@ContextConfiguration(classes = TestConfig.class) +import org.mockito.InjectMocks; +import org.mockito.Mock; +import org.mockito.Spy; +import org.mockito.junit.jupiter.MockitoExtension; + +import java.util.List; + +import static no.nav.testnav.oppdragservice.utilty.Oppdragsdata.TEXT_VALUE; +import static org.hamcrest.MatcherAssert.assertThat; +import static org.hamcrest.Matchers.equalTo; +import static org.hamcrest.Matchers.is; +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.Mockito.when; + +@ExtendWith(MockitoExtension.class) class OppdragServiceTest { - @MockBean + @Mock private OppdragConsumer oppdragConsumer; - @Autowired - private MapperFacade mapperFacade; + @Spy + private MapperFacade mapperFacade = MapperTestUtils.createMapperFacadeForMappingStrategy( + List.of(new LocalDateCustomMapping(), new LocalDateTimeCustomMapping()), + new OppdragRequestMappingStrategy(), new OppdragResponseMappingStrategy()); - @Autowired + @InjectMocks private OppdragService oppdragService; @Test - void execService_OK() { + void execOppdragServiceNominal_OK() { + + when(oppdragConsumer.sendOppdrag(any(SendInnOppdragRequest.class))) + .thenReturn(Oppdragsdata.buildOppdragResponse()); var request = Oppdragsdata.buildOppdragRequest(); - var test = oppdragService.sendInnOppdrag(request); + var target = oppdragService.sendInnOppdrag(request); + + assertThat(target.getInfomelding().getBeskrMelding(), is(equalTo(TEXT_VALUE))); + } + + @Test + void execOppdragServiceOppdragslinje_OK() { + + when(oppdragConsumer.sendOppdrag(any(SendInnOppdragRequest.class))) + .thenReturn(Oppdragsdata.buildOppdragslinjeResponse()); + + var request = Oppdragsdata.buildOppdragsLinjeRequest(); + var target = oppdragService.sendInnOppdrag(request); - System.out.println(test); + assertThat(target.getInfomelding().getBeskrMelding(), is(equalTo(TEXT_VALUE))); } } \ No newline at end of file diff --git a/apps/oppdrag-service/src/test/java/no/nav/testnav/oppdragservice/utilty/Oppdragsdata.java b/apps/oppdrag-service/src/test/java/no/nav/testnav/oppdragservice/utilty/Oppdragsdata.java index b68e5c21a64..3e63d219b41 100644 --- a/apps/oppdrag-service/src/test/java/no/nav/testnav/oppdragservice/utilty/Oppdragsdata.java +++ b/apps/oppdrag-service/src/test/java/no/nav/testnav/oppdragservice/utilty/Oppdragsdata.java @@ -5,6 +5,7 @@ import no.nav.testnav.libs.dto.oppdragservice.v1.OppdragRequest; import no.nav.testnav.oppdragservice.wsdl.Bilagstype; import no.nav.testnav.oppdragservice.wsdl.FradragTillegg; +import no.nav.testnav.oppdragservice.wsdl.Infomelding; import no.nav.testnav.oppdragservice.wsdl.KodeArbeidsgiver; import no.nav.testnav.oppdragservice.wsdl.KodeStatus; import no.nav.testnav.oppdragservice.wsdl.KodeStatusLinje; @@ -51,7 +52,9 @@ public static OppdragRequest buildOppdragRequest() { .datoOmposterFom(LOCAL_DATE) .tidspktReg(LOCAL_DATE_TIME) .omPostering(Oppdrag.JaNei.J) - .saksbehId(TEXT_VALUE).build()) + .saksbehId(TEXT_VALUE) + .feilreg(TEXT_VALUE) + .build()) .kodeEndring(Oppdrag.KodeEndring.NY) .kodeStatus(Oppdrag.KodeStatus.ATTE) .datoStatusFom(LOCAL_DATE) @@ -152,6 +155,10 @@ public static SendInnOppdragResponse buildOppdragResponse() { var response = new SendInnOppdragResponse(); response.setResponse(new SendInnOppdragResponse2()); + var infomelding = new Infomelding(); + infomelding.setBeskrMelding(TEXT_VALUE); + response.getResponse().setInfomelding(infomelding); + var oppdrag = new no.nav.testnav.oppdragservice.wsdl.Oppdrag(); oppdrag.setOppdragsId(LONG_VALUE); response.getResponse().setOppdrag(oppdrag); @@ -171,6 +178,7 @@ public static SendInnOppdragResponse buildOppdragResponse() { ompostering.setTidspktReg(DB2_DATE_TIME_FORMAT); ompostering.setOmPostering(Oppdrag.JaNei.J.toString()); ompostering.setSaksbehId(TEXT_VALUE); + ompostering.setFeilreg(TEXT_VALUE); oppdrag.setOmpostering(ompostering); oppdrag.setKodeEndring(Oppdrag.KodeEndring.NY.toString()); @@ -217,6 +225,10 @@ public static SendInnOppdragResponse buildOppdragslinjeResponse() { var response = new SendInnOppdragResponse(); response.setResponse(new SendInnOppdragResponse2()); + var infomelding = new Infomelding(); + infomelding.setBeskrMelding(TEXT_VALUE); + response.getResponse().setInfomelding(infomelding); + var oppdrag = new no.nav.testnav.oppdragservice.wsdl.Oppdrag(); response.getResponse().setOppdrag(oppdrag); From 72c562c153281a640d290ed9a77d7d03dbd61255 Mon Sep 17 00:00:00 2001 From: "Kristen.Herum" Date: Fri, 1 Nov 2024 13:38:12 +0100 Subject: [PATCH 12/35] Add missing fields to Oppdragsdata and update tests. Extended the Oppdragsdata class with `datoTekstTom`, `tekstKode`, and `feilreg` fields. Updated corresponding test cases in OppdragResponseMappingStrategyTest to ensure the new fields are properly validated. --- .../mapper/OppdragResponseMappingStrategyTest.java | 5 ++++- .../no/nav/testnav/oppdragservice/utilty/Oppdragsdata.java | 6 ++++++ 2 files changed, 10 insertions(+), 1 deletion(-) diff --git a/apps/oppdrag-service/src/test/java/no/nav/testnav/oppdragservice/mapper/OppdragResponseMappingStrategyTest.java b/apps/oppdrag-service/src/test/java/no/nav/testnav/oppdragservice/mapper/OppdragResponseMappingStrategyTest.java index e14c507b243..b16e17d1395 100644 --- a/apps/oppdrag-service/src/test/java/no/nav/testnav/oppdragservice/mapper/OppdragResponseMappingStrategyTest.java +++ b/apps/oppdrag-service/src/test/java/no/nav/testnav/oppdragservice/mapper/OppdragResponseMappingStrategyTest.java @@ -142,7 +142,10 @@ void mapOppdragsLinjeResponse_OK() { hasProperty("tekst", contains(allOf( hasProperty("tekst", is(equalTo(TEXT_VALUE))), hasProperty("tekstLnr", is(equalTo(NUMBER_VALUE))), - hasProperty("datoTekstFom", is(equalTo(LOCAL_DATE)))))), + hasProperty("datoTekstFom", is(equalTo(LOCAL_DATE))), + hasProperty("datoTekstTom", is(equalTo(LOCAL_DATE))), + hasProperty("tekstKode", is(equalTo(TEXT_VALUE))), + hasProperty("feilreg", is(equalTo(TEXT_VALUE)))))), hasProperty("enhet", contains(allOf( hasProperty("typeEnhet", is(equalTo(TEXT_VALUE))), hasProperty("enhet", is(equalTo(TEXT_VALUE))), diff --git a/apps/oppdrag-service/src/test/java/no/nav/testnav/oppdragservice/utilty/Oppdragsdata.java b/apps/oppdrag-service/src/test/java/no/nav/testnav/oppdragservice/utilty/Oppdragsdata.java index 3e63d219b41..ff89f22fab8 100644 --- a/apps/oppdrag-service/src/test/java/no/nav/testnav/oppdragservice/utilty/Oppdragsdata.java +++ b/apps/oppdrag-service/src/test/java/no/nav/testnav/oppdragservice/utilty/Oppdragsdata.java @@ -125,6 +125,9 @@ public static OppdragRequest buildOppdragsLinjeRequest() { .tekst(TEXT_VALUE) .tekstLnr(NUMBER_VALUE) .datoTekstFom(LOCAL_DATE) + .datoTekstTom(LOCAL_DATE) + .tekstKode(TEXT_VALUE) + .feilreg(TEXT_VALUE) .build())) .enhet(List.of(Oppdrag.Enhet.builder() .typeEnhet(TEXT_VALUE) @@ -276,6 +279,9 @@ public static SendInnOppdragResponse buildOppdragslinjeResponse() { tekst.setTekst(TEXT_VALUE); tekst.setTekstLnr(TARGET_NUMBER_VALUE); tekst.setDatoTekstFom(TARGET_DATE_FORMAT); + tekst.setDatoTekstTom(TARGET_DATE_FORMAT); + tekst.setTekstKode(TEXT_VALUE); + tekst.setFeilreg(TEXT_VALUE); oppdragslinje.getTekst().add(tekst); var enhet = new no.nav.testnav.oppdragservice.wsdl.Enhet(); From b99cceadd766d1b5c87d77b2ef5b0605f9b76296 Mon Sep 17 00:00:00 2001 From: "Kristen.Herum" Date: Fri, 1 Nov 2024 13:51:31 +0100 Subject: [PATCH 13/35] Add oppdrag-service GitHub Actions workflow #deploy-oppdrag-service Created a new workflow configuration for the oppdrag-service in the GitHub Actions. Updated `config.yml` by removing unused application entries and redundant reply URLs. --- .github/workflows/app.oppdrag-service.yml | 22 ++++++++++++++++++++++ apps/oppdrag-service/config.yml | 7 ------- 2 files changed, 22 insertions(+), 7 deletions(-) create mode 100644 .github/workflows/app.oppdrag-service.yml diff --git a/.github/workflows/app.oppdrag-service.yml b/.github/workflows/app.oppdrag-service.yml new file mode 100644 index 00000000000..5fb056a22a0 --- /dev/null +++ b/.github/workflows/app.oppdrag-service.yml @@ -0,0 +1,22 @@ +name: oppsummeringsdokument-service + +on: + push: + paths: + - "plugins/**" + - "libs/data-transfer-objects/**" + - "libs/servlet-core/**" + - "libs/servlet-security/**" + - "apps/oppdrag-service/**" + - ".github/workflows/app.oppdrag-service.yml" + +jobs: + workflow: + uses: ./.github/workflows/common.workflow.backend.yml + with: + working-directory: "apps/oppdrag-service" + deploy-tag: "#deploy-oppdrag-service" + permissions: + contents: read + id-token: write + secrets: inherit diff --git a/apps/oppdrag-service/config.yml b/apps/oppdrag-service/config.yml index 605d8dd47ac..caae1df66b7 100644 --- a/apps/oppdrag-service/config.yml +++ b/apps/oppdrag-service/config.yml @@ -19,11 +19,7 @@ spec: - application: dolly-frontend-dev-unstable - application: dolly-idporten - application: team-dolly-lokal-app - - application: testnav-faste-data-frontend - - application: testnav-organisasjon-forvalter - - application: testnav-orgnummer-service - application: testnav-oversikt-frontend - - application: testnav-tps-messaging-service tokenx: enabled: true azure: @@ -31,9 +27,6 @@ spec: allowAllUsers: true enabled: true tenant: nav.no - replyURLs: - - "https://testnav-miljoer-service.intern.dev.nav.no/login/oauth2/code/aad" - - "http://localhost:8080/login/oauth2/code/aad" liveness: path: /internal/isAlive initialDelay: 30 From 27257c0f7d7aa0f536c70e384eb30984f69b4813 Mon Sep 17 00:00:00 2001 From: "Kristen.Herum" Date: Fri, 1 Nov 2024 14:18:58 +0100 Subject: [PATCH 14/35] Update Oppdragsdata.java and Dockerfile #deploy-oppdrag-service Enhanced the builder pattern in Oppdragsdata by adjusting line breaks for improved readability. Updated Dockerfile to include necessary Java module permissions to avoid runtime issues. --- apps/oppdrag-service/Dockerfile | 2 +- .../no/nav/testnav/oppdragservice/utilty/Oppdragsdata.java | 3 ++- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/apps/oppdrag-service/Dockerfile b/apps/oppdrag-service/Dockerfile index 4a36f93546f..99a33947167 100644 --- a/apps/oppdrag-service/Dockerfile +++ b/apps/oppdrag-service/Dockerfile @@ -1,7 +1,7 @@ FROM ghcr.io/navikt/baseimages/temurin:21 LABEL maintainer="Team Dolly" -ENV JAVA_OPTS="-Dspring.profiles.active=prod" +ENV JAVA_OPTS="-Dspring.profiles.active=prod --add-opens java.base/java.lang=ALL-UNNAMED" ADD /build/libs/app.jar /app/app.jar diff --git a/apps/oppdrag-service/src/test/java/no/nav/testnav/oppdragservice/utilty/Oppdragsdata.java b/apps/oppdrag-service/src/test/java/no/nav/testnav/oppdragservice/utilty/Oppdragsdata.java index ff89f22fab8..1f21ff7d952 100644 --- a/apps/oppdrag-service/src/test/java/no/nav/testnav/oppdragservice/utilty/Oppdragsdata.java +++ b/apps/oppdrag-service/src/test/java/no/nav/testnav/oppdragservice/utilty/Oppdragsdata.java @@ -47,7 +47,8 @@ public static OppdragRequest buildOppdragRequest() { .avstemmingsnokkel(List.of(Oppdrag.Avstemmingsnokkel .builder().kodeKomponent(TEXT_VALUE) .avstemmingsNokkel(TEXT_VALUE) - .tidspktReg(LOCAL_DATE_TIME).build())) + .tidspktReg(LOCAL_DATE_TIME) + .build())) .ompostering(Oppdrag.Ompostering.builder() .datoOmposterFom(LOCAL_DATE) .tidspktReg(LOCAL_DATE_TIME) From ad7f2ecb156eea99572ef454979258379fd5e27a Mon Sep 17 00:00:00 2001 From: "Kristen.Herum" Date: Mon, 4 Nov 2024 07:22:26 +0100 Subject: [PATCH 15/35] Refactor date and time initialization logic. #deploy-oppdrag-service Changed the LOCAL_DATE and LOCAL_DATE_TIME initializations to use fixed values for consistency in tests. Reformatted DB2_DATE_TIME_FORMAT and adjusted its parsing mechanism accordingly. --- .../testnav/oppdragservice/utilty/Oppdragsdata.java | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/apps/oppdrag-service/src/test/java/no/nav/testnav/oppdragservice/utilty/Oppdragsdata.java b/apps/oppdrag-service/src/test/java/no/nav/testnav/oppdragservice/utilty/Oppdragsdata.java index 1f21ff7d952..6defd582de4 100644 --- a/apps/oppdrag-service/src/test/java/no/nav/testnav/oppdragservice/utilty/Oppdragsdata.java +++ b/apps/oppdrag-service/src/test/java/no/nav/testnav/oppdragservice/utilty/Oppdragsdata.java @@ -22,13 +22,13 @@ @UtilityClass public class Oppdragsdata { - public static final LocalDate LOCAL_DATE = LocalDate.now(); - public static final LocalDateTime LOCAL_DATE_TIME = LocalDateTime.now(); - + public static final LocalDate LOCAL_DATE = LocalDate.of(2024,11,4); public static final String TARGET_DATE_FORMAT = DateTimeFormatter .ofPattern("dd-MM-yyyy").format(LOCAL_DATE); - public static final String DB2_DATE_TIME_FORMAT = DateTimeFormatter - .ofPattern("yyyy-MM-dd-HH.mm.ss.SSSSSS").format(LOCAL_DATE_TIME); + + public static final String DB2_DATE_TIME_FORMAT = "2024-11-04-07.17.34.123456"; + public static final LocalDateTime LOCAL_DATE_TIME = LocalDateTime.from(DateTimeFormatter + .ofPattern("yyyy-MM-dd-HH.mm.ss.SSSSSS").parse(DB2_DATE_TIME_FORMAT)); public static final String TEXT_VALUE = "tekst"; public static final Integer NUMBER_VALUE = 123; From 08bac2d5d2a801cd88ba0523b0a6392a03df1639 Mon Sep 17 00:00:00 2001 From: "Kristen.Herum" Date: Mon, 4 Nov 2024 08:10:32 +0100 Subject: [PATCH 16/35] Refactor Oppdrag components. #deploy-oppdrag-service Correct enum naming from `ValuteType` to `ValutaType` in various classes, and add a new `KodeverkService` for retrieving code values. This also includes new mappings in `OppdragController` and `OppdragKodeverk` to handle these enums. --- .../provider/OppdragController.java | 14 +++++++++++ .../service/KodeverkService.java | 19 ++++++++++++++ .../OppdragRequestMappingStrategyTest.java | 4 +-- .../OppdragResponseMappingStrategyTest.java | 2 +- .../oppdragservice/utilty/Oppdragsdata.java | 4 +-- .../libs/dto/oppdragservice/v1/Oppdrag.java | 4 +-- .../oppdragservice/v1/OppdragKodeverk.java | 25 +++++++++++++++++++ 7 files changed, 65 insertions(+), 7 deletions(-) create mode 100644 apps/oppdrag-service/src/main/java/no/nav/testnav/oppdragservice/service/KodeverkService.java create mode 100644 libs/data-transfer-objects/src/main/java/no/nav/testnav/libs/dto/oppdragservice/v1/OppdragKodeverk.java diff --git a/apps/oppdrag-service/src/main/java/no/nav/testnav/oppdragservice/provider/OppdragController.java b/apps/oppdrag-service/src/main/java/no/nav/testnav/oppdragservice/provider/OppdragController.java index 17e07ffbdce..9bea11de37e 100644 --- a/apps/oppdrag-service/src/main/java/no/nav/testnav/oppdragservice/provider/OppdragController.java +++ b/apps/oppdrag-service/src/main/java/no/nav/testnav/oppdragservice/provider/OppdragController.java @@ -2,20 +2,27 @@ import io.swagger.v3.oas.annotations.Operation; import lombok.RequiredArgsConstructor; +import no.nav.testnav.libs.dto.oppdragservice.v1.OppdragKodeverk; import no.nav.testnav.libs.dto.oppdragservice.v1.OppdragRequest; import no.nav.testnav.libs.dto.oppdragservice.v1.OppdragResponse; +import no.nav.testnav.oppdragservice.service.KodeverkService; import no.nav.testnav.oppdragservice.service.OppdragService; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.PathVariable; import org.springframework.web.bind.annotation.PostMapping; import org.springframework.web.bind.annotation.RequestBody; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RestController; +import java.util.List; + @RestController @RequestMapping("/api/v1/oppdrag") @RequiredArgsConstructor public class OppdragController { private final OppdragService oppdragService; + private final KodeverkService kodeverkService; @PostMapping @Operation(summary = "Send inn oppdrag") @@ -23,4 +30,11 @@ public OppdragResponse sendInnOppdrag(@RequestBody OppdragRequest oppdragRequest return oppdragService.sendInnOppdrag(oppdragRequest); } + + @GetMapping("/kodeverk/{kodeverk}") + @Operation(summary = "Hent kodeverk") + public List getKodeverk(@PathVariable OppdragKodeverk kodeverk) { + + return kodeverkService.getKodeverk(kodeverk); + } } diff --git a/apps/oppdrag-service/src/main/java/no/nav/testnav/oppdragservice/service/KodeverkService.java b/apps/oppdrag-service/src/main/java/no/nav/testnav/oppdragservice/service/KodeverkService.java new file mode 100644 index 00000000000..e51aaeee377 --- /dev/null +++ b/apps/oppdrag-service/src/main/java/no/nav/testnav/oppdragservice/service/KodeverkService.java @@ -0,0 +1,19 @@ +package no.nav.testnav.oppdragservice.service; + +import no.nav.testnav.libs.dto.oppdragservice.v1.OppdragKodeverk; +import org.springframework.stereotype.Service; + +import java.util.List; +import java.util.stream.Stream; + +@Service +public class KodeverkService { + + public List getKodeverk(OppdragKodeverk oppdragKodeverk) { + + return Stream.of(oppdragKodeverk.getImplementasjon().getEnumConstants()) + .map(Object::toString) + .sorted() + .toList(); + } +} \ No newline at end of file diff --git a/apps/oppdrag-service/src/test/java/no/nav/testnav/oppdragservice/mapper/OppdragRequestMappingStrategyTest.java b/apps/oppdrag-service/src/test/java/no/nav/testnav/oppdragservice/mapper/OppdragRequestMappingStrategyTest.java index daed158f05b..caecdb54c77 100644 --- a/apps/oppdrag-service/src/test/java/no/nav/testnav/oppdragservice/mapper/OppdragRequestMappingStrategyTest.java +++ b/apps/oppdrag-service/src/test/java/no/nav/testnav/oppdragservice/mapper/OppdragRequestMappingStrategyTest.java @@ -2,7 +2,7 @@ import ma.glasnost.orika.MapperFacade; import no.nav.testnav.libs.dto.oppdragservice.v1.Oppdrag; -import no.nav.testnav.libs.dto.oppdragservice.v1.Oppdrag.ValuteType; +import no.nav.testnav.libs.dto.oppdragservice.v1.Oppdrag.ValutaType; import no.nav.testnav.oppdragservice.utilty.Oppdragsdata; import no.nav.testnav.oppdragservice.wsdl.FradragTillegg; import no.nav.testnav.oppdragservice.wsdl.KodeArbeidsgiver; @@ -152,7 +152,7 @@ void mapOppdragsLinjeRequest_OK() { hasProperty("attestantId", is(equalTo(TEXT_VALUE))), hasProperty("datoUgyldigFom", is(equalTo(TARGET_DATE_FORMAT)))))), hasProperty("valuta", contains(allOf( - hasProperty("typeValuta", is(equalTo(ValuteType.FAKT.toString()))), + hasProperty("typeValuta", is(equalTo(ValutaType.FAKT.toString()))), hasProperty("valuta", is(equalTo(TEXT_VALUE))), hasProperty("datoValutaFom", is(equalTo(TARGET_DATE_FORMAT))), hasProperty("feilreg", is(equalTo(TEXT_VALUE)))))) diff --git a/apps/oppdrag-service/src/test/java/no/nav/testnav/oppdragservice/mapper/OppdragResponseMappingStrategyTest.java b/apps/oppdrag-service/src/test/java/no/nav/testnav/oppdragservice/mapper/OppdragResponseMappingStrategyTest.java index b16e17d1395..752655381ad 100644 --- a/apps/oppdrag-service/src/test/java/no/nav/testnav/oppdragservice/mapper/OppdragResponseMappingStrategyTest.java +++ b/apps/oppdrag-service/src/test/java/no/nav/testnav/oppdragservice/mapper/OppdragResponseMappingStrategyTest.java @@ -157,7 +157,7 @@ void mapOppdragsLinjeResponse_OK() { hasProperty("attestantId", is(equalTo(TEXT_VALUE))), hasProperty("datoUgyldigFom", is(equalTo(LOCAL_DATE)))))), hasProperty("valuta", contains(allOf( - hasProperty("typeValuta", is(equalTo(Oppdrag.ValuteType.FAKT))), + hasProperty("typeValuta", is(equalTo(Oppdrag.ValutaType.FAKT))), hasProperty("valuta", is(equalTo(TEXT_VALUE))), hasProperty("datoValutaFom", is(equalTo(LOCAL_DATE))), hasProperty("feilreg", is(equalTo(TEXT_VALUE)))))) diff --git a/apps/oppdrag-service/src/test/java/no/nav/testnav/oppdragservice/utilty/Oppdragsdata.java b/apps/oppdrag-service/src/test/java/no/nav/testnav/oppdragservice/utilty/Oppdragsdata.java index 6defd582de4..4e72cea63c2 100644 --- a/apps/oppdrag-service/src/test/java/no/nav/testnav/oppdragservice/utilty/Oppdragsdata.java +++ b/apps/oppdrag-service/src/test/java/no/nav/testnav/oppdragservice/utilty/Oppdragsdata.java @@ -144,7 +144,7 @@ public static OppdragRequest buildOppdragsLinjeRequest() { .datoUgyldigFom(LOCAL_DATE) .build())) .valuta(List.of(Oppdrag.Valuta.builder() - .typeValuta(Oppdrag.ValuteType.FAKT) + .typeValuta(Oppdrag.ValutaType.FAKT) .valuta(TEXT_VALUE) .datoValutaFom(LOCAL_DATE) .feilreg(TEXT_VALUE) @@ -302,7 +302,7 @@ public static SendInnOppdragResponse buildOppdragslinjeResponse() { oppdragslinje.getAttestant().add(attestant); var valuta = new no.nav.testnav.oppdragservice.wsdl.Valuta(); - valuta.setTypeValuta(Oppdrag.ValuteType.FAKT.toString()); + valuta.setTypeValuta(Oppdrag.ValutaType.FAKT.toString()); valuta.setValuta(TEXT_VALUE); valuta.setDatoValutaFom(TARGET_DATE_FORMAT); valuta.setFeilreg(TEXT_VALUE); diff --git a/libs/data-transfer-objects/src/main/java/no/nav/testnav/libs/dto/oppdragservice/v1/Oppdrag.java b/libs/data-transfer-objects/src/main/java/no/nav/testnav/libs/dto/oppdragservice/v1/Oppdrag.java index 1954544ee2b..30aad8b5dcf 100644 --- a/libs/data-transfer-objects/src/main/java/no/nav/testnav/libs/dto/oppdragservice/v1/Oppdrag.java +++ b/libs/data-transfer-objects/src/main/java/no/nav/testnav/libs/dto/oppdragservice/v1/Oppdrag.java @@ -352,7 +352,7 @@ public static class Attestant { public static class Valuta { @NotBlank - protected ValuteType typeValuta; + protected Oppdrag.ValutaType typeValuta; @NotBlank @Schema(minLength = 1, maxLength = 3) protected String valuta; @@ -431,7 +431,7 @@ public enum UtbetalingFrekvensType { ENG } - public enum ValuteType { + public enum ValutaType { FAKT, FRAM, diff --git a/libs/data-transfer-objects/src/main/java/no/nav/testnav/libs/dto/oppdragservice/v1/OppdragKodeverk.java b/libs/data-transfer-objects/src/main/java/no/nav/testnav/libs/dto/oppdragservice/v1/OppdragKodeverk.java new file mode 100644 index 00000000000..798bd4320db --- /dev/null +++ b/libs/data-transfer-objects/src/main/java/no/nav/testnav/libs/dto/oppdragservice/v1/OppdragKodeverk.java @@ -0,0 +1,25 @@ +package no.nav.testnav.libs.dto.oppdragservice.v1; + +import lombok.Getter; + +@Getter +public enum OppdragKodeverk { + + JA_NEI (Oppdrag.JaNei.class), + KODE_STATUS_LINJE(Oppdrag.KodeStatusLinje.class), + FRADRAG_TILLEGG(Oppdrag.FradragTillegg.class), + KODE_ARBEIDSGIVER(Oppdrag.KodeArbeidsgiver.class), + KODE_STATUS(Oppdrag.KodeStatus.class), + KODE_ENDRING(Oppdrag.KodeEndring.class), + KODE_ENDRING_TYPE(Oppdrag.KodeEndringType.class), + SATS_TYPE(Oppdrag.SatsType.class), + UTBETALING_FREKVENS_TYPE(Oppdrag.UtbetalingFrekvensType.class), + VALUTA_TYPE(Oppdrag.ValutaType.class); + + private Class implementasjon; + + private OppdragKodeverk(Class implementasjon) { + this.implementasjon = implementasjon; + } + } + From 810bea316a81780f66eb779ddfc4524d48a228eb Mon Sep 17 00:00:00 2001 From: "Kristen.Herum" Date: Mon, 4 Nov 2024 08:39:58 +0100 Subject: [PATCH 17/35] Refactor Dockerfile and cleanup code #deploy-oppdrag-service Replaced ADD with COPY in Dockerfile and reordered JAVA_OPTS. Added @RequiredArgsConstructor to OppdragKodeverk enum and removed redundant constructor. Removed @VaultPropertySource from DevConfig for dev profile configuration. --- apps/oppdrag-service/Dockerfile | 4 ++-- .../nav/testnav/oppdragservice/config/DevConfig.java | 2 -- .../libs/dto/oppdragservice/v1/OppdragKodeverk.java | 10 ++++------ 3 files changed, 6 insertions(+), 10 deletions(-) diff --git a/apps/oppdrag-service/Dockerfile b/apps/oppdrag-service/Dockerfile index 99a33947167..b8026e25021 100644 --- a/apps/oppdrag-service/Dockerfile +++ b/apps/oppdrag-service/Dockerfile @@ -1,8 +1,8 @@ FROM ghcr.io/navikt/baseimages/temurin:21 LABEL maintainer="Team Dolly" -ENV JAVA_OPTS="-Dspring.profiles.active=prod --add-opens java.base/java.lang=ALL-UNNAMED" +COPY /build/libs/app.jar /app/app.jar -ADD /build/libs/app.jar /app/app.jar +ENV JAVA_OPTS="--add-opens java.base/java.lang=ALL-UNNAMED -Dspring.profiles.active=prod" EXPOSE 8080 diff --git a/apps/oppdrag-service/src/main/java/no/nav/testnav/oppdragservice/config/DevConfig.java b/apps/oppdrag-service/src/main/java/no/nav/testnav/oppdragservice/config/DevConfig.java index a93f3cd2751..55c35c48b90 100644 --- a/apps/oppdrag-service/src/main/java/no/nav/testnav/oppdragservice/config/DevConfig.java +++ b/apps/oppdrag-service/src/main/java/no/nav/testnav/oppdragservice/config/DevConfig.java @@ -3,11 +3,9 @@ import no.nav.testnav.libs.vault.AbstractLocalVaultConfiguration; import org.springframework.context.annotation.Configuration; import org.springframework.context.annotation.Profile; -import org.springframework.vault.annotation.VaultPropertySource; @Configuration @Profile("dev") -@VaultPropertySource(value = "secret/dolly/lokal", ignoreSecretNotFound = false) public class DevConfig extends AbstractLocalVaultConfiguration { } \ No newline at end of file diff --git a/libs/data-transfer-objects/src/main/java/no/nav/testnav/libs/dto/oppdragservice/v1/OppdragKodeverk.java b/libs/data-transfer-objects/src/main/java/no/nav/testnav/libs/dto/oppdragservice/v1/OppdragKodeverk.java index 798bd4320db..d34a61fa394 100644 --- a/libs/data-transfer-objects/src/main/java/no/nav/testnav/libs/dto/oppdragservice/v1/OppdragKodeverk.java +++ b/libs/data-transfer-objects/src/main/java/no/nav/testnav/libs/dto/oppdragservice/v1/OppdragKodeverk.java @@ -1,8 +1,10 @@ package no.nav.testnav.libs.dto.oppdragservice.v1; import lombok.Getter; +import lombok.RequiredArgsConstructor; @Getter +@RequiredArgsConstructor public enum OppdragKodeverk { JA_NEI (Oppdrag.JaNei.class), @@ -16,10 +18,6 @@ public enum OppdragKodeverk { UTBETALING_FREKVENS_TYPE(Oppdrag.UtbetalingFrekvensType.class), VALUTA_TYPE(Oppdrag.ValutaType.class); - private Class implementasjon; - - private OppdragKodeverk(Class implementasjon) { - this.implementasjon = implementasjon; - } - } + private final Class implementasjon; + } \ No newline at end of file From 3d9565d9b350d60299a2af317260c0b145024ddb Mon Sep 17 00:00:00 2001 From: "Kristen.Herum" Date: Mon, 4 Nov 2024 10:32:58 +0100 Subject: [PATCH 18/35] Fix main class path in build.gradle #deploy-oppdrag-service Corrected the main class path in the bootJar configuration of build.gradle. This change updates the path to align with the actual package structure, ensuring the application starts correctly. --- apps/oppdrag-service/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/oppdrag-service/build.gradle b/apps/oppdrag-service/build.gradle index deb6b04c7fa..7a4b919a162 100644 --- a/apps/oppdrag-service/build.gradle +++ b/apps/oppdrag-service/build.gradle @@ -25,7 +25,7 @@ sonarqube { bootJar { archiveFileName = "app.jar" - mainClass = 'no.nav.testnav.oppdrag.service.OppdragServiceApplicationStarter' + mainClass = 'no.nav.testnav.oppdragservice.OppdragServiceApplicationStarter' duplicatesStrategy = DuplicatesStrategy.EXCLUDE } From 6f9bae68ad9fe3f9c1bad65f39224c986df623c7 Mon Sep 17 00:00:00 2001 From: "Kristen.Herum" Date: Tue, 5 Nov 2024 14:23:36 +0100 Subject: [PATCH 19/35] Initialize oppdrag-proxy project structure #deploy-proxy-oppdrag Add essential configuration files and setup for oppdrag-proxy, including Gradle build scripts, Dockerfile, application properties, and workflow definitions. The initial setup also includes basic logging, security, and routing configurations for the project. --- .github/workflows/proxy.oppdrag-proxy.yml | 24 ++ proxies/oppdrag-proxy/Dockerfile | 8 + proxies/oppdrag-proxy/build.gradle | 20 ++ proxies/oppdrag-proxy/config.yml | 60 +++++ .../gradle/wrapper/gradle-wrapper.jar | Bin 0 -> 59536 bytes .../gradle/wrapper/gradle-wrapper.properties | 5 + proxies/oppdrag-proxy/gradlew | 234 ++++++++++++++++++ proxies/oppdrag-proxy/gradlew.bat | 89 +++++++ proxies/oppdrag-proxy/gradlewUpdate.sh | 3 + proxies/oppdrag-proxy/settings.gradle | 21 ++ .../OppdragProxyApplicationStarter.java | 48 ++++ .../oppdragproxy/config/LocalVaultConfig.java | 10 + .../src/main/resources/application-prod.yml | 9 + .../src/main/resources/application.yml | 26 ++ .../src/main/resources/logback-spring.xml | 31 +++ .../oppdragproxy/ApplicationContextTest.java | 20 ++ .../resources/application-test.properties | 8 + 17 files changed, 616 insertions(+) create mode 100644 .github/workflows/proxy.oppdrag-proxy.yml create mode 100644 proxies/oppdrag-proxy/Dockerfile create mode 100644 proxies/oppdrag-proxy/build.gradle create mode 100644 proxies/oppdrag-proxy/config.yml create mode 100644 proxies/oppdrag-proxy/gradle/wrapper/gradle-wrapper.jar create mode 100644 proxies/oppdrag-proxy/gradle/wrapper/gradle-wrapper.properties create mode 100755 proxies/oppdrag-proxy/gradlew create mode 100644 proxies/oppdrag-proxy/gradlew.bat create mode 100755 proxies/oppdrag-proxy/gradlewUpdate.sh create mode 100644 proxies/oppdrag-proxy/settings.gradle create mode 100644 proxies/oppdrag-proxy/src/main/java/no/nav/testnav/oppdragproxy/OppdragProxyApplicationStarter.java create mode 100644 proxies/oppdrag-proxy/src/main/java/no/nav/testnav/oppdragproxy/config/LocalVaultConfig.java create mode 100644 proxies/oppdrag-proxy/src/main/resources/application-prod.yml create mode 100644 proxies/oppdrag-proxy/src/main/resources/application.yml create mode 100644 proxies/oppdrag-proxy/src/main/resources/logback-spring.xml create mode 100644 proxies/oppdrag-proxy/src/test/java/no/nav/testnav/oppdragproxy/ApplicationContextTest.java create mode 100644 proxies/oppdrag-proxy/src/test/resources/application-test.properties diff --git a/.github/workflows/proxy.oppdrag-proxy.yml b/.github/workflows/proxy.oppdrag-proxy.yml new file mode 100644 index 00000000000..e32fdfe9c02 --- /dev/null +++ b/.github/workflows/proxy.oppdrag-proxy.yml @@ -0,0 +1,24 @@ +name: oppdrag-proxy + +on: + push: + paths: + - "plugins/**" + - "libs/reactive-core/**" + - "libs/reactive-proxy/**" + - "libs/reactive-security/**" + - "libs/security-core/**" + - "proxies/oppdrag-proxy/**" + - ".github/workflows/proxy.oppdrag-proxy.yml" + +jobs: + workflow: + uses: ./.github/workflows/common.workflow.backend.yml + with: + cluster: "dev-fss" + working-directory: "proxies/oppdrag-proxy" + deploy-tag: "#deploy-proxy-oppdrag" + permissions: + contents: read + id-token: write + secrets: inherit diff --git a/proxies/oppdrag-proxy/Dockerfile b/proxies/oppdrag-proxy/Dockerfile new file mode 100644 index 00000000000..3ac8856fdc1 --- /dev/null +++ b/proxies/oppdrag-proxy/Dockerfile @@ -0,0 +1,8 @@ +FROM ghcr.io/navikt/baseimages/temurin:21 +LABEL maintainer="Team Dolly" + +ENV JAVA_OPTS="-Dspring.profiles.active=prod" + +COPY /build/libs/app.jar /app/app.jar + +EXPOSE 8080 diff --git a/proxies/oppdrag-proxy/build.gradle b/proxies/oppdrag-proxy/build.gradle new file mode 100644 index 00000000000..068f07de11d --- /dev/null +++ b/proxies/oppdrag-proxy/build.gradle @@ -0,0 +1,20 @@ +plugins { + id "dolly-proxies" +} + +sonarqube { + properties { + property "sonar.projectKey", "testnav-oppdrag-proxy" + property "sonar.projectName", "testnav-oppdrag-proxy" + } +} + +dependencies { + implementation "no.nav.testnav.libs:data-transfer-objects" + implementation "no.nav.testnav.libs:reactive-security" + implementation "no.nav.testnav.libs:security-core" + implementation "no.nav.testnav.libs:vault" + + implementation "org.springframework.boot:spring-boot-starter-webflux" + implementation "org.springframework.cloud:spring-cloud-starter-vault-config" +} diff --git a/proxies/oppdrag-proxy/config.yml b/proxies/oppdrag-proxy/config.yml new file mode 100644 index 00000000000..e5c2821246a --- /dev/null +++ b/proxies/oppdrag-proxy/config.yml @@ -0,0 +1,60 @@ +apiVersion: "nais.io/v1alpha1" +kind: "Application" +metadata: + name: testnav-oppdrag-proxy + namespace: dolly + labels: + team: dolly + annotations: + nginx.ingress.kubernetes.io/proxy-read-timeout: "2400" + nginx.ingress.kubernetes.io/proxy-send-timeout: "2400" +spec: + image: "{{image}}" + port: 8080 + webproxy: true + tokenx: + enabled: true + azure: + application: + allowAllUsers: true + enabled: true + tenant: nav.no + accessPolicy: + inbound: + rules: + - application: team-dolly-lokal-app + cluster: dev-gcp + - application: testnav-oversikt-frontend + cluster: dev-gcp + - application: testnav-oppdrag-service + cluster: dev-gcp + liveness: + path: /internal/isAlive + initialDelay: 4 + periodSeconds: 5 + failureThreshold: 500 + observability: + logging: + destinations: + - id: elastic + autoInstrumentation: + enabled: true + runtime: java + readiness: + path: /internal/isReady + initialDelay: 4 + periodSeconds: 5 + failureThreshold: 500 + replicas: + min: 1 + max: 1 + vault: + enabled: true + resources: + requests: + cpu: 100m + memory: 1025Mi + limits: + memory: 2048Mi + ingresses: + - "https://testnav-oppdrag-proxy.dev-fss-pub.nais.io" diff --git a/proxies/oppdrag-proxy/gradle/wrapper/gradle-wrapper.jar b/proxies/oppdrag-proxy/gradle/wrapper/gradle-wrapper.jar new file mode 100644 index 0000000000000000000000000000000000000000..7454180f2ae8848c63b8b4dea2cb829da983f2fa GIT binary patch literal 59536 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 QuEJmfE|#`Dqx|px0L@K;Y5)KL literal 0 HcmV?d00001 diff --git a/proxies/oppdrag-proxy/gradle/wrapper/gradle-wrapper.properties b/proxies/oppdrag-proxy/gradle/wrapper/gradle-wrapper.properties new file mode 100644 index 00000000000..48c0a02ca41 --- /dev/null +++ b/proxies/oppdrag-proxy/gradle/wrapper/gradle-wrapper.properties @@ -0,0 +1,5 @@ +distributionBase=GRADLE_USER_HOME +distributionPath=wrapper/dists +distributionUrl=https\://services.gradle.org/distributions/gradle-8.7-bin.zip +zipStoreBase=GRADLE_USER_HOME +zipStorePath=wrapper/dists diff --git a/proxies/oppdrag-proxy/gradlew b/proxies/oppdrag-proxy/gradlew new file mode 100755 index 00000000000..3da45c161b0 --- /dev/null +++ b/proxies/oppdrag-proxy/gradlew @@ -0,0 +1,234 @@ +#!/bin/sh + +# +# Copyright ? 2015-2021 the original authors. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# https://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# + +############################################################################## +# +# Gradle start up script for POSIX generated by Gradle. +# +# Important for running: +# +# (1) You need a POSIX-compliant shell to run this script. If your /bin/sh is +# noncompliant, but you have some other compliant shell such as ksh or +# bash, then to run this script, type that shell name before the whole +# command line, like: +# +# ksh Gradle +# +# Busybox and similar reduced shells will NOT work, because this script +# requires all of these POSIX shell features: +# * functions; +# * expansions ?$var?, ?${var}?, ?${var:-default}?, ?${var+SET}?, +# ?${var#prefix}?, ?${var%suffix}?, and ?$( cmd )?; +# * compound commands having a testable exit status, especially ?case?; +# * various built-in commands including ?command?, ?set?, and ?ulimit?. +# +# Important for patching: +# +# (2) This script targets any POSIX shell, so it avoids extensions provided +# by Bash, Ksh, etc; in particular arrays are avoided. +# +# The "traditional" practice of packing multiple parameters into a +# space-separated string is a well documented source of bugs and security +# problems, so this is (mostly) avoided, by progressively accumulating +# options in "$@", and eventually passing that to Java. +# +# Where the inherited environment variables (DEFAULT_JVM_OPTS, JAVA_OPTS, +# and GRADLE_OPTS) rely on word-splitting, this is performed explicitly; +# see the in-line comments for details. +# +# There are tweaks for specific operating systems such as AIX, CygWin, +# Darwin, MinGW, and NonStop. +# +# (3) This script is generated from the Groovy template +# https://github.com/gradle/gradle/blob/master/subprojects/plugins/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt +# within the Gradle project. +# +# You can find Gradle at https://github.com/gradle/gradle/. +# +############################################################################## + +# Attempt to set APP_HOME + +# Resolve links: $0 may be a link +app_path=$0 + +# Need this for daisy-chained symlinks. +while + APP_HOME=${app_path%"${app_path##*/}"} # leaves a trailing /; empty if no leading path + [ -h "$app_path" ] +do + ls=$( ls -ld "$app_path" ) + link=${ls#*' -> '} + case $link in #( + /*) app_path=$link ;; #( + *) app_path=$APP_HOME$link ;; + esac +done + +APP_HOME=$( cd "${APP_HOME:-./}" && pwd -P ) || exit + +APP_NAME="Gradle" +APP_BASE_NAME=${0##*/} + +# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. +DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"' + +# Use the maximum available, or set MAX_FD != -1 to use that value. +MAX_FD=maximum + +warn () { + echo "$*" +} >&2 + +die () { + echo + echo "$*" + echo + exit 1 +} >&2 + +# OS specific support (must be 'true' or 'false'). +cygwin=false +msys=false +darwin=false +nonstop=false +case "$( uname )" in #( + CYGWIN* ) cygwin=true ;; #( + Darwin* ) darwin=true ;; #( + MSYS* | MINGW* ) msys=true ;; #( + NONSTOP* ) nonstop=true ;; +esac + +CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar + + +# Determine the Java command to use to start the JVM. +if [ -n "$JAVA_HOME" ] ; then + if [ -x "$JAVA_HOME/jre/sh/java" ] ; then + # IBM's JDK on AIX uses strange locations for the executables + JAVACMD=$JAVA_HOME/jre/sh/java + else + JAVACMD=$JAVA_HOME/bin/java + fi + if [ ! -x "$JAVACMD" ] ; then + die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME + +Please set the JAVA_HOME variable in your environment to match the +location of your Java installation." + fi +else + JAVACMD=java + which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. + +Please set the JAVA_HOME variable in your environment to match the +location of your Java installation." +fi + +# Increase the maximum file descriptors if we can. +if ! "$cygwin" && ! "$darwin" && ! "$nonstop" ; then + case $MAX_FD in #( + max*) + MAX_FD=$( ulimit -H -n ) || + warn "Could not query maximum file descriptor limit" + esac + case $MAX_FD in #( + '' | soft) :;; #( + *) + ulimit -n "$MAX_FD" || + warn "Could not set maximum file descriptor limit to $MAX_FD" + esac +fi + +# Collect all arguments for the java command, stacking in reverse order: +# * args from the command line +# * the main class name +# * -classpath +# * -D...appname settings +# * --module-path (only if needed) +# * DEFAULT_JVM_OPTS, JAVA_OPTS, and GRADLE_OPTS environment variables. + +# For Cygwin or MSYS, switch paths to Windows format before running java +if "$cygwin" || "$msys" ; then + APP_HOME=$( cygpath --path --mixed "$APP_HOME" ) + CLASSPATH=$( cygpath --path --mixed "$CLASSPATH" ) + + JAVACMD=$( cygpath --unix "$JAVACMD" ) + + # Now convert the arguments - kludge to limit ourselves to /bin/sh + for arg do + if + case $arg in #( + -*) false ;; # don't mess with options #( + /?*) t=${arg#/} t=/${t%%/*} # looks like a POSIX filepath + [ -e "$t" ] ;; #( + *) false ;; + esac + then + arg=$( cygpath --path --ignore --mixed "$arg" ) + fi + # Roll the args list around exactly as many times as the number of + # args, so each arg winds up back in the position where it started, but + # possibly modified. + # + # NB: a `for` loop captures its iteration list before it begins, so + # changing the positional parameters here affects neither the number of + # iterations, nor the values presented in `arg`. + shift # remove old arg + set -- "$@" "$arg" # push replacement arg + done +fi + +# Collect all arguments for the java command; +# * $DEFAULT_JVM_OPTS, $JAVA_OPTS, and $GRADLE_OPTS can contain fragments of +# shell script including quotes and variable substitutions, so put them in +# double quotes to make sure that they get re-expanded; and +# * put everything else in single quotes, so that it's not re-expanded. + +set -- \ + "-Dorg.gradle.appname=$APP_BASE_NAME" \ + -classpath "$CLASSPATH" \ + org.gradle.wrapper.GradleWrapperMain \ + "$@" + +# Use "xargs" to parse quoted args. +# +# With -n1 it outputs one arg per line, with the quotes and backslashes removed. +# +# In Bash we could simply go: +# +# readarray ARGS < <( xargs -n1 <<<"$var" ) && +# set -- "${ARGS[@]}" "$@" +# +# but POSIX shell has neither arrays nor command substitution, so instead we +# post-process each arg (as a line of input to sed) to backslash-escape any +# character that might be a shell metacharacter, then use eval to reverse +# that process (while maintaining the separation between arguments), and wrap +# the whole thing up as a single "set" statement. +# +# This will of course break if any of these variables contains a newline or +# an unmatched quote. +# + +eval "set -- $( + printf '%s\n' "$DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS" | + xargs -n1 | + sed ' s~[^-[:alnum:]+,./:=@_]~\\&~g; ' | + tr '\n' ' ' + )" '"$@"' + +exec "$JAVACMD" "$@" diff --git a/proxies/oppdrag-proxy/gradlew.bat b/proxies/oppdrag-proxy/gradlew.bat new file mode 100644 index 00000000000..107acd32c4e --- /dev/null +++ b/proxies/oppdrag-proxy/gradlew.bat @@ -0,0 +1,89 @@ +@rem +@rem Copyright 2015 the original author or authors. +@rem +@rem Licensed under the Apache License, Version 2.0 (the "License"); +@rem you may not use this file except in compliance with the License. +@rem You may obtain a copy of the License at +@rem +@rem https://www.apache.org/licenses/LICENSE-2.0 +@rem +@rem Unless required by applicable law or agreed to in writing, software +@rem distributed under the License is distributed on an "AS IS" BASIS, +@rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +@rem See the License for the specific language governing permissions and +@rem limitations under the License. +@rem + +@if "%DEBUG%" == "" @echo off +@rem ########################################################################## +@rem +@rem Gradle startup script for Windows +@rem +@rem ########################################################################## + +@rem Set local scope for the variables with windows NT shell +if "%OS%"=="Windows_NT" setlocal + +set DIRNAME=%~dp0 +if "%DIRNAME%" == "" set DIRNAME=. +set APP_BASE_NAME=%~n0 +set APP_HOME=%DIRNAME% + +@rem Resolve any "." and ".." in APP_HOME to make it shorter. +for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi + +@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. +set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m" + +@rem Find java.exe +if defined JAVA_HOME goto findJavaFromJavaHome + +set JAVA_EXE=java.exe +%JAVA_EXE% -version >NUL 2>&1 +if "%ERRORLEVEL%" == "0" goto execute + +echo. +echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. +echo. +echo Please set the JAVA_HOME variable in your environment to match the +echo location of your Java installation. + +goto fail + +:findJavaFromJavaHome +set JAVA_HOME=%JAVA_HOME:"=% +set JAVA_EXE=%JAVA_HOME%/bin/java.exe + +if exist "%JAVA_EXE%" goto execute + +echo. +echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% +echo. +echo Please set the JAVA_HOME variable in your environment to match the +echo location of your Java installation. + +goto fail + +:execute +@rem Setup the command line + +set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar + + +@rem Execute Gradle +"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %* + +:end +@rem End local scope for the variables with windows NT shell +if "%ERRORLEVEL%"=="0" goto mainEnd + +:fail +rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of +rem the _cmd.exe /c_ return code! +if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1 +exit /b 1 + +:mainEnd +if "%OS%"=="Windows_NT" endlocal + +:omega diff --git a/proxies/oppdrag-proxy/gradlewUpdate.sh b/proxies/oppdrag-proxy/gradlewUpdate.sh new file mode 100755 index 00000000000..e5ee6361152 --- /dev/null +++ b/proxies/oppdrag-proxy/gradlewUpdate.sh @@ -0,0 +1,3 @@ +#!/bin/bash + +gradle wrapper \ No newline at end of file diff --git a/proxies/oppdrag-proxy/settings.gradle b/proxies/oppdrag-proxy/settings.gradle new file mode 100644 index 00000000000..5fdf01193d1 --- /dev/null +++ b/proxies/oppdrag-proxy/settings.gradle @@ -0,0 +1,21 @@ +plugins { + id "com.gradle.develocity" version "3.17.4" +} + +rootProject.name = "oppdrag-proxy" + +includeBuild "../../plugins/java" + +includeBuild "../../libs/data-transfer-objects" +includeBuild "../../libs/reactive-core" +includeBuild "../../libs/reactive-proxy" +includeBuild "../../libs/reactive-security" +includeBuild "../../libs/security-core" +includeBuild "../../libs/vault" + +develocity { + buildScan { + termsOfUseUrl = "https://gradle.com/terms-of-service" + termsOfUseAgree = "yes" + } +} diff --git a/proxies/oppdrag-proxy/src/main/java/no/nav/testnav/oppdragproxy/OppdragProxyApplicationStarter.java b/proxies/oppdrag-proxy/src/main/java/no/nav/testnav/oppdragproxy/OppdragProxyApplicationStarter.java new file mode 100644 index 00000000000..9d04ab88a62 --- /dev/null +++ b/proxies/oppdrag-proxy/src/main/java/no/nav/testnav/oppdragproxy/OppdragProxyApplicationStarter.java @@ -0,0 +1,48 @@ +package no.nav.testnav.oppdragproxy; + +import no.nav.testnav.libs.reactivecore.config.CoreConfig; +import no.nav.testnav.libs.reactiveproxy.config.SecurityConfig; +import org.springframework.boot.SpringApplication; +import org.springframework.boot.autoconfigure.SpringBootApplication; +import org.springframework.cloud.gateway.route.Route; +import org.springframework.cloud.gateway.route.RouteLocator; +import org.springframework.cloud.gateway.route.builder.Buildable; +import org.springframework.cloud.gateway.route.builder.PredicateSpec; +import org.springframework.cloud.gateway.route.builder.RouteLocatorBuilder; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Import; + +import java.util.function.Function; + +@Import({ + CoreConfig.class, + SecurityConfig.class, +}) +@SpringBootApplication +public class OppdragProxyApplicationStarter { + + public static void main(String[] args) { + SpringApplication.run(OppdragProxyApplicationStarter.class, args); + } + + @Bean + public RouteLocator customRouteLocator(RouteLocatorBuilder builder) { + + return builder + .routes() + .route(createRoute("q1", "9210")) + .route(createRoute("q2", "9234")) + .route(createRoute("q4", "9236")) + .build(); + } + + private Function> createRoute(String miljoe, String port) { + + return predicateSpec -> predicateSpec + .path("/" + miljoe + "/**") + .filters(filterSpec -> filterSpec + .rewritePath("/" + miljoe + "/(?.*)", "/${segment}") + ) + .uri("http://ztest.test.local:" + port); + } +} diff --git a/proxies/oppdrag-proxy/src/main/java/no/nav/testnav/oppdragproxy/config/LocalVaultConfig.java b/proxies/oppdrag-proxy/src/main/java/no/nav/testnav/oppdragproxy/config/LocalVaultConfig.java new file mode 100644 index 00000000000..e3d40827a1c --- /dev/null +++ b/proxies/oppdrag-proxy/src/main/java/no/nav/testnav/oppdragproxy/config/LocalVaultConfig.java @@ -0,0 +1,10 @@ +package no.nav.testnav.oppdragproxy.config; + +import no.nav.testnav.libs.vault.AbstractLocalVaultConfiguration; +import org.springframework.context.annotation.Configuration; +import org.springframework.context.annotation.Profile; + +@Profile("dev") +@Configuration +public class LocalVaultConfig extends AbstractLocalVaultConfiguration { +} \ No newline at end of file diff --git a/proxies/oppdrag-proxy/src/main/resources/application-prod.yml b/proxies/oppdrag-proxy/src/main/resources/application-prod.yml new file mode 100644 index 00000000000..894f2d09e4e --- /dev/null +++ b/proxies/oppdrag-proxy/src/main/resources/application-prod.yml @@ -0,0 +1,9 @@ + +spring: + security: + oauth2: + resourceserver: + tokenx: + issuer-uri: ${TOKEN_X_ISSUER} + jwk-set-uri: ${TOKEN_X_JWKS_URI} + accepted-audience: ${TOKEN_X_CLIENT_ID} \ No newline at end of file diff --git a/proxies/oppdrag-proxy/src/main/resources/application.yml b/proxies/oppdrag-proxy/src/main/resources/application.yml new file mode 100644 index 00000000000..a4e6c693f5f --- /dev/null +++ b/proxies/oppdrag-proxy/src/main/resources/application.yml @@ -0,0 +1,26 @@ +AAD_ISSUER_URI: https://login.microsoftonline.com/62366534-1ec3-4962-8869-9b5535279d0b + +spring: + application: + name: testnav-pdl-proxy + desciption: Proxy for pdl som legger på AzureAd sikkerhet og lager en sts token.. + security: + oauth2: + resourceserver: + aad: + issuer-uri: ${AAD_ISSUER_URI}/v2.0 + jwk-set-uri: ${AAD_ISSUER_URI}/discovery/v2.0/keys + accepted-audience: ${azure.app.client.id}, api://${azure.app.client.id} + cloud: + gateway: + httpclient: + response-timeout: 1200s + vault: + enabled: false + +server: + servlet: + encoding: + charset: UTF-8 + error: + include-message: always diff --git a/proxies/oppdrag-proxy/src/main/resources/logback-spring.xml b/proxies/oppdrag-proxy/src/main/resources/logback-spring.xml new file mode 100644 index 00000000000..f4ad86ff115 --- /dev/null +++ b/proxies/oppdrag-proxy/src/main/resources/logback-spring.xml @@ -0,0 +1,31 @@ + + + + + + -1 + true + - + + + + + + + + + + + + %d{HH:mm:ss.SSS} | %5p | %logger{25} | %m%n + + utf8 + + + + + + + + + \ No newline at end of file diff --git a/proxies/oppdrag-proxy/src/test/java/no/nav/testnav/oppdragproxy/ApplicationContextTest.java b/proxies/oppdrag-proxy/src/test/java/no/nav/testnav/oppdragproxy/ApplicationContextTest.java new file mode 100644 index 00000000000..c173cf47714 --- /dev/null +++ b/proxies/oppdrag-proxy/src/test/java/no/nav/testnav/oppdragproxy/ApplicationContextTest.java @@ -0,0 +1,20 @@ +package no.nav.testnav.oppdragproxy; + +import org.junit.jupiter.api.Test; +import org.springframework.boot.test.context.SpringBootTest; +import org.springframework.boot.test.mock.mockito.MockBean; +import org.springframework.security.oauth2.jwt.ReactiveJwtDecoder; +import org.springframework.test.context.ActiveProfiles; + +@SpringBootTest +@ActiveProfiles("test") +class ApplicationContextTest { + + @MockBean + private ReactiveJwtDecoder jwtDecoder; + + @Test + @SuppressWarnings("java:S2699") + void load_app_context() { + } +} diff --git a/proxies/oppdrag-proxy/src/test/resources/application-test.properties b/proxies/oppdrag-proxy/src/test/resources/application-test.properties new file mode 100644 index 00000000000..aa18dbf1e43 --- /dev/null +++ b/proxies/oppdrag-proxy/src/test/resources/application-test.properties @@ -0,0 +1,8 @@ +TOKEN_X_ISSUER=dummy + +sts.token.provider.username=dummy +sts.token.provider.password=dummy +hendelse.lager.api.key=dummy +person.aktor.admin.api=dummy +elastic.username=dummy +elastic.password=dummy \ No newline at end of file From c814b4136daa15761992f7e6f99f7219128b8f3c Mon Sep 17 00:00:00 2001 From: "Kristen.Herum" Date: Tue, 5 Nov 2024 14:32:52 +0100 Subject: [PATCH 20/35] Add Spring Cloud starter bootstrap dependency #deploy-proxy-oppdrag Included `spring-cloud-starter-bootstrap` for legacy bootstrap configuration. This will be temporarily used and should be removed once the new configuration is implemented. --- proxies/oppdrag-proxy/build.gradle | 1 + 1 file changed, 1 insertion(+) diff --git a/proxies/oppdrag-proxy/build.gradle b/proxies/oppdrag-proxy/build.gradle index 068f07de11d..8aac0880d53 100644 --- a/proxies/oppdrag-proxy/build.gradle +++ b/proxies/oppdrag-proxy/build.gradle @@ -16,5 +16,6 @@ dependencies { implementation "no.nav.testnav.libs:vault" implementation "org.springframework.boot:spring-boot-starter-webflux" + implementation "org.springframework.cloud:spring-cloud-starter-bootstrap" // TODO remove legacy bootstrap config. implementation "org.springframework.cloud:spring-cloud-starter-vault-config" } From b422f93669326bfab368f25194cff1b024fca488 Mon Sep 17 00:00:00 2001 From: "Kristen.Herum" Date: Tue, 5 Nov 2024 14:43:01 +0100 Subject: [PATCH 21/35] Remove unused dependencies and test properties file #deploy-proxy-oppdrag Deleted the `application-test.properties` file as it's no longer needed. Also removed the `data-transfer-objects` library from settings.gradle and build.gradle dependencies to clean up the codebase. --- proxies/oppdrag-proxy/build.gradle | 4 +--- proxies/oppdrag-proxy/settings.gradle | 1 - .../src/test/resources/application-test.properties | 8 -------- 3 files changed, 1 insertion(+), 12 deletions(-) delete mode 100644 proxies/oppdrag-proxy/src/test/resources/application-test.properties diff --git a/proxies/oppdrag-proxy/build.gradle b/proxies/oppdrag-proxy/build.gradle index 8aac0880d53..54feba2b22a 100644 --- a/proxies/oppdrag-proxy/build.gradle +++ b/proxies/oppdrag-proxy/build.gradle @@ -10,12 +10,10 @@ sonarqube { } dependencies { - implementation "no.nav.testnav.libs:data-transfer-objects" implementation "no.nav.testnav.libs:reactive-security" implementation "no.nav.testnav.libs:security-core" implementation "no.nav.testnav.libs:vault" implementation "org.springframework.boot:spring-boot-starter-webflux" - implementation "org.springframework.cloud:spring-cloud-starter-bootstrap" // TODO remove legacy bootstrap config. - implementation "org.springframework.cloud:spring-cloud-starter-vault-config" + implementation "org.springframework.cloud:spring-cloud-starter-vault-config" } diff --git a/proxies/oppdrag-proxy/settings.gradle b/proxies/oppdrag-proxy/settings.gradle index 5fdf01193d1..d49e9fbc902 100644 --- a/proxies/oppdrag-proxy/settings.gradle +++ b/proxies/oppdrag-proxy/settings.gradle @@ -6,7 +6,6 @@ rootProject.name = "oppdrag-proxy" includeBuild "../../plugins/java" -includeBuild "../../libs/data-transfer-objects" includeBuild "../../libs/reactive-core" includeBuild "../../libs/reactive-proxy" includeBuild "../../libs/reactive-security" diff --git a/proxies/oppdrag-proxy/src/test/resources/application-test.properties b/proxies/oppdrag-proxy/src/test/resources/application-test.properties deleted file mode 100644 index aa18dbf1e43..00000000000 --- a/proxies/oppdrag-proxy/src/test/resources/application-test.properties +++ /dev/null @@ -1,8 +0,0 @@ -TOKEN_X_ISSUER=dummy - -sts.token.provider.username=dummy -sts.token.provider.password=dummy -hendelse.lager.api.key=dummy -person.aktor.admin.api=dummy -elastic.username=dummy -elastic.password=dummy \ No newline at end of file From 711bc516df42dda852f3d9c6f8b67a82bfebf0f7 Mon Sep 17 00:00:00 2001 From: "Kristen.Herum" Date: Wed, 6 Nov 2024 07:28:06 +0100 Subject: [PATCH 22/35] Disable vault in config #deploy-proxy-oppdrag Removed the vault configuration from the config.yml file. This change ensures that the vault is no longer enabled by default, simplifying resource allocation and management. --- proxies/oppdrag-proxy/config.yml | 2 -- 1 file changed, 2 deletions(-) diff --git a/proxies/oppdrag-proxy/config.yml b/proxies/oppdrag-proxy/config.yml index e5c2821246a..603cabdea3e 100644 --- a/proxies/oppdrag-proxy/config.yml +++ b/proxies/oppdrag-proxy/config.yml @@ -48,8 +48,6 @@ spec: replicas: min: 1 max: 1 - vault: - enabled: true resources: requests: cpu: 100m From 713b43ff721114944f6c90c238c22ad3f42bc4ca Mon Sep 17 00:00:00 2001 From: "Kristen.Herum" Date: Wed, 6 Nov 2024 14:00:07 +0100 Subject: [PATCH 23/35] Refactor OppdragService to use WebClient Replaced OppdragConsumer with OppdragWSConsumer and introduced WebClient for communication. Added new configuration classes for server properties and consumers. Updated application.yml to include new endpoint configurations and modified tests accordingly. --- apps/oppdrag-service/build.gradle | 19 +------ apps/oppdrag-service/settings.gradle | 1 + .../oppdragservice/config/Consumers.java | 20 ++++++++ .../config/OppdragWsConfiguration.java | 9 +++- .../config/ServerProperties.java | 19 +++++++ .../consumer/OppdragConsumer.java | 36 +++++++++---- .../consumer/OppdragWSConsumer.java | 28 ++++++++++ .../consumer/command/OppdragPostComand.java | 35 +++++++++++++ .../provider/OppdragController.java | 8 +-- .../service/OppdragService.java | 41 +++++++++++---- .../src/main/resources/application-prod.yml | 2 +- .../src/main/resources/application.yml | 16 +++++- .../service/OppdragServiceTest.java | 51 ++++++++++--------- 13 files changed, 213 insertions(+), 72 deletions(-) create mode 100644 apps/oppdrag-service/src/main/java/no/nav/testnav/oppdragservice/config/Consumers.java create mode 100644 apps/oppdrag-service/src/main/java/no/nav/testnav/oppdragservice/config/ServerProperties.java create mode 100644 apps/oppdrag-service/src/main/java/no/nav/testnav/oppdragservice/consumer/OppdragWSConsumer.java create mode 100644 apps/oppdrag-service/src/main/java/no/nav/testnav/oppdragservice/consumer/command/OppdragPostComand.java diff --git a/apps/oppdrag-service/build.gradle b/apps/oppdrag-service/build.gradle index 7a4b919a162..b0923bc14d1 100644 --- a/apps/oppdrag-service/build.gradle +++ b/apps/oppdrag-service/build.gradle @@ -23,12 +23,6 @@ sonarqube { } } -bootJar { - archiveFileName = "app.jar" - mainClass = 'no.nav.testnav.oppdragservice.OppdragServiceApplicationStarter' - duplicatesStrategy = DuplicatesStrategy.EXCLUDE -} - wsimport { wsdlSourceRoot = "src/main/resources/schema/eksponering" generatedSourceRoot = "/generated/src/wsdl/main" @@ -42,18 +36,6 @@ wsimport { target = "3.0" } -repositories { - mavenCentral() - maven { - name = "GitHubPackages" - url = uri('https://maven.pkg.github.com/navikt/maven-release') - credentials(PasswordCredentials) { - password System.getenv("NAV_TOKEN") - username 'token' - } - } -} - configurations { jaxws } @@ -69,6 +51,7 @@ dependencies { 'com.sun.xml.ws:jaxws-rt:3.0.0' implementation "no.nav.testnav.libs:data-transfer-objects" + implementation "no.nav.testnav.libs:security-core" implementation "no.nav.testnav.libs:servlet-core" implementation "no.nav.testnav.libs:servlet-security" implementation "no.nav.testnav.libs:vault" diff --git a/apps/oppdrag-service/settings.gradle b/apps/oppdrag-service/settings.gradle index 1b54dd50812..f1063871242 100644 --- a/apps/oppdrag-service/settings.gradle +++ b/apps/oppdrag-service/settings.gradle @@ -5,6 +5,7 @@ plugins { rootProject.name = 'oppdrag-service' includeBuild '../../libs/data-transfer-objects' +includeBuild '../../libs/security-core' includeBuild '../../libs/servlet-core' includeBuild '../../libs/servlet-security' includeBuild '../../libs/vault' diff --git a/apps/oppdrag-service/src/main/java/no/nav/testnav/oppdragservice/config/Consumers.java b/apps/oppdrag-service/src/main/java/no/nav/testnav/oppdragservice/config/Consumers.java new file mode 100644 index 00000000000..17c3f403c31 --- /dev/null +++ b/apps/oppdrag-service/src/main/java/no/nav/testnav/oppdragservice/config/Consumers.java @@ -0,0 +1,20 @@ +package no.nav.testnav.oppdragservice.config; + +import lombok.Getter; +import lombok.NoArgsConstructor; +import lombok.Setter; +import no.nav.testnav.libs.securitycore.domain.ServerProperties; +import org.springframework.boot.context.properties.ConfigurationProperties; +import org.springframework.context.annotation.Configuration; + +import static lombok.AccessLevel.PACKAGE; + +//@Configuration +//@ConfigurationProperties(prefix = "consumers") +@NoArgsConstructor(access = PACKAGE) +@Getter +@Setter(PACKAGE) +public class Consumers { + + ServerProperties oppdragProxy; +} diff --git a/apps/oppdrag-service/src/main/java/no/nav/testnav/oppdragservice/config/OppdragWsConfiguration.java b/apps/oppdrag-service/src/main/java/no/nav/testnav/oppdragservice/config/OppdragWsConfiguration.java index 2cead073f8d..ae6ea68ad3c 100644 --- a/apps/oppdrag-service/src/main/java/no/nav/testnav/oppdragservice/config/OppdragWsConfiguration.java +++ b/apps/oppdrag-service/src/main/java/no/nav/testnav/oppdragservice/config/OppdragWsConfiguration.java @@ -1,6 +1,8 @@ package no.nav.testnav.oppdragservice.config; +import lombok.RequiredArgsConstructor; import no.nav.testnav.oppdragservice.consumer.OppdragClient; +import no.nav.testnav.oppdragservice.consumer.OppdragWSConsumer; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.oxm.jaxb.Jaxb2Marshaller; @@ -9,8 +11,11 @@ @EnableWs @Configuration +@RequiredArgsConstructor public class OppdragWsConfiguration extends WsConfigurerAdapter { + private final ServerProperties serverProperties; + @Bean public Jaxb2Marshaller marshaller() { Jaxb2Marshaller marshaller = new Jaxb2Marshaller(); @@ -21,9 +26,9 @@ public Jaxb2Marshaller marshaller() { } @Bean - public OppdragClient oppdragClient(Jaxb2Marshaller marshaller) { + public OppdragWSConsumer oppdragWSConsumer(Jaxb2Marshaller marshaller) { - var client = new OppdragClient(); + var client = new OppdragWSConsumer(serverProperties); client.setDefaultUri("http://localhost:8080/ws"); client.setMarshaller(marshaller); client.setUnmarshaller(marshaller); diff --git a/apps/oppdrag-service/src/main/java/no/nav/testnav/oppdragservice/config/ServerProperties.java b/apps/oppdrag-service/src/main/java/no/nav/testnav/oppdragservice/config/ServerProperties.java new file mode 100644 index 00000000000..f2b062d4c8a --- /dev/null +++ b/apps/oppdrag-service/src/main/java/no/nav/testnav/oppdragservice/config/ServerProperties.java @@ -0,0 +1,19 @@ +package no.nav.testnav.oppdragservice.config; + +import lombok.Getter; +import lombok.Setter; +import org.springframework.boot.context.properties.ConfigurationProperties; +import org.springframework.context.annotation.Configuration; +import org.springframework.stereotype.Component; + +import java.util.Map; + +@Getter +@Setter +@Configuration +@ConfigurationProperties(prefix = "oppdrag-service") +public class ServerProperties { + + private String host; + private Map ports; +} \ No newline at end of file diff --git a/apps/oppdrag-service/src/main/java/no/nav/testnav/oppdragservice/consumer/OppdragConsumer.java b/apps/oppdrag-service/src/main/java/no/nav/testnav/oppdragservice/consumer/OppdragConsumer.java index 44135515485..1733648c539 100644 --- a/apps/oppdrag-service/src/main/java/no/nav/testnav/oppdragservice/consumer/OppdragConsumer.java +++ b/apps/oppdrag-service/src/main/java/no/nav/testnav/oppdragservice/consumer/OppdragConsumer.java @@ -1,19 +1,33 @@ package no.nav.testnav.oppdragservice.consumer; -import lombok.extern.slf4j.Slf4j; -import no.nav.testnav.oppdragservice.wsdl.SendInnOppdragRequest; -import no.nav.testnav.oppdragservice.wsdl.SendInnOppdragResponse; +import no.nav.testnav.libs.securitycore.domain.ServerProperties; +import no.nav.testnav.libs.servletsecurity.exchange.TokenExchange; +import no.nav.testnav.oppdragservice.config.Consumers; +import no.nav.testnav.oppdragservice.consumer.command.OppdragPostComand; import org.springframework.stereotype.Service; -import org.springframework.ws.client.core.support.WebServiceGatewaySupport; -import org.springframework.ws.soap.client.core.SoapActionCallback; +import org.springframework.web.reactive.function.client.WebClient; +import reactor.core.publisher.Mono; -@Slf4j -@Service -public class OppdragConsumer extends WebServiceGatewaySupport { +//@Service +public class OppdragConsumer { - public SendInnOppdragResponse sendOppdrag(SendInnOppdragRequest melding) { + private final ServerProperties serverProperties; + private final WebClient webClient; + private final TokenExchange tokenExchange; - return (SendInnOppdragResponse) getWebServiceTemplate().marshalSendAndReceive("", melding, - new SoapActionCallback("no.nav.testnav.oppdragservice.wsdl.SendInnOppdragResponse")); + public OppdragConsumer(Consumers consumers, + WebClient.Builder webClientBuilder, + TokenExchange tokenExchange) { + + this.serverProperties = consumers.getOppdragProxy(); + this.webClient = webClientBuilder.baseUrl(serverProperties.getUrl()).build(); + this.tokenExchange = tokenExchange; + } + + public Mono sendOppdrag(String miljoe, String melding) { + + return tokenExchange.exchange(serverProperties) + .flatMap(token -> new OppdragPostComand(webClient, + token.getTokenValue(), miljoe, melding).call()); } } diff --git a/apps/oppdrag-service/src/main/java/no/nav/testnav/oppdragservice/consumer/OppdragWSConsumer.java b/apps/oppdrag-service/src/main/java/no/nav/testnav/oppdragservice/consumer/OppdragWSConsumer.java new file mode 100644 index 00000000000..5e8492cf58c --- /dev/null +++ b/apps/oppdrag-service/src/main/java/no/nav/testnav/oppdragservice/consumer/OppdragWSConsumer.java @@ -0,0 +1,28 @@ +package no.nav.testnav.oppdragservice.consumer; + +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import no.nav.testnav.oppdragservice.config.ServerProperties; +import no.nav.testnav.oppdragservice.wsdl.SendInnOppdragRequest; +import no.nav.testnav.oppdragservice.wsdl.SendInnOppdragResponse; +import org.springframework.stereotype.Service; +import org.springframework.ws.client.core.support.WebServiceGatewaySupport; +import org.springframework.ws.soap.client.core.SoapActionCallback; + +@Slf4j +@RequiredArgsConstructor +public class OppdragWSConsumer extends WebServiceGatewaySupport { + + private static final String OPPDRAG_URL = "/cics/services/oppdragService"; + + private final ServerProperties props; + + public SendInnOppdragResponse sendOppdrag(String miljoe, SendInnOppdragRequest melding) { + + var url = "%s:%s%s".formatted(props.getHost(), + props.getPorts().get(miljoe), OPPDRAG_URL); + + return (SendInnOppdragResponse) getWebServiceTemplate().marshalSendAndReceive(url, melding, + new SoapActionCallback("no.nav.testnav.oppdragservice.wsdl.SendInnOppdragResponse")); + } +} diff --git a/apps/oppdrag-service/src/main/java/no/nav/testnav/oppdragservice/consumer/command/OppdragPostComand.java b/apps/oppdrag-service/src/main/java/no/nav/testnav/oppdragservice/consumer/command/OppdragPostComand.java new file mode 100644 index 00000000000..13b25ba6f6a --- /dev/null +++ b/apps/oppdrag-service/src/main/java/no/nav/testnav/oppdragservice/consumer/command/OppdragPostComand.java @@ -0,0 +1,35 @@ +package no.nav.testnav.oppdragservice.consumer.command; + +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import org.springframework.http.HttpHeaders; +import org.springframework.web.reactive.function.client.WebClient; +import reactor.core.publisher.Mono; + +import java.util.concurrent.Callable; + +@Slf4j +@RequiredArgsConstructor +public class OppdragPostComand implements Callable> { + + private static final String OPPDRAG_URL = "/{miljoe}/cics/services/oppdragService"; + + private final WebClient webClient; + private final String token; + private final String miljoe; + private final String melding; + + @Override + public Mono call() { + + log.info("Sender melding til oppdrag {}", melding); + + return webClient.post() + .uri(uriBuilder -> uriBuilder.path(OPPDRAG_URL).build(miljoe)) + .header(HttpHeaders.AUTHORIZATION, "Bearer " + token) +// .header(HttpHeaders.CONTENT_TYPE, MediaType.APPLICATION_XML_VALUE) + .bodyValue(melding) + .retrieve() + .bodyToMono(String.class); + } +} diff --git a/apps/oppdrag-service/src/main/java/no/nav/testnav/oppdragservice/provider/OppdragController.java b/apps/oppdrag-service/src/main/java/no/nav/testnav/oppdragservice/provider/OppdragController.java index 9bea11de37e..7da96b85803 100644 --- a/apps/oppdrag-service/src/main/java/no/nav/testnav/oppdragservice/provider/OppdragController.java +++ b/apps/oppdrag-service/src/main/java/no/nav/testnav/oppdragservice/provider/OppdragController.java @@ -13,6 +13,7 @@ import org.springframework.web.bind.annotation.RequestBody; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RestController; +import reactor.core.publisher.Mono; import java.util.List; @@ -24,11 +25,12 @@ public class OppdragController { private final OppdragService oppdragService; private final KodeverkService kodeverkService; - @PostMapping + @PostMapping("/{miljoe}") @Operation(summary = "Send inn oppdrag") - public OppdragResponse sendInnOppdrag(@RequestBody OppdragRequest oppdragRequest) { + public Mono sendInnOppdrag(@PathVariable String miljoe, + @RequestBody OppdragRequest oppdragRequest) { - return oppdragService.sendInnOppdrag(oppdragRequest); + return oppdragService.sendInnOppdrag(miljoe, oppdragRequest); } @GetMapping("/kodeverk/{kodeverk}") diff --git a/apps/oppdrag-service/src/main/java/no/nav/testnav/oppdragservice/service/OppdragService.java b/apps/oppdrag-service/src/main/java/no/nav/testnav/oppdragservice/service/OppdragService.java index e3ed0315701..9e587f2c2a5 100644 --- a/apps/oppdrag-service/src/main/java/no/nav/testnav/oppdragservice/service/OppdragService.java +++ b/apps/oppdrag-service/src/main/java/no/nav/testnav/oppdragservice/service/OppdragService.java @@ -6,41 +6,60 @@ import ma.glasnost.orika.MapperFacade; import no.nav.testnav.libs.dto.oppdragservice.v1.OppdragRequest; import no.nav.testnav.libs.dto.oppdragservice.v1.OppdragResponse; -import no.nav.testnav.oppdragservice.consumer.OppdragConsumer; +import no.nav.testnav.oppdragservice.consumer.OppdragWSConsumer; import no.nav.testnav.oppdragservice.wsdl.SendInnOppdragRequest; +import no.nav.testnav.oppdragservice.wsdl.SendInnOppdragResponse; import org.springframework.stereotype.Service; +import reactor.core.publisher.Mono; +import java.io.StringReader; import java.io.StringWriter; @Service public class OppdragService { - private final JAXBContext jaxbContext; - private final OppdragConsumer oppdragConsumer; + private final JAXBContext jaxbRequestContext; + private final JAXBContext jaxbResponseContext; + private final OppdragWSConsumer oppdragWSConsumer; private final MapperFacade mapperFacade; - public OppdragService(OppdragConsumer oppdragConsumer, MapperFacade mapperFacade) throws JAXBException { - this.oppdragConsumer = oppdragConsumer; + public OppdragService(OppdragWSConsumer oppdragWSConsumer, MapperFacade mapperFacade) throws JAXBException { + this.oppdragWSConsumer = oppdragWSConsumer; this.mapperFacade = mapperFacade; - this.jaxbContext = JAXBContext.newInstance(SendInnOppdragRequest.class); + this.jaxbRequestContext = JAXBContext.newInstance(SendInnOppdragRequest.class); + this.jaxbResponseContext = JAXBContext.newInstance(SendInnOppdragResponse.class); } - public OppdragResponse sendInnOppdrag(OppdragRequest oppdragRequest) { + public Mono sendInnOppdrag(String miljoe, OppdragRequest oppdragRequest) { var request = mapperFacade.map(oppdragRequest, SendInnOppdragRequest.class); + var xmlRequest = marshall(request); - var oppdragResponse = oppdragConsumer.sendOppdrag(request); + var oppdragResponse = oppdragWSConsumer.sendOppdrag(miljoe, request); +// .map(this::unmarshall) +// .map(oppdragResponse -> mapperFacade.map(oppdragResponse, OppdragResponse.class)); - return mapperFacade.map(oppdragResponse, OppdragResponse.class); + var response = mapperFacade.map(oppdragResponse, OppdragResponse.class); + + return Mono.just(response); } @SneakyThrows - private String marshallToXml(SendInnOppdragRequest melding) { + private String marshall(SendInnOppdragRequest melding) { - var marshaller = jaxbContext.createMarshaller(); + var marshaller = jaxbRequestContext.createMarshaller(); var writer = new StringWriter(); marshaller.marshal(melding, writer); return writer.toString(); } + + @SneakyThrows + private SendInnOppdragResponse unmarshall(String melding) { + + var unmarshaller = jaxbResponseContext.createUnmarshaller(); + var reader = new StringReader(melding); + + return (SendInnOppdragResponse) unmarshaller.unmarshal(reader); + } } \ No newline at end of file diff --git a/apps/oppdrag-service/src/main/resources/application-prod.yml b/apps/oppdrag-service/src/main/resources/application-prod.yml index 0311ce578e3..e7679d5ce86 100644 --- a/apps/oppdrag-service/src/main/resources/application-prod.yml +++ b/apps/oppdrag-service/src/main/resources/application-prod.yml @@ -5,4 +5,4 @@ spring: tokenx: issuer-uri: ${TOKEN_X_ISSUER} jwk-set-uri: ${TOKEN_X_JWKS_URI} - accepted-audience: ${TOKEN_X_CLIENT_ID} \ No newline at end of file + accepted-audience: ${TOKEN_X_CLIENT_ID} diff --git a/apps/oppdrag-service/src/main/resources/application.yml b/apps/oppdrag-service/src/main/resources/application.yml index e554e357d75..d0a27520189 100644 --- a/apps/oppdrag-service/src/main/resources/application.yml +++ b/apps/oppdrag-service/src/main/resources/application.yml @@ -42,4 +42,18 @@ server: encoding: charset: UTF-8 error: - include-message: always \ No newline at end of file + include-message: always + +consumers: + oppdrag-proxy: + name: testnav-oppdrag-proxy + namespace: dolly + url: https://testnav-oppdrag-proxy.dev-fss-pub.nais.io + cluster: dev-fss + +oppdrag-service: + host: http://ztest.test.local + ports: + q1: 9210 + q2: 9234 + q4: 9236 \ No newline at end of file diff --git a/apps/oppdrag-service/src/test/java/no/nav/testnav/oppdragservice/service/OppdragServiceTest.java b/apps/oppdrag-service/src/test/java/no/nav/testnav/oppdragservice/service/OppdragServiceTest.java index bebbf13318e..dfea3e5d126 100644 --- a/apps/oppdrag-service/src/test/java/no/nav/testnav/oppdragservice/service/OppdragServiceTest.java +++ b/apps/oppdrag-service/src/test/java/no/nav/testnav/oppdragservice/service/OppdragServiceTest.java @@ -1,7 +1,7 @@ package no.nav.testnav.oppdragservice.service; import ma.glasnost.orika.MapperFacade; -import no.nav.testnav.oppdragservice.consumer.OppdragConsumer; +import no.nav.testnav.oppdragservice.consumer.OppdragWSConsumer; import no.nav.testnav.oppdragservice.mapper.LocalDateCustomMapping; import no.nav.testnav.oppdragservice.mapper.LocalDateTimeCustomMapping; import no.nav.testnav.oppdragservice.mapper.MapperTestUtils; @@ -23,13 +23,14 @@ import static org.hamcrest.Matchers.equalTo; import static org.hamcrest.Matchers.is; import static org.mockito.ArgumentMatchers.any; +import static org.mockito.ArgumentMatchers.anyString; import static org.mockito.Mockito.when; @ExtendWith(MockitoExtension.class) class OppdragServiceTest { @Mock - private OppdragConsumer oppdragConsumer; + private OppdragWSConsumer oppdragWSConsumer; @Spy private MapperFacade mapperFacade = MapperTestUtils.createMapperFacadeForMappingStrategy( @@ -39,27 +40,27 @@ class OppdragServiceTest { @InjectMocks private OppdragService oppdragService; - @Test - void execOppdragServiceNominal_OK() { - - when(oppdragConsumer.sendOppdrag(any(SendInnOppdragRequest.class))) - .thenReturn(Oppdragsdata.buildOppdragResponse()); - - var request = Oppdragsdata.buildOppdragRequest(); - var target = oppdragService.sendInnOppdrag(request); - - assertThat(target.getInfomelding().getBeskrMelding(), is(equalTo(TEXT_VALUE))); - } - - @Test - void execOppdragServiceOppdragslinje_OK() { - - when(oppdragConsumer.sendOppdrag(any(SendInnOppdragRequest.class))) - .thenReturn(Oppdragsdata.buildOppdragslinjeResponse()); - - var request = Oppdragsdata.buildOppdragsLinjeRequest(); - var target = oppdragService.sendInnOppdrag(request); - - assertThat(target.getInfomelding().getBeskrMelding(), is(equalTo(TEXT_VALUE))); - } +// @Test +// void execOppdragServiceNominal_OK() { +// +// when(oppdragWSConsumer.sendOppdrag(anyString(), any(String.class))) +// .thenReturn(Oppdragsdata.buildOppdragResponse()); +// +// var request = Oppdragsdata.buildOppdragRequest(); +// var target = oppdragService.sendInnOppdrag(request); +// +// assertThat(target.getInfomelding().getBeskrMelding(), is(equalTo(TEXT_VALUE))); +// } +// +// @Test +// void execOppdragServiceOppdragslinje_OK() { +// +// when(oppdragWSConsumer.sendOppdrag(any(SendInnOppdragRequest.class))) +// .thenReturn(Oppdragsdata.buildOppdragslinjeResponse()); +// +// var request = Oppdragsdata.buildOppdragsLinjeRequest(); +// var target = oppdragService.sendInnOppdrag(request); +// +// assertThat(target.getInfomelding().getBeskrMelding(), is(equalTo(TEXT_VALUE))); +// } } \ No newline at end of file From 978776a394595fe46f9196cad78c81e746007e42 Mon Sep 17 00:00:00 2001 From: "Kristen.Herum" Date: Wed, 6 Nov 2024 15:09:18 +0100 Subject: [PATCH 24/35] Set cluster to "dev-fss" in workflow #deploy-oppdrag-service Added the "cluster" parameter to the GitHub workflow configuration for the oppdrag-service application. This change specifies the deployment environment as "dev-fss", ensuring the service will be deployed correctly in the intended cluster. --- .github/workflows/app.oppdrag-service.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.github/workflows/app.oppdrag-service.yml b/.github/workflows/app.oppdrag-service.yml index 5fb056a22a0..a13f830baeb 100644 --- a/.github/workflows/app.oppdrag-service.yml +++ b/.github/workflows/app.oppdrag-service.yml @@ -14,6 +14,7 @@ jobs: workflow: uses: ./.github/workflows/common.workflow.backend.yml with: + cluster: "dev-fss" working-directory: "apps/oppdrag-service" deploy-tag: "#deploy-oppdrag-service" permissions: From 0ef42feebff6e0ed748ba0125b3f31519d8e84a6 Mon Sep 17 00:00:00 2001 From: "Kristen.Herum" Date: Wed, 6 Nov 2024 15:38:19 +0100 Subject: [PATCH 25/35] Remove vault configuration from config.yml #deploy-oppdrag-service This commit removes the vault configuration section as it is no longer needed. The min and max replicas settings remain unchanged, maintaining the desired state for replicas. --- apps/oppdrag-service/config.yml | 2 -- 1 file changed, 2 deletions(-) diff --git a/apps/oppdrag-service/config.yml b/apps/oppdrag-service/config.yml index caae1df66b7..b617c8306b9 100644 --- a/apps/oppdrag-service/config.yml +++ b/apps/oppdrag-service/config.yml @@ -42,8 +42,6 @@ spec: replicas: min: 1 max: 1 - vault: - enabled: true resources: requests: cpu: 100m From a365043d74ef7ae19ff94689b4ebcbac9e057ddd Mon Sep 17 00:00:00 2001 From: "Kristen.Herum" Date: Wed, 6 Nov 2024 15:43:16 +0100 Subject: [PATCH 26/35] Change workflow name to oppdrag-service This commit changes the name of the workflow from "oppsummeringsdokument-service" to "oppdrag-service". This update ensures that the workflow name accurately reflects the intended service. --- .github/workflows/app.oppdrag-service.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/app.oppdrag-service.yml b/.github/workflows/app.oppdrag-service.yml index a13f830baeb..a7d356771e1 100644 --- a/.github/workflows/app.oppdrag-service.yml +++ b/.github/workflows/app.oppdrag-service.yml @@ -1,4 +1,4 @@ -name: oppsummeringsdokument-service +name: oppdrag-service on: push: From 4b0c7be2aac1524f61356eddbc3091df97502ea1 Mon Sep 17 00:00:00 2001 From: "Kristen.Herum" Date: Wed, 6 Nov 2024 15:46:59 +0100 Subject: [PATCH 27/35] Add cluster configuration for inbound rules in config.yml #deploy-oppdrag-service Each application in the inbound rules now includes a cluster specification, set to 'dev-gcp'. This ensures all specified applications route correctly through the designated cluster in the development environment. --- apps/oppdrag-service/config.yml | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/apps/oppdrag-service/config.yml b/apps/oppdrag-service/config.yml index b617c8306b9..dc5e7c9b51c 100644 --- a/apps/oppdrag-service/config.yml +++ b/apps/oppdrag-service/config.yml @@ -13,13 +13,21 @@ spec: inbound: rules: - application: dolly-backend + cluster: dev-gcp - application: dolly-backend-dev + cluster: dev-gcp - application: dolly-frontend + cluster: dev-gcp - application: dolly-frontend-dev + cluster: dev-gcp - application: dolly-frontend-dev-unstable + cluster: dev-gcp - application: dolly-idporten + cluster: dev-gcp - application: team-dolly-lokal-app + cluster: dev-gcp - application: testnav-oversikt-frontend + cluster: dev-gcp tokenx: enabled: true azure: From db1a6c0dcb6197919f1e577b478a234e0b760672 Mon Sep 17 00:00:00 2001 From: "Kristen.Herum" Date: Thu, 7 Nov 2024 07:39:35 +0100 Subject: [PATCH 28/35] Remove Reactor Mono from OppdragService #deploy-oppdrag-service Updated OppdragService to return OppdragResponse directly instead of using Reactor Mono. This simplifies the response handling and aligns the test cases with the new service method signature. Also, removed unused imports and corrected SoapActionCallback usage in the consumer. --- .../consumer/OppdragWSConsumer.java | 5 +- .../provider/OppdragController.java | 3 +- .../service/OppdragService.java | 5 +- .../service/OppdragServiceTest.java | 48 ++++++++++--------- 4 files changed, 30 insertions(+), 31 deletions(-) diff --git a/apps/oppdrag-service/src/main/java/no/nav/testnav/oppdragservice/consumer/OppdragWSConsumer.java b/apps/oppdrag-service/src/main/java/no/nav/testnav/oppdragservice/consumer/OppdragWSConsumer.java index 5e8492cf58c..f45e6c8f615 100644 --- a/apps/oppdrag-service/src/main/java/no/nav/testnav/oppdragservice/consumer/OppdragWSConsumer.java +++ b/apps/oppdrag-service/src/main/java/no/nav/testnav/oppdragservice/consumer/OppdragWSConsumer.java @@ -5,7 +5,6 @@ import no.nav.testnav.oppdragservice.config.ServerProperties; import no.nav.testnav.oppdragservice.wsdl.SendInnOppdragRequest; import no.nav.testnav.oppdragservice.wsdl.SendInnOppdragResponse; -import org.springframework.stereotype.Service; import org.springframework.ws.client.core.support.WebServiceGatewaySupport; import org.springframework.ws.soap.client.core.SoapActionCallback; @@ -22,7 +21,7 @@ public SendInnOppdragResponse sendOppdrag(String miljoe, SendInnOppdragRequest m var url = "%s:%s%s".formatted(props.getHost(), props.getPorts().get(miljoe), OPPDRAG_URL); - return (SendInnOppdragResponse) getWebServiceTemplate().marshalSendAndReceive(url, melding, - new SoapActionCallback("no.nav.testnav.oppdragservice.wsdl.SendInnOppdragResponse")); + return (SendInnOppdragResponse) getWebServiceTemplate() + .marshalSendAndReceive(url, melding, new SoapActionCallback("")); } } diff --git a/apps/oppdrag-service/src/main/java/no/nav/testnav/oppdragservice/provider/OppdragController.java b/apps/oppdrag-service/src/main/java/no/nav/testnav/oppdragservice/provider/OppdragController.java index 7da96b85803..63cf55d07f0 100644 --- a/apps/oppdrag-service/src/main/java/no/nav/testnav/oppdragservice/provider/OppdragController.java +++ b/apps/oppdrag-service/src/main/java/no/nav/testnav/oppdragservice/provider/OppdragController.java @@ -13,7 +13,6 @@ import org.springframework.web.bind.annotation.RequestBody; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RestController; -import reactor.core.publisher.Mono; import java.util.List; @@ -27,7 +26,7 @@ public class OppdragController { @PostMapping("/{miljoe}") @Operation(summary = "Send inn oppdrag") - public Mono sendInnOppdrag(@PathVariable String miljoe, + public OppdragResponse sendInnOppdrag(@PathVariable String miljoe, @RequestBody OppdragRequest oppdragRequest) { return oppdragService.sendInnOppdrag(miljoe, oppdragRequest); diff --git a/apps/oppdrag-service/src/main/java/no/nav/testnav/oppdragservice/service/OppdragService.java b/apps/oppdrag-service/src/main/java/no/nav/testnav/oppdragservice/service/OppdragService.java index 9e587f2c2a5..4f32c2e7daa 100644 --- a/apps/oppdrag-service/src/main/java/no/nav/testnav/oppdragservice/service/OppdragService.java +++ b/apps/oppdrag-service/src/main/java/no/nav/testnav/oppdragservice/service/OppdragService.java @@ -10,7 +10,6 @@ import no.nav.testnav.oppdragservice.wsdl.SendInnOppdragRequest; import no.nav.testnav.oppdragservice.wsdl.SendInnOppdragResponse; import org.springframework.stereotype.Service; -import reactor.core.publisher.Mono; import java.io.StringReader; import java.io.StringWriter; @@ -30,7 +29,7 @@ public OppdragService(OppdragWSConsumer oppdragWSConsumer, MapperFacade mapperFa this.jaxbResponseContext = JAXBContext.newInstance(SendInnOppdragResponse.class); } - public Mono sendInnOppdrag(String miljoe, OppdragRequest oppdragRequest) { + public OppdragResponse sendInnOppdrag(String miljoe, OppdragRequest oppdragRequest) { var request = mapperFacade.map(oppdragRequest, SendInnOppdragRequest.class); var xmlRequest = marshall(request); @@ -41,7 +40,7 @@ public Mono sendInnOppdrag(String miljoe, OppdragRequest oppdra var response = mapperFacade.map(oppdragResponse, OppdragResponse.class); - return Mono.just(response); + return response; } @SneakyThrows diff --git a/apps/oppdrag-service/src/test/java/no/nav/testnav/oppdragservice/service/OppdragServiceTest.java b/apps/oppdrag-service/src/test/java/no/nav/testnav/oppdragservice/service/OppdragServiceTest.java index dfea3e5d126..c160774b1b6 100644 --- a/apps/oppdrag-service/src/test/java/no/nav/testnav/oppdragservice/service/OppdragServiceTest.java +++ b/apps/oppdrag-service/src/test/java/no/nav/testnav/oppdragservice/service/OppdragServiceTest.java @@ -29,6 +29,8 @@ @ExtendWith(MockitoExtension.class) class OppdragServiceTest { + private static final String MILJOE = "q2"; + @Mock private OppdragWSConsumer oppdragWSConsumer; @@ -40,27 +42,27 @@ class OppdragServiceTest { @InjectMocks private OppdragService oppdragService; -// @Test -// void execOppdragServiceNominal_OK() { -// -// when(oppdragWSConsumer.sendOppdrag(anyString(), any(String.class))) -// .thenReturn(Oppdragsdata.buildOppdragResponse()); -// -// var request = Oppdragsdata.buildOppdragRequest(); -// var target = oppdragService.sendInnOppdrag(request); -// -// assertThat(target.getInfomelding().getBeskrMelding(), is(equalTo(TEXT_VALUE))); -// } -// -// @Test -// void execOppdragServiceOppdragslinje_OK() { -// -// when(oppdragWSConsumer.sendOppdrag(any(SendInnOppdragRequest.class))) -// .thenReturn(Oppdragsdata.buildOppdragslinjeResponse()); -// -// var request = Oppdragsdata.buildOppdragsLinjeRequest(); -// var target = oppdragService.sendInnOppdrag(request); -// -// assertThat(target.getInfomelding().getBeskrMelding(), is(equalTo(TEXT_VALUE))); -// } + @Test + void execOppdragServiceNominal_OK() { + + when(oppdragWSConsumer.sendOppdrag(anyString(), any(SendInnOppdragRequest.class))) + .thenReturn(Oppdragsdata.buildOppdragResponse()); + + var request = Oppdragsdata.buildOppdragRequest(); + var target = oppdragService.sendInnOppdrag(MILJOE, request); + + assertThat(target.getInfomelding().getBeskrMelding(), is(equalTo(TEXT_VALUE))); + } + + @Test + void execOppdragServiceOppdragslinje_OK() { + + when(oppdragWSConsumer.sendOppdrag(anyString(), any(SendInnOppdragRequest.class))) + .thenReturn(Oppdragsdata.buildOppdragslinjeResponse()); + + var request = Oppdragsdata.buildOppdragsLinjeRequest(); + var target = oppdragService.sendInnOppdrag(MILJOE, request); + + assertThat(target.getInfomelding().getBeskrMelding(), is(equalTo(TEXT_VALUE))); + } } \ No newline at end of file From 4bea7061ce652cab963f5937d0a63287f4202ae3 Mon Sep 17 00:00:00 2001 From: "Kristen.Herum" Date: Thu, 7 Nov 2024 08:35:09 +0100 Subject: [PATCH 29/35] Handle SendInnOppdragFeilUnderBehandling exception #deploy-oppdrag-service Add a try-catch block to specifically catch and log details of SendInnOppdragFeilUnderBehandling exceptions. This improves error logging by providing more context about the error cause and source, while still logging general exceptions. --- .../consumer/OppdragWSConsumer.java | 21 +++++++++++++++++-- 1 file changed, 19 insertions(+), 2 deletions(-) diff --git a/apps/oppdrag-service/src/main/java/no/nav/testnav/oppdragservice/consumer/OppdragWSConsumer.java b/apps/oppdrag-service/src/main/java/no/nav/testnav/oppdragservice/consumer/OppdragWSConsumer.java index f45e6c8f615..15d0503abb8 100644 --- a/apps/oppdrag-service/src/main/java/no/nav/testnav/oppdragservice/consumer/OppdragWSConsumer.java +++ b/apps/oppdrag-service/src/main/java/no/nav/testnav/oppdragservice/consumer/OppdragWSConsumer.java @@ -3,6 +3,7 @@ import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; import no.nav.testnav.oppdragservice.config.ServerProperties; +import no.nav.testnav.oppdragservice.wsdl.SendInnOppdragFeilUnderBehandling; import no.nav.testnav.oppdragservice.wsdl.SendInnOppdragRequest; import no.nav.testnav.oppdragservice.wsdl.SendInnOppdragResponse; import org.springframework.ws.client.core.support.WebServiceGatewaySupport; @@ -21,7 +22,23 @@ public SendInnOppdragResponse sendOppdrag(String miljoe, SendInnOppdragRequest m var url = "%s:%s%s".formatted(props.getHost(), props.getPorts().get(miljoe), OPPDRAG_URL); - return (SendInnOppdragResponse) getWebServiceTemplate() - .marshalSendAndReceive(url, melding, new SoapActionCallback("")); + try { + return (SendInnOppdragResponse) getWebServiceTemplate() + .marshalSendAndReceive(url, melding, new SoapActionCallback("")); + + } catch (Exception e) { + + if (e instanceof SendInnOppdragFeilUnderBehandling sendInnOppdragFeilUnderBehandling) { + log.error("SendInnOppdragFeilUnderBehandling message: {}, rootCause: {}, errorSource; {}", + sendInnOppdragFeilUnderBehandling.getMessage(), + sendInnOppdragFeilUnderBehandling.getFaultInfo().getRootCause(), + sendInnOppdragFeilUnderBehandling.getFaultInfo().getErrorSource(), e); + + } else { + log.error(e.getMessage(), e); + } + + throw e; + } } } From 23ec4e9e5b12f8d2a612b0a142c146a0b41c1378 Mon Sep 17 00:00:00 2001 From: "Kristen.Herum" Date: Thu, 7 Nov 2024 08:51:40 +0100 Subject: [PATCH 30/35] Remove redundant SoapActionCallback. #deploy-oppdrag-service The SoapActionCallback argument was removed from the marshalSendAndReceive method call as it was deemed unnecessary. This cleanup enhances code readability and maintainability without altering the function's core behavior. --- .../nav/testnav/oppdragservice/consumer/OppdragWSConsumer.java | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/apps/oppdrag-service/src/main/java/no/nav/testnav/oppdragservice/consumer/OppdragWSConsumer.java b/apps/oppdrag-service/src/main/java/no/nav/testnav/oppdragservice/consumer/OppdragWSConsumer.java index 15d0503abb8..4301a5f5b93 100644 --- a/apps/oppdrag-service/src/main/java/no/nav/testnav/oppdragservice/consumer/OppdragWSConsumer.java +++ b/apps/oppdrag-service/src/main/java/no/nav/testnav/oppdragservice/consumer/OppdragWSConsumer.java @@ -7,7 +7,6 @@ import no.nav.testnav.oppdragservice.wsdl.SendInnOppdragRequest; import no.nav.testnav.oppdragservice.wsdl.SendInnOppdragResponse; import org.springframework.ws.client.core.support.WebServiceGatewaySupport; -import org.springframework.ws.soap.client.core.SoapActionCallback; @Slf4j @RequiredArgsConstructor @@ -24,7 +23,7 @@ public SendInnOppdragResponse sendOppdrag(String miljoe, SendInnOppdragRequest m try { return (SendInnOppdragResponse) getWebServiceTemplate() - .marshalSendAndReceive(url, melding, new SoapActionCallback("")); + .marshalSendAndReceive(url, melding); } catch (Exception e) { From 07bc5ff4f3337ed1a3f170374f4f54350e5bedee Mon Sep 17 00:00:00 2001 From: "Kristen.Herum" Date: Thu, 7 Nov 2024 09:04:32 +0100 Subject: [PATCH 31/35] Handle SoapFaultClientException in OppdragWSConsumer #deploy-oppdrag-service Added a specific case to handle SoapFaultClientException in the exception block of OppdragWSConsumer. This logs detailed information about the SOAP fault, including faultCode and faultStringOrReason, improving error diagnosis and monitoring. --- .../oppdragservice/consumer/OppdragWSConsumer.java | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/apps/oppdrag-service/src/main/java/no/nav/testnav/oppdragservice/consumer/OppdragWSConsumer.java b/apps/oppdrag-service/src/main/java/no/nav/testnav/oppdragservice/consumer/OppdragWSConsumer.java index 4301a5f5b93..4056d9f22dd 100644 --- a/apps/oppdrag-service/src/main/java/no/nav/testnav/oppdragservice/consumer/OppdragWSConsumer.java +++ b/apps/oppdrag-service/src/main/java/no/nav/testnav/oppdragservice/consumer/OppdragWSConsumer.java @@ -7,6 +7,7 @@ import no.nav.testnav.oppdragservice.wsdl.SendInnOppdragRequest; import no.nav.testnav.oppdragservice.wsdl.SendInnOppdragResponse; import org.springframework.ws.client.core.support.WebServiceGatewaySupport; +import org.springframework.ws.soap.client.SoapFaultClientException; @Slf4j @RequiredArgsConstructor @@ -28,13 +29,19 @@ public SendInnOppdragResponse sendOppdrag(String miljoe, SendInnOppdragRequest m } catch (Exception e) { if (e instanceof SendInnOppdragFeilUnderBehandling sendInnOppdragFeilUnderBehandling) { + log.error("SendInnOppdragFeilUnderBehandling message: {}, rootCause: {}, errorSource; {}", sendInnOppdragFeilUnderBehandling.getMessage(), sendInnOppdragFeilUnderBehandling.getFaultInfo().getRootCause(), sendInnOppdragFeilUnderBehandling.getFaultInfo().getErrorSource(), e); - } else { - log.error(e.getMessage(), e); + } else if (e instanceof SoapFaultClientException soapFaultClientException){ + + log.error("SoapFaultClientException message: {}, faultCode: {}, soapfault: {}, faultStringOrReason: {}", + soapFaultClientException.getMessage(), + soapFaultClientException.getFaultCode(), + soapFaultClientException.getSoapFault(), + soapFaultClientException.getFaultStringOrReason(), e); } throw e; From 8c6b7e59397375bc488309ecc382f2f25d24601b Mon Sep 17 00:00:00 2001 From: "Kristen.Herum" Date: Thu, 7 Nov 2024 10:11:05 +0100 Subject: [PATCH 32/35] Update error logging for SOAP faults in OppdragWSConsumer #deploy-oppdrag-service Removed handling of `SendInnOppdragFeilUnderBehandling` exception and enhanced logging details for `SoapFaultClientException`. This change ensures more comprehensive error information is captured when SOAP faults occur. --- .../consumer/OppdragWSConsumer.java | 19 ++++++------------- 1 file changed, 6 insertions(+), 13 deletions(-) diff --git a/apps/oppdrag-service/src/main/java/no/nav/testnav/oppdragservice/consumer/OppdragWSConsumer.java b/apps/oppdrag-service/src/main/java/no/nav/testnav/oppdragservice/consumer/OppdragWSConsumer.java index 4056d9f22dd..bcdb1ecdff9 100644 --- a/apps/oppdrag-service/src/main/java/no/nav/testnav/oppdragservice/consumer/OppdragWSConsumer.java +++ b/apps/oppdrag-service/src/main/java/no/nav/testnav/oppdragservice/consumer/OppdragWSConsumer.java @@ -3,7 +3,6 @@ import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; import no.nav.testnav.oppdragservice.config.ServerProperties; -import no.nav.testnav.oppdragservice.wsdl.SendInnOppdragFeilUnderBehandling; import no.nav.testnav.oppdragservice.wsdl.SendInnOppdragRequest; import no.nav.testnav.oppdragservice.wsdl.SendInnOppdragResponse; import org.springframework.ws.client.core.support.WebServiceGatewaySupport; @@ -28,20 +27,14 @@ public SendInnOppdragResponse sendOppdrag(String miljoe, SendInnOppdragRequest m } catch (Exception e) { - if (e instanceof SendInnOppdragFeilUnderBehandling sendInnOppdragFeilUnderBehandling) { + if (e instanceof SoapFaultClientException soapFaultClientException) { - log.error("SendInnOppdragFeilUnderBehandling message: {}, rootCause: {}, errorSource; {}", - sendInnOppdragFeilUnderBehandling.getMessage(), - sendInnOppdragFeilUnderBehandling.getFaultInfo().getRootCause(), - sendInnOppdragFeilUnderBehandling.getFaultInfo().getErrorSource(), e); - - } else if (e instanceof SoapFaultClientException soapFaultClientException){ - - log.error("SoapFaultClientException message: {}, faultCode: {}, soapfault: {}, faultStringOrReason: {}", + log.error("SoapFaultClientException message: {}, faultCode: {}, faultDetail: {}, faultActorOrRole: {}, faultStringOrReason: {}", soapFaultClientException.getMessage(), - soapFaultClientException.getFaultCode(), - soapFaultClientException.getSoapFault(), - soapFaultClientException.getFaultStringOrReason(), e); + soapFaultClientException.getSoapFault().getFaultCode(), + soapFaultClientException.getSoapFault().getFaultDetail(), + soapFaultClientException.getSoapFault().getFaultActorOrRole(), + soapFaultClientException.getSoapFault().getFaultStringOrReason(), e); } throw e; From ce89fc74ac37ed89c951d43cdea7ad18b2a5f7c9 Mon Sep 17 00:00:00 2001 From: "Kristen.Herum" Date: Thu, 7 Nov 2024 10:36:59 +0100 Subject: [PATCH 33/35] Update error logging for SOAP faults in OppdragWSConsumer #deploy-oppdrag-service Removed handling of `SendInnOppdragFeilUnderBehandling` exception and enhanced logging details for `SoapFaultClientException`. This change ensures more comprehensive error information is captured when SOAP faults occur. --- .../oppdragservice/consumer/OppdragWSConsumer.java | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) diff --git a/apps/oppdrag-service/src/main/java/no/nav/testnav/oppdragservice/consumer/OppdragWSConsumer.java b/apps/oppdrag-service/src/main/java/no/nav/testnav/oppdragservice/consumer/OppdragWSConsumer.java index bcdb1ecdff9..7d54c9dc732 100644 --- a/apps/oppdrag-service/src/main/java/no/nav/testnav/oppdragservice/consumer/OppdragWSConsumer.java +++ b/apps/oppdrag-service/src/main/java/no/nav/testnav/oppdragservice/consumer/OppdragWSConsumer.java @@ -6,8 +6,14 @@ import no.nav.testnav.oppdragservice.wsdl.SendInnOppdragRequest; import no.nav.testnav.oppdragservice.wsdl.SendInnOppdragResponse; import org.springframework.ws.client.core.support.WebServiceGatewaySupport; +import org.springframework.ws.soap.SoapFaultDetailElement; import org.springframework.ws.soap.client.SoapFaultClientException; +import java.util.Spliterator; +import java.util.Spliterators; +import java.util.stream.Collectors; +import java.util.stream.StreamSupport; + @Slf4j @RequiredArgsConstructor public class OppdragWSConsumer extends WebServiceGatewaySupport { @@ -32,7 +38,13 @@ public SendInnOppdragResponse sendOppdrag(String miljoe, SendInnOppdragRequest m log.error("SoapFaultClientException message: {}, faultCode: {}, faultDetail: {}, faultActorOrRole: {}, faultStringOrReason: {}", soapFaultClientException.getMessage(), soapFaultClientException.getSoapFault().getFaultCode(), - soapFaultClientException.getSoapFault().getFaultDetail(), + StreamSupport.stream( + Spliterators.spliteratorUnknownSize( + soapFaultClientException.getSoapFault().getFaultDetail().getDetailEntries(), + Spliterator.ORDERED), false) + .map(SoapFaultDetailElement::getResult) + .map(Object::toString) + .collect(Collectors.joining(", ")), soapFaultClientException.getSoapFault().getFaultActorOrRole(), soapFaultClientException.getSoapFault().getFaultStringOrReason(), e); } From 176e9f656798fff46655214dcdf805fbc830504a Mon Sep 17 00:00:00 2001 From: "Kristen.Herum" Date: Thu, 7 Nov 2024 11:03:51 +0100 Subject: [PATCH 34/35] Improve SOAP fault detail logging Switched from generic Object to DOMResult for SOAP fault details extraction. Enhanced logging by adding detailed node information such as systemId, nodeName, nodeValue, nodeType, and nextSibling. This will facilitate better debugging and troubleshooting of SOAP faults. --- .../oppdragservice/consumer/OppdragWSConsumer.java | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/apps/oppdrag-service/src/main/java/no/nav/testnav/oppdragservice/consumer/OppdragWSConsumer.java b/apps/oppdrag-service/src/main/java/no/nav/testnav/oppdragservice/consumer/OppdragWSConsumer.java index 7d54c9dc732..411cfa53c8b 100644 --- a/apps/oppdrag-service/src/main/java/no/nav/testnav/oppdragservice/consumer/OppdragWSConsumer.java +++ b/apps/oppdrag-service/src/main/java/no/nav/testnav/oppdragservice/consumer/OppdragWSConsumer.java @@ -9,6 +9,7 @@ import org.springframework.ws.soap.SoapFaultDetailElement; import org.springframework.ws.soap.client.SoapFaultClientException; +import javax.xml.transform.dom.DOMResult; import java.util.Spliterator; import java.util.Spliterators; import java.util.stream.Collectors; @@ -43,7 +44,12 @@ public SendInnOppdragResponse sendOppdrag(String miljoe, SendInnOppdragRequest m soapFaultClientException.getSoapFault().getFaultDetail().getDetailEntries(), Spliterator.ORDERED), false) .map(SoapFaultDetailElement::getResult) - .map(Object::toString) + .map(DOMResult.class::cast) + .map(result -> "systemId: " + result.getSystemId() + + ", nodeName: " + result.getNode().getNodeName() + + ", nodeValue: " + result.getNode().getNodeValue() + + ", nodeType: " + result.getNode().getNodeType() + + ", nextSibling: " + result.getNextSibling()) .collect(Collectors.joining(", ")), soapFaultClientException.getSoapFault().getFaultActorOrRole(), soapFaultClientException.getSoapFault().getFaultStringOrReason(), e); From 9f3c2e63e28b81c6bd2c3236ea76101f6ea2ef81 Mon Sep 17 00:00:00 2001 From: "Kristen.Herum" Date: Thu, 7 Nov 2024 11:18:14 +0100 Subject: [PATCH 35/35] Refactor SoapFaultDetailElement processing logic #deploy-oppdrag-service Introduce a helper method to encapsulate node information extraction from SoapFaultDetailElement. This improves code readability and centralizes the logic for easier maintenance and potential future modifications. --- .../consumer/OppdragWSConsumer.java | 23 +++++++++++++++---- 1 file changed, 19 insertions(+), 4 deletions(-) diff --git a/apps/oppdrag-service/src/main/java/no/nav/testnav/oppdragservice/consumer/OppdragWSConsumer.java b/apps/oppdrag-service/src/main/java/no/nav/testnav/oppdragservice/consumer/OppdragWSConsumer.java index 411cfa53c8b..689f3ac02ee 100644 --- a/apps/oppdrag-service/src/main/java/no/nav/testnav/oppdragservice/consumer/OppdragWSConsumer.java +++ b/apps/oppdrag-service/src/main/java/no/nav/testnav/oppdragservice/consumer/OppdragWSConsumer.java @@ -8,6 +8,7 @@ import org.springframework.ws.client.core.support.WebServiceGatewaySupport; import org.springframework.ws.soap.SoapFaultDetailElement; import org.springframework.ws.soap.client.SoapFaultClientException; +import org.w3c.dom.Node; import javax.xml.transform.dom.DOMResult; import java.util.Spliterator; @@ -15,6 +16,8 @@ import java.util.stream.Collectors; import java.util.stream.StreamSupport; +import static java.util.Objects.isNull; + @Slf4j @RequiredArgsConstructor public class OppdragWSConsumer extends WebServiceGatewaySupport { @@ -46,10 +49,7 @@ public SendInnOppdragResponse sendOppdrag(String miljoe, SendInnOppdragRequest m .map(SoapFaultDetailElement::getResult) .map(DOMResult.class::cast) .map(result -> "systemId: " + result.getSystemId() + - ", nodeName: " + result.getNode().getNodeName() + - ", nodeValue: " + result.getNode().getNodeValue() + - ", nodeType: " + result.getNode().getNodeType() + - ", nextSibling: " + result.getNextSibling()) + getNodeInfo(result.getNode(), new StringBuilder())) .collect(Collectors.joining(", ")), soapFaultClientException.getSoapFault().getFaultActorOrRole(), soapFaultClientException.getSoapFault().getFaultStringOrReason(), e); @@ -58,4 +58,19 @@ public SendInnOppdragResponse sendOppdrag(String miljoe, SendInnOppdragRequest m throw e; } } + + private static String getNodeInfo(Node node, StringBuilder tekst) { + + if (isNull(node)) { + return tekst.toString(); + } + + return getNodeInfo(node.getNextSibling(), tekst + .append(", nodeName: ") + .append(node.getNodeName()) + .append(", nodeValue: ") + .append(node.getNodeValue()) + .append(", nodeType: ") + .append(node.getNodeType())); + } }