This is an automated email from the ASF dual-hosted git repository.

kaze pushed a commit to branch develop
in repository https://gitbox.apache.org/repos/asf/fineract-credit-scorecard.git

commit 238669a673ec2651f21db05bdc2e8af5926bbe2e
Author: Nasser Kaze <[email protected]>
AuthorDate: Sun Aug 29 21:00:27 2021 +0100

    FINCN-351 Make the scorecard integration into a plugin
---
 .classpath                                         |    6 -
 .github/workflows/build.yml                        |   16 +-
 .gitignore                                         |    5 +-
 README.md                                          |  Bin 10088 -> 10020 bytes
 api/views.py                                       |    2 +-
 build.gradle                                       |   46 +-
 clients/java/.idea/.gitignore                      |    8 -
 clients/java/.idea/.name                           |    1 -
 clients/java/.idea/compiler.xml                    |    6 -
 clients/java/.idea/gradle.xml                      |   18 -
 clients/java/.idea/jarRepositories.xml             |   20 -
 clients/java/.idea/misc.xml                        |    8 -
 clients/java/.idea/vcs.xml                         |    6 -
 clients/java/build.gradle                          |  114 --
 clients/java/gradle.properties                     |    2 -
 clients/java/gradle/wrapper/gradle-wrapper.jar     |  Bin 59203 -> 0 bytes
 .../java/gradle/wrapper/gradle-wrapper.properties  |    5 -
 clients/java/gradlew                               |  185 ----
 clients/java/gradlew.bat                           |   89 --
 clients/java/pom.xml                               |  276 -----
 clients/java/settings.gradle                       |    1 -
 openapi.yml                                        | 1094 ++++++++++----------
 {clients/java => scorecard-client}/README.md       |    0
 scorecard-client/build.gradle                      |   55 +
 .../java => scorecard-client}/docs/Algorithm.md    |    0
 .../docs/AlgorithmsApi.md                          |    0
 {clients/java => scorecard-client}/docs/Dataset.md |    0
 .../java => scorecard-client}/docs/DatasetsApi.md  |    0
 .../docs/PredictionRequest.md                      |    0
 .../docs/PredictionResponse.md                     |    0
 .../java => scorecard-client}/docs/RequestsApi.md  |    0
 .../src/main/AndroidManifest.xml                   |    0
 .../fineract/credit/scorecard/ApiCallback.java     |    0
 .../fineract/credit/scorecard/ApiClient.java       |    0
 .../fineract/credit/scorecard/ApiException.java    |    0
 .../fineract/credit/scorecard/ApiResponse.java     |    0
 .../fineract/credit/scorecard/Configuration.java   |    0
 .../credit/scorecard/GzipRequestInterceptor.java   |    0
 .../org/apache/fineract/credit/scorecard/JSON.java |    0
 .../org/apache/fineract/credit/scorecard/Pair.java |    0
 .../credit/scorecard/ProgressRequestBody.java      |    0
 .../credit/scorecard/ProgressResponseBody.java     |    0
 .../credit/scorecard/ServerConfiguration.java      |    0
 .../fineract/credit/scorecard/ServerVariable.java  |    0
 .../fineract/credit/scorecard/StringUtil.java      |    0
 .../fineract/credit/scorecard/auth/ApiKeyAuth.java |    0
 .../credit/scorecard/auth/Authentication.java      |    0
 .../credit/scorecard/auth/HttpBasicAuth.java       |    0
 .../credit/scorecard/auth/HttpBearerAuth.java      |    0
 .../credit/scorecard/models/Algorithm.java         |    0
 .../fineract/credit/scorecard/models/Dataset.java  |    0
 .../credit/scorecard/models/PredictionRequest.java |    0
 .../scorecard/models/PredictionResponse.java       |    0
 .../credit/scorecard/services/AlgorithmsApi.java   |    0
 .../credit/scorecard/services/DatasetsApi.java     |    0
 .../credit/scorecard/services/RequestsApi.java     |    0
 scorecard-plugin/README.md                         |   39 +
 scorecard-plugin/TODO.md                           |   17 +
 scorecard-plugin/build.gradle                      |   80 ++
 scorecard-plugin/run                               |   13 +
 scorecard-plugin/run.bat                           |   33 +
 .../service/CreditScorecardAssemblerImpl.java      |  255 +++++
 ...corecardFeatureDropdownReadPlatformService.java |   52 +-
 ...cardFeatureDropdownReadPlatformServiceImpl.java |   55 +
 .../CreditScorecardReadPlatformServiceImpl.java    |  228 ++++
 .../CreditScorecardWritePlatformServiceImpl.java   |  376 +++++++
 .../src/main/resources/scorecard-client.properties |   11 +-
 server/settings.py                                 |    5 +-
 settings.gradle                                    |    4 +
 .../statistical_scoring.py                         |    0
 70 files changed, 1759 insertions(+), 1372 deletions(-)

diff --git a/.classpath b/.classpath
index c0c2f18..4f3f504 100644
--- a/.classpath
+++ b/.classpath
@@ -1,11 +1,5 @@
 <?xml version="1.0" encoding="UTF-8"?>
 <classpath>
-       <classpathentry kind="src" output="bin/generated" 
path="build/generated/java/src/main/java">
-               <attributes>
-                       <attribute name="gradle_scope" value="generated"/>
-                       <attribute name="gradle_used_by_scope" 
value="generated"/>
-               </attributes>
-       </classpathentry>
        <classpathentry kind="con" 
path="org.eclipse.jdt.launching.JRE_CONTAINER/org.eclipse.jdt.internal.debug.ui.launcher.StandardVMType/JavaSE-1.8/"/>
        <classpathentry kind="con" 
path="org.eclipse.buildship.core.gradleclasspathcontainer"/>
        <classpathentry kind="output" path="bin/default"/>
diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml
index e4a2c68..809f075 100644
--- a/.github/workflows/build.yml
+++ b/.github/workflows/build.yml
@@ -16,14 +16,14 @@ jobs:
         python-version: [3.7, 3.8]
 
     services:
-          mysql:
-            image: mysql:5.7
-            env:
-              MYSQL_ROOT_PASSWORD: mysql
-              MYSQL_DATABASE: fineract_credit_scorecard
-            ports:
-              - '3306:3306'
-            options: --health-cmd="mysqladmin ping" --health-interval=10s 
--health-timeout=5s --health-retries=3
+      mysql:
+        image: mysql:5.7
+        env:
+          MYSQL_ROOT_PASSWORD: mysql
+          MYSQL_DATABASE: fineract_credit_scorecard
+        ports:
+          - '3306:3306'
+        options: --health-cmd="mysqladmin ping" --health-interval=10s 
--health-timeout=5s --health-retries=3
 
     steps:
     - uses: actions/checkout@v2
diff --git a/.gitignore b/.gitignore
index 040215e..623696e 100644
--- a/.gitignore
+++ b/.gitignore
@@ -121,5 +121,8 @@ build
 
 .settings
 .project
+.classpath
 
-data/
\ No newline at end of file
+data/
+
+.idea
diff --git a/README.md b/README.md
index e34a5b0..5a2b294 100644
Binary files a/README.md and b/README.md differ
diff --git a/api/views.py b/api/views.py
index 4198d29..33ee8c8 100644
--- a/api/views.py
+++ b/api/views.py
@@ -19,7 +19,7 @@
 
 import json
 import logging
-from statistical_scripts.statistical_scoring import stat_score
+from stats.statistical_scoring import stat_score
 from typing import Any, Dict
 
 from drf_spectacular.utils import extend_schema, OpenApiParameter, 
OpenApiExample, inline_serializer
diff --git a/build.gradle b/build.gradle
index ca95c94..cbd7246 100644
--- a/build.gradle
+++ b/build.gradle
@@ -25,7 +25,7 @@ buildscript {
 
 plugins {
     id "java"
-    id "org.openapi.generator" version "5.1.0"
+    id "org.openapi.generator" version "5.2.1"
     id "com.github.hierynomus.license" version"0.15.0"
 }
 
@@ -33,6 +33,11 @@ description = 'Fineract Credit Scorecard Build Tool'
 
 ext['openapiSpecFile'] = "$rootDir/openapi.yml".toString()
 
+java {
+    sourceCompatibility = JavaVersion.VERSION_1_8
+    targetCompatibility = JavaVersion.VERSION_1_8
+}
+
 license {
     header rootProject.file("$rootDir/APACHE_LICENSETEXT.md")
     excludes([
@@ -93,36 +98,6 @@ task buildJavaSdk(type: 
org.openapitools.generator.gradle.plugin.tasks.GenerateT
     ]
     generateModelTests = false
     generateApiTests = false
-    finalizedBy = ["copyClients"]
-}
-
-task buildTypescriptAngularSdk(type: 
org.openapitools.generator.gradle.plugin.tasks.GenerateTask) {
-    generatorName = 'typescript-angular'
-    verbose = false
-    validateSpec = false
-    skipValidateSpec = true
-    inputSpec = "$openapiSpecFile"
-    outputDir = "$buildDir/generated/typescript".toString()
-    apiPackage = 'org.apache.fineract.credit.scorecard.services'
-    invokerPackage = 'org.apache.fineract.credit.scorecard'
-    modelPackage = 'org.apache.fineract.credit.scorecard.models'
-    configOptions = [
-        apiModulePrefix: 'scorecard',
-        configurationPrefix: 'scorecard',
-        ngVersion: '10.0.0',
-        npmName: 'apache-fineract-credit-scorecard-client'
-    ]
-    finalizedBy = [licenseFormat]
-}
-
-task copyClients {
-    copy {
-        from 'build/generated'
-        into 'clients'
-        exclude '**/*.sbt', '**/*.yml', '**/*.sh', '**/api', 
'**/.openapi-generator', '**/.openapi-generator-ignore'
-        // filter(ReplaceTokens, tokens: [version: '2.3.1'])
-    }
-
     finalizedBy = [licenseFormat]
 }
 
@@ -134,11 +109,6 @@ sourceSets {
     }
 }
 
-java {
-    sourceCompatibility = JavaVersion.VERSION_1_8
-    targetCompatibility = JavaVersion.VERSION_1_8
-}
-
 compileJava {
     source += sourceSets.generated.java
 }
@@ -147,7 +117,3 @@ configurations {
     generatedCompile.extendsFrom implementation
     generatedRuntime.extendsFrom runtime
 }
-
-test {
-    useJUnitPlatform()
-}
diff --git a/clients/java/.idea/.gitignore b/clients/java/.idea/.gitignore
deleted file mode 100644
index 4aa91ea..0000000
--- a/clients/java/.idea/.gitignore
+++ /dev/null
@@ -1,8 +0,0 @@
-# Default ignored files
-/shelf/
-/workspace.xml
-# Datasource local storage ignored files
-/dataSources/
-/dataSources.local.xml
-# Editor-based HTTP Client requests
-/httpRequests/
diff --git a/clients/java/.idea/.name b/clients/java/.idea/.name
deleted file mode 100644
index da9779d..0000000
--- a/clients/java/.idea/.name
+++ /dev/null
@@ -1 +0,0 @@
-credit-scorecard-java-client
\ No newline at end of file
diff --git a/clients/java/.idea/compiler.xml b/clients/java/.idea/compiler.xml
deleted file mode 100644
index 245a82c..0000000
--- a/clients/java/.idea/compiler.xml
+++ /dev/null
@@ -1,6 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<project version="4">
-  <component name="CompilerConfiguration">
-    <bytecodeTargetLevel target="1.8" />
-  </component>
-</project>
\ No newline at end of file
diff --git a/clients/java/.idea/gradle.xml b/clients/java/.idea/gradle.xml
deleted file mode 100644
index 222345a..0000000
--- a/clients/java/.idea/gradle.xml
+++ /dev/null
@@ -1,18 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<project version="4">
-  <component name="GradleSettings">
-    <option name="linkedExternalProjectsSettings">
-      <GradleProjectSettings>
-        <option name="distributionType" value="DEFAULT_WRAPPED" />
-        <option name="externalProjectPath" value="$PROJECT_DIR$" />
-        <option name="gradleHome" 
value="$PROJECT_DIR$/../../../../../../../../tools/Gradle/gradle-7.1" />
-        <option name="gradleJvm" value="#JAVA_HOME" />
-        <option name="modules">
-          <set>
-            <option value="$PROJECT_DIR$" />
-          </set>
-        </option>
-      </GradleProjectSettings>
-    </option>
-  </component>
-</project>
\ No newline at end of file
diff --git a/clients/java/.idea/jarRepositories.xml 
b/clients/java/.idea/jarRepositories.xml
deleted file mode 100644
index 83f06a7..0000000
--- a/clients/java/.idea/jarRepositories.xml
+++ /dev/null
@@ -1,20 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<project version="4">
-  <component name="RemoteRepositoriesConfiguration">
-    <remote-repository>
-      <option name="id" value="central" />
-      <option name="name" value="Maven Central repository" />
-      <option name="url" value="https://repo1.maven.org/maven2"; />
-    </remote-repository>
-    <remote-repository>
-      <option name="id" value="jboss.community" />
-      <option name="name" value="JBoss Community repository" />
-      <option name="url" 
value="https://repository.jboss.org/nexus/content/repositories/public/"; />
-    </remote-repository>
-    <remote-repository>
-      <option name="id" value="BintrayJCenter" />
-      <option name="name" value="BintrayJCenter" />
-      <option name="url" value="https://jcenter.bintray.com/"; />
-    </remote-repository>
-  </component>
-</project>
\ No newline at end of file
diff --git a/clients/java/.idea/misc.xml b/clients/java/.idea/misc.xml
deleted file mode 100644
index a2556d3..0000000
--- a/clients/java/.idea/misc.xml
+++ /dev/null
@@ -1,8 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<project version="4">
-  <component name="ExternalStorageConfigurationManager" enabled="true" />
-  <component name="FrameworkDetectionExcludesConfiguration">
-    <file type="web" url="file://$PROJECT_DIR$" />
-  </component>
-  <component name="ProjectRootManager" version="2" languageLevel="JDK_1_8" 
project-jdk-name="11" project-jdk-type="JavaSDK" />
-</project>
\ No newline at end of file
diff --git a/clients/java/.idea/vcs.xml b/clients/java/.idea/vcs.xml
deleted file mode 100644
index c8ade07..0000000
--- a/clients/java/.idea/vcs.xml
+++ /dev/null
@@ -1,6 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<project version="4">
-  <component name="VcsDirectoryMappings">
-    <mapping directory="$PROJECT_DIR$/../.." vcs="Git" />
-  </component>
-</project>
\ No newline at end of file
diff --git a/clients/java/build.gradle b/clients/java/build.gradle
deleted file mode 100644
index 58ff79f..0000000
--- a/clients/java/build.gradle
+++ /dev/null
@@ -1,114 +0,0 @@
-apply plugin: 'idea'
-apply plugin: 'eclipse'
-apply plugin: 'java'
-
-group = 'org.apache.fineract'
-version = '0.1.0-SNAPSHOT'
-
-buildscript {
-    repositories {
-        maven { url "https://repo1.maven.org/maven2"; }
-        jcenter()
-    }
-    dependencies {
-        classpath 'com.android.tools.build:gradle:2.3.+'
-        classpath 'com.github.dcendents:android-maven-gradle-plugin:1.5'
-    }
-}
-
-repositories {
-    jcenter()
-}
-sourceSets {
-    main.java.srcDirs = ['src/main/java']
-}
-
-if(hasProperty('target') && target == 'android') {
-
-    apply plugin: 'com.android.library'
-    apply plugin: 'com.github.dcendents.android-maven'
-
-    android {
-        compileSdkVersion 25
-        buildToolsVersion '25.0.2'
-        defaultConfig {
-            minSdkVersion 14
-            targetSdkVersion 25
-        }
-        compileOptions {
-            sourceCompatibility JavaVersion.VERSION_1_8
-            targetCompatibility JavaVersion.VERSION_1_8
-        }
-
-        // Rename the aar correctly
-        libraryVariants.all { variant ->
-            variant.outputs.each { output ->
-                def outputFile = output.outputFile
-                if (outputFile != null && outputFile.name.endsWith('.aar')) {
-                    def fileName = 
"${project.name}-${variant.baseName}-${version}.aar"
-                    output.outputFile = new File(outputFile.parent, fileName)
-                }
-            }
-        }
-
-        dependencies {
-            provided 'javax.annotation:javax.annotation-api:1.3.2'
-        }
-    }
-
-    afterEvaluate {
-        android.libraryVariants.all { variant ->
-            def task = project.tasks.create "jar${variant.name.capitalize()}", 
Jar
-            task.description = "Create jar artifact for ${variant.name}"
-            task.dependsOn variant.javaCompile
-            task.from variant.javaCompile.destinationDir
-            task.destinationDir = 
project.file("${project.buildDir}/outputs/jar")
-            task.archiveName = 
"${project.name}-${variant.baseName}-${version}.jar"
-            artifacts.add('archives', task);
-        }
-    }
-
-    task sourcesJar(type: Jar) {
-        from android.sourceSets.main.java.srcDirs
-        classifier = 'sources'
-    }
-
-    artifacts {
-        archives sourcesJar
-    }
-
-} else {
-
-    apply plugin: 'java'
-    apply plugin: 'maven'
-
-    sourceCompatibility = JavaVersion.VERSION_1_8
-    targetCompatibility = JavaVersion.VERSION_1_8
-
-    install {
-        repositories.mavenInstaller {
-            pom.artifactId = 'credit-scorecard-java-client'
-        }
-    }
-
-    task execute(type:JavaExec) {
-       main = System.getProperty('mainClass')
-       classpath = sourceSets.main.runtimeClasspath
-    }
-}
-
-dependencies {
-    implementation 'io.swagger:swagger-annotations:1.5.24'
-    implementation "com.google.code.findbugs:jsr305:3.0.2"
-    implementation 'com.squareup.okhttp3:okhttp:3.14.7'
-    implementation 'com.squareup.okhttp3:logging-interceptor:3.14.7'
-    implementation 'com.google.code.gson:gson:2.8.6'
-    implementation 'io.gsonfire:gson-fire:1.8.4'
-    implementation group: 'org.apache.commons', name: 'commons-lang3', 
version: '3.10'
-    implementation 'javax.annotation:javax.annotation-api:1.3.2'
-    testImplementation 'junit:junit:4.13.1'
-}
-
-javadoc {
-    options.tags = [ "http.response.details:a:Http Response Details" ]
-}
diff --git a/clients/java/gradle.properties b/clients/java/gradle.properties
deleted file mode 100644
index 05644f0..0000000
--- a/clients/java/gradle.properties
+++ /dev/null
@@ -1,2 +0,0 @@
-# Uncomment to build for Android
-#target = android
\ No newline at end of file
diff --git a/clients/java/gradle/wrapper/gradle-wrapper.jar 
b/clients/java/gradle/wrapper/gradle-wrapper.jar
deleted file mode 100644
index e708b1c..0000000
Binary files a/clients/java/gradle/wrapper/gradle-wrapper.jar and /dev/null 
differ
diff --git a/clients/java/gradle/wrapper/gradle-wrapper.properties 
b/clients/java/gradle/wrapper/gradle-wrapper.properties
deleted file mode 100644
index 4d9ca16..0000000
--- a/clients/java/gradle/wrapper/gradle-wrapper.properties
+++ /dev/null
@@ -1,5 +0,0 @@
-distributionBase=GRADLE_USER_HOME
-distributionPath=wrapper/dists
-distributionUrl=https\://services.gradle.org/distributions/gradle-6.7.1-bin.zip
-zipStoreBase=GRADLE_USER_HOME
-zipStorePath=wrapper/dists
diff --git a/clients/java/gradlew b/clients/java/gradlew
deleted file mode 100644
index 4f906e0..0000000
--- a/clients/java/gradlew
+++ /dev/null
@@ -1,185 +0,0 @@
-#!/usr/bin/env sh
-
-#
-# Copyright 2015 the original author or authors.
-#
-# Licensed under the Apache License, Version 2.0 (the "License");
-# you may not use this file except in compliance with the License.
-# You may obtain a copy of the License at
-#
-#      https://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS,
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-# See the License for the specific language governing permissions and
-# limitations under the License.
-#
-
-##############################################################################
-##
-##  Gradle start up script for UN*X
-##
-##############################################################################
-
-# Attempt to set APP_HOME
-# Resolve links: $0 may be a link
-PRG="$0"
-# Need this for relative symlinks.
-while [ -h "$PRG" ] ; do
-    ls=`ls -ld "$PRG"`
-    link=`expr "$ls" : '.*-> \(.*\)$'`
-    if expr "$link" : '/.*' > /dev/null; then
-        PRG="$link"
-    else
-        PRG=`dirname "$PRG"`"/$link"
-    fi
-done
-SAVED="`pwd`"
-cd "`dirname \"$PRG\"`/" >/dev/null
-APP_HOME="`pwd -P`"
-cd "$SAVED" >/dev/null
-
-APP_NAME="Gradle"
-APP_BASE_NAME=`basename "$0"`
-
-# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to 
pass JVM options to this script.
-DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"'
-
-# Use the maximum available, or set MAX_FD != -1 to use that value.
-MAX_FD="maximum"
-
-warn () {
-    echo "$*"
-}
-
-die () {
-    echo
-    echo "$*"
-    echo
-    exit 1
-}
-
-# OS specific support (must be 'true' or 'false').
-cygwin=false
-msys=false
-darwin=false
-nonstop=false
-case "`uname`" in
-  CYGWIN* )
-    cygwin=true
-    ;;
-  Darwin* )
-    darwin=true
-    ;;
-  MINGW* )
-    msys=true
-    ;;
-  NONSTOP* )
-    nonstop=true
-    ;;
-esac
-
-CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar
-
-
-# Determine the Java command to use to start the JVM.
-if [ -n "$JAVA_HOME" ] ; then
-    if [ -x "$JAVA_HOME/jre/sh/java" ] ; then
-        # IBM's JDK on AIX uses strange locations for the executables
-        JAVACMD="$JAVA_HOME/jre/sh/java"
-    else
-        JAVACMD="$JAVA_HOME/bin/java"
-    fi
-    if [ ! -x "$JAVACMD" ] ; then
-        die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME
-
-Please set the JAVA_HOME variable in your environment to match the
-location of your Java installation."
-    fi
-else
-    JAVACMD="java"
-    which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 
'java' command could be found in your PATH.
-
-Please set the JAVA_HOME variable in your environment to match the
-location of your Java installation."
-fi
-
-# Increase the maximum file descriptors if we can.
-if [ "$cygwin" = "false" -a "$darwin" = "false" -a "$nonstop" = "false" ] ; 
then
-    MAX_FD_LIMIT=`ulimit -H -n`
-    if [ $? -eq 0 ] ; then
-        if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then
-            MAX_FD="$MAX_FD_LIMIT"
-        fi
-        ulimit -n $MAX_FD
-        if [ $? -ne 0 ] ; then
-            warn "Could not set maximum file descriptor limit: $MAX_FD"
-        fi
-    else
-        warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT"
-    fi
-fi
-
-# For Darwin, add options to specify how the application appears in the dock
-if $darwin; then
-    GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" 
\"-Xdock:icon=$APP_HOME/media/gradle.icns\""
-fi
-
-# For Cygwin or MSYS, switch paths to Windows format before running java
-if [ "$cygwin" = "true" -o "$msys" = "true" ] ; then
-    APP_HOME=`cygpath --path --mixed "$APP_HOME"`
-    CLASSPATH=`cygpath --path --mixed "$CLASSPATH"`
-
-    JAVACMD=`cygpath --unix "$JAVACMD"`
-
-    # We build the pattern for arguments to be converted via cygpath
-    ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null`
-    SEP=""
-    for dir in $ROOTDIRSRAW ; do
-        ROOTDIRS="$ROOTDIRS$SEP$dir"
-        SEP="|"
-    done
-    OURCYGPATTERN="(^($ROOTDIRS))"
-    # Add a user-defined pattern to the cygpath arguments
-    if [ "$GRADLE_CYGPATTERN" != "" ] ; then
-        OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)"
-    fi
-    # Now convert the arguments - kludge to limit ourselves to /bin/sh
-    i=0
-    for arg in "$@" ; do
-        CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -`
-        CHECK2=`echo "$arg"|egrep -c "^-"`                                 ### 
Determine if an option
-
-        if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then                    ### 
Added a condition
-            eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"`
-        else
-            eval `echo args$i`="\"$arg\""
-        fi
-        i=`expr $i + 1`
-    done
-    case $i in
-        0) set -- ;;
-        1) set -- "$args0" ;;
-        2) set -- "$args0" "$args1" ;;
-        3) set -- "$args0" "$args1" "$args2" ;;
-        4) set -- "$args0" "$args1" "$args2" "$args3" ;;
-        5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;;
-        6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;;
-        7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" 
"$args6" ;;
-        8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" 
"$args6" "$args7" ;;
-        9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" 
"$args6" "$args7" "$args8" ;;
-    esac
-fi
-
-# Escape application args
-save () {
-    for i do printf %s\\n "$i" | sed "s/'/'\\\\''/g;1s/^/'/;\$s/\$/' \\\\/" ; 
done
-    echo " "
-}
-APP_ARGS=`save "$@"`
-
-# Collect all arguments for the java command, following the shell quoting and 
substitution rules
-eval set -- $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS 
"\"-Dorg.gradle.appname=$APP_BASE_NAME\"" -classpath "\"$CLASSPATH\"" 
org.gradle.wrapper.GradleWrapperMain "$APP_ARGS"
-
-exec "$JAVACMD" "$@"
diff --git a/clients/java/gradlew.bat b/clients/java/gradlew.bat
deleted file mode 100644
index 107acd3..0000000
--- a/clients/java/gradlew.bat
+++ /dev/null
@@ -1,89 +0,0 @@
-@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/clients/java/pom.xml b/clients/java/pom.xml
deleted file mode 100644
index 83e6745..0000000
--- a/clients/java/pom.xml
+++ /dev/null
@@ -1,276 +0,0 @@
-<project xmlns="http://maven.apache.org/POM/4.0.0"; 
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance";
-         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 
http://maven.apache.org/maven-v4_0_0.xsd";>
-    <modelVersion>4.0.0</modelVersion>
-    <groupId>org.apache.fineract</groupId>
-    <artifactId>credit-scorecard-java-client</artifactId>
-    <packaging>jar</packaging>
-    <name>credit-scorecard-java-client</name>
-    <version>0.1.0-SNAPSHOT</version>
-    <url>https://github.com/openapitools/openapi-generator</url>
-    <description>OpenAPI Java</description>
-    <scm>
-        
<connection>scm:git:[email protected]:openapitools/openapi-generator.git</connection>
-        
<developerConnection>scm:git:[email protected]:openapitools/openapi-generator.git</developerConnection>
-        <url>https://github.com/openapitools/openapi-generator</url>
-    </scm>
-
-    <licenses>
-        <license>
-            <name>Unlicense</name>
-            <url>https://www.apache.org/licenses/LICENSE-2.0.html</url>
-            <distribution>repo</distribution>
-        </license>
-    </licenses>
-
-    <developers>
-        <developer>
-            <name>Apache Fineract</name>
-            <email>[email protected]</email>
-            <organization>Apache Software Foundation</organization>
-            <organizationUrl>https://apache.org</organizationUrl>
-        </developer>
-    </developers>
-
-    <build>
-        <plugins>
-           <plugin>
-                <groupId>org.apache.maven.plugins</groupId>
-                <artifactId>maven-compiler-plugin</artifactId>
-                <version>3.8.1</version>
-                <configuration>
-                    <fork>true</fork>
-                    <meminitial>128m</meminitial>
-                    <maxmem>512m</maxmem>
-                    <compilerArgs>
-                        <arg>-Xlint:all</arg>
-                        <arg>-J-Xss4m</arg><!-- Compiling the generated 
JSON.java file may require larger stack size. -->
-                    </compilerArgs>
-                </configuration>
-            </plugin>
-            <plugin>
-                <groupId>org.apache.maven.plugins</groupId>
-                <artifactId>maven-enforcer-plugin</artifactId>
-                <version>3.0.0-M1</version>
-                <executions>
-                    <execution>
-                        <id>enforce-maven</id>
-                        <goals>
-                            <goal>enforce</goal>
-                        </goals>
-                        <configuration>
-                            <rules>
-                                <requireMavenVersion>
-                                    <version>2.2.0</version>
-                                </requireMavenVersion>
-                            </rules>
-                        </configuration>
-                    </execution>
-                </executions>
-            </plugin>
-            <plugin>
-                <groupId>org.apache.maven.plugins</groupId>
-                <artifactId>maven-surefire-plugin</artifactId>
-                <version>3.0.0-M4</version>
-                <configuration>
-                    <systemProperties>
-                        <property>
-                            <name>loggerPath</name>
-                            <value>conf/log4j.properties</value>
-                        </property>
-                    </systemProperties>
-                    <argLine>-Xms512m -Xmx1500m</argLine>
-                    <parallel>methods</parallel>
-                    <threadCount>10</threadCount>
-                </configuration>
-            </plugin>
-            <plugin>
-                <artifactId>maven-dependency-plugin</artifactId>
-                <executions>
-                    <execution>
-                        <phase>package</phase>
-                        <goals>
-                            <goal>copy-dependencies</goal>
-                        </goals>
-                        <configuration>
-                            
<outputDirectory>${project.build.directory}/lib</outputDirectory>
-                        </configuration>
-                    </execution>
-                </executions>
-            </plugin>
-
-            <!-- attach test jar -->
-            <plugin>
-                <groupId>org.apache.maven.plugins</groupId>
-                <artifactId>maven-jar-plugin</artifactId>
-                <version>2.2</version>
-                <executions>
-                    <execution>
-                        <goals>
-                            <goal>jar</goal>
-                            <goal>test-jar</goal>
-                        </goals>
-                    </execution>
-                </executions>
-                <configuration>
-                </configuration>
-            </plugin>
-
-            <plugin>
-                <groupId>org.codehaus.mojo</groupId>
-                <artifactId>build-helper-maven-plugin</artifactId>
-                <version>1.10</version>
-                <executions>
-                    <execution>
-                        <id>add_sources</id>
-                        <phase>generate-sources</phase>
-                        <goals>
-                            <goal>add-source</goal>
-                        </goals>
-                        <configuration>
-                            <sources>
-                                <source>src/main/java</source>
-                            </sources>
-                        </configuration>
-                    </execution>
-                    <execution>
-                        <id>add_test_sources</id>
-                        <phase>generate-test-sources</phase>
-                        <goals>
-                            <goal>add-test-source</goal>
-                        </goals>
-                        <configuration>
-                            <sources>
-                                <source>src/test/java</source>
-                            </sources>
-                        </configuration>
-                    </execution>
-                </executions>
-            </plugin>
-            <plugin>
-                <groupId>org.apache.maven.plugins</groupId>
-                <artifactId>maven-javadoc-plugin</artifactId>
-                <version>3.1.1</version>
-                <executions>
-                    <execution>
-                        <id>attach-javadocs</id>
-                        <goals>
-                            <goal>jar</goal>
-                        </goals>
-                    </execution>
-                </executions>
-                <configuration>
-                    <doclint>none</doclint>
-                    <tags>
-                        <tag>
-                            <name>http.response.details</name>
-                            <placement>a</placement>
-                            <head>Http Response Details:</head>
-                        </tag>
-                    </tags>
-                </configuration>
-            </plugin>
-            <plugin>
-                <groupId>org.apache.maven.plugins</groupId>
-                <artifactId>maven-source-plugin</artifactId>
-                <version>2.2.1</version>
-                <executions>
-                    <execution>
-                        <id>attach-sources</id>
-                        <goals>
-                            <goal>jar-no-fork</goal>
-                        </goals>
-                    </execution>
-                </executions>
-            </plugin>
-        </plugins>
-    </build>
-
-    <profiles>
-        <profile>
-            <id>sign-artifacts</id>
-            <build>
-                <plugins>
-                    <plugin>
-                        <groupId>org.apache.maven.plugins</groupId>
-                        <artifactId>maven-gpg-plugin</artifactId>
-                        <version>1.5</version>
-                        <executions>
-                            <execution>
-                                <id>sign-artifacts</id>
-                                <phase>verify</phase>
-                                <goals>
-                                    <goal>sign</goal>
-                                </goals>
-                            </execution>
-                        </executions>
-                    </plugin>
-                </plugins>
-            </build>
-        </profile>
-    </profiles>
-
-    <dependencies>
-        <dependency>
-            <groupId>io.swagger</groupId>
-            <artifactId>swagger-annotations</artifactId>
-            <version>${swagger-core-version}</version>
-        </dependency>
-        <!-- @Nullable annotation -->
-        <dependency>
-            <groupId>com.google.code.findbugs</groupId>
-            <artifactId>jsr305</artifactId>
-            <version>3.0.2</version>
-        </dependency>
-        <dependency>
-            <groupId>com.squareup.okhttp3</groupId>
-            <artifactId>okhttp</artifactId>
-            <version>${okhttp-version}</version>
-        </dependency>
-        <dependency>
-            <groupId>com.squareup.okhttp3</groupId>
-            <artifactId>logging-interceptor</artifactId>
-            <version>${okhttp-version}</version>
-        </dependency>
-        <dependency>
-            <groupId>com.google.code.gson</groupId>
-            <artifactId>gson</artifactId>
-            <version>${gson-version}</version>
-        </dependency>
-        <dependency>
-            <groupId>io.gsonfire</groupId>
-            <artifactId>gson-fire</artifactId>
-            <version>${gson-fire-version}</version>
-        </dependency>
-        <dependency>
-            <groupId>org.apache.commons</groupId>
-            <artifactId>commons-lang3</artifactId>
-            <version>${commons-lang3-version}</version>
-        </dependency>
-        <dependency>
-            <groupId>javax.annotation</groupId>
-            <artifactId>javax.annotation-api</artifactId>
-            <version>${javax-annotation-version}</version>
-            <scope>provided</scope>
-        </dependency>
-        <!-- test dependencies -->
-        <dependency>
-            <groupId>junit</groupId>
-            <artifactId>junit</artifactId>
-            <version>${junit-version}</version>
-            <scope>test</scope>
-        </dependency>
-    </dependencies>
-    <properties>
-        <java.version>1.8</java.version>
-        <maven.compiler.source>${java.version}</maven.compiler.source>
-        <maven.compiler.target>${java.version}</maven.compiler.target>
-        <gson-fire-version>1.8.5</gson-fire-version>
-        <swagger-core-version>1.6.2</swagger-core-version>
-        <okhttp-version>4.9.1</okhttp-version>
-        <gson-version>2.8.6</gson-version>
-        <commons-lang3-version>3.11</commons-lang3-version>
-        <javax-annotation-version>1.3.2</javax-annotation-version>
-        <junit-version>4.13.1</junit-version>
-        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
-    </properties>
-</project>
diff --git a/clients/java/settings.gradle b/clients/java/settings.gradle
deleted file mode 100644
index 805e86f..0000000
--- a/clients/java/settings.gradle
+++ /dev/null
@@ -1 +0,0 @@
-rootProject.name = "credit-scorecard-java-client"
\ No newline at end of file
diff --git a/openapi.yml b/openapi.yml
index f26c051..e28c543 100644
--- a/openapi.yml
+++ b/openapi.yml
@@ -1,547 +1,547 @@
-openapi: 3.0.3
-info:
-  title: Fineract Credit Scorecard
-  version: 0.1.0-SNAPSHOT
-  description: An API module for credit risk assessment
-  license:
-    name: Apache-2.0
-    url: https://www.apache.org/licenses/LICENSE-2.0.html
-paths:
-  /api/v1/algorithms:
-    get:
-      operationId: algorithms_list
-      description: ''
-      tags:
-      - algorithms
-      security:
-      - {}
-      responses:
-        '200':
-          content:
-            application/json:
-              schema:
-                type: array
-                items:
-                  $ref: '#/components/schemas/Algorithm'
-          description: ''
-    post:
-      operationId: algorithms_create
-      description: ''
-      tags:
-      - algorithms
-      requestBody:
-        content:
-          application/json:
-            schema:
-              $ref: '#/components/schemas/Algorithm'
-          application/x-www-form-urlencoded:
-            schema:
-              $ref: '#/components/schemas/Algorithm'
-          multipart/form-data:
-            schema:
-              $ref: '#/components/schemas/Algorithm'
-        required: true
-      security:
-      - {}
-      responses:
-        '201':
-          content:
-            application/json:
-              schema:
-                $ref: '#/components/schemas/Algorithm'
-          description: ''
-  /api/v1/algorithms/{id}:
-    get:
-      operationId: algorithms_retrieve
-      description: ''
-      parameters:
-      - in: path
-        name: id
-        schema:
-          type: integer
-        description: A unique integer value identifying this algorithm.
-        required: true
-      tags:
-      - algorithms
-      security:
-      - {}
-      responses:
-        '200':
-          content:
-            application/json:
-              schema:
-                $ref: '#/components/schemas/Algorithm'
-          description: ''
-    put:
-      operationId: algorithms_update
-      description: ''
-      parameters:
-      - in: path
-        name: id
-        schema:
-          type: integer
-        description: A unique integer value identifying this algorithm.
-        required: true
-      tags:
-      - algorithms
-      requestBody:
-        content:
-          application/json:
-            schema:
-              $ref: '#/components/schemas/Algorithm'
-          application/x-www-form-urlencoded:
-            schema:
-              $ref: '#/components/schemas/Algorithm'
-          multipart/form-data:
-            schema:
-              $ref: '#/components/schemas/Algorithm'
-        required: true
-      security:
-      - {}
-      responses:
-        '200':
-          content:
-            application/json:
-              schema:
-                $ref: '#/components/schemas/Algorithm'
-          description: ''
-    patch:
-      operationId: algorithms_partial_update
-      description: ''
-      parameters:
-      - in: path
-        name: id
-        schema:
-          type: integer
-        description: A unique integer value identifying this algorithm.
-        required: true
-      tags:
-      - algorithms
-      requestBody:
-        content:
-          application/json:
-            schema:
-              $ref: '#/components/schemas/Algorithm'
-          application/x-www-form-urlencoded:
-            schema:
-              $ref: '#/components/schemas/Algorithm'
-          multipart/form-data:
-            schema:
-              $ref: '#/components/schemas/Algorithm'
-        required: true
-      security:
-      - {}
-      responses:
-        '200':
-          content:
-            application/json:
-              schema:
-                $ref: '#/components/schemas/Algorithm'
-          description: ''
-    delete:
-      operationId: algorithms_destroy
-      description: ''
-      parameters:
-      - in: path
-        name: id
-        schema:
-          type: integer
-        description: A unique integer value identifying this algorithm.
-        required: true
-      tags:
-      - algorithms
-      security:
-      - {}
-      responses:
-        '204':
-          description: No response body
-  /api/v1/algorithms/predict:
-    post:
-      operationId: algorithms_predict
-      description: Predict credit risk for a loan
-      parameters:
-      - in: query
-        name: classifier
-        schema:
-          type: string
-        description: The algorithm/classifier to use
-        required: true
-        examples:
-          Example1:
-            value: RandomForestClassifier
-            summary: Example 1
-      - in: query
-        name: dataset
-        schema:
-          type: string
-        description: The name of the dataset
-        examples:
-          Example1:
-            value: german
-            summary: Example 1
-      - in: query
-        name: status
-        schema:
-          type: string
-        description: The status of the algorithm
-        deprecated: true
-        examples:
-          Example1:
-            value: production
-            summary: Example 1
-      - in: query
-        name: version
-        schema:
-          type: string
-          default: 0.0.1
-        description: Algorithm version
-        required: true
-        examples:
-          Example1:
-            value: 0.0.1
-            summary: Example 1
-      tags:
-      - algorithms
-      requestBody:
-        content:
-          application/json:
-            schema:
-              type: object
-              additionalProperties: {}
-              description: Unspecified request body
-          application/x-www-form-urlencoded:
-            schema:
-              type: object
-              additionalProperties: {}
-              description: Unspecified request body
-          multipart/form-data:
-            schema:
-              type: object
-              additionalProperties: {}
-              description: Unspecified request body
-      security:
-      - {}
-      responses:
-        '200':
-          content:
-            application/json:
-              schema:
-                $ref: '#/components/schemas/PredictionResponse'
-          description: ''
-  /api/v1/datasets:
-    get:
-      operationId: datasets_list
-      description: ''
-      tags:
-      - datasets
-      security:
-      - {}
-      responses:
-        '200':
-          content:
-            application/json:
-              schema:
-                type: array
-                items:
-                  $ref: '#/components/schemas/Dataset'
-          description: ''
-  /api/v1/datasets/{id}:
-    get:
-      operationId: datasets_retrieve
-      description: ''
-      parameters:
-      - in: path
-        name: id
-        schema:
-          type: integer
-        description: A unique integer value identifying this dataset.
-        required: true
-      tags:
-      - datasets
-      security:
-      - {}
-      responses:
-        '200':
-          content:
-            application/json:
-              schema:
-                $ref: '#/components/schemas/Dataset'
-          description: ''
-  /api/v1/requests:
-    get:
-      operationId: requests_list
-      description: ''
-      tags:
-      - requests
-      security:
-      - {}
-      responses:
-        '200':
-          content:
-            application/json:
-              schema:
-                type: array
-                items:
-                  $ref: '#/components/schemas/PredictionRequest'
-          description: ''
-    post:
-      operationId: requests_create
-      description: ''
-      tags:
-      - requests
-      requestBody:
-        content:
-          application/json:
-            schema:
-              $ref: '#/components/schemas/PredictionRequest'
-          application/x-www-form-urlencoded:
-            schema:
-              $ref: '#/components/schemas/PredictionRequest'
-          multipart/form-data:
-            schema:
-              $ref: '#/components/schemas/PredictionRequest'
-        required: true
-      security:
-      - {}
-      responses:
-        '201':
-          content:
-            application/json:
-              schema:
-                $ref: '#/components/schemas/PredictionRequest'
-          description: ''
-  /api/v1/requests/{id}:
-    get:
-      operationId: requests_retrieve
-      description: ''
-      parameters:
-      - in: path
-        name: id
-        schema:
-          type: integer
-        description: A unique integer value identifying this prediction 
request.
-        required: true
-      tags:
-      - requests
-      security:
-      - {}
-      responses:
-        '200':
-          content:
-            application/json:
-              schema:
-                $ref: '#/components/schemas/PredictionRequest'
-          description: ''
-    put:
-      operationId: requests_update
-      description: ''
-      parameters:
-      - in: path
-        name: id
-        schema:
-          type: integer
-        description: A unique integer value identifying this prediction 
request.
-        required: true
-      tags:
-      - requests
-      requestBody:
-        content:
-          application/json:
-            schema:
-              $ref: '#/components/schemas/PredictionRequest'
-          application/x-www-form-urlencoded:
-            schema:
-              $ref: '#/components/schemas/PredictionRequest'
-          multipart/form-data:
-            schema:
-              $ref: '#/components/schemas/PredictionRequest'
-        required: true
-      security:
-      - {}
-      responses:
-        '200':
-          content:
-            application/json:
-              schema:
-                $ref: '#/components/schemas/PredictionRequest'
-          description: ''
-    patch:
-      operationId: requests_partial_update
-      description: ''
-      parameters:
-      - in: path
-        name: id
-        schema:
-          type: integer
-        description: A unique integer value identifying this prediction 
request.
-        required: true
-      tags:
-      - requests
-      requestBody:
-        content:
-          application/json:
-            schema:
-              $ref: '#/components/schemas/PredictionRequest'
-          application/x-www-form-urlencoded:
-            schema:
-              $ref: '#/components/schemas/PredictionRequest'
-          multipart/form-data:
-            schema:
-              $ref: '#/components/schemas/PredictionRequest'
-        required: true
-      security:
-      - {}
-      responses:
-        '200':
-          content:
-            application/json:
-              schema:
-                $ref: '#/components/schemas/PredictionRequest'
-          description: ''
-    delete:
-      operationId: requests_destroy
-      description: ''
-      parameters:
-      - in: path
-        name: id
-        schema:
-          type: integer
-        description: A unique integer value identifying this prediction 
request.
-        required: true
-      tags:
-      - requests
-      security:
-      - {}
-      responses:
-        '204':
-          description: No response body
-components:
-  schemas:
-    Algorithm:
-      type: object
-      properties:
-        id:
-          type: integer
-          readOnly: true
-        classifier:
-          type: string
-          maxLength: 128
-        description:
-          type: string
-          nullable: true
-        version:
-          type: string
-          maxLength: 128
-        status:
-          type: string
-          maxLength: 128
-        created_at:
-          type: string
-          format: date-time
-          readOnly: true
-        created_by:
-          type: string
-          maxLength: 128
-        dataset:
-          type: string
-          nullable: true
-      required:
-      - classifier
-      - created_at
-      - created_by
-      - id
-      - status
-      - version
-    Dataset:
-      type: object
-      properties:
-        id:
-          type: integer
-          readOnly: true
-        name:
-          type: string
-          maxLength: 128
-        region:
-          type: string
-          maxLength: 128
-      required:
-      - id
-      - name
-      - region
-    PredictionRequest:
-      type: object
-      properties:
-        id:
-          type: integer
-          readOnly: true
-        input:
-          type: object
-          additionalProperties: {}
-        response:
-          type: object
-          additionalProperties: {}
-        prediction:
-          type: string
-          maxLength: 128
-        feedback:
-          type: string
-          nullable: true
-          maxLength: 128
-        notes:
-          type: string
-          nullable: true
-        created_at:
-          type: string
-          format: date-time
-          readOnly: true
-        created_by:
-          type: string
-          maxLength: 128
-        algorithm:
-          type: integer
-      required:
-      - created_at
-      - created_by
-      - id
-      - input
-      - prediction
-      - response
-    PredictionResponse:
-      type: object
-      properties:
-        probability:
-          type: number
-          format: float
-        label:
-          type: string
-        method:
-          type: string
-        color:
-          type: string
-        wilkis_lambda:
-          type: number
-          format: float
-        pillais_trace:
-          type: number
-          format: float
-        hotelling_tawley:
-          type: number
-          format: float
-        roys_reatest_roots:
-          type: number
-          format: float
-        request_id:
-          type: integer
-      required:
-      - color
-      - hotelling_tawley
-      - label
-      - method
-      - pillais_trace
-      - probability
-      - request_id
-      - roys_reatest_roots
-      - wilkis_lambda
-servers:
-- url: http://127.0.0.1:8000
-  description: server on localhost
+openapi: 3.0.3
+info:
+  title: Fineract Credit Scorecard
+  version: 0.1.0-SNAPSHOT
+  description: An API module for credit risk assessment
+  license:
+    name: Apache-2.0
+    url: https://www.apache.org/licenses/LICENSE-2.0.html
+paths:
+  /api/v1/algorithms:
+    get:
+      operationId: algorithms_list
+      description: ''
+      tags:
+        - algorithms
+      security:
+        - {}
+      responses:
+        '200':
+          content:
+            application/json:
+              schema:
+                type: array
+                items:
+                  $ref: '#/components/schemas/Algorithm'
+          description: ''
+    post:
+      operationId: algorithms_create
+      description: ''
+      tags:
+        - algorithms
+      requestBody:
+        content:
+          application/json:
+            schema:
+              $ref: '#/components/schemas/Algorithm'
+          application/x-www-form-urlencoded:
+            schema:
+              $ref: '#/components/schemas/Algorithm'
+          multipart/form-data:
+            schema:
+              $ref: '#/components/schemas/Algorithm'
+        required: true
+      security:
+        - {}
+      responses:
+        '201':
+          content:
+            application/json:
+              schema:
+                $ref: '#/components/schemas/Algorithm'
+          description: ''
+  /api/v1/algorithms/{id}:
+    get:
+      operationId: algorithms_retrieve
+      description: ''
+      parameters:
+        - in: path
+          name: id
+          schema:
+            type: integer
+          description: A unique integer value identifying this algorithm.
+          required: true
+      tags:
+        - algorithms
+      security:
+        - {}
+      responses:
+        '200':
+          content:
+            application/json:
+              schema:
+                $ref: '#/components/schemas/Algorithm'
+          description: ''
+    put:
+      operationId: algorithms_update
+      description: ''
+      parameters:
+        - in: path
+          name: id
+          schema:
+            type: integer
+          description: A unique integer value identifying this algorithm.
+          required: true
+      tags:
+        - algorithms
+      requestBody:
+        content:
+          application/json:
+            schema:
+              $ref: '#/components/schemas/Algorithm'
+          application/x-www-form-urlencoded:
+            schema:
+              $ref: '#/components/schemas/Algorithm'
+          multipart/form-data:
+            schema:
+              $ref: '#/components/schemas/Algorithm'
+        required: true
+      security:
+        - {}
+      responses:
+        '200':
+          content:
+            application/json:
+              schema:
+                $ref: '#/components/schemas/Algorithm'
+          description: ''
+    patch:
+      operationId: algorithms_partial_update
+      description: ''
+      parameters:
+        - in: path
+          name: id
+          schema:
+            type: integer
+          description: A unique integer value identifying this algorithm.
+          required: true
+      tags:
+        - algorithms
+      requestBody:
+        content:
+          application/json:
+            schema:
+              $ref: '#/components/schemas/Algorithm'
+          application/x-www-form-urlencoded:
+            schema:
+              $ref: '#/components/schemas/Algorithm'
+          multipart/form-data:
+            schema:
+              $ref: '#/components/schemas/Algorithm'
+        required: true
+      security:
+        - {}
+      responses:
+        '200':
+          content:
+            application/json:
+              schema:
+                $ref: '#/components/schemas/Algorithm'
+          description: ''
+    delete:
+      operationId: algorithms_destroy
+      description: ''
+      parameters:
+        - in: path
+          name: id
+          schema:
+            type: integer
+          description: A unique integer value identifying this algorithm.
+          required: true
+      tags:
+        - algorithms
+      security:
+        - {}
+      responses:
+        '204':
+          description: No response body
+  /api/v1/algorithms/predict:
+    post:
+      operationId: algorithms_predict
+      description: Predict credit risk for a loan
+      parameters:
+        - in: query
+          name: classifier
+          schema:
+            type: string
+          description: The algorithm/classifier to use
+          required: true
+          examples:
+            Example1:
+              value: RandomForestClassifier
+              summary: Example 1
+        - in: query
+          name: dataset
+          schema:
+            type: string
+          description: The name of the dataset
+          examples:
+            Example1:
+              value: german
+              summary: Example 1
+        - in: query
+          name: status
+          schema:
+            type: string
+          description: The status of the algorithm
+          deprecated: true
+          examples:
+            Example1:
+              value: production
+              summary: Example 1
+        - in: query
+          name: version
+          schema:
+            type: string
+            default: 0.0.1
+          description: Algorithm version
+          required: true
+          examples:
+            Example1:
+              value: 0.0.1
+              summary: Example 1
+      tags:
+        - algorithms
+      requestBody:
+        content:
+          application/json:
+            schema:
+              type: object
+              additionalProperties: {}
+              description: Unspecified request body
+          application/x-www-form-urlencoded:
+            schema:
+              type: object
+              additionalProperties: {}
+              description: Unspecified request body
+          multipart/form-data:
+            schema:
+              type: object
+              additionalProperties: {}
+              description: Unspecified request body
+      security:
+        - {}
+      responses:
+        '200':
+          content:
+            application/json:
+              schema:
+                $ref: '#/components/schemas/PredictionResponse'
+          description: ''
+  /api/v1/datasets:
+    get:
+      operationId: datasets_list
+      description: ''
+      tags:
+        - datasets
+      security:
+        - {}
+      responses:
+        '200':
+          content:
+            application/json:
+              schema:
+                type: array
+                items:
+                  $ref: '#/components/schemas/Dataset'
+          description: ''
+  /api/v1/datasets/{id}:
+    get:
+      operationId: datasets_retrieve
+      description: ''
+      parameters:
+        - in: path
+          name: id
+          schema:
+            type: integer
+          description: A unique integer value identifying this dataset.
+          required: true
+      tags:
+        - datasets
+      security:
+        - {}
+      responses:
+        '200':
+          content:
+            application/json:
+              schema:
+                $ref: '#/components/schemas/Dataset'
+          description: ''
+  /api/v1/requests:
+    get:
+      operationId: requests_list
+      description: ''
+      tags:
+        - requests
+      security:
+        - {}
+      responses:
+        '200':
+          content:
+            application/json:
+              schema:
+                type: array
+                items:
+                  $ref: '#/components/schemas/PredictionRequest'
+          description: ''
+    post:
+      operationId: requests_create
+      description: ''
+      tags:
+        - requests
+      requestBody:
+        content:
+          application/json:
+            schema:
+              $ref: '#/components/schemas/PredictionRequest'
+          application/x-www-form-urlencoded:
+            schema:
+              $ref: '#/components/schemas/PredictionRequest'
+          multipart/form-data:
+            schema:
+              $ref: '#/components/schemas/PredictionRequest'
+        required: true
+      security:
+        - {}
+      responses:
+        '201':
+          content:
+            application/json:
+              schema:
+                $ref: '#/components/schemas/PredictionRequest'
+          description: ''
+  /api/v1/requests/{id}:
+    get:
+      operationId: requests_retrieve
+      description: ''
+      parameters:
+        - in: path
+          name: id
+          schema:
+            type: integer
+          description: A unique integer value identifying this prediction 
request.
+          required: true
+      tags:
+        - requests
+      security:
+        - {}
+      responses:
+        '200':
+          content:
+            application/json:
+              schema:
+                $ref: '#/components/schemas/PredictionRequest'
+          description: ''
+    put:
+      operationId: requests_update
+      description: ''
+      parameters:
+        - in: path
+          name: id
+          schema:
+            type: integer
+          description: A unique integer value identifying this prediction 
request.
+          required: true
+      tags:
+        - requests
+      requestBody:
+        content:
+          application/json:
+            schema:
+              $ref: '#/components/schemas/PredictionRequest'
+          application/x-www-form-urlencoded:
+            schema:
+              $ref: '#/components/schemas/PredictionRequest'
+          multipart/form-data:
+            schema:
+              $ref: '#/components/schemas/PredictionRequest'
+        required: true
+      security:
+        - {}
+      responses:
+        '200':
+          content:
+            application/json:
+              schema:
+                $ref: '#/components/schemas/PredictionRequest'
+          description: ''
+    patch:
+      operationId: requests_partial_update
+      description: ''
+      parameters:
+        - in: path
+          name: id
+          schema:
+            type: integer
+          description: A unique integer value identifying this prediction 
request.
+          required: true
+      tags:
+        - requests
+      requestBody:
+        content:
+          application/json:
+            schema:
+              $ref: '#/components/schemas/PredictionRequest'
+          application/x-www-form-urlencoded:
+            schema:
+              $ref: '#/components/schemas/PredictionRequest'
+          multipart/form-data:
+            schema:
+              $ref: '#/components/schemas/PredictionRequest'
+        required: true
+      security:
+        - {}
+      responses:
+        '200':
+          content:
+            application/json:
+              schema:
+                $ref: '#/components/schemas/PredictionRequest'
+          description: ''
+    delete:
+      operationId: requests_destroy
+      description: ''
+      parameters:
+        - in: path
+          name: id
+          schema:
+            type: integer
+          description: A unique integer value identifying this prediction 
request.
+          required: true
+      tags:
+        - requests
+      security:
+        - {}
+      responses:
+        '204':
+          description: No response body
+components:
+  schemas:
+    Algorithm:
+      type: object
+      properties:
+        id:
+          type: integer
+          readOnly: true
+        classifier:
+          type: string
+          maxLength: 128
+        description:
+          type: string
+          nullable: true
+        version:
+          type: string
+          maxLength: 128
+        status:
+          type: string
+          maxLength: 128
+        created_at:
+          type: string
+          format: date-time
+          readOnly: true
+        created_by:
+          type: string
+          maxLength: 128
+        dataset:
+          type: string
+          nullable: true
+      required:
+        - classifier
+        - created_at
+        - created_by
+        - id
+        - status
+        - version
+    Dataset:
+      type: object
+      properties:
+        id:
+          type: integer
+          readOnly: true
+        name:
+          type: string
+          maxLength: 128
+        region:
+          type: string
+          maxLength: 128
+      required:
+        - id
+        - name
+        - region
+    PredictionRequest:
+      type: object
+      properties:
+        id:
+          type: integer
+          readOnly: true
+        input:
+          type: object
+          additionalProperties: {}
+        response:
+          type: object
+          additionalProperties: {}
+        prediction:
+          type: string
+          maxLength: 128
+        feedback:
+          type: string
+          nullable: true
+          maxLength: 128
+        notes:
+          type: string
+          nullable: true
+        created_at:
+          type: string
+          format: date-time
+          readOnly: true
+        created_by:
+          type: string
+          maxLength: 128
+        algorithm:
+          type: integer
+      required:
+        - created_at
+        - created_by
+        - id
+        - input
+        - prediction
+        - response
+    PredictionResponse:
+      type: object
+      properties:
+        probability:
+          type: number
+          format: float
+        label:
+          type: string
+        method:
+          type: string
+        color:
+          type: string
+        wilkis_lambda:
+          type: number
+          format: float
+        pillais_trace:
+          type: number
+          format: float
+        hotelling_tawley:
+          type: number
+          format: float
+        roys_reatest_roots:
+          type: number
+          format: float
+        request_id:
+          type: integer
+      required:
+        - color
+        - hotelling_tawley
+        - label
+        - method
+        - pillais_trace
+        - probability
+        - request_id
+        - roys_reatest_roots
+        - wilkis_lambda
+servers:
+  - url: http://127.0.0.1:8000
+    description: server on localhost
diff --git a/clients/java/README.md b/scorecard-client/README.md
similarity index 100%
rename from clients/java/README.md
rename to scorecard-client/README.md
diff --git a/scorecard-client/build.gradle b/scorecard-client/build.gradle
new file mode 100644
index 0000000..b49b6fa
--- /dev/null
+++ b/scorecard-client/build.gradle
@@ -0,0 +1,55 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+plugins {
+    id 'java-library'
+}
+
+group = 'org.apache.fineract'
+version = '0.1.0-SNAPSHOT'
+
+repositories {
+    mavenCentral()
+}
+
+sourceSets {
+    main.java.srcDirs = ['src/main/java']
+}
+
+task execute(type:JavaExec) {
+    classpath = sourceSets.main.runtimeClasspath
+}
+
+dependencies {
+    implementation 'io.swagger:swagger-annotations:1.5.24'
+    implementation "com.google.code.findbugs:jsr305:3.0.2"
+
+    api 'com.squareup.okhttp3:okhttp:3.14.7'
+    api 'com.squareup.okhttp3:logging-interceptor:3.14.7'
+    api 'com.google.code.gson:gson:2.8.6'
+    api 'io.gsonfire:gson-fire:1.8.4'
+
+    implementation group: 'org.apache.commons', name: 'commons-lang3', 
version: '3.10'
+    implementation 'javax.annotation:javax.annotation-api:1.3.2'
+    testImplementation 'junit:junit:4.13.1'
+}
+
+javadoc {
+    options.tags = [ "http.response.details:a:Http Response Details" ]
+}
diff --git a/clients/java/docs/Algorithm.md b/scorecard-client/docs/Algorithm.md
similarity index 100%
rename from clients/java/docs/Algorithm.md
rename to scorecard-client/docs/Algorithm.md
diff --git a/clients/java/docs/AlgorithmsApi.md 
b/scorecard-client/docs/AlgorithmsApi.md
similarity index 100%
rename from clients/java/docs/AlgorithmsApi.md
rename to scorecard-client/docs/AlgorithmsApi.md
diff --git a/clients/java/docs/Dataset.md b/scorecard-client/docs/Dataset.md
similarity index 100%
rename from clients/java/docs/Dataset.md
rename to scorecard-client/docs/Dataset.md
diff --git a/clients/java/docs/DatasetsApi.md 
b/scorecard-client/docs/DatasetsApi.md
similarity index 100%
rename from clients/java/docs/DatasetsApi.md
rename to scorecard-client/docs/DatasetsApi.md
diff --git a/clients/java/docs/PredictionRequest.md 
b/scorecard-client/docs/PredictionRequest.md
similarity index 100%
rename from clients/java/docs/PredictionRequest.md
rename to scorecard-client/docs/PredictionRequest.md
diff --git a/clients/java/docs/PredictionResponse.md 
b/scorecard-client/docs/PredictionResponse.md
similarity index 100%
rename from clients/java/docs/PredictionResponse.md
rename to scorecard-client/docs/PredictionResponse.md
diff --git a/clients/java/docs/RequestsApi.md 
b/scorecard-client/docs/RequestsApi.md
similarity index 100%
rename from clients/java/docs/RequestsApi.md
rename to scorecard-client/docs/RequestsApi.md
diff --git a/clients/java/src/main/AndroidManifest.xml 
b/scorecard-client/src/main/AndroidManifest.xml
similarity index 100%
rename from clients/java/src/main/AndroidManifest.xml
rename to scorecard-client/src/main/AndroidManifest.xml
diff --git 
a/clients/java/src/main/java/org/apache/fineract/credit/scorecard/ApiCallback.java
 
b/scorecard-client/src/main/java/org/apache/fineract/credit/scorecard/ApiCallback.java
similarity index 100%
rename from 
clients/java/src/main/java/org/apache/fineract/credit/scorecard/ApiCallback.java
rename to 
scorecard-client/src/main/java/org/apache/fineract/credit/scorecard/ApiCallback.java
diff --git 
a/clients/java/src/main/java/org/apache/fineract/credit/scorecard/ApiClient.java
 
b/scorecard-client/src/main/java/org/apache/fineract/credit/scorecard/ApiClient.java
similarity index 100%
rename from 
clients/java/src/main/java/org/apache/fineract/credit/scorecard/ApiClient.java
rename to 
scorecard-client/src/main/java/org/apache/fineract/credit/scorecard/ApiClient.java
diff --git 
a/clients/java/src/main/java/org/apache/fineract/credit/scorecard/ApiException.java
 
b/scorecard-client/src/main/java/org/apache/fineract/credit/scorecard/ApiException.java
similarity index 100%
rename from 
clients/java/src/main/java/org/apache/fineract/credit/scorecard/ApiException.java
rename to 
scorecard-client/src/main/java/org/apache/fineract/credit/scorecard/ApiException.java
diff --git 
a/clients/java/src/main/java/org/apache/fineract/credit/scorecard/ApiResponse.java
 
b/scorecard-client/src/main/java/org/apache/fineract/credit/scorecard/ApiResponse.java
similarity index 100%
rename from 
clients/java/src/main/java/org/apache/fineract/credit/scorecard/ApiResponse.java
rename to 
scorecard-client/src/main/java/org/apache/fineract/credit/scorecard/ApiResponse.java
diff --git 
a/clients/java/src/main/java/org/apache/fineract/credit/scorecard/Configuration.java
 
b/scorecard-client/src/main/java/org/apache/fineract/credit/scorecard/Configuration.java
similarity index 100%
rename from 
clients/java/src/main/java/org/apache/fineract/credit/scorecard/Configuration.java
rename to 
scorecard-client/src/main/java/org/apache/fineract/credit/scorecard/Configuration.java
diff --git 
a/clients/java/src/main/java/org/apache/fineract/credit/scorecard/GzipRequestInterceptor.java
 
b/scorecard-client/src/main/java/org/apache/fineract/credit/scorecard/GzipRequestInterceptor.java
similarity index 100%
rename from 
clients/java/src/main/java/org/apache/fineract/credit/scorecard/GzipRequestInterceptor.java
rename to 
scorecard-client/src/main/java/org/apache/fineract/credit/scorecard/GzipRequestInterceptor.java
diff --git 
a/clients/java/src/main/java/org/apache/fineract/credit/scorecard/JSON.java 
b/scorecard-client/src/main/java/org/apache/fineract/credit/scorecard/JSON.java
similarity index 100%
rename from 
clients/java/src/main/java/org/apache/fineract/credit/scorecard/JSON.java
rename to 
scorecard-client/src/main/java/org/apache/fineract/credit/scorecard/JSON.java
diff --git 
a/clients/java/src/main/java/org/apache/fineract/credit/scorecard/Pair.java 
b/scorecard-client/src/main/java/org/apache/fineract/credit/scorecard/Pair.java
similarity index 100%
rename from 
clients/java/src/main/java/org/apache/fineract/credit/scorecard/Pair.java
rename to 
scorecard-client/src/main/java/org/apache/fineract/credit/scorecard/Pair.java
diff --git 
a/clients/java/src/main/java/org/apache/fineract/credit/scorecard/ProgressRequestBody.java
 
b/scorecard-client/src/main/java/org/apache/fineract/credit/scorecard/ProgressRequestBody.java
similarity index 100%
rename from 
clients/java/src/main/java/org/apache/fineract/credit/scorecard/ProgressRequestBody.java
rename to 
scorecard-client/src/main/java/org/apache/fineract/credit/scorecard/ProgressRequestBody.java
diff --git 
a/clients/java/src/main/java/org/apache/fineract/credit/scorecard/ProgressResponseBody.java
 
b/scorecard-client/src/main/java/org/apache/fineract/credit/scorecard/ProgressResponseBody.java
similarity index 100%
rename from 
clients/java/src/main/java/org/apache/fineract/credit/scorecard/ProgressResponseBody.java
rename to 
scorecard-client/src/main/java/org/apache/fineract/credit/scorecard/ProgressResponseBody.java
diff --git 
a/clients/java/src/main/java/org/apache/fineract/credit/scorecard/ServerConfiguration.java
 
b/scorecard-client/src/main/java/org/apache/fineract/credit/scorecard/ServerConfiguration.java
similarity index 100%
rename from 
clients/java/src/main/java/org/apache/fineract/credit/scorecard/ServerConfiguration.java
rename to 
scorecard-client/src/main/java/org/apache/fineract/credit/scorecard/ServerConfiguration.java
diff --git 
a/clients/java/src/main/java/org/apache/fineract/credit/scorecard/ServerVariable.java
 
b/scorecard-client/src/main/java/org/apache/fineract/credit/scorecard/ServerVariable.java
similarity index 100%
rename from 
clients/java/src/main/java/org/apache/fineract/credit/scorecard/ServerVariable.java
rename to 
scorecard-client/src/main/java/org/apache/fineract/credit/scorecard/ServerVariable.java
diff --git 
a/clients/java/src/main/java/org/apache/fineract/credit/scorecard/StringUtil.java
 
b/scorecard-client/src/main/java/org/apache/fineract/credit/scorecard/StringUtil.java
similarity index 100%
rename from 
clients/java/src/main/java/org/apache/fineract/credit/scorecard/StringUtil.java
rename to 
scorecard-client/src/main/java/org/apache/fineract/credit/scorecard/StringUtil.java
diff --git 
a/clients/java/src/main/java/org/apache/fineract/credit/scorecard/auth/ApiKeyAuth.java
 
b/scorecard-client/src/main/java/org/apache/fineract/credit/scorecard/auth/ApiKeyAuth.java
similarity index 100%
rename from 
clients/java/src/main/java/org/apache/fineract/credit/scorecard/auth/ApiKeyAuth.java
rename to 
scorecard-client/src/main/java/org/apache/fineract/credit/scorecard/auth/ApiKeyAuth.java
diff --git 
a/clients/java/src/main/java/org/apache/fineract/credit/scorecard/auth/Authentication.java
 
b/scorecard-client/src/main/java/org/apache/fineract/credit/scorecard/auth/Authentication.java
similarity index 100%
rename from 
clients/java/src/main/java/org/apache/fineract/credit/scorecard/auth/Authentication.java
rename to 
scorecard-client/src/main/java/org/apache/fineract/credit/scorecard/auth/Authentication.java
diff --git 
a/clients/java/src/main/java/org/apache/fineract/credit/scorecard/auth/HttpBasicAuth.java
 
b/scorecard-client/src/main/java/org/apache/fineract/credit/scorecard/auth/HttpBasicAuth.java
similarity index 100%
rename from 
clients/java/src/main/java/org/apache/fineract/credit/scorecard/auth/HttpBasicAuth.java
rename to 
scorecard-client/src/main/java/org/apache/fineract/credit/scorecard/auth/HttpBasicAuth.java
diff --git 
a/clients/java/src/main/java/org/apache/fineract/credit/scorecard/auth/HttpBearerAuth.java
 
b/scorecard-client/src/main/java/org/apache/fineract/credit/scorecard/auth/HttpBearerAuth.java
similarity index 100%
rename from 
clients/java/src/main/java/org/apache/fineract/credit/scorecard/auth/HttpBearerAuth.java
rename to 
scorecard-client/src/main/java/org/apache/fineract/credit/scorecard/auth/HttpBearerAuth.java
diff --git 
a/clients/java/src/main/java/org/apache/fineract/credit/scorecard/models/Algorithm.java
 
b/scorecard-client/src/main/java/org/apache/fineract/credit/scorecard/models/Algorithm.java
similarity index 100%
rename from 
clients/java/src/main/java/org/apache/fineract/credit/scorecard/models/Algorithm.java
rename to 
scorecard-client/src/main/java/org/apache/fineract/credit/scorecard/models/Algorithm.java
diff --git 
a/clients/java/src/main/java/org/apache/fineract/credit/scorecard/models/Dataset.java
 
b/scorecard-client/src/main/java/org/apache/fineract/credit/scorecard/models/Dataset.java
similarity index 100%
rename from 
clients/java/src/main/java/org/apache/fineract/credit/scorecard/models/Dataset.java
rename to 
scorecard-client/src/main/java/org/apache/fineract/credit/scorecard/models/Dataset.java
diff --git 
a/clients/java/src/main/java/org/apache/fineract/credit/scorecard/models/PredictionRequest.java
 
b/scorecard-client/src/main/java/org/apache/fineract/credit/scorecard/models/PredictionRequest.java
similarity index 100%
rename from 
clients/java/src/main/java/org/apache/fineract/credit/scorecard/models/PredictionRequest.java
rename to 
scorecard-client/src/main/java/org/apache/fineract/credit/scorecard/models/PredictionRequest.java
diff --git 
a/clients/java/src/main/java/org/apache/fineract/credit/scorecard/models/PredictionResponse.java
 
b/scorecard-client/src/main/java/org/apache/fineract/credit/scorecard/models/PredictionResponse.java
similarity index 100%
rename from 
clients/java/src/main/java/org/apache/fineract/credit/scorecard/models/PredictionResponse.java
rename to 
scorecard-client/src/main/java/org/apache/fineract/credit/scorecard/models/PredictionResponse.java
diff --git 
a/clients/java/src/main/java/org/apache/fineract/credit/scorecard/services/AlgorithmsApi.java
 
b/scorecard-client/src/main/java/org/apache/fineract/credit/scorecard/services/AlgorithmsApi.java
similarity index 100%
rename from 
clients/java/src/main/java/org/apache/fineract/credit/scorecard/services/AlgorithmsApi.java
rename to 
scorecard-client/src/main/java/org/apache/fineract/credit/scorecard/services/AlgorithmsApi.java
diff --git 
a/clients/java/src/main/java/org/apache/fineract/credit/scorecard/services/DatasetsApi.java
 
b/scorecard-client/src/main/java/org/apache/fineract/credit/scorecard/services/DatasetsApi.java
similarity index 100%
rename from 
clients/java/src/main/java/org/apache/fineract/credit/scorecard/services/DatasetsApi.java
rename to 
scorecard-client/src/main/java/org/apache/fineract/credit/scorecard/services/DatasetsApi.java
diff --git 
a/clients/java/src/main/java/org/apache/fineract/credit/scorecard/services/RequestsApi.java
 
b/scorecard-client/src/main/java/org/apache/fineract/credit/scorecard/services/RequestsApi.java
similarity index 100%
rename from 
clients/java/src/main/java/org/apache/fineract/credit/scorecard/services/RequestsApi.java
rename to 
scorecard-client/src/main/java/org/apache/fineract/credit/scorecard/services/RequestsApi.java
diff --git a/scorecard-plugin/README.md b/scorecard-plugin/README.md
new file mode 100644
index 0000000..7c79239
--- /dev/null
+++ b/scorecard-plugin/README.md
@@ -0,0 +1,39 @@
+# Credit Scorecard Plugin for Apache Fineract
+
+This is a [_Plugin_ for Apache 
Fineract](https://github.com/apache/fineract/blob/develop/fineract-doc/src/docs/en/deployment.adoc).
 
+(This work is inspired by the design approach of the [fineract-pentaho 
plugin](https://github.com/openMF/fineract-pentaho).)
+
+see [TODO](TODO.md) for possible future follow-up enhancement work. The TODO 
list was inherited from [fineract-pentaho 
plugin]((https://github.com/openMF/fineract-pentaho))
+
+
+## Build & Use
+
+This project is currently only tested against the very latest and greatest
+bleeding edge Fineract `develop` branch.  Building and using it against
+older versions may be possible, but is not tested or documented here.
+
+    git clone https://github.com/apache/fineract.git
+    cd fineract && ./gradlew bootJar && cd ..
+
+    git clone https://github.com/apache/fineract-credit-scorecard.git
+    cd fineract-credit-scorecard && ./gradlew -x test distZip && cd ..
+
+    ./fineract-credit-scorecard/scorecard-plugin/run
+
+The [`run`](run) script basically just creates the following directory 
structure:
+
+    fineract-provider.jar
+    lib/scorecard-plugin.jar
+    lib/lib*.jar
+
+and then launches Apache Fineract with the Pentaho Plugin and all its JARs 
like this:
+
+    java -Dloader.path=lib/ -jar fineract-provider.jar
+
+## Contribute
+
+If this Fineract plugin project is useful to you, please contribute back to it 
(and
+Fineract) by raising Pull Requests yourself with any enhancements you make, 
and by helping
+to maintain this project by helping other users on Issues and reviewing PR 
from others
+(you will be promoted to committer on this project when you contribute).  We 
recommend
+that you _Watch_ and _Star_ this project on GitHub to make it easy to get 
notified.
diff --git a/scorecard-plugin/TODO.md b/scorecard-plugin/TODO.md
new file mode 100644
index 0000000..deb28c0
--- /dev/null
+++ b/scorecard-plugin/TODO.md
@@ -0,0 +1,17 @@
+# TODO
+
+1. move Java package name (back, again); see 
[FINERACT-1174](https://issues.apache.org/jira/browse/FINERACT-1174)
+
+1. how to avoid `files("../")` ?  We would have to have an `api` artifact, and 
publish it..
+   watch [FINERACT-1171](https://issues.apache.org/jira/browse/FINERACT-1171)
+
+1. inherit dependency management from Fineract, so that e.g.
+   JAX RS & commons lang versions don't have to be repeated.
+   Actually, perhaps JAX RS & commons lang should be considered
+   part of a (future..) Fineract Plugin API, and not need to be declared at 
all!
+
+1. run `ClasspathDuplicateTest`, on all such plugins
+
+1. run usual Fineract code style checks against plugin code like this
+
+1. build standalone "service", not just "plugin"
diff --git a/scorecard-plugin/build.gradle b/scorecard-plugin/build.gradle
new file mode 100644
index 0000000..8e3d14f
--- /dev/null
+++ b/scorecard-plugin/build.gradle
@@ -0,0 +1,80 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+plugins {
+       id 'java-library'
+       id 'java-library-distribution'
+    id 'io.spring.dependency-management' version '1.0.10.RELEASE'
+}
+
+repositories {
+    flatDir {
+        dirs "$rootDir/scorecard-client/build/libs"
+    }
+    mavenCentral()
+}
+
+dependencies {
+    compileOnly(
+        // Fineract!
+        files("../../fineract/fineract-provider/build/classes/java/main/"),
+
+        // Fineract dependencies (TODO version should *NOT* be specified 
here...)
+        'org.slf4j:slf4j-api:1.7.30',
+        'javax.ws.rs:jsr311-api:1.1.1',
+        'org.apache.openjpa:openjpa:3.1.2',
+        'org.apache.commons:commons-lang3:3.10',
+        'org.springframework:spring-context:5.2.6.RELEASE',
+        'org.springframework.data:spring-data-commons:2.3.4.RELEASE',
+        'org.springframework.security:spring-security-core:5.3.4.RELEASE',
+        'org.springframework.boot:spring-boot-starter-data-jpa:2.3.5.RELEASE'
+    )
+
+    implementation(
+        // Fineract Credit Scorecard Dependencies
+        project(":scorecard-client"),
+        'com.google.code.gson:gson:2.8.7'
+    )
+
+    testImplementation 'org.junit.jupiter:junit-jupiter-api:5.7.0'
+    testRuntimeOnly 'org.junit.jupiter:junit-jupiter-engine:5.7.0'
+}
+
+tasks.named('test') {
+    // Use JUnit Platform for unit tests.
+    useJUnitPlatform()
+}
+
+distributions {
+    main {
+        contents {
+               into('/') {
+               from "README.md", "../LICENSE", "run", "run.bat"
+            }
+            
+            into('/lib') {
+                from(jar)
+            }
+
+            eachFile { FileCopyDetails fcp ->
+              fcp.relativePath = new RelativePath(true, 
fcp.relativePath.pathString.replace('scorecard-plugin/', ''))
+            }
+        }
+    }
+}
diff --git a/scorecard-plugin/run b/scorecard-plugin/run
new file mode 100644
index 0000000..5e36220
--- /dev/null
+++ b/scorecard-plugin/run
@@ -0,0 +1,13 @@
+#!/usr/bin/env bash
+set -euxo pipefail
+
+# Copy Apache Fineract JAR
+mkdir -p build/run
+cp ./fineract/fineract-provider/build/libs/fineract-provider*.jar build/run
+
+# Add our scorecard-plugin reporting plugin, like so:
+unzip ./FINCS/scorecard-plugin/build/distributions/scorecard-plugin.zip -d 
build/run/
+rm build/run/scorecard-plugin.jar
+
+# Start!
+java -Dloader.path=build/run/lib/ -jar build/run/fineract-provider.jar
diff --git a/scorecard-plugin/run.bat b/scorecard-plugin/run.bat
new file mode 100644
index 0000000..32b7c40
--- /dev/null
+++ b/scorecard-plugin/run.bat
@@ -0,0 +1,33 @@
+@REM
+@REM Licensed to the Apache Software Foundation (ASF) under one
+@REM or more contributor license agreements. See the NOTICE file
+@REM distributed with this work for additional information
+@REM regarding copyright ownership. The ASF licenses this file
+@REM to you under the Apache License, Version 2.0 (the
+@REM "License"); you may not use this file except in compliance
+@REM with the License. You may obtain a copy of the License at
+@REM
+@REM http://www.apache.org/licenses/LICENSE-2.0
+@REM
+@REM Unless required by applicable law or agreed to in writing,
+@REM software distributed under the License is distributed on an
+@REM "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+@REM KIND, either express or implied. See the License for the
+@REM specific language governing permissions and limitations
+@REM under the License.
+@REM
+
+@echo on
+
+rem Copy Apache Fineract JAR
+md build\run
+copy .\fineract\fineract-provider\build\libs\fineract-provider.jar build\run
+
+rem Add our scorecard-plugin reporting plugin, like so:
+
+powershell -command "Expand-Archive -Force 
'.\fineract-credit-scorecard\scorecard-plugin\build\distributions\scorecard-plugin.zip'
 'build\run'"
+del .\build\run\scorecard-plugin.jar
+
+rem Start!
+
+java -Dloader.path=build\run\lib\ -jar build\run\fineract-provider.jar
\ No newline at end of file
diff --git 
a/scorecard-plugin/src/main/java/org/apache/fineract/portfolio/creditscorecard/service/CreditScorecardAssemblerImpl.java
 
b/scorecard-plugin/src/main/java/org/apache/fineract/portfolio/creditscorecard/service/CreditScorecardAssemblerImpl.java
new file mode 100644
index 0000000..a1f8f04
--- /dev/null
+++ 
b/scorecard-plugin/src/main/java/org/apache/fineract/portfolio/creditscorecard/service/CreditScorecardAssemblerImpl.java
@@ -0,0 +1,255 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.fineract.portfolio.creditscorecard.service;
+
+import com.google.gson.JsonArray;
+import com.google.gson.JsonElement;
+import com.google.gson.JsonObject;
+import java.math.BigDecimal;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Locale;
+import org.apache.fineract.infrastructure.core.api.JsonCommand;
+import org.apache.fineract.infrastructure.core.serialization.FromJsonHelper;
+import 
org.apache.fineract.portfolio.creditscorecard.annotation.ScorecardService;
+import org.apache.fineract.portfolio.creditscorecard.domain.CreditScorecard;
+import 
org.apache.fineract.portfolio.creditscorecard.domain.CreditScorecardFeature;
+import org.apache.fineract.portfolio.creditscorecard.domain.FeatureCriteria;
+import 
org.apache.fineract.portfolio.creditscorecard.domain.FeatureCriteriaScore;
+import org.apache.fineract.portfolio.creditscorecard.domain.MLScorecard;
+import org.apache.fineract.portfolio.creditscorecard.domain.MLScorecardFields;
+import org.apache.fineract.portfolio.creditscorecard.domain.RuleBasedScorecard;
+import org.apache.fineract.portfolio.creditscorecard.domain.StatScorecard;
+import org.apache.fineract.portfolio.loanproduct.domain.LoanProduct;
+import 
org.apache.fineract.portfolio.loanproduct.domain.LoanProductScorecardFeature;
+import 
org.apache.fineract.portfolio.loanproduct.domain.LoanProductScorecardFeatureRepositoryWrapper;
+import org.springframework.beans.factory.annotation.Autowired;
+
+@ScorecardService(name = "CreditScorecardAssembler")
+public class CreditScorecardAssemblerImpl implements CreditScorecardAssembler {
+
+    private final FromJsonHelper fromApiJsonHelper;
+    private final CreditScorecardReadPlatformService readPlatformService;
+    private final LoanProductScorecardFeatureRepositoryWrapper 
productFeatureRepository;
+
+    @Autowired
+    public CreditScorecardAssemblerImpl(final FromJsonHelper fromApiJsonHelper,
+            final CreditScorecardReadPlatformService readPlatformService,
+            final LoanProductScorecardFeatureRepositoryWrapper 
productFeatureRepository) {
+        this.fromApiJsonHelper = fromApiJsonHelper;
+        this.readPlatformService = readPlatformService;
+        this.productFeatureRepository = productFeatureRepository;
+    }
+
+    @Override
+    public CreditScorecard assembleFrom(final JsonElement element) {
+        CreditScorecard creditScorecard = null;
+
+        if (element.isJsonObject()) {
+
+            final String scoringMethod = 
this.fromApiJsonHelper.extractStringNamed("scoringMethod", element);
+            final String scoringModel = 
this.fromApiJsonHelper.extractStringNamed("scoringModel", element);
+
+            RuleBasedScorecard ruleBasedScorecard = null;
+            StatScorecard statScorecard = null;
+            MLScorecard mlScorecard = null;
+
+            if (scoringMethod.equalsIgnoreCase("ruleBased")) {
+                ruleBasedScorecard = this.assembleRuleBasedScorecard(element);
+            }
+
+            if (scoringMethod.equalsIgnoreCase("ml")) {
+                mlScorecard = this.assembleMLScorecard(element);
+            }
+
+            if (scoringMethod.equalsIgnoreCase("stat")) {
+                statScorecard = this.assembleStatScorecard(element);
+            }
+
+            creditScorecard = new CreditScorecard(scoringMethod, scoringModel, 
ruleBasedScorecard, statScorecard, mlScorecard);
+        }
+
+        return creditScorecard;
+    }
+
+    public RuleBasedScorecard assembleRuleBasedScorecard(final JsonElement 
element) {
+
+        final RuleBasedScorecard ruleBasedScorecard = new RuleBasedScorecard();
+
+        final List<FeatureCriteriaScore> criteriaScores = new ArrayList<>();
+
+        if (element.isJsonObject()) {
+            final JsonObject topLevelJsonElement = element.getAsJsonObject();
+
+            final String dateFormat = 
this.fromApiJsonHelper.extractDateFormatParameter(topLevelJsonElement);
+            final Locale locale = 
this.fromApiJsonHelper.extractLocaleParameter(topLevelJsonElement);
+
+            final String rbScorecardParameterName = "ruleBasedScorecard";
+            if (topLevelJsonElement.has(rbScorecardParameterName) && 
topLevelJsonElement.get(rbScorecardParameterName).isJsonObject()) {
+                final JsonObject rbScorecardElement = 
topLevelJsonElement.getAsJsonObject(rbScorecardParameterName);
+
+                final String criteriaScoresParameterName = "criteriaScores";
+                if (rbScorecardElement.has(criteriaScoresParameterName)
+                        && 
rbScorecardElement.get(criteriaScoresParameterName).isJsonArray()) {
+                    final JsonArray array = 
rbScorecardElement.get(criteriaScoresParameterName).getAsJsonArray();
+                    for (int i = 0; i < array.size(); i++) {
+
+                        final JsonObject criteriaScoreElement = 
array.get(i).getAsJsonObject();
+
+                        final Long featureId = 
this.fromApiJsonHelper.extractLongNamed("featureId", criteriaScoreElement);
+                        final String value = 
this.fromApiJsonHelper.extractStringNamed("value", criteriaScoreElement);
+
+                        final LoanProductScorecardFeature lpScorecardFeature = 
this.productFeatureRepository
+                                .findOneWithNotFoundDetection(featureId);
+
+                        criteriaScores.add(new 
FeatureCriteriaScore(lpScorecardFeature, value));
+
+                    }
+
+                } else {
+                    return null;
+
+                }
+            }
+        }
+
+        ruleBasedScorecard.setCriteriaScores(criteriaScores);
+
+        return ruleBasedScorecard;
+    }
+
+    public StatScorecard assembleStatScorecard(final JsonElement element) {
+
+        StatScorecard statScorecard = null;
+
+        if (element.isJsonObject()) {
+
+            final JsonObject topLevelJsonElement = element.getAsJsonObject();
+
+            final String dateFormat = 
this.fromApiJsonHelper.extractDateFormatParameter(topLevelJsonElement);
+            final Locale locale = 
this.fromApiJsonHelper.extractLocaleParameter(topLevelJsonElement);
+
+            final String statScorecardParameterName = "statScorecard";
+            if (topLevelJsonElement.has(statScorecardParameterName) && 
topLevelJsonElement.get(statScorecardParameterName).isJsonObject()) {
+                final JsonObject scorecardDataElement = 
topLevelJsonElement.getAsJsonObject(statScorecardParameterName);
+
+                statScorecard = new StatScorecard(
+                        new 
MLScorecardFields(this.fromApiJsonHelper.extractIntegerWithLocaleNamed("age", 
scorecardDataElement),
+                                
this.fromApiJsonHelper.extractStringNamed("sex", scorecardDataElement),
+                                
this.fromApiJsonHelper.extractStringNamed("job", scorecardDataElement),
+                                
this.fromApiJsonHelper.extractStringNamed("housing", scorecardDataElement),
+                                
this.fromApiJsonHelper.extractBigDecimalNamed("creditAmount", 
scorecardDataElement, locale),
+                                
this.fromApiJsonHelper.extractIntegerNamed("duration", scorecardDataElement, 
locale),
+                                
this.fromApiJsonHelper.extractStringNamed("purpose", scorecardDataElement)));
+            }
+        }
+        return statScorecard;
+    }
+
+    public MLScorecard assembleMLScorecard(final JsonElement element) {
+
+        MLScorecard mlScorecard = null;
+
+        if (element.isJsonObject()) {
+
+            final JsonObject topLevelJsonElement = element.getAsJsonObject();
+
+            final String dateFormat = 
this.fromApiJsonHelper.extractDateFormatParameter(topLevelJsonElement);
+            final Locale locale = 
this.fromApiJsonHelper.extractLocaleParameter(topLevelJsonElement);
+
+            final String mlScorecardParameterName = "mlScorecard";
+            if (topLevelJsonElement.has(mlScorecardParameterName) && 
topLevelJsonElement.get(mlScorecardParameterName).isJsonObject()) {
+                final JsonObject scorecardDataElement = 
topLevelJsonElement.getAsJsonObject(mlScorecardParameterName);
+
+                mlScorecard = new MLScorecard(
+                        new 
MLScorecardFields(this.fromApiJsonHelper.extractIntegerWithLocaleNamed("age", 
scorecardDataElement),
+                                
this.fromApiJsonHelper.extractStringNamed("sex", scorecardDataElement),
+                                
this.fromApiJsonHelper.extractStringNamed("job", scorecardDataElement),
+                                
this.fromApiJsonHelper.extractStringNamed("housing", scorecardDataElement),
+                                
this.fromApiJsonHelper.extractBigDecimalNamed("creditAmount", 
scorecardDataElement, locale),
+                                
this.fromApiJsonHelper.extractIntegerNamed("duration", scorecardDataElement, 
locale),
+                                
this.fromApiJsonHelper.extractStringNamed("purpose", scorecardDataElement)));
+            }
+        }
+        return mlScorecard;
+    }
+
+
+    @Override
+    public List<LoanProductScorecardFeature> 
assembleListOfProductScoringFeatures(final JsonCommand command, LoanProduct 
loanProduct) {
+
+        final List<LoanProductScorecardFeature> loanProductFeatures = new 
ArrayList<>();
+
+        // JsonCommand incentivesCommand = 
JsonCommand.fromExistingCommand(command, incentiveElement);
+        // 
chartSlab.slabFields().validateChartSlabPlatformRules(chartSlabsCommand, 
baseDataValidator, locale);
+
+        if (command.parameterExists("scorecardFeatures")) {
+            final JsonArray featuresArray = 
command.arrayOfParameterNamed("scorecardFeatures");
+            if (featuresArray != null) {
+                for (int i = 0; i < featuresArray.size(); i++) {
+
+                    final JsonObject jsonObject = 
featuresArray.get(i).getAsJsonObject();
+                    if (jsonObject.has("featureId")) {
+                        final Long id = 
jsonObject.get("featureId").getAsLong();
+
+                        final BigDecimal weightage = 
jsonObject.get("weightage").getAsBigDecimal();
+                        final Integer greenMin = 
jsonObject.get("greenMin").getAsInt();
+                        final Integer greenMax = 
jsonObject.get("greenMax").getAsInt();
+                        final Integer amberMin = 
jsonObject.get("amberMin").getAsInt();
+                        final Integer amberMax = 
jsonObject.get("amberMax").getAsInt();
+                        final Integer redMin = 
jsonObject.get("redMin").getAsInt();
+                        final Integer redMax = 
jsonObject.get("redMax").getAsInt();
+
+                        final List<FeatureCriteria> criteria = this
+                                
.assembleListOfProductScoringFeatureCriteriaScores(jsonObject.get("criteriaScores").getAsJsonArray());
+
+                        final CreditScorecardFeature feature = 
this.readPlatformService.findOneFeatureWithNotFoundDetection(id);
+
+                        final LoanProductScorecardFeature loanProductFeature = 
new LoanProductScorecardFeature(feature, weightage, greenMin,
+                                greenMax, amberMin, amberMax, redMin, redMax);
+
+                        loanProductFeature.setFeatureCriteria(criteria);
+                        loanProductFeatures.add(loanProductFeature);
+                    }
+                }
+            }
+        }
+
+        return loanProductFeatures;
+    }
+
+    private List<FeatureCriteria> 
assembleListOfProductScoringFeatureCriteriaScores(final JsonArray jsonArray) {
+
+        final List<FeatureCriteria> featureCriteria = new ArrayList<>();
+
+        if (jsonArray != null) {
+            for (int i = 0; i < jsonArray.size(); i++) {
+
+                final JsonObject jsonObject = 
jsonArray.get(i).getAsJsonObject();
+                final BigDecimal score = 
jsonObject.get("score").getAsBigDecimal();
+                final String scoreCriteria = 
jsonObject.get("criteria").getAsString();
+
+                featureCriteria.add(new FeatureCriteria(scoreCriteria, score));
+            }
+        }
+
+        return featureCriteria;
+    }
+
+}
diff --git a/settings.gradle 
b/scorecard-plugin/src/main/java/org/apache/fineract/portfolio/creditscorecard/service/CreditScorecardFeatureDropdownReadPlatformService.java
similarity index 68%
copy from settings.gradle
copy to 
scorecard-plugin/src/main/java/org/apache/fineract/portfolio/creditscorecard/service/CreditScorecardFeatureDropdownReadPlatformService.java
index e278339..e3f0eb7 100644
--- a/settings.gradle
+++ 
b/scorecard-plugin/src/main/java/org/apache/fineract/portfolio/creditscorecard/service/CreditScorecardFeatureDropdownReadPlatformService.java
@@ -1,20 +1,32 @@
-/**
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements. See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership. The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied. See the License for the
- * specific language governing permissions and limitations
- * under the License.
- */
-
-rootProject.name = 'fineract-credit-scorecard'
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.fineract.portfolio.creditscorecard.service;
+
+import java.util.List;
+import org.apache.fineract.infrastructure.core.data.EnumOptionData;
+
+public interface CreditScorecardFeatureDropdownReadPlatformService {
+
+    List<EnumOptionData> retrieveValueTypes();
+
+    List<EnumOptionData> retrieveDataTypes();
+
+    List<EnumOptionData> retrieveCategoryTypes();
+
+}
diff --git 
a/scorecard-plugin/src/main/java/org/apache/fineract/portfolio/creditscorecard/service/CreditScorecardFeatureDropdownReadPlatformServiceImpl.java
 
b/scorecard-plugin/src/main/java/org/apache/fineract/portfolio/creditscorecard/service/CreditScorecardFeatureDropdownReadPlatformServiceImpl.java
new file mode 100644
index 0000000..e92fa76
--- /dev/null
+++ 
b/scorecard-plugin/src/main/java/org/apache/fineract/portfolio/creditscorecard/service/CreditScorecardFeatureDropdownReadPlatformServiceImpl.java
@@ -0,0 +1,55 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.fineract.portfolio.creditscorecard.service;
+
+import java.util.Arrays;
+import java.util.List;
+import org.apache.fineract.infrastructure.core.data.EnumOptionData;
+import org.apache.fineract.portfolio.creditscorecard.domain.FeatureCategory;
+import org.apache.fineract.portfolio.creditscorecard.domain.FeatureDataType;
+import org.apache.fineract.portfolio.creditscorecard.domain.FeatureValueType;
+import org.springframework.stereotype.Service;
+
+@Service
+public class CreditScorecardFeatureDropdownReadPlatformServiceImpl implements 
CreditScorecardFeatureDropdownReadPlatformService {
+
+    @Override
+    public List<EnumOptionData> retrieveValueTypes() {
+        return 
Arrays.asList(CreditScorecardEnumerations.featureValueType(FeatureValueType.BINARY),
+                
CreditScorecardEnumerations.featureValueType(FeatureValueType.NOMINAL),
+                
CreditScorecardEnumerations.featureValueType(FeatureValueType.RATIO),
+                
CreditScorecardEnumerations.featureValueType(FeatureValueType.INTERVAL));
+    }
+
+    @Override
+    public List<EnumOptionData> retrieveDataTypes() {
+        return 
Arrays.asList(CreditScorecardEnumerations.featureDataType(FeatureDataType.STRING),
+                
CreditScorecardEnumerations.featureDataType(FeatureDataType.NUMERIC),
+                
CreditScorecardEnumerations.featureDataType(FeatureDataType.DATE));
+    }
+
+    @Override
+    public List<EnumOptionData> retrieveCategoryTypes() {
+        return 
Arrays.asList(CreditScorecardEnumerations.featureCategory(FeatureCategory.INDIVIDUAL),
+                
CreditScorecardEnumerations.featureCategory(FeatureCategory.ORGANISATION),
+                
CreditScorecardEnumerations.featureCategory(FeatureCategory.COUNTRY),
+                
CreditScorecardEnumerations.featureCategory(FeatureCategory.CREDIT_HISTORY),
+                
CreditScorecardEnumerations.featureCategory(FeatureCategory.LOAN));
+    }
+}
diff --git 
a/scorecard-plugin/src/main/java/org/apache/fineract/portfolio/creditscorecard/service/CreditScorecardReadPlatformServiceImpl.java
 
b/scorecard-plugin/src/main/java/org/apache/fineract/portfolio/creditscorecard/service/CreditScorecardReadPlatformServiceImpl.java
new file mode 100644
index 0000000..d99255e
--- /dev/null
+++ 
b/scorecard-plugin/src/main/java/org/apache/fineract/portfolio/creditscorecard/service/CreditScorecardReadPlatformServiceImpl.java
@@ -0,0 +1,228 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.fineract.portfolio.creditscorecard.service;
+
+import java.math.BigDecimal;
+import java.sql.ResultSet;
+import java.sql.SQLException;
+import java.util.Collection;
+import java.util.List;
+import java.util.stream.Collectors;
+import org.apache.fineract.infrastructure.core.data.EnumOptionData;
+import org.apache.fineract.infrastructure.core.service.RoutingDataSource;
+import 
org.apache.fineract.portfolio.charge.exception.ChargeIsNotActiveException;
+import 
org.apache.fineract.portfolio.creditscorecard.annotation.ScorecardService;
+import org.apache.fineract.portfolio.creditscorecard.data.CreditScorecardData;
+import 
org.apache.fineract.portfolio.creditscorecard.data.CreditScorecardFeatureData;
+import org.apache.fineract.portfolio.creditscorecard.data.MLScorecardData;
+import 
org.apache.fineract.portfolio.creditscorecard.data.RuleBasedScorecardData;
+import 
org.apache.fineract.portfolio.creditscorecard.data.ScorecardFeatureCriteriaData;
+import org.apache.fineract.portfolio.creditscorecard.data.StatScorecardData;
+import org.apache.fineract.portfolio.creditscorecard.domain.CreditScorecard;
+import 
org.apache.fineract.portfolio.creditscorecard.domain.CreditScorecardFeature;
+import 
org.apache.fineract.portfolio.creditscorecard.domain.CreditScorecardFeatureRepository;
+import 
org.apache.fineract.portfolio.creditscorecard.domain.CreditScorecardRepository;
+import 
org.apache.fineract.portfolio.creditscorecard.domain.FeatureNotFoundException;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.jdbc.core.JdbcTemplate;
+import org.springframework.jdbc.core.RowMapper;
+
+@ScorecardService(name = "CreditScorecardReadPlatformService")
+public class CreditScorecardReadPlatformServiceImpl implements 
CreditScorecardReadPlatformService {
+
+    private final JdbcTemplate jdbcTemplate;
+    private final CreditScorecardRepository scorecardRepository;
+    private final CreditScorecardFeatureRepository featureRepository;
+    private final CreditScorecardFeatureDropdownReadPlatformService 
creditScorecardFeatureDropdownReadPlatformService;
+
+    @Autowired
+    public CreditScorecardReadPlatformServiceImpl(final RoutingDataSource 
dataSource, final CreditScorecardRepository scorecardRepository,
+                                                  final 
CreditScorecardFeatureRepository featureRepository,
+                                                  final 
CreditScorecardFeatureDropdownReadPlatformService 
creditScorecardFeatureDropdownReadPlatformService) {
+        this.jdbcTemplate = new JdbcTemplate(dataSource);
+        this.scorecardRepository = scorecardRepository;
+        this.featureRepository = featureRepository;
+        this.creditScorecardFeatureDropdownReadPlatformService = 
creditScorecardFeatureDropdownReadPlatformService;
+    }
+
+    @Override
+    public CreditScorecardFeatureData retrieveNewScorecardFeatureDetails() {
+
+        final Collection<EnumOptionData> valueTypeOptions = 
this.creditScorecardFeatureDropdownReadPlatformService.retrieveValueTypes();
+        final Collection<EnumOptionData> dataTypeOptions = 
this.creditScorecardFeatureDropdownReadPlatformService.retrieveDataTypes();
+        final Collection<EnumOptionData> categoryOptions = 
this.creditScorecardFeatureDropdownReadPlatformService.retrieveCategoryTypes();
+
+        return CreditScorecardFeatureData.template(valueTypeOptions, 
dataTypeOptions, categoryOptions);
+    }
+
+    @Override
+    public Collection<CreditScorecardFeatureData> 
retrieveLoanProductFeatures(Long productId) {
+        final ScorecardFeatureMapper rm = new ScorecardFeatureMapper();
+
+        final String sql = "SELECT " + rm.featureSchema()
+                + " WHERE scf.is_deleted=false AND scf.is_active=true AND 
lpscf.product_loan_id=? ";
+
+        final Collection<CreditScorecardFeatureData> scorecardFeatures = 
this.jdbcTemplate.query(sql, rm, new Object[] { productId });
+
+        for (CreditScorecardFeatureData scorecardFeature : scorecardFeatures) {
+            Collection<ScorecardFeatureCriteriaData> criteriaData = 
this.retrieveFeatureCriteria(scorecardFeature.getId());
+            scorecardFeature.getCriteria().addAll(criteriaData);
+        }
+        return scorecardFeatures;
+    }
+
+    @Override
+    public CreditScorecardData retrieveCreditScorecard(Long scorecardId) {
+        final CreditScorecard scorecard = 
this.scorecardRepository.findById(scorecardId).orElse(null);
+
+        if (scorecard == null) {
+            return null;
+        }
+
+        CreditScorecardData scorecardData = null;
+
+        final String method = scorecard.getScoringMethod();
+        switch (method) {
+            case "ml":
+                final MLScorecardData mlScorecardData = 
MLScorecardData.instance(scorecard.getMlScorecard());
+                scorecardData = 
CreditScorecardData.mlInstance(scorecard.getId(), scorecard.getScoringMethod(), 
scorecard.getScoringModel(),
+                        mlScorecardData);
+                break;
+
+            case "stat":
+                final StatScorecardData statScorecardData = 
StatScorecardData.instance(scorecard.getStatScorecard());
+                scorecardData = 
CreditScorecardData.statInstance(scorecard.getId(), 
scorecard.getScoringMethod(),
+                        scorecard.getScoringModel(), statScorecardData);
+                break;
+
+            case "ruleBased":
+                final RuleBasedScorecardData ruleBasedScorecardData = 
RuleBasedScorecardData.instance(scorecard.getRuleBasedScorecard());
+                scorecardData = 
CreditScorecardData.ruleBasedInstance(scorecard.getId(), 
scorecard.getScoringMethod(),
+                        scorecard.getScoringModel(), ruleBasedScorecardData);
+                break;
+
+            default:
+                break;
+        }
+
+        return scorecardData;
+    }
+
+    @Override
+    public CreditScorecardData loanScorecardTemplate() {
+        return CreditScorecardData.loanTemplate();
+    }
+
+    @Override
+    public CreditScorecardData loanScorecardTemplate(CreditScorecardData 
scorecard) {
+        return CreditScorecardData.loanScorecardWithTemplate(scorecard);
+    }
+
+    private Collection<ScorecardFeatureCriteriaData> 
retrieveFeatureCriteria(Long featureId) {
+        final FeatureCriteriaMapper rm = new FeatureCriteriaMapper();
+
+        final String sql = "SELECT " + rm.featureCriteriaSchema() + " WHERE 
crit.product_loan_scorecard_feature_id=?";
+
+        return this.jdbcTemplate.query(sql, rm, new Object[] { featureId });
+    }
+
+    private static final class FeatureCriteriaMapper implements 
RowMapper<ScorecardFeatureCriteriaData> {
+
+        public String featureCriteriaSchema() {
+            return "crit.id as id, crit.criteria as criteria, crit.score as 
score " + "FROM m_scorecard_feature_criteria crit";
+        }
+
+        @Override
+        public ScorecardFeatureCriteriaData mapRow(ResultSet rs, int rowNum) 
throws SQLException {
+            final Long id = rs.getLong("id");
+            final String criteria = rs.getString("criteria");
+            final int score = rs.getInt("score");
+            return ScorecardFeatureCriteriaData.instance(id, criteria, 
BigDecimal.valueOf(score));
+        }
+    }
+
+    private static final class ScorecardFeatureMapper implements 
RowMapper<CreditScorecardFeatureData> {
+
+        public String featureSchema() {
+            return "scf.id as featureId, scf.name as name, scf.value_type_enum 
as valueType, "
+                    + "scf.data_type_enum as dataType, scf.category_enum as 
category, scf.is_active as active, "
+                    + "lpscf.id as id, lpscf.weightage as weightage, 
lpscf.green_min as greenMin, "
+                    + "lpscf.green_max as greenMax, lpscf.amber_min as 
amberMin, lpscf.amber_max as amberMax, "
+                    + "lpscf.red_min as redMin, lpscf.red_max as redMax "
+
+                    + "FROM m_product_loan_scorecard_feature lpscf "
+                    + "JOIN m_credit_scorecard_feature scf ON scf.id = 
lpscf.scorecard_feature_id ";
+        }
+
+        @Override
+        public CreditScorecardFeatureData mapRow(final ResultSet rs, 
@SuppressWarnings("unused") final int rowNum) throws SQLException {
+            final Long id = rs.getLong("id");
+
+            final Long featureId = rs.getLong("featureId");
+            final String name = rs.getString("name");
+
+            final int valueType = rs.getInt("valueType");
+            final EnumOptionData valueTypeEnum = 
CreditScorecardEnumerations.featureValueType(valueType);
+
+            final int dataType = rs.getInt("dataType");
+            final EnumOptionData dataTypeEnum = 
CreditScorecardEnumerations.featureDataType(dataType);
+
+            final int category = rs.getInt("category");
+            final EnumOptionData categoryEnum = 
CreditScorecardEnumerations.featureCategory(category);
+
+            final boolean active = rs.getBoolean("active");
+
+            final BigDecimal weightage = rs.getBigDecimal("weightage");
+
+            final int greenMin = rs.getInt("greenMin");
+            final int greenMax = rs.getInt("greenMax");
+
+            final int amberMin = rs.getInt("amberMin");
+            final int amberMax = rs.getInt("amberMax");
+
+            final int redMin = rs.getInt("redMin");
+            final int redMax = rs.getInt("redMax");
+
+            return CreditScorecardFeatureData.instance(id, featureId, name, 
valueTypeEnum, dataTypeEnum, categoryEnum, active, weightage,
+                    greenMin, greenMax, amberMin, amberMax, redMin, redMax);
+        }
+    }
+
+    @Override
+    public CreditScorecardFeature findOneFeatureWithNotFoundDetection(final 
Long id) {
+
+        final CreditScorecardFeature scorecardFeature = 
this.featureRepository.findById(id)
+                .orElseThrow(() -> new FeatureNotFoundException(id));
+        if (scorecardFeature.isDeleted()) {
+            throw new FeatureNotFoundException(id);
+        }
+        if (!scorecardFeature.isActive()) {
+            throw new ChargeIsNotActiveException(id, 
scorecardFeature.getName());
+        }
+
+        return scorecardFeature;
+    }
+
+    @Override
+    public List<CreditScorecardFeature> findAllFeaturesWithNotFoundDetection() 
{
+        return 
this.featureRepository.findAll().stream().filter(CreditScorecardFeature::isActive).filter(feature
 -> !feature.isDeleted())
+                .collect(Collectors.toList());
+    }
+
+}
diff --git 
a/scorecard-plugin/src/main/java/org/apache/fineract/portfolio/creditscorecard/service/CreditScorecardWritePlatformServiceImpl.java
 
b/scorecard-plugin/src/main/java/org/apache/fineract/portfolio/creditscorecard/service/CreditScorecardWritePlatformServiceImpl.java
new file mode 100644
index 0000000..178a3b0
--- /dev/null
+++ 
b/scorecard-plugin/src/main/java/org/apache/fineract/portfolio/creditscorecard/service/CreditScorecardWritePlatformServiceImpl.java
@@ -0,0 +1,376 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.fineract.portfolio.creditscorecard.service;
+
+import java.math.BigDecimal;
+import java.util.Collection;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import javax.persistence.PersistenceException;
+import org.apache.commons.lang3.exception.ExceptionUtils;
+import org.apache.fineract.credit.scorecard.ApiException;
+import org.apache.fineract.credit.scorecard.Configuration;
+import org.apache.fineract.credit.scorecard.models.PredictionResponse;
+import org.apache.fineract.credit.scorecard.services.AlgorithmsApi;
+import org.apache.fineract.infrastructure.core.api.JsonCommand;
+import org.apache.fineract.infrastructure.core.data.CommandProcessingResult;
+import 
org.apache.fineract.infrastructure.core.data.CommandProcessingResultBuilder;
+import org.apache.fineract.infrastructure.core.data.EnumOptionData;
+import 
org.apache.fineract.infrastructure.core.exception.PlatformDataIntegrityException;
+import 
org.apache.fineract.infrastructure.security.service.PlatformSecurityContext;
+import 
org.apache.fineract.portfolio.creditscorecard.annotation.ScorecardService;
+import org.apache.fineract.portfolio.creditscorecard.domain.CreditScorecard;
+import 
org.apache.fineract.portfolio.creditscorecard.domain.CreditScorecardFeature;
+import 
org.apache.fineract.portfolio.creditscorecard.domain.CreditScorecardFeatureRepository;
+import 
org.apache.fineract.portfolio.creditscorecard.domain.CreditScorecardRepository;
+import 
org.apache.fineract.portfolio.creditscorecard.domain.FeatureConfiguration;
+import org.apache.fineract.portfolio.creditscorecard.domain.FeatureCriteria;
+import 
org.apache.fineract.portfolio.creditscorecard.domain.FeatureCriteriaScore;
+import org.apache.fineract.portfolio.creditscorecard.domain.MLScorecard;
+import org.apache.fineract.portfolio.creditscorecard.domain.MLScorecardFields;
+import org.apache.fineract.portfolio.creditscorecard.domain.RuleBasedScorecard;
+import org.apache.fineract.portfolio.creditscorecard.domain.StatScorecard;
+import 
org.apache.fineract.portfolio.creditscorecard.exception.FeatureCannotBeDeletedException;
+import 
org.apache.fineract.portfolio.creditscorecard.exception.FeatureNotFoundException;
+import 
org.apache.fineract.portfolio.creditscorecard.serialization.CreditScorecardApiJsonHelper;
+import org.apache.fineract.portfolio.loanaccount.domain.Loan;
+import org.apache.fineract.portfolio.loanproduct.domain.LoanProduct;
+import org.apache.fineract.portfolio.loanproduct.domain.LoanProductRepository;
+import 
org.apache.fineract.portfolio.loanproduct.domain.LoanProductScorecardFeature;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.beans.factory.annotation.Value;
+import org.springframework.context.annotation.PropertySource;
+import org.springframework.dao.DataIntegrityViolationException;
+import org.springframework.orm.jpa.JpaSystemException;
+import org.springframework.transaction.annotation.Transactional;
+
+@PropertySource(value = "classpath:scorecard-client.properties")
+@ScorecardService(name = "CreditScorecardWritePlatformService")
+public class CreditScorecardWritePlatformServiceImpl implements 
CreditScorecardWritePlatformService {
+
+    private static final Logger LOG = 
LoggerFactory.getLogger(CreditScorecardWritePlatformServiceImpl.class);
+
+    @Value("${fineract.credit.scorecard.uid}")
+    String username;
+
+    @Value("${fineract.credit.scorecard.password}")
+    String password;
+
+    @Value("${fineract.credit.scorecard.baseUrl}")
+    String baseUrl;
+
+    private final PlatformSecurityContext context;
+
+    private final LoanProductRepository loanProductRepository;
+    private final CreditScorecardApiJsonHelper fromApiJsonDeserializer;
+    private final CreditScorecardFeatureRepository featureRepository;
+    private final CreditScorecardRepository scorecardRepository;
+
+    AlgorithmsApi scorecardApiClient;
+
+    @Autowired
+    public CreditScorecardWritePlatformServiceImpl(final 
PlatformSecurityContext context,
+            final CreditScorecardApiJsonHelper fromApiJsonDeserializer,
+            final LoanProductRepository loanProductRepository,
+            final CreditScorecardFeatureRepository featureRepository,
+            final CreditScorecardRepository scorecardRepository) {
+        this.context = context;
+        this.fromApiJsonDeserializer = fromApiJsonDeserializer;
+        this.loanProductRepository = loanProductRepository;
+        this.featureRepository = featureRepository;
+        this.scorecardRepository = scorecardRepository;
+
+    }
+
+    private void initScorecardClient() {
+        LOG.warn("Base URL at init : {}", baseUrl);
+        this.scorecardApiClient = new 
AlgorithmsApi(Configuration.getDefaultApiClient().setBasePath(baseUrl));
+    }
+
+    @Override
+    public CommandProcessingResult createScoringFeature(JsonCommand command) {
+
+        try {
+            this.context.authenticatedUser();
+            
this.fromApiJsonDeserializer.validateFeatureForCreate(command.json());
+
+            final CreditScorecardFeature scorecardFeature = 
CreditScorecardFeature.fromJson(command);
+            this.featureRepository.save(scorecardFeature);
+
+            return new 
CommandProcessingResultBuilder().withCommandId(command.commandId()).withEntityId(scorecardFeature.getId()).build();
+        } catch (final JpaSystemException | DataIntegrityViolationException 
dve) {
+            handleDataIntegrityIssues(command, dve.getMostSpecificCause(), 
dve);
+            return CommandProcessingResult.empty();
+        } catch (final PersistenceException dve) {
+            Throwable throwable = ExceptionUtils.getRootCause(dve.getCause());
+            handleDataIntegrityIssues(command, throwable, dve);
+            return CommandProcessingResult.empty();
+        }
+    }
+
+    @Override
+    public CommandProcessingResult updateScoringFeature(Long featureId, 
JsonCommand command) {
+
+        try {
+            this.context.authenticatedUser();
+            
this.fromApiJsonDeserializer.validateFeatureForUpdate(command.json());
+
+            final CreditScorecardFeature featureForUpdate = 
this.featureRepository.findById(featureId)
+                    .orElseThrow(() -> new 
FeatureNotFoundException(featureId));
+
+            final Map<String, Object> changes = 
featureForUpdate.update(command);
+
+            if (!changes.isEmpty()) {
+                this.featureRepository.save(featureForUpdate);
+            }
+
+            return new 
CommandProcessingResultBuilder().withCommandId(command.commandId()).withEntityId(featureId).with(changes).build();
+        } catch (final JpaSystemException | DataIntegrityViolationException 
dve) {
+            handleDataIntegrityIssues(command, dve.getMostSpecificCause(), 
dve);
+            return CommandProcessingResult.empty();
+        } catch (final PersistenceException dve) {
+            Throwable throwable = ExceptionUtils.getRootCause(dve.getCause());
+            handleDataIntegrityIssues(command, throwable, dve);
+            return CommandProcessingResult.empty();
+        }
+    }
+
+    @Transactional
+    @Override
+    public CreditScorecard assessCreditRisk(final Loan loan) {
+        final CreditScorecard scorecard = loan.getScorecard();
+
+        if (scorecard != null) {
+            final String scoringMethod = scorecard.getScoringMethod();
+            final String scoringModel = scorecard.getScoringModel();
+
+            if (scoringMethod.equalsIgnoreCase("ruleBased")) {
+
+                final RuleBasedScorecard ruleBasedScorecard = 
scorecard.getRuleBasedScorecard();
+
+                final List<FeatureCriteriaScore> criteriaScores = 
ruleBasedScorecard.getCriteriaScores();
+
+                for (final FeatureCriteriaScore criteriaScore : 
criteriaScores) {
+
+                    final LoanProductScorecardFeature lpFeature = 
criteriaScore.getFeature();
+
+                    final FeatureConfiguration featureConfig = 
lpFeature.getFeatureConfiguration();
+
+                    final EnumOptionData dataType = 
lpFeature.getScorecardFeature().getDataType();
+
+                    final List<FeatureCriteria> featureCriteriaList = 
lpFeature.getFeatureCriteria();
+
+                    for (final FeatureCriteria featureCriteria : 
featureCriteriaList) {
+
+                        final String value = criteriaScore.getValue();
+
+                        if (value != null) {
+
+                            if 
(dataType.getValue().equalsIgnoreCase("string")) {
+
+                                if 
(value.equalsIgnoreCase(featureCriteria.getCriteria())) {
+                                    final BigDecimal score = 
featureCriteria.getScore().multiply(featureConfig.getWeightage());
+                                    final String color = 
featureConfig.getColorFromScore(score);
+                                    criteriaScore.setScore(score, color);
+                                    break;
+
+                                }
+
+                            } else if 
(dataType.getValue().equalsIgnoreCase("numeric")) {
+
+                                final String criteria = 
featureCriteria.getCriteria().strip();
+
+                                final float min = 
Float.parseFloat(criteria.substring(0, criteria.indexOf("-")).strip());
+                                final float max = 
Float.parseFloat(criteria.substring(criteria.indexOf("-") + 1).strip());
+
+                                final float floatValue = 
Float.parseFloat(value);
+
+                                if (floatValue >= min && floatValue <= max) {
+                                    final BigDecimal score = 
featureCriteria.getScore().multiply(featureConfig.getWeightage());
+                                    final String color = 
featureConfig.getColorFromScore(score);
+                                    criteriaScore.setScore(score, color);
+                                    break;
+
+                                }
+
+                            }
+
+                        }
+
+                    }
+
+                }
+
+                BigDecimal scorecardScore = BigDecimal.ZERO;
+                int greenCount = 0;
+                int amberCount = 0;
+                int redCount = 0;
+                for (final FeatureCriteriaScore ctScore : criteriaScores) {
+                    scorecardScore = scorecardScore.add(ctScore.getScore());
+
+                    if (ctScore.getColor().equalsIgnoreCase("green")) {
+                        greenCount += 1;
+
+                    } else if (ctScore.getColor().equalsIgnoreCase("amber")) {
+                        amberCount += 1;
+
+                    } else if (ctScore.getColor().equalsIgnoreCase("red")) {
+                        redCount += 1;
+
+                    }
+
+                }
+
+                String scorecardColor = "amber";
+                if (greenCount > amberCount && greenCount > redCount) {
+                    scorecardColor = "green";
+
+                } else if (redCount >= greenCount && redCount >= amberCount) {
+                    scorecardColor = "red";
+
+                }
+
+                ruleBasedScorecard.setScore(scorecardScore, scorecardColor);
+
+                return scorecard;
+
+            } else {
+
+                this.initScorecardClient();
+
+                if (scoringMethod.equalsIgnoreCase("ml")) {
+
+                    final MLScorecard mlScorecard = scorecard.getMlScorecard();
+
+                    final MLScorecardFields loanScorecardFields = 
mlScorecard.getScorecardFields();
+
+                    final PredictionResponse response = 
this.fetchScorecard(loanScorecardFields, scoringModel);
+
+                    if (response != null) {
+                        
mlScorecard.setPredictionResponse(BigDecimal.valueOf(response.getProbability()),
+                            response.getLabel(), response.getRequestId());
+                    }
+
+                } else if (scoringMethod.equalsIgnoreCase("stat")) {
+
+                    final StatScorecard statScorecard = 
scorecard.getStatScorecard();
+
+                    final MLScorecardFields loanScorecardFields = 
statScorecard.getScorecardFields();
+
+                    final PredictionResponse response = 
this.fetchScorecard(loanScorecardFields, scoringModel);
+
+                    if (response != null) {
+                        final String method = response.getMethod();
+                        final String color = response.getColor();
+                        final BigDecimal probability = 
BigDecimal.valueOf(response.getProbability());
+
+                        BigDecimal wilikis = null;
+                        BigDecimal pillaisTrace = null;
+                        BigDecimal hotelling = null;
+                        BigDecimal roys = null;
+
+                        if (method.equalsIgnoreCase("manova")) {
+                            wilikis = 
BigDecimal.valueOf(response.getWilkisLambda());
+                            pillaisTrace = 
BigDecimal.valueOf(response.getPillaisTrace());
+                            hotelling = 
BigDecimal.valueOf(response.getHotellingTawley());
+                            roys = 
BigDecimal.valueOf(response.getRoysReatestRoots());
+                        }
+                        statScorecard.setPredictionResponse(method, color, 
probability, wilikis, pillaisTrace, hotelling, roys);
+                    }
+
+                }
+            }
+
+        } else {
+            return null;
+
+        }
+
+        this.scorecardRepository.save(scorecard);
+
+        return scorecard;
+    }
+
+    private PredictionResponse fetchScorecard(final MLScorecardFields fields, 
final String scoringModel) {
+        try {
+
+            final Map<String, Object> predictionData = new HashMap<>();
+
+            predictionData.put("age", fields.getAge());
+            predictionData.put("sex", fields.getSex());
+            predictionData.put("job", fields.getJob());
+            predictionData.put("housing", fields.getHousing());
+            predictionData.put("credit_amount", fields.getCreditAmount());
+            predictionData.put("duration", fields.getDuration());
+            predictionData.put("purpose", fields.getPurpose());
+
+            return this.scorecardApiClient.algorithmsPredict(scoringModel, 
"0.0.1", null, null,
+                    predictionData);
+
+        } catch (ApiException e) {
+            LOG.debug("An Error Occurred: {}", e.getLocalizedMessage());
+        }
+        return null;
+    }
+
+    @Override
+    public CommandProcessingResult deleteScoringFeature(Long entityId) {
+
+        this.context.authenticatedUser();
+
+        final CreditScorecardFeature featureForDelete = 
this.featureRepository.findById(entityId)
+                .orElseThrow(() -> new FeatureNotFoundException(entityId));
+        if (featureForDelete.isDeleted()) {
+            throw new FeatureNotFoundException(entityId);
+        }
+
+        final Collection<LoanProduct> loanProducts = 
this.loanProductRepository.retrieveLoanProductsByScorecardFeatureId(entityId);
+
+        if (!loanProducts.isEmpty()) {
+            throw new 
FeatureCannotBeDeletedException("error.msg.scorecard.feature.cannot.be.deleted.it.is.already.used.in.loan",
+                    "This Scoring Feature cannot be deleted, it is already 
used in loan");
+        }
+
+        featureForDelete.delete();
+
+        this.featureRepository.save(featureForDelete);
+
+        return new 
CommandProcessingResultBuilder().withEntityId(featureForDelete.getId()).build();
+    }
+
+    /*
+     * Guaranteed to throw an exception no matter what the data integrity 
issue is.
+     */
+    private void handleDataIntegrityIssues(final JsonCommand command, final 
Throwable realCause, final Exception dve) {
+
+        if (realCause.getMessage().contains("name")) {
+            final String name = command.stringValueOfParameterNamed("name");
+            throw new 
PlatformDataIntegrityException("error.msg.scorecard.feature.duplicate.name",
+                    "Scorecard Feature with name `" + name + "` already 
exists", "name", name);
+        }
+
+        LOG.error("Error occured.", dve);
+        throw new 
PlatformDataIntegrityException("error.msg.scorecard.feature.unknown.data.integrity.issue",
+                "Unknown data integrity issue with resource: " + 
realCause.getMessage());
+    }
+
+}
diff --git a/MySQL.cnf 
b/scorecard-plugin/src/main/resources/scorecard-client.properties
similarity index 83%
rename from MySQL.cnf
rename to scorecard-plugin/src/main/resources/scorecard-client.properties
index eba0a5f..55f3e96 100644
--- a/MySQL.cnf
+++ b/scorecard-plugin/src/main/resources/scorecard-client.properties
@@ -1,3 +1,4 @@
+#
 # Licensed to the Apache Software Foundation (ASF) under one
 # or more contributor license agreements. See the NOTICE file
 # distributed with this work for additional information
@@ -14,10 +15,8 @@
 # KIND, either express or implied. See the License for the
 # specific language governing permissions and limitations
 # under the License.
+#
 
-# MySQL.cnf
-[client]
-database = fineract_credit_scorecard
-user = root
-password = mysql
-default-character-set = utf8
\ No newline at end of file
+fineract.credit.scorecard.uid=
+fineract.credit.scorecard.password=
+fineract.credit.scorecard.baseUrl=http://127.0.0.1:8000
diff --git a/server/settings.py b/server/settings.py
index 6f78666..b67a098 100644
--- a/server/settings.py
+++ b/server/settings.py
@@ -116,10 +116,7 @@ DATABASES = {
         'USER': os.environ.get('DB_USER', 'root'),
         'PASSWORD': os.environ.get('DB_PASSWORD', 'mysql'),
         'HOST': os.environ.get('DB_HOST', '127.0.0.1'),
-        'PORT': os.environ.get('DB_PORT', '3306'),
-        'OPTIONS': {
-            'read_default_file': 'MySQL.cnf',
-        },
+        'PORT': os.environ.get('DB_PORT', '3306')
     },
     'sqlite3': {
         'ENGINE': 'django.db.backends.sqlite3',
diff --git a/settings.gradle b/settings.gradle
index e278339..3f5001d 100644
--- a/settings.gradle
+++ b/settings.gradle
@@ -18,3 +18,7 @@
  */
 
 rootProject.name = 'fineract-credit-scorecard'
+include(
+    'scorecard-plugin',
+    'scorecard-client'
+)
diff --git a/statistical_scripts/statistical_scoring.py 
b/stats/statistical_scoring.py
similarity index 100%
rename from statistical_scripts/statistical_scoring.py
rename to stats/statistical_scoring.py

Reply via email to