Compare commits
500
Commits
1f5d240ddb
...
7b3ab9bd24
@@ -0,0 +1,19 @@
|
||||
# https://issues.apache.org/jira/browse/FINERACT-1453
|
||||
# https://docs.github.com/en/code-security/supply-chain-security/keeping-your-dependencies-updated-automatically/configuration-options-for-dependency-updates
|
||||
|
||||
version: 2
|
||||
updates:
|
||||
- package-ecosystem: "gradle"
|
||||
directory: "/"
|
||||
schedule:
|
||||
interval: "daily"
|
||||
timezone: "Europe/Zurich"
|
||||
open-pull-requests-limit: 13
|
||||
- package-ecosystem: "github-actions"
|
||||
directory: "/"
|
||||
schedule:
|
||||
interval: "daily"
|
||||
- package-ecosystem: "docker"
|
||||
directory: "/"
|
||||
schedule:
|
||||
interval: "daily"
|
||||
@@ -0,0 +1,25 @@
|
||||
name: Fineract Docker build for PostgreSQL
|
||||
|
||||
on: [push, pull_request]
|
||||
|
||||
jobs:
|
||||
build:
|
||||
runs-on: ubuntu-20.04
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
- name: Set up JDK 17
|
||||
uses: actions/setup-java@v3
|
||||
with:
|
||||
java-version: '17'
|
||||
distribution: 'zulu'
|
||||
- name: Build the image
|
||||
run: ./gradlew :fineract-provider:clean :fineract-provider:jibDockerBuild -x test
|
||||
- name: Start the stack
|
||||
run: docker-compose -f docker-compose-postgresql.yml up -d
|
||||
- name: Wait for stack to come up
|
||||
run: sleep 60
|
||||
- name: Check health
|
||||
run: curl -f -k --retry 5 --retry-connrefused --connect-timeout 30 --retry-delay 30 https://localhost:8443/fineract-provider/actuator/health
|
||||
- name: Check info
|
||||
run: (( $(curl -f -k --retry 5 --retry-connrefused --connect-timeout 30 --retry-delay 30 https://localhost:8443/fineract-provider/actuator/info | wc --chars) > 100 ))
|
||||
@@ -0,0 +1,25 @@
|
||||
name: Fineract Docker build
|
||||
|
||||
on: [push, pull_request]
|
||||
|
||||
jobs:
|
||||
build:
|
||||
runs-on: ubuntu-20.04
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
- name: Set up JDK 17
|
||||
uses: actions/setup-java@v3
|
||||
with:
|
||||
java-version: '17'
|
||||
distribution: 'zulu'
|
||||
- name: Build the image
|
||||
run: ./gradlew :fineract-provider:clean :fineract-provider:jibDockerBuild -x test
|
||||
- name: Start the stack
|
||||
run: docker-compose up -d
|
||||
- name: Wait for stack to come up
|
||||
run: sleep 60
|
||||
- name: Check health
|
||||
run: curl -f -k --retry 5 --retry-connrefused --connect-timeout 30 --retry-delay 30 https://localhost:8443/fineract-provider/actuator/health
|
||||
- name: Check info
|
||||
run: (( $(curl -f -k --retry 5 --retry-connrefused --connect-timeout 30 --retry-delay 30 https://localhost:8443/fineract-provider/actuator/info | wc --chars) > 100 ))
|
||||
@@ -0,0 +1,68 @@
|
||||
name: Fineract Gradle build - basicauth - PostgreSQL
|
||||
on: [push, pull_request]
|
||||
|
||||
jobs:
|
||||
build:
|
||||
runs-on: ubuntu-20.04
|
||||
|
||||
services:
|
||||
postgresql:
|
||||
image: postgres:13.4
|
||||
ports:
|
||||
- 5432:5432
|
||||
env:
|
||||
POSTGRES_USER: root
|
||||
POSTGRES_PASSWORD: postgres
|
||||
options: --health-cmd="pg_isready -q -d postgres -U root" --health-interval=5s --health-timeout=2s --health-retries=3
|
||||
|
||||
mock-oauth2-server:
|
||||
image: ghcr.io/navikt/mock-oauth2-server:0.4.0
|
||||
ports:
|
||||
- 9000:9000
|
||||
env:
|
||||
SERVER_PORT: 9000
|
||||
JSON_CONFIG: '{ "interactiveLogin": true, "httpServer": "NettyWrapper", "tokenCallbacks": [ { "issuerId": "auth/realms/fineract", "tokenExpiry": 120, "requestMappings": [{ "requestParam": "scope", "match": "fineract", "claims": { "sub": "mifos", "scope": [ "test" ] } } ] } ] }'
|
||||
|
||||
env:
|
||||
TZ: Asia/Kolkata
|
||||
steps:
|
||||
- name: Set up cache
|
||||
uses: actions/cache@v2
|
||||
with:
|
||||
path: |
|
||||
~/.gradle/caches
|
||||
~/.gradle/wrapper
|
||||
key: ${{ runner.os }}-gradle-${{ hashFiles('**/*.gradle*', '**/gradle-wrapper.properties') }}
|
||||
restore-keys: |
|
||||
${{ runner.os }}-gradle-
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v3
|
||||
- name: Set up JDK 17
|
||||
uses: actions/setup-java@v3
|
||||
with:
|
||||
java-version: '17'
|
||||
distribution: 'zulu'
|
||||
- name: Validate Gradle wrapper
|
||||
uses: gradle/wrapper-validation-action@859c33240bd026ce8d5f711f5adcc65c2f8eafc1
|
||||
- name: Verify PostgreSQL connection
|
||||
run: |
|
||||
while ! pg_isready -d postgres -U root -h 127.0.0.1 -p 5432 ; do
|
||||
sleep 1
|
||||
done
|
||||
- name: Initialise databases
|
||||
run: |
|
||||
./gradlew --no-daemon -q createPGDB -PdbName=fineract_tenants
|
||||
./gradlew --no-daemon -q createPGDB -PdbName=fineract_default
|
||||
- name: Install additional software
|
||||
run: |
|
||||
sudo apt-get update
|
||||
sudo apt-get install ghostscript -y
|
||||
|
||||
- name: Basic Auth Build & Test
|
||||
run: ./gradlew --no-daemon -q --console=plain licenseMain licenseTest check build test --fail-fast doc -x :twofactor-tests:test -x :oauth2-test:test -PdbType=postgresql
|
||||
|
||||
- name: 2FA Build & Test
|
||||
run: ./gradlew --no-daemon -q --console=plain :twofactor-tests:test --fail-fast -PdbType=postgresql
|
||||
|
||||
- name: OAuth2 Build & Test
|
||||
run: ./gradlew --no-daemon -q --console=plain :oauth2-tests:test --fail-fast -PdbType=postgresql
|
||||
@@ -0,0 +1,67 @@
|
||||
name: Fineract Gradle build - basicauth
|
||||
on: [push, pull_request]
|
||||
|
||||
jobs:
|
||||
build:
|
||||
runs-on: ubuntu-20.04
|
||||
|
||||
services:
|
||||
mariad:
|
||||
image: mariadb:10.8
|
||||
ports:
|
||||
- 3306:3306
|
||||
env:
|
||||
MARIADB_ROOT_PASSWORD: mysql
|
||||
options: --health-cmd="mysqladmin ping" --health-interval=5s --health-timeout=2s --health-retries=3
|
||||
|
||||
mock-oauth2-server:
|
||||
image: ghcr.io/navikt/mock-oauth2-server:0.4.0
|
||||
ports:
|
||||
- 9000:9000
|
||||
env:
|
||||
SERVER_PORT: 9000
|
||||
JSON_CONFIG: '{ "interactiveLogin": true, "httpServer": "NettyWrapper", "tokenCallbacks": [ { "issuerId": "auth/realms/fineract", "tokenExpiry": 120, "requestMappings": [{ "requestParam": "scope", "match": "fineract", "claims": { "sub": "mifos", "scope": [ "test" ] } } ] } ] }'
|
||||
|
||||
env:
|
||||
TZ: Asia/Kolkata
|
||||
steps:
|
||||
- name: Set up cache
|
||||
uses: actions/cache@v2
|
||||
with:
|
||||
path: |
|
||||
~/.gradle/caches
|
||||
~/.gradle/wrapper
|
||||
key: ${{ runner.os }}-gradle-${{ hashFiles('**/*.gradle*', '**/gradle-wrapper.properties') }}
|
||||
restore-keys: |
|
||||
${{ runner.os }}-gradle-
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v3
|
||||
- name: Set up JDK 17
|
||||
uses: actions/setup-java@v3
|
||||
with:
|
||||
java-version: '17'
|
||||
distribution: 'zulu'
|
||||
- name: Validate Gradle wrapper
|
||||
uses: gradle/wrapper-validation-action@859c33240bd026ce8d5f711f5adcc65c2f8eafc1
|
||||
- name: Verify MariaDB connection
|
||||
run: |
|
||||
while ! mysqladmin ping -h"127.0.0.1" -P3306 ; do
|
||||
sleep 1
|
||||
done
|
||||
- name: Initialise databases
|
||||
run: |
|
||||
./gradlew --no-daemon -q createDB -PdbName=fineract_tenants
|
||||
./gradlew --no-daemon -q createDB -PdbName=fineract_default
|
||||
- name: Install additional software
|
||||
run: |
|
||||
sudo apt-get update
|
||||
sudo apt-get install ghostscript -y
|
||||
|
||||
- name: Basic Auth Build & Test
|
||||
run: ./gradlew --no-daemon -q --console=plain licenseMain licenseTest check build test --fail-fast doc -x :twofactor-tests:test -x :oauth2-test:test
|
||||
|
||||
- name: 2FA Build & Test
|
||||
run: ./gradlew --no-daemon -q --console=plain :twofactor-tests:test --fail-fast
|
||||
|
||||
- name: OAuth2 Build & Test
|
||||
run: ./gradlew --no-daemon -q --console=plain :oauth2-tests:test --fail-fast
|
||||
@@ -22,15 +22,21 @@ jobs:
|
||||
runs-on: ubuntu-latest
|
||||
|
||||
steps:
|
||||
- uses: GoogleCloudPlatform/github-actions/setup-gcloud@master
|
||||
- uses: actions/checkout@v3
|
||||
|
||||
- id: 'auth'
|
||||
uses: google-github-actions/auth@v0
|
||||
with:
|
||||
credentials_json: '${{ secrets.GOOGLE_APPLICATION_CREDENTIALS}}'
|
||||
|
||||
- uses: google-github-actions/setup-gcloud@v0
|
||||
with:
|
||||
project_id: ${{ secrets.GOOGLE_PROJECT_ID }}
|
||||
service_account_key: ${{ secrets.GOOGLE_APPLICATION_CREDENTIALS}}
|
||||
|
||||
- uses: actions/checkout@v2
|
||||
|
||||
- run: gcloud components install beta
|
||||
|
||||
- run: JOBS=$(gcloud beta builds list --ongoing --format="value[terminator=' '](id)") && [ ! -z "$JOBS" ] && echo "Cancelling $JOBS..." && gcloud builds cancel $JOBS --no-user-output-enabled || true
|
||||
|
||||
- run: gcloud beta builds triggers run deploy-demo --branch master --format=none
|
||||
- run: gcloud beta builds triggers list
|
||||
|
||||
- run: gcloud beta builds triggers run deploy-demo --branch=master
|
||||
|
||||
@@ -1,10 +0,0 @@
|
||||
name: "Validate Gradle Wrapper"
|
||||
on: [push, pull_request]
|
||||
|
||||
jobs:
|
||||
validation:
|
||||
name: "Validation"
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
- uses: gradle/wrapper-validation-action@v1
|
||||
@@ -1,18 +0,0 @@
|
||||
# https://github.com/marketplace/actions/automatic-rebase (https://github.com/cirrus-actions/rebase)
|
||||
on:
|
||||
issue_comment:
|
||||
types: [created]
|
||||
name: Automatic Rebase
|
||||
jobs:
|
||||
rebase:
|
||||
name: Rebase
|
||||
if: github.event.issue.pull_request != '' && contains(github.event.comment.body, '/rebase')
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
with:
|
||||
fetch-depth: 0
|
||||
- name: Automatic Rebase
|
||||
uses: cirrus-actions/rebase@1.4
|
||||
env:
|
||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
@@ -0,0 +1,32 @@
|
||||
name: Fineract Sonarqube
|
||||
on: [push, pull_request]
|
||||
|
||||
jobs:
|
||||
build:
|
||||
runs-on: ubuntu-20.04
|
||||
env:
|
||||
TZ: Asia/Kolkata
|
||||
SONAR_ORGANIZATION: apache
|
||||
SONAR_HOST_URL: https://sonarcloud.io
|
||||
SONAR_TOKEN: ${{ secrets.SONAR_TOKEN }}
|
||||
steps:
|
||||
- name: Set up cache
|
||||
uses: actions/cache@v2
|
||||
with:
|
||||
path: |
|
||||
~/.gradle/caches
|
||||
~/.gradle/wrapper
|
||||
key: ${{ runner.os }}-gradle-${{ hashFiles('**/*.gradle*', '**/gradle-wrapper.properties') }}
|
||||
restore-keys: |
|
||||
${{ runner.os }}-gradle-
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v3
|
||||
- name: Set up JDK 17
|
||||
uses: actions/setup-java@v3
|
||||
with:
|
||||
java-version: '17'
|
||||
distribution: 'zulu'
|
||||
- name: Validate Gradle wrapper
|
||||
uses: gradle/wrapper-validation-action@859c33240bd026ce8d5f711f5adcc65c2f8eafc1
|
||||
- name: Sonarqube
|
||||
run: ./gradlew --no-daemon --console=plain -Dsonar.verbose=true -Dsonar.login=$SONAR_TOKEN -Dsonar.host.url=$SONAR_HOST_URL -Dsonar.organization=$SONAR_ORGANIZATION --info -x rat -x test -x spotbugsMain -x spotbugsTest -x spotbugsGenerated -x licenseMain -x licenseTest -x checkstyleMain -x checkstyleTest --info --stacktrace build sonarqube
|
||||
@@ -9,7 +9,7 @@ jobs:
|
||||
stale:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/stale@v3
|
||||
- uses: actions/stale@v5
|
||||
with:
|
||||
repo-token: ${{ secrets.GITHUB_TOKEN }}
|
||||
# stale-issue-message: 'Stale issue message'
|
||||
|
||||
+2
-1
@@ -10,14 +10,15 @@ build
|
||||
*.iml
|
||||
*.ipr
|
||||
*.iws
|
||||
*.swp
|
||||
*.DS_Store
|
||||
.idea
|
||||
.vscode
|
||||
catalina.base_IS_UNDEFINED/
|
||||
keystore.jks
|
||||
bin/
|
||||
fineract-provider/src/main/resources/application.properties
|
||||
.lock
|
||||
fineract-provider/out/
|
||||
fineract-provider/config/swagger/config.json
|
||||
fineract-provider/config/swagger/fineract-input.yaml
|
||||
licenses
|
||||
|
||||
+32
-31
@@ -23,36 +23,33 @@ dist: bionic
|
||||
|
||||
language: generic
|
||||
|
||||
services:
|
||||
- mysql
|
||||
- docker
|
||||
|
||||
addons:
|
||||
apt:
|
||||
packages:
|
||||
- curl
|
||||
- graphviz
|
||||
- gv
|
||||
sonarcloud:
|
||||
organization: "apache"
|
||||
token:
|
||||
secure: "Q2E9ijK+9+R6nkb9o2FQrKUiAozp0325mlGfM25rGV3mCRPyWR/lU8o48r2eaBEX8SEvMvXIO3XXD9SPyUX2+svLz0MOMdfZfNveg6jmcHNRjkzzBK0bMIIGbEH/YqJ+psl4nDmlDd6IK4685/1JSRUJLqeKKK2ulixm6PXcmwZWeKD6TjyXsW50zz3yYIOuROHzys/M6H05h1dZD3j6ztnRsjbr7SmqFEVWSRgEd/aAs+HZB9Fv1xN66csRoQUQKgzoBO9egAQcel65Av0Bf+pOQuzVDVyXNohZEYia02MCGlC6OFvtL7xIXGf/vo02RdnlN4Jnma6P37TaNrmpk2e+EGJaZHmL9cb98+Zc39uPb7qEZkMfDdKrW6QVRtScSuCJzpY58WRgTS0jLCxsDBAMfsrIvWbHntFZL9q5aEkFgecj0pg9u6WHxgA8cuPUY5QzHQo9fEUxNJHGJHQ2FkafLniqJp7DVbsyQHmEggaTrGGrketeYvCbSR1oOnBgImUwzjIV9/zOdd10Wzi8x9HsmzrGBPSBaO4fBxjC1LZwdyue2a2+oKvBqpAGcLpGaCRfHTh2yPXhZW4bw11rOmQxgtOQVBXhveciWAUQuVXIak+RZnu/zRvnul9sZ6bb1hEUPkpUypk+FDeLm8T7y2A++u/jBam2vLc0iff5xtA="
|
||||
|
||||
# See https://issues.apache.org/jira/browse/FINERACT-937 for background re. what below is all about..
|
||||
# We basically remove the outdated OpenJDK 11.0.2 which Travis image grabbed from java.net in
|
||||
# https://github.com/travis-ci/travis-cookbooks/blob/master/cookbooks/travis_jdk/files/install-jdk.sh#L200
|
||||
# (which has 11.0.2 hard-coded!), and instead replace it with the latest openjdk-11-jdk-headless Ubuntu package.
|
||||
# (which has 11.0.2 hard-coded!), and instead replace it with the latest Azul Zulu Debian package.
|
||||
# NB /usr/local/lib/jvm/openjdk11/bin is also on the PATH, but there's no need to change it (because we rm -rf anyway)
|
||||
# Installing Azul Zulu as per official instructions https://docs.azul.com/core/zulu-openjdk/install/debian
|
||||
before_install:
|
||||
- echo $JAVA_HOME
|
||||
- which java
|
||||
- sudo rm -rf /usr/local/lib/jvm/
|
||||
- sudo apt-get install -y openjdk-11-jdk-headless
|
||||
- export JAVA_HOME=/usr/lib/jvm/java-11-openjdk-amd64/
|
||||
- which java
|
||||
- java -version
|
||||
- $JAVA_HOME/bin/java -version
|
||||
- echo "USE mysql;\nALTER USER 'root'@'localhost' IDENTIFIED BY 'mysql';\n" | mysql -u root
|
||||
- mysql -u root -pmysql -e 'CREATE DATABASE IF NOT EXISTS `fineract_tenants`;'
|
||||
- mysql -u root -pmysql -e 'CREATE DATABASE IF NOT EXISTS `fineract_default`;'
|
||||
# Hardcoding the time zone is a temporary fix for https://issues.apache.org/jira/browse/FINERACT-723
|
||||
- export TZ=Asia/Kolkata
|
||||
|
||||
install:
|
||||
- unset _JAVA_OPTIONS
|
||||
- sudo apt-get -q update
|
||||
- sudo apt-get -yq install gnupg curl dirmngr
|
||||
- sudo apt-key adv --keyserver hkp://keyserver.ubuntu.com:80 --recv-keys 0xB1998361219BD9C9
|
||||
- curl -O https://cdn.azul.com/zulu/bin/zulu-repo_1.0.0-3_all.deb
|
||||
- sudo apt-get -yq install ./zulu-repo_1.0.0-3_all.deb
|
||||
- sudo apt-get -q update
|
||||
- sudo apt-get -yq install zulu17-jdk
|
||||
- export JAVA_HOME=/usr/lib/jvm/zulu17
|
||||
|
||||
# https://docs.travis-ci.com/user/languages/java/#caching
|
||||
before_cache:
|
||||
@@ -64,16 +61,20 @@ cache:
|
||||
- $HOME/.gradle/wrapper/
|
||||
- $HOME/.m2
|
||||
|
||||
# NOTE: We used to run with --info, which is quite a bit more verbose, but is VERY useful to understand failures on Travis,
|
||||
# where you do not have access to any files like build/reports/tests/index.html, only the Console.
|
||||
# @see http://mrhaki.blogspot.ch/2013/05/gradle-goodness-show-more-information.html
|
||||
# @see http://forums.gradle.org/gradle/topics/whats_new_in_gradle_1_1_test_logging for alternative
|
||||
# https://jira.apache.org/jira/browse/FINERACT-732 removed that again, because it made Travis CI fail.
|
||||
# Check Java environment variables
|
||||
before_script:
|
||||
- echo $JDK_JAVA_OPTIONS
|
||||
- echo $JAVA_OPTIONS
|
||||
- echo $JAVA_HOME
|
||||
- which java
|
||||
- java -version
|
||||
- which javac
|
||||
- javac -version
|
||||
- $JAVA_HOME/bin/java -version
|
||||
|
||||
script:
|
||||
- date
|
||||
# using "&&" instead of several "-" means that integrationTest does not run if test fails,
|
||||
# and Docker test does not run if integration test fails, which makes PR failure easier to understand.
|
||||
# @see https://docs.travis-ci.com/user/job-lifecycle/#customizing-the-build-phase
|
||||
- ./gradlew --no-daemon --console=plain licenseMain licenseTest check build test --fail-fast doc && sudo service mysql stop && docker-compose build && docker-compose up -d && sleep 60s && curl -f -k --retry 5 --retry-connrefused --connect-timeout 30 --retry-delay 30 https://localhost:8443/fineract-provider/actuator/health && (( $(curl -f -k --retry 5 --retry-connrefused --connect-timeout 30 --retry-delay 30 https://localhost:8443/fineract-provider/actuator/info | wc --chars) > 100 ))
|
||||
# We stop the mysql system service when running the Docker test to avoid port 3306 conflicts (unless we run the mysql in docker-compose on another port; req. FINERACT-773)
|
||||
# The fancy /actuator/info test makes sure that has more than 100 characters of JSON to test that the git.properties worked (see FINERACT-983)
|
||||
# Using travis_wait for a proccess that could take longer than 20 minutes, in this case the SonaQube analysis
|
||||
# https://docs.travis-ci.com/user/common-build-problems/#build-times-out-because-no-output-was-received
|
||||
- travis_wait 30 ./gradlew -q --no-daemon --console=plain -x rat -x test sonarqube -Pcoverage=true
|
||||
- date
|
||||
|
||||
-46
@@ -1,46 +0,0 @@
|
||||
# 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.
|
||||
#
|
||||
FROM openjdk:11 AS builder
|
||||
|
||||
RUN apt-get update -qq && apt-get install -y wget
|
||||
|
||||
COPY . fineract
|
||||
WORKDIR /fineract
|
||||
|
||||
RUN ./gradlew --no-daemon -q -x rat -x compileTestJava -x test -x spotlessJavaCheck -x spotlessJava bootJar
|
||||
|
||||
WORKDIR /fineract/target
|
||||
RUN jar -xf /fineract/fineract-provider/build/libs/fineract-provider*.jar
|
||||
|
||||
# https://issues.apache.org/jira/browse/LEGAL-462
|
||||
# https://issues.apache.org/jira/browse/FINERACT-762
|
||||
# We include an alternative JDBC driver (which is faster, but not allowed to be default in Apache distribution)
|
||||
# allowing implementations to switch the driver used by changing start-up parameters (for both tenants and each tenant DB)
|
||||
# The commented out lines in the docker-compose.yml illustrate how to do this.
|
||||
WORKDIR /fineract/target/BOOT-INF/lib
|
||||
RUN wget -q https://repo1.maven.org/maven2/mysql/mysql-connector-java/8.0.20/mysql-connector-java-8.0.20.jar
|
||||
|
||||
# =========================================
|
||||
|
||||
FROM gcr.io/distroless/java:11 as fineract
|
||||
|
||||
COPY --from=builder /fineract/target/BOOT-INF/lib /app/lib
|
||||
COPY --from=builder /fineract/target/META-INF /app/META-INF
|
||||
COPY --from=builder /fineract/target/BOOT-INF/classes /app
|
||||
|
||||
ENTRYPOINT ["java", "-cp", "app:app/lib/*", "org.apache.fineract.ServerApplication"]
|
||||
+4
-87
@@ -216,92 +216,9 @@ and resource files are also released under the ASF license above.
|
||||
==================================================
|
||||
*The exceptions for binary release are as follows:
|
||||
==================================================
|
||||
This product bundles AOP Alliance v1.0, which is available under a
|
||||
Public Domain license. For details, see licenses/binary/Aopa.PL
|
||||
|
||||
This product bundles ASM Core v3.1, which is available under a BSD license.
|
||||
For details, see licenses/binary/Asm.BSD
|
||||
This product bundles third party jars and resource files that are
|
||||
released under other licenses than the ASF license. You can find
|
||||
details of all third party licenses in the directory "licenses".
|
||||
|
||||
This product bundles JavaMail API(compat) v1.5.0-b01,
|
||||
which is available under a CDDL v1.0 license.
|
||||
For details, see licenses/binary/Javamail.CDDL
|
||||
|
||||
This product bundles AspectJ Runtime v1.8.2, Copyright (c) 1999-2001
|
||||
Xerox Corporation, 2002 Palo Alto Research Center, Incorporated (PARC),
|
||||
which is available under a EPL v1.0 license.
|
||||
For details, see licenses/binary/Aspectrt.EPL
|
||||
|
||||
This product bundles AspectJ Weaver v1.8.2, Copyright (c) 2002 Palo Alto
|
||||
Research Center, Incorporated (PARC), which is available under a EPL v1.0
|
||||
license. For details, see licenses/binary/Aspectweaver.EPL
|
||||
|
||||
This product bundles IText(A Free Java PDF Library) v2.1.7, Copyright 2007
|
||||
Bruno Lowagie, which is available under a MPL v1.1 license.
|
||||
For details, see licenses/binary/IText.MPL
|
||||
|
||||
This product bundles DOM4J, Copyright 2001-2005 (C) MetaStuff, Ltd.,
|
||||
which is available under a BSD license.
|
||||
For details, see licenses/binary/Dom4J.BSD
|
||||
|
||||
This product bundles JDBC driver for MySQL and Drizzle v1.3, Copyright (c)
|
||||
2009-2013, Marcus Eriksson which is available under a BSD license.
|
||||
For details, see licenses/binary/Drizzle.BSD
|
||||
|
||||
This product bundles Ical4J v1.0.4, Copyright (c) 2012, Ben Fortuna,
|
||||
which is available under a BSD license.
|
||||
For details, see licenses/binary/Ical4J.BSD
|
||||
|
||||
This product bundles Jersey Core v1.17, Copyright (c) 2010-2012 Oracle
|
||||
and/or its affiliates, which is available under a CDDL 1.1 license.
|
||||
For details, see licenses/binary/Jersey.CDDL
|
||||
|
||||
This product bundles Jersey Json v1.17, Copyright (c) 2010-2012 Oracle
|
||||
and/or its affiliates, which is available under a CDDL 1.1 license.
|
||||
For details, see licenses/binary/Jersey.CDDL
|
||||
|
||||
This product bundles Jersey Multipart v1.17, Copyright (c) 2010-2011 Oracle
|
||||
and/or its affiliates, which is available under a CDDL 1.1 license.
|
||||
For details, see licenses/binary/Jersey.CDDL
|
||||
|
||||
This product bundles Jersey Server v1.17, Copyright (c) 2010-2011 Oracle
|
||||
and/or its affiliates, which is available under a CDDL 1.1 license.
|
||||
For details, see licenses/binary/Jersey.CDDL
|
||||
|
||||
This product bundles Jersey Servlet v1.17, Copyright (c) 2010-2011 Oracle
|
||||
and/or its affiliates, which is available under a CDDL 1.1 license.
|
||||
For details, see licenses/binary/Jersey.CDDL
|
||||
|
||||
This product bundles Jersey Spring v1.17, Copyright (c) 2010-2011 Oracle
|
||||
and/or its affiliates, which is available under a CDDL 1.1 license.
|
||||
For details, see licenses/binary/Jersey.CDDL
|
||||
|
||||
This product bundles Logback Classic Module v1.1.2, Copyright (C) 1999-2012,
|
||||
QOS.ch. All rights reserved, which is available under a EPL v1.0 license.
|
||||
For details, see licenses/binary/Logback.EPL
|
||||
|
||||
This product bundles Logback Core Module v1.1.2, Copyright (C) 1999-2012,
|
||||
QOS.ch. All rights reserved, which is available under a EPL v1.0 license.
|
||||
For details, see licenses/binary/Logback.EPL
|
||||
|
||||
This product bundles MIME Streaming Extension v1.6, Copyright (c) 1997-2010
|
||||
Oracle and/or its affiliates. All rights reserved., which is available under
|
||||
a CDDL v1.1 license.
|
||||
For details, see licenses/binary/Mimepull.CDDL
|
||||
|
||||
This product bundles JUnit v3.8.1 created by Erich Gamma and Kent Beck which
|
||||
is available under a CPL v1.0 license.
|
||||
For details, see licenses/binary/Junit.CPL
|
||||
|
||||
This product bundles SLF4J API Module v1.7.7 opyright (c) 2004-2013 QOS.ch
|
||||
All rights reserved., which is available under a MIT license.
|
||||
For details, see licenses/binary/Slf4j.MIT
|
||||
|
||||
This product bundles Backport Util Concurrent v3.1 written by Dawid Kurzyniec,
|
||||
which is avilable under Public Domain license.
|
||||
For details see licenses/binary/Backport.PL
|
||||
|
||||
This product bundles JarAnalyzer v1.2 written by Kirk Knoernschild,
|
||||
which is available under BSD license.
|
||||
For details see licences/binary/JarAnalyzer.BSD
|
||||
|
||||
******************************************
|
||||
******************************************
|
||||
|
||||
+4
-63
@@ -217,70 +217,11 @@ and resource files are also released under the ASF license above.
|
||||
*The exceptions for source release are as follows:
|
||||
==================================================
|
||||
|
||||
For API & System Architecture Documentation Apache Fineract includes
|
||||
following css and js packages.
|
||||
|
||||
This product bundles normalize v1.1.1 and v2.1.0, copyright Nicolas
|
||||
Gallagher and Jonathan Neal, which is available under a MIT license.
|
||||
For details, see licenses/source/normalize.MIT
|
||||
|
||||
This product bundles Modernizr v2.6.2, which is available under a MIT license.
|
||||
For details, see licenses/source/modernizr.MIT
|
||||
|
||||
This product bundles filesaver, copyright Eli Grey, which is available under
|
||||
a MIT license.
|
||||
For details, see licenses/source/filesaver.MIT
|
||||
|
||||
This product bundles Glyphicons Halflings Regular, copyright Jan Kovarik,
|
||||
which is available under a MIT license.
|
||||
For details, see licenses/source/glyphicons.MIT
|
||||
|
||||
This product bundles jszip, copyright Stuart Knightley,
|
||||
David Duponchel, Franz Buchinger and António Afonso, which is available
|
||||
under a MIT license.
|
||||
For details, see licenses/source/jszip.MIT
|
||||
For API Documentation for Apache Fineract includes
|
||||
following css and js packages:
|
||||
|
||||
This product bundles jQuery v1.7, v1.7.1, Copyright (c) 2011 John Resig,
|
||||
which is available under a MIT license.
|
||||
For details, see licenses/source/jQuery1.MIT
|
||||
For details, see https://jquery.org/license/
|
||||
|
||||
This product bundles jQuery v1.9.1, v1.10.2, copyright jQuery Foundation,
|
||||
Inc. which is available under a MIT license.
|
||||
For details, see licenses/source/jQuery.MIT
|
||||
|
||||
This product bundles Respond v1.1.0, copyright Scott Jehl,
|
||||
which is available under a MIT license.
|
||||
For details, see licenses/source/respond.MIT
|
||||
|
||||
This product bundles matchMedia polyfill, copyright Scott Jehl,
|
||||
which is available under a MIT license.
|
||||
For details, see licenses/polyfill.MIT
|
||||
|
||||
This product bundles HTML5Shiv v3.6.2, copyright Alexander Farkas,
|
||||
which is available under a MIT license.
|
||||
For details, see licenses/source/html5shiv.MIT
|
||||
|
||||
This product bundles UglifyJS copyright Mihai Bazon,
|
||||
which available under a BSD license.
|
||||
For details, see licenses/source/uglify.BSD
|
||||
|
||||
This product bundles sizzle copyright jQuery Foundation and other
|
||||
contributors, which is available under a MIT license.
|
||||
For details, see licenses/source/sizzle.MIT
|
||||
|
||||
This product bundles some parts of es5-shim, copyright Kristopher Michael
|
||||
Kowal and contributors, which is available under a MIT license.
|
||||
For details, see licenses/source/es5shim.MIT
|
||||
|
||||
This product bundles toc v0.1.2, copyright Greg Allen,
|
||||
which is available under a MIT license.
|
||||
For details, see licenses/source/toc.MIT
|
||||
|
||||
This product bundles livejs Version 4, copyright Martin Kool and Q42,
|
||||
which is available under a MIT license.
|
||||
For details, see licenses/source/livejs.MIT
|
||||
|
||||
This product bundles HTML5 Boilerplate, which is under a MIT license.
|
||||
For details, see licenses/source/h5bp.MIT.
|
||||
|
||||
******************************************
|
||||
******************************************
|
||||
|
||||
+4
-74
@@ -1,79 +1,9 @@
|
||||
Apache Fineract
|
||||
Copyright 2008-2016 The Apache Software Foundation
|
||||
Copyright 2008-2021 The Apache Software Foundation
|
||||
|
||||
This product includes software developed by The Apache Software
|
||||
Foundation (http://www.apache.org/).
|
||||
|
||||
Apache Fineract - notice for binary distribution
|
||||
==========================================
|
||||
Apache Fineract includes JavaMail API(compat) v1.5.0-b01.
|
||||
Copyright (c) 1997-2013 Oracle and/or its affiliates. All rights reserved.
|
||||
Fineract elects to include this software in this distribution under the
|
||||
CDDL license. You can obtain a copy of the License at:
|
||||
https://glassfish.java.net/public/CDDL+GPL.html
|
||||
|
||||
Apache Fineract includes all Jersey libraries (Jersey Core v1.17,
|
||||
Jersey Json v1.17, Jersey Multipart v1.17, Jersey Server v1.17,
|
||||
Jersey Servlet v1.17, Jersey Spring v1.17).
|
||||
Copyright (c) 2010-2011 Oracle and/or its affiliates. All rights reserved.
|
||||
Fineract elects to include this software in this distribution under the
|
||||
CDDL license. You can obtain a copy of the License at:
|
||||
https://glassfish.java.net/public/CDDL+GPL.html
|
||||
|
||||
Apache Fineract includes Logback Classic Module v1.1.2 and Logback Core
|
||||
Module v1.1.2, Copyright (C) 1999-2012, QOS.ch.
|
||||
All rights reserved. Fineract elects to include this software in this
|
||||
distribution under the EPL license. You can obtain a copy of the License at:
|
||||
http://www.eclipse.org/legal/epl-v10.html
|
||||
|
||||
Apache Fineract includes MIME Streaming Extension v1.6,
|
||||
Copyright (c) 1997-2010 Oracle and/or its affiliates.
|
||||
All rights reserved. Fineract elects to include this software in this
|
||||
distribution under the CDDL license. You can obtain a copy of the License at:
|
||||
https://glassfish.java.net/public/CDDL+GPL_1_1.html
|
||||
|
||||
Apache Fineract includes JUnit v3.8.1 created by Erich Gamma and Kent Beck.
|
||||
Fineract elects to include this software in this distribution under the
|
||||
CPL license. You can obtain a copy of the License at:
|
||||
https://opensource.org/licenses/cpl1.0.txt
|
||||
|
||||
Apache Fineract includes Log4j Implemented Over SLF4J. Fineract elects to
|
||||
include this software in this distribution under the Apache license.
|
||||
You can obtain a copy of the License at:
|
||||
http://apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Apache Fineract includes Jackson Core v2.3.4, Jackson Annotations v2.3.0,
|
||||
Jackson Databind v2.3.4, JAX RS Provider For JSON Content Type v1.9.2,
|
||||
Xml Compatibility Extensions For Jackson v1.9.2 libraries.
|
||||
Fineract elects to include this software in this distribution under the
|
||||
Apache license. You can obtain a copy of the License at:
|
||||
http://apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Apache Fineract includes AspectJ Runtime v1.8.2, Copyright (c) 1999-2001
|
||||
Xerox Corporation, 2002 Palo Alto Research Center, Incorporated (PARC) and
|
||||
AspectJ Weaver v1.8.2 Copyright (c) 2002 Palo Alto Research Center,
|
||||
Incorporated (PARC)., libraries. The library information is available at
|
||||
(https://eclipse.org/aspectj/)
|
||||
|
||||
Apache Fineract includes IText(A Free Java PDF Library) v2.1.7 library,
|
||||
Copyright 2007 Bruno Lowagie. The library information is available at
|
||||
(http://developers.itextpdf.com/itext-java)
|
||||
|
||||
=====================
|
||||
Apache OpenJPA NOTICE
|
||||
|
||||
OpenJPA includes software developed by the SERP project
|
||||
Copyright (c) 2002-2006, A. Abram White. All rights reserved.
|
||||
|
||||
OpenJPA includes the persistence and orm schemas from the JPA specifications.
|
||||
Copyright 2005-2014 Sun Microsystems, Inc. All rights reserved.
|
||||
|
||||
OpenJPA includes the persistence and orm schemas from the JPA specifications.
|
||||
Copyright 2005-2009 Sun Microsystems, Inc. All rights reserved.
|
||||
OpenJPA elects to include this software in this distribution under the
|
||||
CDDL license. You can obtain a copy of the License at:
|
||||
https://glassfish.dev.java.net/public/CDDL+GPL.html
|
||||
The source code is available at:
|
||||
https://glassfish.dev.java.net/source/browse/glassfish/
|
||||
|
||||
OpenJPA includes software written by Miroslav Nachev
|
||||
This product includes third party libraries and resource files from
|
||||
different providers. The details of the different packages and their
|
||||
respective licenses can be found under "licenses"
|
||||
|
||||
+1
-1
@@ -1,5 +1,5 @@
|
||||
Apache Fineract
|
||||
Copyright 2008-2016 The Apache Software Foundation
|
||||
Copyright 2008-2021 The Apache Software Foundation
|
||||
|
||||
This product includes software developed by The Apache Software
|
||||
Foundation (http://www.apache.org/).
|
||||
|
||||
@@ -1,7 +1,9 @@
|
||||
Apache Fineract: A Platform for Microfinance [](https://travis-ci.org/apache/fineract) [](https://validator.swagger.io/validator/debug?url=https://demo.fineract.dev/fineract-provider/swagger-ui/fineract.yaml) [](https://hub.docker.com/r/apache/fineract) [](https://hub.docker.com/r/apache/fineract/builds)
|
||||
Apache Fineract: A Platform for Microfinance
|
||||
============
|
||||
[](https://validator.swagger.io/validator/debug?url=https://demo.fineract.dev/fineract-provider/swagger-ui/fineract.yaml) [](https://github.com/apache/fineract/actions/workflows/build.yml) [](https://hub.docker.com/r/apache/fineract) [](https://hub.docker.com/r/apache/fineract/builds) [](https://sonarcloud.io/summary/new_code?id=apache_fineract)
|
||||
|
||||
Fineract is a mature platform with open APIs that provides a reliable, robust, and affordable core banking solution for financial institutions offering services to the world’s 2 billion underbanked and unbanked.
|
||||
|
||||
Fineract is a mature platform with open APIs that provides a reliable, robust, and affordable core banking solution for financial institutions offering services to the world’s 3 billion underbanked and unbanked.
|
||||
|
||||
[Have a look at the FAQ on our Wiki at apache.org](https://cwiki.apache.org/confluence/display/FINERACT/FAQ) if this README does not answer what you are looking for. [Visit our JIRA Dashboard](https://issues.apache.org/jira/secure/Dashboard.jspa?selectPageId=12335824) to find issues to work on, see what others are working on, or open new issues.
|
||||
|
||||
@@ -18,18 +20,18 @@ If you are interested in contributing to this project, but perhaps don't quite k
|
||||
|
||||
Requirements
|
||||
============
|
||||
* Java >= 11 (OpenJDK JVM is tested by our CI on Travis)
|
||||
* MySQL 5.7
|
||||
* Java >= 17 (OpenJDK JVM is tested by our CI on Travis)
|
||||
* MariaDB 10.6
|
||||
|
||||
You can run the required version of the database server in a container, instead of having to install it, like this:
|
||||
|
||||
docker run --name mysql-5.7 -p 3306:3306 -e MYSQL_ROOT_PASSWORD=mysql -d mysql:5.7
|
||||
docker run --name mariadb-10.8 -p 3306:3306 -e MARIADB_ROOT_PASSWORD=mysql -d mariadb:10.8
|
||||
|
||||
and stop and destroy it like this:
|
||||
|
||||
docker rm -f mysql-5.7
|
||||
docker rm -f mariadb-10.8
|
||||
|
||||
Beware that this database container database keeps its state inside the container and not on the host filesystem. It is lost when you destroy (rm) this container. This is typically fine for development. See [Caveats: Where to Store Data on the database container documentation](https://hub.docker.com/_/mysql) re. how to make it persistent instead of ephemeral.
|
||||
Beware that this database container database keeps its state inside the container and not on the host filesystem. It is lost when you destroy (rm) this container. This is typically fine for development. See [Caveats: Where to Store Data on the database container documentation](https://hub.docker.com/_/mariadb) re. how to make it persistent instead of ephemeral.
|
||||
|
||||
Tomcat v9 is only required if you wish to deploy the Fineract WAR to a separate external servlet container. Note that you do not require to install Tomcat to develop Fineract, or to run it in production if you use the self-contained JAR, which transparently embeds a servlet container using Spring Boot. (Until FINERACT-730, Tomcat 7/8 were also supported, but now Tomcat 9 is required.)
|
||||
|
||||
@@ -46,20 +48,67 @@ Run the following commands:
|
||||
Instructions to build the JAR file
|
||||
============
|
||||
1. Clone the repository or download and extract the archive file to your local directory.
|
||||
2. Run `./gradlew clean bootJar` to build a modern cloud native fully self contained JAR file which will be created at `build/libs` directory.
|
||||
3. Start it using `java -jar build/libs/fineract-provider.jar` (does not require external Tomcat)
|
||||
2. Run `./gradlew clean bootJar` to build a modern cloud native fully self contained JAR file which will be created at `fineract-provider/build/libs` directory.
|
||||
3. As we are not allowed to include a JDBC driver in the built JAR, download a JDBC driver of your choice. For example: `wget https://downloads.mariadb.com/Connectors/java/connector-java-2.7.5/mariadb-java-client-2.7.5.jar`
|
||||
4. Start the jar and pass the directory where you have downloaded the JDBC driver as loader.path, for example: `java -Dloader.path=. -jar fineract-provider/build/libs/fineract-provider.jar` (does not require external Tomcat)
|
||||
|
||||
NOTE: we cannot upgrade to version 3.0.x of the MariaDB driver just yet; have to wait until 3.0.4 is out for a bug fix.
|
||||
|
||||
The tenants database connection details are configured [via environment variables (as with Docker container)](#instructions-to-run-using-docker-and-docker-compose), e.g. like this:
|
||||
|
||||
export fineract_tenants_pwd=verysecret
|
||||
export FINERACT_HIKARI_PASSWORD=verysecret
|
||||
...
|
||||
java -jar fineract-provider.jar
|
||||
|
||||
|
||||
Security
|
||||
============
|
||||
NOTE: The HTTP Basic and OAuth2 authentication schemes are mutually exclusive. You can't enable them both at the same time. Fineract checks these settings on startup and will fail if more than one authentication scheme is enabled.
|
||||
|
||||
HTTP Basic Authentication
|
||||
------------
|
||||
By default Fineract is configured with a HTTP Basic Authentication scheme, so you actually don't have to do anything if you want to use it. But if you would like to explicitly choose this authentication scheme then there are two ways to enable it:
|
||||
1. Use environment variables (best choice if you run with Docker Compose):
|
||||
```
|
||||
FINERACT_SECURITY_BASICAUTH_ENABLED=true
|
||||
FINERACT_SECURITY_OAUTH_ENABLED=false
|
||||
```
|
||||
2. Use JVM parameters (best choice if you run the Spring Boot JAR):
|
||||
```
|
||||
java -Dfineract.security.basicauth.enabled=true -Dfineract.security.oauth.enabled=false -jar fineract-provider.jar
|
||||
```
|
||||
|
||||
OAuth2 Authentication
|
||||
------------
|
||||
There is also an OAuth2 authentication scheme available. Again, two ways to enable it:
|
||||
1. Use environment variables (best choice if you run with Docker Compose):
|
||||
```
|
||||
FINERACT_SECURITY_BASICAUTH_ENABLED=false
|
||||
FINERACT_SECURITY_OAUTH_ENABLED=true
|
||||
```
|
||||
2. Use JVM parameters (best choice if you run the Spring Boot JAR):
|
||||
```
|
||||
java -Dfineract.security.basicauth.enabled=false -Dfineract.security.oauth.enabled=true -jar fineract-provider.jar
|
||||
```
|
||||
|
||||
Two Factor Authentication
|
||||
------------
|
||||
You can also enable 2FA authentication. Depending on how you start Fineract add the following:
|
||||
|
||||
1. Use environment variable (best choice if you run with Docker Compose):
|
||||
```
|
||||
FINERACT_SECURITY_2FA_ENABLED=true
|
||||
```
|
||||
2. Use JVM parameter (best choice if you run the Spring Boot JAR):
|
||||
```
|
||||
-Dfineract.security.2fa.enabled=true
|
||||
```
|
||||
|
||||
|
||||
Instructions to build a WAR file
|
||||
============
|
||||
1. Clone the repository or download and extract the archive file to your local directory.
|
||||
2. Run `./gradlew clean war` to build a traditional WAR file which will be created at `build/libs` directory.
|
||||
2. Run `./gradlew :fineract-war:clean :fineract-war:war` to build a traditional WAR file which will be created at `fineract-war/build/libs` directory.
|
||||
3. Deploy this WAR to your Tomcat v9 Servlet Container.
|
||||
|
||||
We recommend using the JAR instead of the WAR file deployment, because it's much easier.
|
||||
@@ -83,10 +132,13 @@ Instructions to run and debug in Eclipse IDE
|
||||
It is possible to run Fineract in Eclipse IDE and also to debug Fineract using Eclipse's debugging facilities.
|
||||
To do this, you need to create the Eclipse project files and import the project into an Eclipse workspace:
|
||||
|
||||
1. Import the fineract-provider project into your Eclipse workspace (File->Import->Gradle->Existing Gradle Project into Workspace, choose root directory fineract/fineract-provider)
|
||||
2. Do a clean build of the project in Eclipse (Project->Clean...)
|
||||
1. Create Eclipse project files into the Fineract project by running `./gradlew cleanEclipse eclipse`
|
||||
2. Import the fineract-provider project into your Eclipse workspace (File->Import->General->Existing Projects into Workspace, choose root directory fineract/fineract-provider)
|
||||
3. Do a clean build of the project in Eclipse (Project->Clean...)
|
||||
3. Run / debug Fineract by right clicking on org.apache.fineract.ServerApplication class and choosing Run As / Debug As -> Java Application. All normal Eclipse debugging features (breakpoints, watchpoints etc) should work as expected.
|
||||
|
||||
If you change the project settings (dependencies etc) in Gradle, you should redo step 1 and refresh the project in Eclipse.
|
||||
|
||||
You can also use Eclipse Junit support to run tests in Eclipse (Run As->Junit Test)
|
||||
|
||||
Finally, modifying source code in Eclipse automatically triggers hot code replace to a running instance, allowing you to immediately test your changes
|
||||
@@ -111,7 +163,8 @@ Alternatively, you can also use [Podman](https://github.com/containers/libpod)
|
||||
Now to run a new Fineract instance you can simply:
|
||||
|
||||
1. `git clone https://github.com/apache/fineract.git ; cd fineract`
|
||||
1. `docker-compose build`
|
||||
1. for windows, use `git clone https://github.com/apache/fineract.git --config core.autocrlf=input ; cd fineract`
|
||||
1. `./gradlew :fineract-provider:jibDockerBuild -x test`
|
||||
1. `docker-compose up -d`
|
||||
1. fineract (back-end) is running at https://localhost:8443/fineract-provider/
|
||||
1. wait for https://localhost:8443/fineract-provider/actuator/health to return `{"status":"UP"}`
|
||||
@@ -119,8 +172,6 @@ Now to run a new Fineract instance you can simply:
|
||||
1. community-app (UI) is running at http://localhost:9090/?baseApiUrl=https://localhost:8443/fineract-provider&tenantIdentifier=default
|
||||
1. login using default _username_ `mifos` and _password_ `password`
|
||||
|
||||
The [`docker-compose.yml`](docker-compose.yml) will build the `fineract` container from the source based on the [`Dockerfile`](Dockerfile). You could change that to use the pre-built container image instead of having to re-build it.
|
||||
|
||||
https://hub.docker.com/r/apache/fineract has a pre-built container image of this project, built continuously.
|
||||
|
||||
You must specify the MySQL tenants database JDBC URL by passing it to the `fineract` container via environment
|
||||
@@ -130,6 +181,28 @@ _(Note that in previous versions, the `mysqlserver` environment variable used at
|
||||
and the `mysqlserver` environment variable is now no longer supported.)_
|
||||
|
||||
|
||||
Connection pool configuration
|
||||
=============================
|
||||
|
||||
Please check `application.properties` to see which connection pool settings can be tweaked. The associated environment variables are prefixed with `FINERACT_HIKARI_*`. You can find more information about specific connection pool settings (Hikari) at https://github.com/brettwooldridge/HikariCP#configuration-knobs-baby
|
||||
|
||||
NOTE: we'll keep backwards compatibility until one of the next releases to ensure that things are working as expected. Environment variables prefixed `fineract_tenants_*` can still be used to configure the database connection, but we strongly encourage using `FINERACT_HIKARI_*` with more options.
|
||||
|
||||
SSL configuration
|
||||
=================
|
||||
|
||||
Read also [the HTTPS related doc](fineract-doc/src/docs/en/deployment.adoc#https).
|
||||
|
||||
By default SSL is enabled, but all SSL related properties are now tunable. SSL can be turned off by setting the environment variable `FINERACT_SERVER_SSL_ENABLED` to false. If you do that then please make sure to also change the server port to `8080` via the variable `FINERACT_SERVER_PORT`, just for the sake of keeping the conventions.
|
||||
You can choose now easily a different SSL keystore by setting `FINERACT_SERVER_SSL_KEY_STORE` with a path to a different (not embedded) keystore. The password can be set via `FINERACT_SERVER_SSL_KEY_STORE_PASSWORD`. See the `application.properties` file and the latest Spring Boot documentation (https://docs.spring.io/spring-boot/docs/current/reference/html/application-properties.html) for more details.
|
||||
|
||||
|
||||
Tomcat configuration
|
||||
====================
|
||||
|
||||
Please refer to the `application.properties` and the official Spring Boot documentation (https://docs.spring.io/spring-boot/docs/current/reference/html/application-properties.html) on how to do performance tuning for Tomcat. Note: you can set now the acceptable form POST size (default is 2MB) via environment variable `FINERACT_SERVER_TOMCAT_MAX_HTTP_FORM_POST_SIZE`.
|
||||
|
||||
|
||||
Instructions to run on Kubernetes
|
||||
=================================
|
||||
|
||||
@@ -253,11 +326,11 @@ License
|
||||
This project is licensed under Apache License Version 2.0. See <https://github.com/apache/incubator-fineract/blob/develop/LICENSE.md> for reference.
|
||||
|
||||
The Connector/J JDBC Driver client library from MariaDB.org, which is licensed under the LGPL,
|
||||
is used in development when running integration tests that use the Flyway library. That JDBC
|
||||
is used in development when running integration tests that use the Liquibase library. That JDBC
|
||||
driver is however not included in and distributed with the Fineract product and is not
|
||||
required to use the product.
|
||||
If you are developer and object to using the LGPL licensed Connector/J JDBC driver,
|
||||
simply do not run the integration tests that use the Flyway library.
|
||||
simply do not run the integration tests that use the Liquibase library and/or use another JDBC driver.
|
||||
As discussed in [LEGAL-462](https://issues.apache.org/jira/browse/LEGAL-462), this project therefore
|
||||
complies with the [Apache Software Foundation third-party license policy](https://www.apache.org/legal/resolved.html).
|
||||
|
||||
@@ -391,7 +464,7 @@ Releasing
|
||||
|
||||
Before you use Gradle to create a release you need to make sure that you provide the proper GPG parameters. You have to options:
|
||||
|
||||
1. Provide the parameters via ~/gradle/gradle.properties in your home folder:
|
||||
1. Provide the parameters via ~/.gradle/gradle.properties in your home folder:
|
||||
```
|
||||
signing.gnupg.keyName=7890ABCD
|
||||
signing.gnupg.passphrase=secret
|
||||
@@ -413,23 +486,23 @@ NOTE: Let's assume your GPG key ID would be "ABCDEFGHIJKLMNOPQRSTUVWXYZ123456789
|
||||
|
||||
Above tasks will create the following files in folder build/distributions:
|
||||
|
||||
- binary distribution file: apache-fineract-1.4.0-binary.tar.gz
|
||||
- ASCII armored signature for binary distribution: apache-fineract-1.4.0-binary.tar.gz.asc
|
||||
- SHA512 checksum for binary distribution: apache-fineract-1.4.0-binary.tar.gz.sha512
|
||||
- source distribution file: apache-fineract-1.4.0-src.tar.gz
|
||||
- ASCII armored signature for source distribution: apache-fineract-1.4.0-src.tar.gz.asc
|
||||
- SHA512 checksum for source distribution: apache-fineract-1.4.0-src.tar.gz.sha512
|
||||
- binary distribution file: apache-fineract-1.6.0-binary.tar.gz
|
||||
- ASCII armored signature for binary distribution: apache-fineract-1.6.0-binary.tar.gz.asc
|
||||
- SHA512 checksum for binary distribution: apache-fineract-1.6.0-binary.tar.gz.sha512
|
||||
- source distribution file: apache-fineract-1.6.0-src.tar.gz
|
||||
- ASCII armored signature for source distribution: apache-fineract-1.6.0-src.tar.gz.asc
|
||||
- SHA512 checksum for source distribution: apache-fineract-1.6.0-src.tar.gz.sha512
|
||||
|
||||
The signatures are automatically verified by the build script. It will throw an exception if the verification fails.
|
||||
|
||||
Additionally, you can verify the validity of the release distribution files e. g. with:
|
||||
```
|
||||
gpg --verify build/distributions/apache-fineract-1.4.0-binary.tar.gz.asc
|
||||
gpg --verify build/distributions/apache-fineract-1.6.0-binary.tar.gz.asc
|
||||
```
|
||||
|
||||
The output should look somewhat like this:
|
||||
```
|
||||
gpg: assuming signed data in 'build/distributions/apache-fineract-1.4.0-binary.tgz'
|
||||
gpg: assuming signed data in 'build/distributions/apache-fineract-1.6.0-binary.tgz'
|
||||
gpg: Signature made Mi 26 Aug 2020 17:17:45 CEST
|
||||
gpg: using RSA key ABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890ABCD
|
||||
gpg: Good signature from "Aleksandar Vidakovic (Apache Fineract Release Manager) <aleks@apache.org>" [ultimate]
|
||||
|
||||
+136
-98
@@ -19,15 +19,17 @@
|
||||
// TODO: this is work in progress, please follow FINERACT-1171
|
||||
buildscript {
|
||||
ext {
|
||||
jacocoVersion = '0.8.6'
|
||||
jacocoVersion = '0.8.7'
|
||||
retrofitVersion = '2.9.0'
|
||||
okhttpVersion = '4.9.0'
|
||||
okhttpVersion = '4.9.3'
|
||||
oltuVersion = '1.0.1'
|
||||
fineractJavaProjects = subprojects.findAll{
|
||||
[
|
||||
'fineract-api',
|
||||
'fineract-provider',
|
||||
'integration-tests',
|
||||
'twofactor-tests',
|
||||
'oauth2-tests',
|
||||
'fineract-client'
|
||||
].contains(it.name)
|
||||
}
|
||||
@@ -38,66 +40,80 @@ buildscript {
|
||||
}
|
||||
}
|
||||
repositories {
|
||||
jcenter()
|
||||
maven { url "https://plugins.gradle.org/m2/" }
|
||||
}
|
||||
|
||||
dependencies {
|
||||
classpath 'com.bmuschko:gradle-cargo-plugin:2.8.0'
|
||||
classpath 'org.apache.openjpa:openjpa:3.1.2' // when upgrading, also change OpenJPA version repeated in fineract-provider/build.gradle!
|
||||
classpath 'com.radcortez.gradle:openjpa-gradle-plugin:3.1.0'
|
||||
classpath 'gradle.plugin.com.github.spotbugs.snom:spotbugs-gradle-plugin:4.6.0'
|
||||
classpath 'gradle.plugin.com.github.andygoossens:gradle-modernizer-plugin:1.3.0'
|
||||
classpath 'com.bmuschko:gradle-cargo-plugin:2.9.0'
|
||||
classpath 'org.eclipse.persistence:eclipselink:2.7.10'
|
||||
classpath 'jakarta.ws.rs:jakarta.ws.rs-api:2.1.6'
|
||||
classpath 'com.google.cloud.tools:jib-layer-filter-extension-gradle:0.1.0'
|
||||
}
|
||||
}
|
||||
|
||||
plugins {
|
||||
id 'io.spring.dependency-management' version '1.0.11.RELEASE'
|
||||
id 'com.diffplug.spotless' version '5.9.0' apply false
|
||||
id "org.barfuin.gradle.taskinfo" version "1.3.1"
|
||||
id 'com.adarshr.test-logger' version '3.2.0'
|
||||
id 'com.diffplug.spotless' version '6.3.0' apply false
|
||||
id 'org.nosphere.apache.rat' version '0.7.0' apply false
|
||||
id 'com.github.hierynomus.license' version '0.15.0' apply false
|
||||
id 'com.github.hierynomus.license' version '0.16.1' apply false
|
||||
id 'com.github.jk1.dependency-license-report' version '2.1' apply false
|
||||
id 'org.openapi.generator' version '4.3.1' apply false
|
||||
id 'org.zeroturnaround.gradle.jrebel' version '1.1.10' apply false
|
||||
id 'org.springframework.boot' version '2.3.5.RELEASE' apply false
|
||||
id 'net.ltgt.errorprone' version '1.3.0' apply false
|
||||
id 'io.swagger.core.v3.swagger-gradle-plugin' version '2.1.6' apply false
|
||||
id 'com.gorylenko.gradle-git-properties' version '2.2.4' apply false
|
||||
id 'org.asciidoctor.jvm.convert' version '3.3.0' apply false
|
||||
id 'org.asciidoctor.jvm.pdf' version '3.3.0' apply false
|
||||
id 'org.asciidoctor.jvm.epub' version '3.3.0' apply false
|
||||
id 'org.asciidoctor.jvm.revealjs' version '3.3.0' apply false
|
||||
id 'org.asciidoctor.jvm.gems' version '3.3.0' apply false
|
||||
id 'org.zeroturnaround.gradle.jrebel' version '1.1.11' apply false
|
||||
id 'org.springframework.boot' version '2.6.4' apply false
|
||||
id 'net.ltgt.errorprone' version '2.0.2' apply false
|
||||
id 'io.swagger.core.v3.swagger-gradle-plugin' version '2.1.13' apply false
|
||||
id 'com.gorylenko.gradle-git-properties' version '2.4.0' apply false
|
||||
id 'org.asciidoctor.jvm.convert' version '3.3.2' apply false
|
||||
id 'org.asciidoctor.jvm.pdf' version '3.3.2' apply false
|
||||
id 'org.asciidoctor.jvm.epub' version '3.3.2' apply false
|
||||
id 'org.asciidoctor.jvm.revealjs' version '3.3.2' apply false
|
||||
id 'org.asciidoctor.jvm.gems' version '3.3.2' apply false
|
||||
id 'org.asciidoctor.kindlegen.base' version '3.2.0' apply false
|
||||
id "com.google.cloud.tools.jib" version "3.2.0" apply false
|
||||
id 'fr.brouillard.oss.gradle.jgitver' version '0.10.0-rc03'
|
||||
id "org.sonarqube" version "3.3"
|
||||
id "com.github.andygoossens.modernizer" version "1.6.2" apply false
|
||||
id 'com.github.spotbugs' version '5.0.6' apply false
|
||||
}
|
||||
|
||||
description = '''\
|
||||
Run as:
|
||||
gradle clean bootRun'''
|
||||
|
||||
project.ext.jerseyVersion = '1.19.4'
|
||||
ext['groovy.version'] = '3.0.6'
|
||||
ext['swaggerFile'] = "$rootDir/fineract-provider/build/classes/java/main/static/swagger-ui/fineract.yaml".toString()
|
||||
ext['swaggerFile'] = "$rootDir/fineract-provider/build/generated/swagger-ui/fineract.yaml".toString()
|
||||
|
||||
allprojects {
|
||||
group = 'org.apache.fineract'
|
||||
|
||||
jgitver {
|
||||
strategy 'PATTERN'
|
||||
versionPattern '${M}.${m}.${p}-${meta.GIT_SHA1_8}'
|
||||
// versionPattern '${v}'
|
||||
}
|
||||
|
||||
repositories {
|
||||
jcenter()
|
||||
mavenCentral()
|
||||
}
|
||||
|
||||
apply plugin: 'io.spring.dependency-management'
|
||||
apply plugin: 'com.adarshr.test-logger'
|
||||
apply plugin: 'com.diffplug.spotless'
|
||||
apply plugin: 'com.github.hierynomus.license'
|
||||
apply plugin: 'org.nosphere.apache.rat'
|
||||
apply plugin: 'project-report'
|
||||
apply plugin: 'com.github.jk1.dependency-license-report'
|
||||
|
||||
// Configuration for the dependency management plugin
|
||||
// https://github.com/spring-gradle-plugins/dependency-management-plugin
|
||||
dependencyManagement {
|
||||
imports {
|
||||
mavenBom 'org.springframework:spring-framework-bom:5.3.3'
|
||||
mavenBom 'org.springframework.boot:spring-boot-dependencies:2.3.5.RELEASE'
|
||||
mavenBom 'org.junit:junit-bom:5.7.0'
|
||||
mavenBom 'org.springframework:spring-framework-bom:5.3.16'
|
||||
mavenBom 'org.springframework.boot:spring-boot-dependencies:2.6.4'
|
||||
mavenBom 'org.junit:junit-bom:5.8.2'
|
||||
mavenBom 'com.fasterxml.jackson:jackson-bom:2.13.2'
|
||||
}
|
||||
|
||||
dependencies {
|
||||
@@ -105,37 +121,38 @@ allprojects {
|
||||
// We do not use :+ to get the latest available version available on Maven Central, as that could suddenly break things.
|
||||
// We use the Renovate Bot to automatically propose Pull Requests (PRs) when upgrades for all of these versions are available.
|
||||
|
||||
dependency 'org.springframework.security.oauth:spring-security-oauth2:2.5.0.RELEASE'
|
||||
dependency 'org.apache.openjpa:openjpa:3.1.2' // when upgrading, also change OpenJPA version repeated above in buildscript!
|
||||
dependency 'com.google.guava:guava:30.1-jre'
|
||||
dependency 'com.google.code.gson:gson:2.8.6'
|
||||
dependency 'org.eclipse.persistence:org.eclipse.persistence.jpa:2.7.10'
|
||||
dependency 'com.google.guava:guava:31.1-jre'
|
||||
dependency 'com.google.code.gson:gson:2.9.0'
|
||||
dependency 'com.google.truth:truth:1.1.3'
|
||||
dependency 'com.google.truth.extensions:truth-java8-extension:1.1.3'
|
||||
dependency 'org.apache.commons:commons-email:1.5'
|
||||
dependency 'commons-io:commons-io:2.8.0'
|
||||
dependency 'org.drizzle.jdbc:drizzle-jdbc:1.4'
|
||||
dependency 'com.github.librepdf:openpdf:1.3.24'
|
||||
dependency 'org.mnode.ical4j:ical4j:3.0.21'
|
||||
dependency 'commons-io:commons-io:2.11.0'
|
||||
dependency 'com.github.librepdf:openpdf:1.3.27'
|
||||
dependency 'org.mnode.ical4j:ical4j:3.2.1'
|
||||
dependency 'org.quartz-scheduler:quartz:2.3.2'
|
||||
dependency 'com.amazonaws:aws-java-sdk-s3:1.11.934'
|
||||
dependency 'org.ehcache:ehcache:3.9.0'
|
||||
dependency 'com.github.spullara.mustache.java:compiler:0.9.7'
|
||||
dependency 'com.jayway.jsonpath:json-path:2.5.0'
|
||||
dependency 'org.apache.tika:tika-core:1.25'
|
||||
dependency 'com.amazonaws:aws-java-sdk-s3:1.12.179'
|
||||
dependency 'org.ehcache:ehcache:3.10.0'
|
||||
dependency 'com.github.spullara.mustache.java:compiler:0.9.10'
|
||||
dependency 'com.jayway.jsonpath:json-path:2.7.0'
|
||||
dependency 'org.apache.tika:tika-core:2.3.0'
|
||||
dependency 'org.apache.httpcomponents:httpclient:4.5.13'
|
||||
dependency 'io.swagger.core.v3:swagger-annotations:2.1.6'
|
||||
dependency 'io.swagger.core.v3:swagger-annotations:2.1.13'
|
||||
dependency 'jakarta.management.j2ee:jakarta.management.j2ee-api:1.1.4'
|
||||
dependency 'jakarta.jms:jakarta.jms-api:2.0.3'
|
||||
dependency 'jakarta.xml.bind:jakarta.xml.bind-api:2.3.3'
|
||||
dependency 'jakarta.validation:jakarta.validation-api:3.0.0'
|
||||
dependency 'org.apache.activemq:activemq-broker:5.16.1'
|
||||
dependency 'jakarta.xml.bind:jakarta.xml.bind-api:2.3.3' // Swagger needs exactly this version
|
||||
dependency 'org.glassfish.jaxb:jaxb-runtime:2.3.6' // Swagger needs exactly this version
|
||||
dependency 'org.apache.activemq:activemq-broker:5.16.4'
|
||||
dependency 'org.apache.bval:org.apache.bval.bundle:2.0.5'
|
||||
|
||||
dependency 'io.github.classgraph:classgraph:4.8.90'
|
||||
dependency 'org.awaitility:awaitility:4.0.3'
|
||||
dependency 'com.github.spotbugs:spotbugs-annotations:4.2.0'
|
||||
dependency 'io.github.classgraph:classgraph:4.8.141'
|
||||
dependency 'org.awaitility:awaitility:4.2.0'
|
||||
dependency 'com.github.spotbugs:spotbugs-annotations:4.6.0'
|
||||
dependency 'javax.cache:cache-api:1.1.1'
|
||||
dependency 'org.mock-server:mockserver-junit-jupiter:5.11.2'
|
||||
dependency 'org.webjars.npm:swagger-ui-dist:3.40.0'
|
||||
dependency 'org.webjars:webjars-locator-core:0.46'
|
||||
dependency 'org.mock-server:mockserver-junit-jupiter:5.12.0'
|
||||
dependency 'org.webjars.npm:swagger-ui-dist:4.6.2'
|
||||
dependency 'org.webjars:webjars-locator-core:0.50'
|
||||
dependency 'com.icegreen:greenmail-junit5:1.6.7'
|
||||
|
||||
// fineract client dependencies
|
||||
dependency "com.squareup.retrofit2:retrofit:$retrofitVersion"
|
||||
@@ -163,18 +180,16 @@ allprojects {
|
||||
dependency "com.squareup.okhttp3:okhttp-urlconnection:$okhttpVersion"
|
||||
dependency "com.squareup.okhttp3:okhttp-sse:$okhttpVersion"
|
||||
dependency "io.gsonfire:gson-fire:1.8.5"
|
||||
dependency "io.swagger:swagger-core:1.6.2"
|
||||
dependency "io.swagger:swagger-annotations:1.6.2"
|
||||
dependency "io.swagger:swagger-core:1.6.5"
|
||||
dependency "io.swagger:swagger-annotations:1.6.5"
|
||||
dependency "javax.annotation:javax.annotation-api:1.3.2"
|
||||
dependency "com.google.code.findbugs:jsr305:3.0.2"
|
||||
dependency "commons-codec:commons-codec:1.15"
|
||||
dependency "org.bouncycastle:bcpkix-jdk15on:1.70"
|
||||
dependency "org.bouncycastle:bcprov-jdk15on:1.70"
|
||||
|
||||
dependency ('org.flywaydb:flyway-core:7.0.0') {
|
||||
// https://issues.apache.org/jira/browse/FINERACT-1172
|
||||
// https://github.com/apache/fineract/pull/1355
|
||||
// https://github.com/flyway/flyway/issues/2957
|
||||
// exclude conflicting non-<optional> dependencies from https://github.com/flyway/flyway/blob/master/flyway-core/pom.xml
|
||||
exclude 'software.amazon.awssdk:s3'
|
||||
dependency ('org.liquibase:liquibase-core:4.8.0') {
|
||||
exclude 'javax.xml.bind:jaxb-api'
|
||||
}
|
||||
|
||||
dependency ('org.dom4j:dom4j:2.1.3') {
|
||||
@@ -184,22 +199,12 @@ allprojects {
|
||||
exclude 'pull-parser:pull-parser'
|
||||
}
|
||||
|
||||
dependencySet(group: 'com.sun.jersey', version: jerseyVersion) {
|
||||
entry 'jersey-core'
|
||||
entry 'jersey-servlet'
|
||||
entry 'jersey-server'
|
||||
entry 'jersey-json'
|
||||
}
|
||||
dependencySet(group: 'com.sun.jersey.contribs', version: jerseyVersion) {
|
||||
entry 'jersey-spring'
|
||||
entry 'jersey-multipart'
|
||||
}
|
||||
dependencySet(group: 'org.apache.poi', version: '4.1.2') {
|
||||
entry 'poi'
|
||||
entry 'poi-ooxml'
|
||||
entry 'poi-ooxml-schemas'
|
||||
}
|
||||
dependencySet(group: 'io.rest-assured', version: '4.3.0')
|
||||
dependencySet(group: 'io.rest-assured', version: '4.5.1')
|
||||
{
|
||||
entry 'rest-assured'
|
||||
entry 'json-path'
|
||||
@@ -208,12 +213,20 @@ allprojects {
|
||||
}
|
||||
}
|
||||
|
||||
// Configuration for the sonarqube plugin
|
||||
// https://docs.sonarqube.org/latest/analysis/scan/sonarscanner-for-gradle/
|
||||
sonarqube {
|
||||
properties {
|
||||
property "sonar.projectKey", "apache_fineract"
|
||||
}
|
||||
}
|
||||
|
||||
// Configuration for the spotless plugin
|
||||
// https://github.com/diffplug/spotless/tree/main/plugin-gradle
|
||||
spotless {
|
||||
format 'misc', {
|
||||
target '**/*.md', '**/*.properties', '**/.gitignore', '**/.openapi-generator-ignore', '**/*.yml', '**/*.xml', '**/**.json', '**/*.sql'
|
||||
targetExclude '**/build/**', '**/bin/**', '**/.settings/**', '**/.idea/**', '**/.gradle/**', '**/gradlew.bat'
|
||||
targetExclude '**/build/**', '**/bin/**', '**/.settings/**', '**/.idea/**', '**/.gradle/**', '**/gradlew.bat', '**/licenses/**', '**/banner.txt'
|
||||
indentWithSpaces(4)
|
||||
endWithNewline()
|
||||
trimTrailingWhitespace()
|
||||
@@ -244,6 +257,7 @@ allprojects {
|
||||
"**/keystore.jks",
|
||||
"**/static/swagger-ui/**",
|
||||
"**/api-docs/**",
|
||||
"**/banner.txt",
|
||||
])
|
||||
strictCheck true
|
||||
}
|
||||
@@ -257,8 +271,13 @@ allprojects {
|
||||
'**/gradlew*'
|
||||
])
|
||||
}
|
||||
|
||||
licenseFormat.dependsOn licenseFormatBuildScripts
|
||||
|
||||
licenseReport {
|
||||
outputDir = "$projectDir/licenses"
|
||||
}
|
||||
|
||||
// Configuration for Apache Release Audit Tool task
|
||||
// https://github.com/eskatos/creadur-rat-gradle
|
||||
rat {
|
||||
@@ -351,19 +370,19 @@ allprojects {
|
||||
configure(project.fineractJavaProjects) {
|
||||
// NOTE: order matters!
|
||||
|
||||
apply plugin: 'java-library'
|
||||
apply plugin: 'java'
|
||||
apply plugin: 'idea'
|
||||
apply plugin: 'eclipse'
|
||||
apply plugin: 'checkstyle'
|
||||
apply plugin: 'jacoco'
|
||||
apply plugin: "net.ltgt.errorprone"
|
||||
apply plugin: "com.github.spotbugs"
|
||||
apply plugin: 'com.github.andygoossens.gradle-modernizer-plugin'
|
||||
apply plugin: 'com.github.andygoossens.modernizer'
|
||||
|
||||
/* define the valid syntax level for source files */
|
||||
sourceCompatibility = JavaVersion.VERSION_11
|
||||
sourceCompatibility = JavaVersion.VERSION_17
|
||||
/* define binary compatibility version */
|
||||
targetCompatibility = JavaVersion.VERSION_11
|
||||
targetCompatibility = JavaVersion.VERSION_17
|
||||
|
||||
/* http://stackoverflow.com/questions/19653311/jpa-repository-works-in-idea-and-production-but-not-in-gradle */
|
||||
sourceSets.main.output.resourcesDir = sourceSets.main.java.outputDir
|
||||
@@ -400,27 +419,25 @@ configure(project.fineractJavaProjects) {
|
||||
"-Xlint:varargs",
|
||||
"-Xlint:preview",
|
||||
"-Xlint:static",
|
||||
"-Werror"
|
||||
]
|
||||
// TODO FINERACT-959 (gradually) enable -Xlint:all (see "javac -help -X")
|
||||
|
||||
options.deprecation = true
|
||||
|
||||
options.compilerArgs +=[
|
||||
// -Werror needs to be disabled because EclipseLink's static weaving doesn't generate warning-free code
|
||||
// and during an IntelliJ recompilation, it fails
|
||||
//"-Werror",
|
||||
"-Xmaxwarns",
|
||||
1500,
|
||||
"-Xmaxerrs",
|
||||
1500
|
||||
]
|
||||
// TODO FINERACT-959 (gradually) enable -Xlint:all (see "javac -help -X")
|
||||
|
||||
options.deprecation = true
|
||||
}
|
||||
|
||||
dependencies {
|
||||
spotbugsPlugins 'jp.skypencil.findbugs.slf4j:bug-pattern:1.5.0@jar'
|
||||
}
|
||||
|
||||
// Configuration for the spotless plugin
|
||||
// https://github.com/diffplug/spotless/tree/main/plugin-gradle
|
||||
dependencies {
|
||||
spotbugsPlugins 'jp.skypencil.findbugs.slf4j:bug-pattern:1.5.0@jar'
|
||||
spotbugs 'com.github.spotbugs:spotbugs:4.2.0'
|
||||
}
|
||||
|
||||
spotless {
|
||||
java {
|
||||
targetExclude '**/build/**', '**/bin/**', '**/out/**'
|
||||
@@ -462,9 +479,11 @@ configure(project.fineractJavaProjects) {
|
||||
lineEndings 'UNIX'
|
||||
}
|
||||
|
||||
compileJava.dependsOn spotlessCheck
|
||||
// compileJava may create more source files into generated, hence we need to run these tasks after it
|
||||
licenseMain.dependsOn compileJava
|
||||
processResources.dependsOn compileJava
|
||||
|
||||
// If we are running Gradle within Eclipse to enhance classes with OpenJPA,
|
||||
// If we are running Gradle within Eclipse to enhance classes,
|
||||
// set the classes directory to point to Eclipse's default build directory
|
||||
if (project.hasProperty('env') && project.getProperty('env') == 'eclipse') {
|
||||
sourceSets.main.java.outputDir = file("$projectDir/bin/main")
|
||||
@@ -473,8 +492,8 @@ configure(project.fineractJavaProjects) {
|
||||
// Configuration for the Checkstyle plugin
|
||||
// https://docs.gradle.org/current/userguide/checkstyle_plugin.html
|
||||
dependencies {
|
||||
checkstyle 'com.puppycrawl.tools:checkstyle:8.39'
|
||||
checkstyle 'com.github.sevntu-checkstyle:sevntu-checks:1.38.0'
|
||||
checkstyle 'com.puppycrawl.tools:checkstyle:10.0'
|
||||
checkstyle 'com.github.sevntu-checkstyle:sevntu-checks:1.41.0'
|
||||
}
|
||||
|
||||
// Configuration for JaCoCo code coverage task
|
||||
@@ -495,7 +514,7 @@ configure(project.fineractJavaProjects) {
|
||||
// Configuration for the errorprone plugin
|
||||
// https://github.com/tbroyer/gradle-errorprone-plugin
|
||||
dependencies {
|
||||
errorprone "com.google.errorprone:error_prone_core:2.5.1"
|
||||
errorprone "com.google.errorprone:error_prone_core:2.11.0"
|
||||
}
|
||||
|
||||
tasks.withType(JavaCompile) {
|
||||
@@ -513,6 +532,7 @@ configure(project.fineractJavaProjects) {
|
||||
"AlmostJavadoc",
|
||||
"InvalidBlockTag",
|
||||
"JavaUtilDate", // TODO FINERACT-1298
|
||||
"ReturnValueIgnored"
|
||||
)
|
||||
error(
|
||||
"DefaultCharset",
|
||||
@@ -556,7 +576,6 @@ configure(project.fineractJavaProjects) {
|
||||
"UnsafeFinalization",
|
||||
"JavaTimeDefaultTimeZone",
|
||||
"JodaPlusMinusLong",
|
||||
"MutableMethodReturnType",
|
||||
"SwitchDefault",
|
||||
"VarTypeName",
|
||||
"ArgumentSelectionDefectChecker",
|
||||
@@ -599,21 +618,26 @@ configure(project.fineractJavaProjects) {
|
||||
|
||||
test {
|
||||
useJUnitPlatform()
|
||||
testLogging {
|
||||
// FINERACT-927
|
||||
events "skipped", "failed"
|
||||
showStandardStreams = false
|
||||
exceptionFormat "full"
|
||||
|
||||
if (project.hasProperty('excludeTests')) {
|
||||
filter {
|
||||
excludeTestsMatching project.property('excludeTests')
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
testlogger {
|
||||
logLevel 'quiet'
|
||||
}
|
||||
|
||||
// Configuration for spotbugs plugin
|
||||
// https://github.com/spotbugs/spotbugs-gradle-plugin
|
||||
|
||||
// To generate an HTML report instead of XML
|
||||
spotbugs {
|
||||
reportLevel = 'high'
|
||||
showProgress = true
|
||||
showProgress = false
|
||||
excludeFilter = file("$rootDir/config/spotbugs/exclude.xml")
|
||||
}
|
||||
// https://github.com/spotbugs/spotbugs-gradle-plugin/issues/242
|
||||
spotbugsMain {
|
||||
@@ -644,7 +668,6 @@ configure(project.fineractJavaProjects) {
|
||||
}
|
||||
|
||||
configure(project.fineractPublishProjects) {
|
||||
apply plugin: 'maven'
|
||||
apply plugin: 'maven-publish'
|
||||
|
||||
publishing {
|
||||
@@ -683,3 +706,18 @@ configure(project.fineractPublishProjects) {
|
||||
// TODO FINERACT-1102: Actually use this to deploy to ASF (Apache Software Foundation) Nexus Maven Repository
|
||||
}
|
||||
}
|
||||
|
||||
task printSourceSetInformation() {
|
||||
doLast{
|
||||
sourceSets.each { srcSet ->
|
||||
println "["+srcSet.name+"]"
|
||||
print "-->Source directories: "+srcSet.allJava.srcDirs+"\n"
|
||||
print "-->Output directories: "+srcSet.output.classesDirs.files+"\n"
|
||||
print "-->Compile classpath:\n"
|
||||
srcSet.compileClasspath.files.each {
|
||||
print " "+it.path+"\n"
|
||||
}
|
||||
println ""
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -100,7 +100,7 @@
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_switch" value="insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.comment.align_tags_descriptions_grouped" value="false"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.comment.line_length" value="120"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.use_on_off_tags" value="false"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.use_on_off_tags" value="true"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.keep_method_body_on_one_line" value="one_line_if_empty"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_between_empty_brackets_in_array_allocation_expression" value="do not insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.keep_loop_body_block_on_one_line" value="one_line_if_empty"/>
|
||||
|
||||
@@ -0,0 +1,9 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<FindBugsFilter
|
||||
xmlns="https://github.com/spotbugs/filter/3.0.0"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="https://github.com/spotbugs/filter/3.0.0 https://raw.githubusercontent.com/spotbugs/spotbugs/3.1.0/spotbugs/etc/findbugsfilter.xsd">
|
||||
<Match>
|
||||
<Package name="~.*\.domain"/>
|
||||
</Match>
|
||||
</FindBugsFilter>
|
||||
+9
-9
@@ -1,4 +1,3 @@
|
||||
#
|
||||
# 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
|
||||
@@ -17,11 +16,12 @@
|
||||
# under the License.
|
||||
#
|
||||
|
||||
DRIVERCLASS_NAME:org.drizzle.jdbc.DrizzleDriver
|
||||
PROTOCOL:jdbc
|
||||
SUB_PROTOCOL:mysql:thin
|
||||
|
||||
fineract_tenants_driver:org.drizzle.jdbc.DrizzleDriver
|
||||
fineract_tenants_url:jdbc:mysql:thin://localhost:3306/fineract_tenants
|
||||
fineract_tenants_uid:root
|
||||
fineract_tenants_pwd:mysql
|
||||
version: '3.7'
|
||||
services:
|
||||
# Frontend service
|
||||
community-app:
|
||||
image: openmf/community-app:latest
|
||||
container_name: mifos-ui
|
||||
restart: always
|
||||
ports:
|
||||
- 9090:80
|
||||
@@ -0,0 +1,96 @@
|
||||
# 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.
|
||||
#
|
||||
|
||||
# NB: Travis CI (dist: bionic) supports up to v3.7
|
||||
# (unless we'd install a more recent version in .travis.yml)
|
||||
version: '3.7'
|
||||
services:
|
||||
# Backend service
|
||||
fineractpostgresql:
|
||||
image: postgres:14.2
|
||||
volumes:
|
||||
- ./fineract-db/docker/postgresql:/docker-entrypoint-initdb.d/:Z,ro
|
||||
restart: always
|
||||
environment:
|
||||
POSTGRES_USER: root
|
||||
POSTGRES_PASSWORD: skdcnwauicn2ucnaecasdsajdnizucawencascdca
|
||||
FINERACT_DB_USER: postgres
|
||||
FINERACT_DB_PASS: skdcnwauicn2ucnaecasdsajdnizucawencascdca
|
||||
FINERACT_TENANTS_DB_NAME: fineract_tenants
|
||||
FINERACT_TENANT_DEFAULT_DB_NAME: fineract_default
|
||||
healthcheck:
|
||||
test: [ "CMD", "pg_isready", "-q", "-d", "postgres", "-U", "root" ]
|
||||
timeout: 10s
|
||||
retries: 10
|
||||
ports:
|
||||
- "5432:5432"
|
||||
fineract-server:
|
||||
image: fineract:latest
|
||||
volumes:
|
||||
- ./fineract-provider/build/data:/data
|
||||
healthcheck:
|
||||
test: ["CMD", 'sh', '-c', 'echo -e "Checking for the availability of Fineract server deployment"; while ! nc -z "fineract-server" 8443; do sleep 1; printf "-"; done; echo -e " >> Fineract server has started";' ]
|
||||
timeout: 10s
|
||||
retries: 10
|
||||
ports:
|
||||
- 8443:8443
|
||||
depends_on:
|
||||
fineractpostgresql:
|
||||
condition: service_healthy
|
||||
environment:
|
||||
# TODO: env vars prefixed with "fineract_tenants_*" will be removed with one of the next releases
|
||||
#- fineract_tenants_driver=org.postgresql.Driver
|
||||
#- fineract_tenants_url=jdbc:postgresql://fineractpostgresql:5432/fineract_tenants
|
||||
#- fineract_tenants_uid=postgres
|
||||
#- fineract_tenants_pwd=skdcnwauicn2ucnaecasdsajdnizucawencascdca
|
||||
# NOTE: node aware scheduler
|
||||
- FINERACT_NODE_ID=1
|
||||
# NOTE: env vars prefixed "FINERACT_HIKARI_*" are used to configure the database connection pool
|
||||
- FINERACT_HIKARI_DRIVER_SOURCE_CLASS_NAME=org.postgresql.Driver
|
||||
- FINERACT_HIKARI_JDBC_URL=jdbc:postgresql://fineractpostgresql:5432/fineract_tenants
|
||||
- FINERACT_HIKARI_USERNAME=postgres
|
||||
- FINERACT_HIKARI_PASSWORD=skdcnwauicn2ucnaecasdsajdnizucawencascdca
|
||||
# ... following variables are optional; "application.properties" contains reasonable defaults (same as here)
|
||||
- FINERACT_HIKARI_MINIMUM_IDLE=3
|
||||
- FINERACT_HIKARI_MAXIMUM_POOL_SIZE=10
|
||||
- FINERACT_HIKARI_IDLE_TIMEOUT=60000
|
||||
- FINERACT_HIKARI_CONNECTION_TIMEOUT=20000
|
||||
- FINERACT_HIKARI_TEST_QUERY=SELECT 1
|
||||
- FINERACT_HIKARI_AUTO_COMMIT=true
|
||||
- FINERACT_HIKARI_DS_PROPERTIES_CACHE_PREP_STMTS=true
|
||||
- FINERACT_HIKARI_DS_PROPERTIES_PREP_STMT_CACHE_SIZE=250
|
||||
- FINERACT_HIKARI_DS_PROPERTIES_PREP_STMT_CACHE_SQL_LIMIT=2048
|
||||
- FINERACT_HIKARI_DS_PROPERTIES_USE_SERVER_PREP_STMTS=true
|
||||
- FINERACT_HIKARI_DS_PROPERTIES_USE_LOCAL_SESSION_STATE=true
|
||||
- FINERACT_HIKARI_DS_PROPERTIES_REWRITE_BATCHED_STATEMENTS=true
|
||||
- FINERACT_HIKARI_DS_PROPERTIES_CACHE_RESULT_SET_METADATA=true
|
||||
- FINERACT_HIKARI_DS_PROPERTIES_CACHE_SERVER_CONFIGURATION=true
|
||||
- FINERACT_HIKARI_DS_PROPERTIES_ELIDE_SET_AUTO_COMMITS=true
|
||||
- FINERACT_HIKARI_DS_PROPERTIES_MAINTAIN_TIME_STATS=false
|
||||
- FINERACT_HIKARI_DS_PROPERTIES_LOG_SLOW_QUERIES=true
|
||||
- FINERACT_HIKARI_DS_PROPERTIES_DUMP_QUERIES_IN_EXCEPTION=true
|
||||
# NOTE: env vars prefixed "FINERACT_DEFAULT_TENANTDB_*" are used to create the default tenant database
|
||||
- FINERACT_DEFAULT_TENANTDB_HOSTNAME=fineractpostgresql
|
||||
- FINERACT_DEFAULT_TENANTDB_PORT=5432
|
||||
- FINERACT_DEFAULT_TENANTDB_UID=postgres
|
||||
- FINERACT_DEFAULT_TENANTDB_PWD=skdcnwauicn2ucnaecasdsajdnizucawencascdca
|
||||
- FINERACT_DEFAULT_TENANTDB_CONN_PARAMS=
|
||||
- FINERACT_DEFAULT_TENANTDB_TIMEZONE=Asia/Kolkata
|
||||
- FINERACT_DEFAULT_TENANTDB_IDENTIFIER=default
|
||||
- FINERACT_DEFAULT_TENANTDB_NAME=fineract_default
|
||||
- FINERACT_DEFAULT_TENANTDB_DESCRIPTION=Default Demo Tenant
|
||||
+47
-27
@@ -22,8 +22,9 @@ version: '3.7'
|
||||
services:
|
||||
# Backend service
|
||||
fineractmysql:
|
||||
image: mysql:5.7
|
||||
image: mariadb:10.8
|
||||
volumes:
|
||||
- ./fineract-db/server_collation.cnf:/etc/mysql/conf.d/server_collation.cnf
|
||||
- ./fineract-db/docker:/docker-entrypoint-initdb.d:Z,ro
|
||||
restart: always
|
||||
environment:
|
||||
@@ -35,38 +36,57 @@ services:
|
||||
ports:
|
||||
- "3306:3306"
|
||||
fineract-server:
|
||||
build:
|
||||
context: .
|
||||
target: fineract
|
||||
image: fineract:latest
|
||||
volumes:
|
||||
- ./fineract-provider/build/data:/data
|
||||
healthcheck:
|
||||
test: ["CMD", 'sh', '-c', 'echo -e "Checking for the availability of Fineract server deployment"; while ! nc -z "fineract-server" 8443; do sleep 1; printf "-"; done; echo -e " >> Fineract server has started";' ]
|
||||
timeout: 10s
|
||||
retries: 10
|
||||
ports:
|
||||
- 8443:8443
|
||||
depends_on:
|
||||
- fineractmysql
|
||||
fineractmysql:
|
||||
condition: service_healthy
|
||||
environment:
|
||||
- DRIVERCLASS_NAME=org.drizzle.jdbc.DrizzleDriver
|
||||
- PROTOCOL=jdbc
|
||||
- SUB_PROTOCOL=mysql:thin
|
||||
- fineract_tenants_driver=org.drizzle.jdbc.DrizzleDriver
|
||||
- fineract_tenants_url=jdbc:mysql:thin://fineractmysql:3306/fineract_tenants
|
||||
- fineract_tenants_uid=root
|
||||
- fineract_tenants_pwd=skdcnwauicn2ucnaecasdsajdnizucawencascdca
|
||||
# TODO: env vars prefixed with "fineract_tenants_*" will be removed with one of the next releases
|
||||
#- fineract_tenants_driver=org.mariadb.jdbc.Driver
|
||||
#- fineract_tenants_url=jdbc:mariadb://fineractmysql:3306/fineract_tenants
|
||||
#- fineract_tenants_uid=root
|
||||
#- fineract_tenants_pwd=skdcnwauicn2ucnaecasdsajdnizucawencascdca
|
||||
# NOTE: node aware scheduler
|
||||
- FINERACT_NODE_ID=1
|
||||
# NOTE: env vars prefixed "FINERACT_HIKARI_*" are used to configure the database connection pool
|
||||
- FINERACT_HIKARI_DRIVER_SOURCE_CLASS_NAME=org.mariadb.jdbc.Driver
|
||||
- FINERACT_HIKARI_JDBC_URL=jdbc:mariadb://fineractmysql:3306/fineract_tenants
|
||||
- FINERACT_HIKARI_USERNAME=root
|
||||
- FINERACT_HIKARI_PASSWORD=skdcnwauicn2ucnaecasdsajdnizucawencascdca
|
||||
# ... following variables are optional; "application.properties" contains reasonable defaults (same as here)
|
||||
- FINERACT_HIKARI_MINIMUM_IDLE=3
|
||||
- FINERACT_HIKARI_MAXIMUM_POOL_SIZE=10
|
||||
- FINERACT_HIKARI_IDLE_TIMEOUT=60000
|
||||
- FINERACT_HIKARI_CONNECTION_TIMEOUT=20000
|
||||
- FINERACT_HIKARI_TEST_QUERY=SELECT 1
|
||||
- FINERACT_HIKARI_AUTO_COMMIT=true
|
||||
- FINERACT_HIKARI_DS_PROPERTIES_CACHE_PREP_STMTS=true
|
||||
- FINERACT_HIKARI_DS_PROPERTIES_PREP_STMT_CACHE_SIZE=250
|
||||
- FINERACT_HIKARI_DS_PROPERTIES_PREP_STMT_CACHE_SQL_LIMIT=2048
|
||||
- FINERACT_HIKARI_DS_PROPERTIES_USE_SERVER_PREP_STMTS=true
|
||||
- FINERACT_HIKARI_DS_PROPERTIES_USE_LOCAL_SESSION_STATE=true
|
||||
- FINERACT_HIKARI_DS_PROPERTIES_REWRITE_BATCHED_STATEMENTS=true
|
||||
- FINERACT_HIKARI_DS_PROPERTIES_CACHE_RESULT_SET_METADATA=true
|
||||
- FINERACT_HIKARI_DS_PROPERTIES_CACHE_SERVER_CONFIGURATION=true
|
||||
- FINERACT_HIKARI_DS_PROPERTIES_ELIDE_SET_AUTO_COMMITS=true
|
||||
- FINERACT_HIKARI_DS_PROPERTIES_MAINTAIN_TIME_STATS=false
|
||||
- FINERACT_HIKARI_DS_PROPERTIES_LOG_SLOW_QUERIES=true
|
||||
- FINERACT_HIKARI_DS_PROPERTIES_DUMP_QUERIES_IN_EXCEPTION=true
|
||||
# NOTE: env vars prefixed "FINERACT_DEFAULT_TENANTDB_*" are used to create the default tenant database
|
||||
- FINERACT_DEFAULT_TENANTDB_HOSTNAME=fineractmysql
|
||||
- FINERACT_DEFAULT_TENANTDB_PORT=3306
|
||||
- FINERACT_DEFAULT_TENANTDB_UID=root
|
||||
- FINERACT_DEFAULT_TENANTDB_PWD=skdcnwauicn2ucnaecasdsajdnizucawencascdca
|
||||
- FINERACT_DEFAULT_TENANTDB_CONN_PARAMS=
|
||||
|
||||
# Frontend service
|
||||
community-app:
|
||||
image: openmf/community-app:latest
|
||||
container_name: mifos-ui
|
||||
restart: always
|
||||
ports:
|
||||
- 9090:80
|
||||
|
||||
|
||||
# https://issues.apache.org/jira/browse/FINERACT-762
|
||||
# To use an altnerative JDBC driver (which is faster, but not allowed to be default in Apache distribution)
|
||||
# replace org.drizzle.jdbc.DrizzleDriver with com.mysql.jdbc.Driver in DRIVERCLASS_NAME and fineract_tenants_driver,
|
||||
# and remove ":thin:" from SUB_PROTOCOL and fineract_tenants_url. Note that the mysql-connector-java-*.jar is already
|
||||
# bundled in the container by the Dockerfile, but just not used by default.
|
||||
- FINERACT_DEFAULT_TENANTDB_TIMEZONE=Asia/Kolkata
|
||||
- FINERACT_DEFAULT_TENANTDB_IDENTIFIER=default
|
||||
- FINERACT_DEFAULT_TENANTDB_NAME=fineract_default
|
||||
- FINERACT_DEFAULT_TENANTDB_DESCRIPTION=Default Demo Tenant
|
||||
|
||||
@@ -0,0 +1,7 @@
|
||||
This is the source of the official Apache Fineract Java Client library.
|
||||
|
||||
It is mostly autogenerated using **Swagger Codegen**, but includes a number of hand-written utility classes to aid in its usage.
|
||||
|
||||
There is some [documentation about it here](https://github.com/apache/fineract/blob/develop/fineract-doc/src/docs/en/05_client.adoc).
|
||||
|
||||
Please contribute improvements to this (a submodule of Apache Fineract) if this client library has gaps for what you need it for.
|
||||
@@ -31,7 +31,7 @@ openApiMeta {
|
||||
}
|
||||
|
||||
openApiValidate {
|
||||
inputSpec = "$swaggerFile"
|
||||
inputSpec = "file:///$swaggerFile"
|
||||
recommend = true
|
||||
}
|
||||
|
||||
@@ -40,8 +40,9 @@ task buildJavaSdk(type: org.openapitools.generator.gradle.plugin.tasks.GenerateT
|
||||
verbose = false
|
||||
validateSpec = false
|
||||
skipValidateSpec = true
|
||||
inputSpec = "$swaggerFile"
|
||||
inputSpec = "file:///$swaggerFile"
|
||||
outputDir = "$buildDir/generated/java".toString()
|
||||
templateDir = "$rootDir/fineract-client/src/main/resources/java/template/"
|
||||
groupId = 'org.apache.fineract'
|
||||
apiPackage = 'org.apache.fineract.client.services'
|
||||
invokerPackage = 'org.apache.fineract.client'
|
||||
@@ -57,9 +58,14 @@ task buildJavaSdk(type: org.openapitools.generator.gradle.plugin.tasks.GenerateT
|
||||
ignoreFileOverride = "$projectDir/.openapi-generator-ignore"
|
||||
// trick to make sure fineract.yaml is generated first
|
||||
dependsOn = [
|
||||
':fineract-provider:compileJava'
|
||||
':fineract-provider:resolve'
|
||||
]
|
||||
finalizedBy = [licenseFormat]
|
||||
// uncomment below block to automatically copy the custom files in generated SDK
|
||||
/*copy {
|
||||
from file('src/main/java')
|
||||
into file("$buildDir/generated/java/src/main/java")
|
||||
}*/
|
||||
}
|
||||
|
||||
task buildTypescriptAngularSdk(type: org.openapitools.generator.gradle.plugin.tasks.GenerateTask){
|
||||
@@ -67,7 +73,7 @@ task buildTypescriptAngularSdk(type: org.openapitools.generator.gradle.plugin.ta
|
||||
verbose = false
|
||||
validateSpec = false
|
||||
skipValidateSpec = true
|
||||
inputSpec = "$swaggerFile"
|
||||
inputSpec = "file:///$swaggerFile"
|
||||
outputDir = "$buildDir/generated/typescript".toString()
|
||||
apiPackage = 'org.apache.fineract.client.services'
|
||||
invokerPackage = 'org.apache.fineract.client'
|
||||
@@ -78,6 +84,9 @@ task buildTypescriptAngularSdk(type: org.openapitools.generator.gradle.plugin.ta
|
||||
ngVersion: '10.0.0',
|
||||
npmName: 'apache-fineract-client'
|
||||
]
|
||||
dependsOn = [
|
||||
':fineract-provider:resolve'
|
||||
]
|
||||
finalizedBy = [licenseFormat]
|
||||
}
|
||||
|
||||
@@ -93,7 +102,7 @@ sourceSets {
|
||||
}
|
||||
|
||||
java {
|
||||
// keep this at Java 8, not 11; see https://issues.apache.org/jira/browse/FINERACT-1214
|
||||
// keep this at Java 8, not 17; see https://issues.apache.org/jira/browse/FINERACT-1214
|
||||
sourceCompatibility = JavaVersion.VERSION_1_8
|
||||
targetCompatibility = JavaVersion.VERSION_1_8
|
||||
}
|
||||
@@ -112,10 +121,13 @@ tasks.withType(JavaCompile) {
|
||||
}
|
||||
|
||||
configurations {
|
||||
generatedCompile.extendsFrom implementation
|
||||
generatedRuntime.extendsFrom runtime
|
||||
generatedCompileClasspath.extendsFrom implementation
|
||||
generatedRuntimeClasspath.extendsFrom runtimeClasspath
|
||||
}
|
||||
|
||||
test {
|
||||
useJUnitPlatform()
|
||||
}
|
||||
|
||||
// Gradle 7.x asks for explicit dependencies between tasks
|
||||
licenseFormatBuildScripts.dependsOn spotlessGroovyGradle, spotlessJava, spotlessMisc, compileJava, processResources, compileGeneratedJava, compileTestJava, rat, test
|
||||
|
||||
@@ -36,11 +36,11 @@ dependencies {
|
||||
}
|
||||
|
||||
testImplementation(
|
||||
'org.junit.jupiter:junit-jupiter-api:5.7.0',
|
||||
'com.google.truth:truth:1.1.1',
|
||||
'com.google.truth.extensions:truth-java8-extension:1.1.1'
|
||||
'org.junit.jupiter:junit-jupiter-api',
|
||||
'com.google.truth:truth',
|
||||
'com.google.truth.extensions:truth-java8-extension'
|
||||
)
|
||||
testRuntimeOnly(
|
||||
'org.junit.jupiter:junit-jupiter-engine:5.7.0'
|
||||
'org.junit.jupiter:junit-jupiter-engine'
|
||||
)
|
||||
}
|
||||
|
||||
@@ -28,6 +28,7 @@ import javax.net.ssl.SSLContext;
|
||||
import javax.net.ssl.SSLSocketFactory;
|
||||
import javax.net.ssl.TrustManager;
|
||||
import javax.net.ssl.X509TrustManager;
|
||||
import okhttp3.HttpUrl;
|
||||
import okhttp3.OkHttpClient;
|
||||
import okhttp3.logging.HttpLoggingInterceptor;
|
||||
import okhttp3.logging.HttpLoggingInterceptor.Level;
|
||||
@@ -105,6 +106,7 @@ import org.apache.fineract.client.services.ReportsApi;
|
||||
import org.apache.fineract.client.services.RolesApi;
|
||||
import org.apache.fineract.client.services.RunReportsApi;
|
||||
import org.apache.fineract.client.services.SavingsAccountApi;
|
||||
import org.apache.fineract.client.services.SavingsAccountTransactionsApi;
|
||||
import org.apache.fineract.client.services.SavingsChargesApi;
|
||||
import org.apache.fineract.client.services.SavingsProductApi;
|
||||
import org.apache.fineract.client.services.SchedulerApi;
|
||||
@@ -157,6 +159,7 @@ public final class FineractClient {
|
||||
// Matching org.apache.fineract.client.util.JSON.LocalDateTypeAdapter.formatter
|
||||
public static final String DATE_FORMAT = "yyyy-MM-dd";
|
||||
|
||||
private final OkHttpClient okHttpClient;
|
||||
private final Retrofit retrofit;
|
||||
|
||||
public final AccountingClosureApi glClosures;
|
||||
@@ -233,6 +236,7 @@ public final class FineractClient {
|
||||
public final SavingsAccountApi savingsAccounts;
|
||||
public final SavingsChargesApi savingsAccountCharges;
|
||||
public final SavingsProductApi savingsProducts;
|
||||
public final SavingsAccountTransactionsApi savingsTransactions;
|
||||
public final SchedulerApi jobsScheduler;
|
||||
public final ScoreCardApi surveyScorecards;
|
||||
public final SearchApiApi search;
|
||||
@@ -264,7 +268,8 @@ public final class FineractClient {
|
||||
public final UsersApi users;
|
||||
public final WorkingDaysApi workingDays;
|
||||
|
||||
private FineractClient(Retrofit retrofit) {
|
||||
private FineractClient(OkHttpClient okHttpClient, Retrofit retrofit) {
|
||||
this.okHttpClient = okHttpClient;
|
||||
this.retrofit = retrofit;
|
||||
|
||||
glClosures = retrofit.create(AccountingClosureApi.class);
|
||||
@@ -341,6 +346,7 @@ public final class FineractClient {
|
||||
savingsAccounts = retrofit.create(SavingsAccountApi.class);
|
||||
savingsAccountCharges = retrofit.create(SavingsChargesApi.class);
|
||||
savingsProducts = retrofit.create(SavingsProductApi.class);
|
||||
savingsTransactions = retrofit.create(SavingsAccountTransactionsApi.class);
|
||||
jobsScheduler = retrofit.create(SchedulerApi.class);
|
||||
surveyScorecards = retrofit.create(ScoreCardApi.class);
|
||||
search = retrofit.create(SearchApiApi.class);
|
||||
@@ -377,6 +383,14 @@ public final class FineractClient {
|
||||
return new Builder();
|
||||
}
|
||||
|
||||
public OkHttpClient okHttpClient() {
|
||||
return this.okHttpClient;
|
||||
}
|
||||
|
||||
public HttpUrl baseURL() {
|
||||
return this.retrofit.baseUrl();
|
||||
}
|
||||
|
||||
/**
|
||||
* Create an implementation of the API endpoints defined by the {@code service} interface, using
|
||||
* {@link Retrofit#create(Class)}. This method is typically not required to be invoked for standard API usage, but
|
||||
@@ -480,9 +494,10 @@ public final class FineractClient {
|
||||
basicAuth.setCredentials(has("username", username), has("password", password));
|
||||
okBuilder.addInterceptor(basicAuth);
|
||||
|
||||
retrofitBuilder.client(okBuilder.build());
|
||||
OkHttpClient okHttpClient = okBuilder.build();
|
||||
retrofitBuilder.client(okHttpClient);
|
||||
|
||||
return new FineractClient(retrofitBuilder.build());
|
||||
return new FineractClient(okHttpClient, retrofitBuilder.build());
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -0,0 +1,218 @@
|
||||
{{!
|
||||
/**
|
||||
* 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.
|
||||
*/
|
||||
}}
|
||||
apply plugin: 'idea'
|
||||
apply plugin: 'eclipse'
|
||||
|
||||
group = '{{groupId}}'
|
||||
version = '{{artifactVersion}}'
|
||||
|
||||
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()
|
||||
}
|
||||
|
||||
|
||||
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 {
|
||||
{{#java8}}
|
||||
sourceCompatibility JavaVersion.VERSION_1_8
|
||||
targetCompatibility JavaVersion.VERSION_1_8
|
||||
{{/java8}}
|
||||
{{^java8}}
|
||||
sourceCompatibility JavaVersion.VERSION_1_7
|
||||
targetCompatibility JavaVersion.VERSION_1_7
|
||||
{{/java8}}
|
||||
}
|
||||
|
||||
// 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:jsr250-api:1.0'
|
||||
}
|
||||
}
|
||||
|
||||
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'
|
||||
|
||||
{{#java8}}
|
||||
sourceCompatibility = JavaVersion.VERSION_1_8
|
||||
targetCompatibility = JavaVersion.VERSION_1_8
|
||||
{{/java8}}
|
||||
{{^java8}}
|
||||
sourceCompatibility = JavaVersion.VERSION_1_7
|
||||
targetCompatibility = JavaVersion.VERSION_1_7
|
||||
{{/java8}}
|
||||
|
||||
install {
|
||||
repositories.mavenInstaller {
|
||||
pom.artifactId = '{{artifactId}}'
|
||||
}
|
||||
}
|
||||
|
||||
task execute(type:JavaExec) {
|
||||
main = System.getProperty('mainClass')
|
||||
classpath = sourceSets.main.runtimeClasspath
|
||||
}
|
||||
}
|
||||
|
||||
ext {
|
||||
oltu_version = "1.0.1"
|
||||
retrofit_version = "2.9.0"
|
||||
okhttp3_version = "4.9.0"
|
||||
{{#usePlayWS}}
|
||||
jackson_version = "2.10.5"
|
||||
jackson_databind_version = "2.10.5.1"
|
||||
{{#openApiNullable}}
|
||||
jackson_databind_nullable_version = "0.2.1"
|
||||
{{/openApiNullable}}
|
||||
{{#play24}}
|
||||
play_version = "2.4.11"
|
||||
{{/play24}}
|
||||
{{#play25}}
|
||||
play_version = "2.5.14"
|
||||
{{/play25}}
|
||||
{{#play26}}
|
||||
play_version = "2.6.7"
|
||||
{{/play26}}
|
||||
{{/usePlayWS}}
|
||||
swagger_annotations_version = "1.5.22"
|
||||
junit_version = "4.13.1"
|
||||
{{#useRxJava}}
|
||||
rx_java_version = "1.3.0"
|
||||
{{/useRxJava}}
|
||||
{{#useRxJava2}}
|
||||
rx_java_version = "2.1.1"
|
||||
{{/useRxJava2}}
|
||||
{{#useRxJava3}}
|
||||
rx_java_version = "3.0.4"
|
||||
{{/useRxJava3}}
|
||||
{{#joda}}
|
||||
jodatime_version = "2.9.9"
|
||||
{{/joda}}
|
||||
{{#threetenbp}}
|
||||
threetenbp_version = "1.4.0"
|
||||
{{/threetenbp}}
|
||||
json_fire_version = "1.8.0"
|
||||
}
|
||||
|
||||
dependencies {
|
||||
implementation "com.squareup.retrofit2:retrofit:$retrofit_version"
|
||||
implementation "com.squareup.retrofit2:converter-scalars:$retrofit_version"
|
||||
implementation "com.squareup.retrofit2:converter-gson:$retrofit_version"
|
||||
implementation "com.squareup.okhttp3:logging-interceptor:4.9.0"
|
||||
implementation "com.squareup.okhttp3:okhttp:$okhttp3_version"
|
||||
{{#useRxJava}}
|
||||
implementation "com.squareup.retrofit2:adapter-rxjava:$retrofit_version"
|
||||
implementation "io.reactivex:rxjava:$rx_java_version"
|
||||
{{/useRxJava}}
|
||||
{{#useRxJava2}}
|
||||
implementation 'com.squareup.retrofit2:adapter-rxjava2:2.3.0'
|
||||
implementation "io.reactivex.rxjava2:rxjava:$rx_java_version"
|
||||
{{/useRxJava2}}
|
||||
{{#useRxJava3}}
|
||||
implementation 'com.github.akarnokd:rxjava3-retrofit-adapter:3.0.0'
|
||||
implementation "io.reactivex.rxjava3:rxjava:$rx_java_version"
|
||||
{{/useRxJava3}}
|
||||
implementation "io.swagger:swagger-annotations:$swagger_annotations_version"
|
||||
implementation "com.google.code.findbugs:jsr305:3.0.2"
|
||||
implementation ("org.apache.oltu.oauth2:org.apache.oltu.oauth2.client:$oltu_version"){
|
||||
exclude group:'org.apache.oltu.oauth2' , module: 'org.apache.oltu.oauth2.common'
|
||||
}
|
||||
implementation "io.gsonfire:gson-fire:$json_fire_version"
|
||||
{{#joda}}
|
||||
implementation "joda-time:joda-time:$jodatime_version"
|
||||
{{/joda}}
|
||||
{{#threetenbp}}
|
||||
implementation "org.threeten:threetenbp:$threetenbp_version"
|
||||
{{/threetenbp}}
|
||||
{{#usePlayWS}}
|
||||
{{#play26}}
|
||||
implementation "com.typesafe.play:play-ahc-ws_2.12:$play_version"
|
||||
implementation "javax.validation:validation-api:1.1.0.Final"
|
||||
{{/play26}}
|
||||
{{^play26}}
|
||||
implementation "com.typesafe.play:play-java-ws_2.11:$play_version"
|
||||
{{/play26}}
|
||||
implementation "com.squareup.retrofit2:converter-jackson:$retrofit_version"
|
||||
implementation "com.fasterxml.jackson.core:jackson-core:$jackson_version"
|
||||
implementation "com.fasterxml.jackson.core:jackson-annotations:$jackson_version"
|
||||
implementation "com.fasterxml.jackson.core:jackson-databind:$jackson_databind_version"
|
||||
{{#openApiNullable}}
|
||||
implementation "org.openapitools:jackson-databind-nullable:$jackson_databind_nullable_version"
|
||||
{{/openApiNullable}}
|
||||
implementation "com.fasterxml.jackson.datatype:jackson-datatype-{{^java8}}joda{{/java8}}{{#java8}}jsr310{{/java8}}:$jackson_version"
|
||||
{{/usePlayWS}}
|
||||
implementation 'javax.annotation:javax.annotation-api:1.3.2'
|
||||
testImplementation "junit:junit:$junit_version"
|
||||
}
|
||||
@@ -0,0 +1,479 @@
|
||||
{{!
|
||||
/**
|
||||
* 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.
|
||||
*/
|
||||
}}
|
||||
<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>{{groupId}}</groupId>
|
||||
<artifactId>{{artifactId}}</artifactId>
|
||||
<packaging>jar</packaging>
|
||||
<name>{{artifactId}}</name>
|
||||
<version>{{artifactVersion}}</version>
|
||||
<url>{{artifactUrl}}</url>
|
||||
<description>{{artifactDescription}}</description>
|
||||
<scm>
|
||||
<connection>{{scmConnection}}</connection>
|
||||
<developerConnection>{{scmDeveloperConnection}}</developerConnection>
|
||||
<url>{{scmUrl}}</url>
|
||||
</scm>
|
||||
{{#parentOverridden}}
|
||||
<parent>
|
||||
<groupId>{{{parentGroupId}}}</groupId>
|
||||
<artifactId>{{{parentArtifactId}}}</artifactId>
|
||||
<version>{{{parentVersion}}}</version>
|
||||
</parent>
|
||||
{{/parentOverridden}}
|
||||
|
||||
<licenses>
|
||||
<license>
|
||||
<name>{{licenseName}}</name>
|
||||
<url>{{licenseUrl}}</url>
|
||||
<distribution>repo</distribution>
|
||||
</license>
|
||||
</licenses>
|
||||
|
||||
<developers>
|
||||
<developer>
|
||||
<name>{{developerName}}</name>
|
||||
<email>{{developerEmail}}</email>
|
||||
<organization>{{developerOrganization}}</organization>
|
||||
<organizationUrl>{{developerOrganizationUrl}}</organizationUrl>
|
||||
</developer>
|
||||
</developers>
|
||||
|
||||
<build>
|
||||
<plugins>
|
||||
<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>2.12</version>
|
||||
<configuration>
|
||||
<systemProperties>
|
||||
<property>
|
||||
<name>loggerPath</name>
|
||||
<value>conf/log4j.properties</value>
|
||||
</property>
|
||||
</systemProperties>
|
||||
<argLine>-Xms512m -Xmx1500m</argLine>
|
||||
<parallel>methods</parallel>
|
||||
<forkMode>pertest</forkMode>
|
||||
</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-compiler-plugin</artifactId>
|
||||
<version>3.6.1</version>
|
||||
<configuration>
|
||||
{{#java8}}
|
||||
<source>1.8</source>
|
||||
<target>1.8</target>
|
||||
{{/java8}}
|
||||
{{^java8}}
|
||||
<source>1.7</source>
|
||||
<target>1.7</target>
|
||||
{{/java8}}
|
||||
</configuration>
|
||||
</plugin>
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-javadoc-plugin</artifactId>
|
||||
<version>3.1.1</version>
|
||||
<configuration>
|
||||
<doclint>none</doclint>
|
||||
{{#java8}}
|
||||
<source>1.8</source>
|
||||
{{/java8}}
|
||||
{{^java8}}
|
||||
<source>1.7</source>
|
||||
{{/java8}}
|
||||
</configuration>
|
||||
<executions>
|
||||
<execution>
|
||||
<id>attach-javadocs</id>
|
||||
<goals>
|
||||
<goal>jar</goal>
|
||||
</goals>
|
||||
</execution>
|
||||
</executions>
|
||||
</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-annotations-version}</version>
|
||||
</dependency>
|
||||
<!-- https://mvnrepository.com/artifact/com.squareup.okhttp3/okhttp -->
|
||||
<dependency>
|
||||
<groupId>com.squareup.okhttp3</groupId>
|
||||
<artifactId>okhttp</artifactId>
|
||||
<version>${okhttp3-version}</version>
|
||||
</dependency>
|
||||
<!-- https://mvnrepository.com/artifact/com.squareup.okhttp3/logging-interceptor -->
|
||||
<dependency>
|
||||
<groupId>com.squareup.okhttp3</groupId>
|
||||
<artifactId>logging-interceptor</artifactId>
|
||||
<version>3.12.1</version>
|
||||
</dependency>
|
||||
<!-- @Nullable annotation -->
|
||||
<dependency>
|
||||
<groupId>com.google.code.findbugs</groupId>
|
||||
<artifactId>jsr305</artifactId>
|
||||
<version>3.0.2</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.squareup.retrofit2</groupId>
|
||||
<artifactId>converter-gson</artifactId>
|
||||
<version>${retrofit-version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.squareup.retrofit2</groupId>
|
||||
<artifactId>retrofit</artifactId>
|
||||
<version>${retrofit-version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.squareup.retrofit2</groupId>
|
||||
<artifactId>converter-scalars</artifactId>
|
||||
<version>${retrofit-version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.apache.oltu.oauth2</groupId>
|
||||
<artifactId>org.apache.oltu.oauth2.client</artifactId>
|
||||
<version>${oltu-version}</version>
|
||||
<exclusions>
|
||||
<exclusion>
|
||||
<groupId>org.apache.oltu.oauth2</groupId>
|
||||
<artifactId>common</artifactId>
|
||||
</exclusion>
|
||||
</exclusions>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>io.gsonfire</groupId>
|
||||
<artifactId>gson-fire</artifactId>
|
||||
<version>${gson-fire-version}</version>
|
||||
</dependency>
|
||||
{{#joda}}
|
||||
<dependency>
|
||||
<groupId>joda-time</groupId>
|
||||
<artifactId>joda-time</artifactId>
|
||||
<version>${jodatime-version}</version>
|
||||
</dependency>
|
||||
{{/joda}}
|
||||
{{#threetenbp}}
|
||||
<dependency>
|
||||
<groupId>org.threeten</groupId>
|
||||
<artifactId>threetenbp</artifactId>
|
||||
<version>${threetenbp-version}</version>
|
||||
</dependency>
|
||||
{{/threetenbp}}
|
||||
{{#useRxJava}}
|
||||
<dependency>
|
||||
<groupId>io.reactivex</groupId>
|
||||
<artifactId>rxjava</artifactId>
|
||||
<version>${rxjava-version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.squareup.retrofit2</groupId>
|
||||
<artifactId>adapter-rxjava</artifactId>
|
||||
<version>${retrofit-version}</version>
|
||||
</dependency>
|
||||
{{/useRxJava}}
|
||||
{{#useRxJava2}}
|
||||
<dependency>
|
||||
<groupId>io.reactivex.rxjava2</groupId>
|
||||
<artifactId>rxjava</artifactId>
|
||||
<version>${rxjava-version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.squareup.retrofit2</groupId>
|
||||
<artifactId>adapter-rxjava2</artifactId>
|
||||
<version>${retrofit-version}</version>
|
||||
</dependency>
|
||||
{{/useRxJava2}}
|
||||
{{#useRxJava3}}
|
||||
<dependency>
|
||||
<groupId>io.reactivex.rxjava3</groupId>
|
||||
<artifactId>rxjava</artifactId>
|
||||
<version>${rxjava-version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.github.akarnokd</groupId>
|
||||
<artifactId>rxjava3-retrofit-adapter</artifactId>
|
||||
<version>3.0.0</version>
|
||||
</dependency>
|
||||
{{/useRxJava3}}
|
||||
{{#usePlayWS}}
|
||||
<!-- JSON processing: jackson -->
|
||||
<dependency>
|
||||
<groupId>com.squareup.retrofit2</groupId>
|
||||
<artifactId>converter-jackson</artifactId>
|
||||
<version>${retrofit-version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.fasterxml.jackson.core</groupId>
|
||||
<artifactId>jackson-core</artifactId>
|
||||
<version>${jackson-version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.fasterxml.jackson.core</groupId>
|
||||
<artifactId>jackson-annotations</artifactId>
|
||||
<version>${jackson-version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.fasterxml.jackson.core</groupId>
|
||||
<artifactId>jackson-databind</artifactId>
|
||||
<version>${jackson-version}</version>
|
||||
</dependency>
|
||||
{{#openApiNullable}}
|
||||
<dependency>
|
||||
<groupId>org.openapitools</groupId>
|
||||
<artifactId>jackson-databind-nullable</artifactId>
|
||||
<version>${jackson-databind-nullable-version}</version>
|
||||
</dependency>
|
||||
{{/openApiNullable}}
|
||||
<dependency>
|
||||
<groupId>com.fasterxml.jackson.datatype</groupId>
|
||||
<artifactId>jackson-datatype-{{^java8}}joda{{/java8}}{{#java8}}jsr310{{/java8}}</artifactId>
|
||||
<version>${jackson-version}</version>
|
||||
</dependency>
|
||||
{{#withXml}}
|
||||
<!-- XML processing: Jackson -->
|
||||
<dependency>
|
||||
<groupId>com.fasterxml.jackson.dataformat</groupId>
|
||||
<artifactId>jackson-dataformat-xml</artifactId>
|
||||
<version>${jackson-version}</version>
|
||||
</dependency>
|
||||
{{/withXml}}
|
||||
{{#play24}}
|
||||
<dependency>
|
||||
<groupId>com.typesafe.play</groupId>
|
||||
<artifactId>play-java-ws_2.11</artifactId>
|
||||
<version>${play-version}</version>
|
||||
</dependency>
|
||||
{{/play24}}
|
||||
{{#play25}}
|
||||
<dependency>
|
||||
<groupId>com.typesafe.play</groupId>
|
||||
<artifactId>play-java-ws_2.11</artifactId>
|
||||
<version>${play-version}</version>
|
||||
</dependency>
|
||||
{{/play25}}
|
||||
{{#play26}}
|
||||
<dependency>
|
||||
<groupId>com.typesafe.play</groupId>
|
||||
<artifactId>play-ahc-ws_2.12</artifactId>
|
||||
<version>${play-version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>javax.validation</groupId>
|
||||
<artifactId>validation-api</artifactId>
|
||||
<version>1.1.0.Final</version>
|
||||
</dependency>
|
||||
{{/play26}}
|
||||
{{/usePlayWS}}
|
||||
{{#parcelableModel}}
|
||||
<!-- Needed for Parcelable support-->
|
||||
<dependency>
|
||||
<groupId>com.google.android</groupId>
|
||||
<artifactId>android</artifactId>
|
||||
<version>4.1.1.4</version>
|
||||
<scope>provided</scope>
|
||||
</dependency>
|
||||
{{/parcelableModel}}
|
||||
<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>
|
||||
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
|
||||
<java.version>{{#java8}}1.8{{/java8}}{{^java8}}1.7{{/java8}}</java.version>
|
||||
<maven.compiler.source>${java.version}</maven.compiler.source>
|
||||
<maven.compiler.target>${java.version}</maven.compiler.target>
|
||||
<gson-fire-version>1.8.3</gson-fire-version>
|
||||
<swagger-annotations-version>1.5.22</swagger-annotations-version>
|
||||
{{#usePlayWS}}
|
||||
<jackson-version>2.12.1</jackson-version>
|
||||
{{#play24}}
|
||||
<play-version>2.4.11</play-version>
|
||||
{{/play24}}
|
||||
{{#play25}}
|
||||
<play-version>2.5.15</play-version>
|
||||
{{/play25}}
|
||||
{{#play26}}
|
||||
<play-version>2.6.7</play-version>
|
||||
{{/play26}}
|
||||
{{#openApiNullable}}
|
||||
<jackson-databind-nullable-version>0.2.1</jackson-databind-nullable-version>
|
||||
{{/openApiNullable}}
|
||||
{{/usePlayWS}}
|
||||
<retrofit-version>2.9.0</retrofit-version>
|
||||
<okhttp3-version>4.9.0</okhttp3-version>
|
||||
{{#useRxJava}}
|
||||
<rxjava-version>1.3.0</rxjava-version>
|
||||
{{/useRxJava}}
|
||||
{{#useRxJava2}}
|
||||
<rxjava-version>2.1.1</rxjava-version>
|
||||
{{/useRxJava2}}
|
||||
{{#useRxJava3}}
|
||||
<rxjava-version>3.0.4</rxjava-version>
|
||||
{{/useRxJava3}}
|
||||
{{#joda}}
|
||||
<jodatime-version>2.9.9</jodatime-version>
|
||||
{{/joda}}
|
||||
{{#threetenbp}}
|
||||
<threetenbp-version>1.4.0</threetenbp-version>
|
||||
{{/threetenbp}}
|
||||
<javax-annotation-version>1.3.2</javax-annotation-version>
|
||||
<oltu-version>1.0.1</oltu-version>
|
||||
<junit-version>4.13.1</junit-version>
|
||||
</properties>
|
||||
</project>
|
||||
+10
-10
@@ -1,3 +1,4 @@
|
||||
#!/bin/bash
|
||||
#
|
||||
# Licensed to the Apache Software Foundation (ASF) under one
|
||||
# or more contributor license agreements. See the NOTICE file
|
||||
@@ -17,13 +18,12 @@
|
||||
# under the License.
|
||||
#
|
||||
|
||||
spring.profiles.default=basicauth
|
||||
spring.profiles.active=oauth
|
||||
management.health.jms.enabled=false
|
||||
|
||||
# FINERACT-883
|
||||
management.info.git.mode=FULL
|
||||
|
||||
# FINERACT-914
|
||||
server.forward-headers-strategy=framework
|
||||
spring.cache.jcache.config=classpath:/META-INF/spring/ehcache.xml
|
||||
set -e
|
||||
export PGPASSWORD=$POSTGRES_PASSWORD;
|
||||
psql -v ON_ERROR_STOP=1 --username "$POSTGRES_USER" --dbname "$POSTGRES_DB" <<-EOSQL
|
||||
CREATE USER $FINERACT_DB_USER WITH PASSWORD '$FINERACT_DB_PASS';
|
||||
CREATE DATABASE $FINERACT_TENANTS_DB_NAME;
|
||||
CREATE DATABASE $FINERACT_TENANT_DEFAULT_DB_NAME;
|
||||
GRANT ALL PRIVILEGES ON DATABASE $FINERACT_TENANTS_DB_NAME TO $FINERACT_DB_USER;
|
||||
GRANT ALL PRIVILEGES ON DATABASE $FINERACT_TENANT_DEFAULT_DB_NAME TO $FINERACT_DB_USER;
|
||||
EOSQL
|
||||
+8
-8
@@ -1,4 +1,3 @@
|
||||
#
|
||||
# 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
|
||||
@@ -17,12 +16,13 @@
|
||||
# under the License.
|
||||
#
|
||||
|
||||
spring.profiles.default=basicauth
|
||||
spring.profiles.active=basicauth,twofactor
|
||||
management.health.jms.enabled=false
|
||||
[client]
|
||||
default-character-set=utf8mb4
|
||||
|
||||
# FINERACT-883
|
||||
management.info.git.mode=FULL
|
||||
[mysql]
|
||||
default-character-set=utf8mb4
|
||||
|
||||
# FINERACT-914
|
||||
server.forward-headers-strategy=framework
|
||||
[mysqld]
|
||||
collation-server=utf8mb4_unicode_ci
|
||||
init-connect='SET NAMES utf8mb4'
|
||||
character-set-server=utf8mb4
|
||||
@@ -1,4 +1,4 @@
|
||||
:years: 2015-2020
|
||||
:years: 2015-2022
|
||||
:revnumber: 1.0.0
|
||||
:draft: true
|
||||
:rootdir: ../../../..
|
||||
|
||||
@@ -44,14 +44,11 @@ asciidoctorj {
|
||||
version = '2.4.0'
|
||||
|
||||
attributes = [
|
||||
revnumber: {
|
||||
project.version.toString()
|
||||
},
|
||||
generated: "${buildDir}/generated/asciidoc",
|
||||
imagesdir: 'images',
|
||||
diagrams: 'diagrams',
|
||||
years: '2015-2020',
|
||||
revnumber: "$releaseVersion".toString(),
|
||||
years: '2015-2022',
|
||||
revnumber: "$version".toString(),
|
||||
rootdir: "$rootDir".toString(),
|
||||
baseurl: 'fineract.apache.org'
|
||||
]
|
||||
|
||||
@@ -10,7 +10,7 @@ The target audience for this report is both system integrators (who will use the
|
||||
|
||||
==== The Idea
|
||||
|
||||
Mifos was an idea born out of a wish to create and deploy technology that allows the microfinance industry to scale. The goal is to:
|
||||
Fineract was an idea born out of a wish to create and deploy technology that allows the microfinance industry to scale. The goal is to:
|
||||
|
||||
- Produce a gold standard management information system suitable for microfinance operations
|
||||
- Acts as the basis of a platform for microfinance
|
||||
@@ -23,12 +23,13 @@ Mifos was an idea born out of a wish to create and deploy technology that allows
|
||||
- Late 2011: Grameen Foundation handed over full responsibility to open source community.
|
||||
- 2012: Mifos X platform started. Previous members of project come together under the name of Community for Open Source Microfinance (COSM / OpenMF)
|
||||
- 2013: COSM / OpenMF officially rebranded to Mifos Initiative and receive US 501c3 status.
|
||||
- 2016: Fineract 1.x began incubation at Apache
|
||||
|
||||
==== Project Related
|
||||
|
||||
- Project url is https://github.com/openMF/mifosx
|
||||
- Download from https://sourceforge.net/projects/mifos/
|
||||
- Download stats
|
||||
- Project url is https://github.com/apache/fineract
|
||||
- Issue tracker is https://issues.apache.org/jira/projects/FINERACT/summary
|
||||
- Download from http://fineract.apache.org/
|
||||
|
||||
=== System Overview
|
||||
|
||||
@@ -91,17 +92,18 @@ At a higher level though we see the capabilities fall into the following categor
|
||||
|
||||
=== Technology
|
||||
|
||||
* Java 11: http://www.oracle.com/technetwork/java/javase/downloads/index.html
|
||||
* JAX-RS 1.0: using Jersey (1.17.x)
|
||||
* Java: http://www.oracle.com/technetwork/java/javase/downloads/index.html
|
||||
* JAX-RS using Jersey
|
||||
* JSON using Google GSON
|
||||
* Spring I/O Platform: http://spring.io/platform
|
||||
** Spring Framework
|
||||
** Spring Boot
|
||||
** Spring Security
|
||||
** Spring Data (JPA) backed by Hibernate
|
||||
** Spring Data (JPA) backed by EclipseLink
|
||||
* MySQL: http://www.oracle.com/us/products/mysql/overview/index.html
|
||||
* PostgreSQL
|
||||
|
||||
=== Principals
|
||||
=== Principles
|
||||
|
||||
==== RESTful API
|
||||
|
||||
@@ -116,7 +118,7 @@ See online API Documentation for more detail.
|
||||
|
||||
==== Multi-tenanted
|
||||
|
||||
The mifos platform has been developed with support for multi-tenancy at the core of its design. This means that it is just as easy to use the platform for Software-as-a-Service (SaaS) type offerings as it is for local installations.
|
||||
The Fineract platform has been developed with support for multi-tenancy at the core of its design. This means that it is just as easy to use the platform for Software-as-a-Service (SaaS) type offerings as it is for local installations.
|
||||
|
||||
The platform uses an approach that isolates an FIs data per database/schema (See Separate Databases and Shared Database, Separate Schemas).
|
||||
|
||||
@@ -207,3 +209,64 @@ NOTE: if a RollbackTransactionAsCommandIsNotApprovedByCheckerException occurs at
|
||||
* Process command using handler (In transactional scope).
|
||||
* CommandSource object created/updated with all details for logging to 'm_portfolio_command_source' table.
|
||||
* In update scenario, we check to see if there where really any changes/updates. If so only JSON for changes is stored in audit log.
|
||||
|
||||
=== Database support
|
||||
|
||||
Fineract supports multiple databases:
|
||||
|
||||
* MySQL compatible databases (e.g. MariaDB)
|
||||
* PostgreSQL
|
||||
|
||||
The platform differentiates between these database types in certain cases when there's a need to use some database specific tooling. To do so, the platform examines the JDBC driver used for running the platform and tries to determine which database is being used.
|
||||
|
||||
The currently supported JDBC driver and corresponding mappings can be found below.
|
||||
|
||||
[cols="1,1"]
|
||||
|===
|
||||
|*JDBC driver class name*
|
||||
|*Resolved database type*
|
||||
|
||||
|`org.mariadb.jdbc.Driver`
|
||||
|MySQL
|
||||
|
||||
|`com.mysql.jdbc.Driver`
|
||||
|MySQL
|
||||
|
||||
|`org.postgresql.Driver`
|
||||
|PostgreSQL
|
||||
|
||||
|===
|
||||
|
||||
The actual code can be found in the `DatabaseTypeResolver` class.
|
||||
|
||||
=== Data-access layer
|
||||
|
||||
The data-access layer of Fineract is implemented by using JPA (Java Persistence API) with the EclipseLink provider.
|
||||
Despite the fact that JPA is used quite extensively in the system, there are cases where the performance is a key element for an operation therefore you can easily find native SQLs as well.
|
||||
|
||||
The data-access layer of Fineract is compatible with different databases. Since a lot of the native queries are using specific database functions, a wrapper class - `DatabaseSpecificSQLGenerator` - has been introduced to handle these database specifics. Whenever there's a need to rely on new database level functions, make sure to extend this class and implement the specific functions provided by the database.
|
||||
|
||||
Fineract has been developed for 10+ years by the community and unfortunately there are places where entity relationships are configured with `EAGER` fetching strategy. This must not confuse anybody. The long-term goal is to use the `LAZY` fetching strategy for every single relationship. If you're about to introduce a new one, make sure to use `LAZY` as a fetching strategy, otherwise your PR will be rejected.
|
||||
|
||||
=== Database schema migration
|
||||
|
||||
As for every system, the database structure will and need to evolve over time. Fineract is no different. Originally for Fineract, Flyway was used until Fineract 1.6.x.
|
||||
|
||||
After 1.6.x, PostgreSQL support was added to the platform hence there was a need to make the data-access layer and the schema migration as database independent as possible. Becuase of that, from Fineract 1.7.0, Flyway is not used anymore but Liquibase is.
|
||||
|
||||
Some of the changesets in the Liquibase changelogs have database specifics into it but they only run for the relevant databases. This is controller by Liquibase contexts.
|
||||
|
||||
The currently available Liquibase contexts are:
|
||||
|
||||
* `mysql` - only set when the database is a MySQL compatible database (e.g. MariaDB)
|
||||
* `postgresql` - only set when the database is a PostgreSQL database
|
||||
* configured Spring active profiles
|
||||
* `tenant_store_db` - only set when the database migration runs the Tenant Store upgrade
|
||||
* `tenant_db` - only set when the database migration runs the Tenant upgrade
|
||||
* `initial_switch` - this is a technical context and should *NOT* be used
|
||||
|
||||
The switch from Flyway (1.6.x) to Liquibase (1.7.x) was planned to be as smooth as possible so there's no need for manual work hence the behavior is described as following:
|
||||
|
||||
* If the database is empty, Liquibase will create the database schema from scratch
|
||||
* If the database contains the latest Fineract 1.6.x database structure which was previously migrated with Flyway. Liquibase will seamlessly upgrade it to the latest version. Note: the Flyway related 2 database tables are left as they are and are not deleted.
|
||||
* If the database contains an earlier version of the database structure than Fineract 1.6.x. Liquibase will *NOT* do anything and *will fail the application during startup*. The proper approach in this case is to first upgrade your application version to the latest Fineract 1.6.x so that the latest Flyway changes are executed and then upgrade to the newer Fineract version where Liquibase will seamlessly take over the database upgrades.
|
||||
@@ -1,41 +1,66 @@
|
||||
== OAuth
|
||||
|
||||
Fineract has (basic) OAuth (2.0?) support. Here's how to use it:
|
||||
Fineract has a (basic) OAuth2 support based on Spring Boot Security. Here's how to use it:
|
||||
|
||||
=== Build
|
||||
|
||||
You must re-build the distribution JAR (or WAR) using the special `-Psecurity=oauth` flag:
|
||||
|
||||
----
|
||||
./gradlew bootJAR -Psecurity=oauth
|
||||
java -jar build/libs/fineract-provider.jar
|
||||
./gradlew bootRun -Psecurity=oauth
|
||||
----
|
||||
|
||||
Downloads from https://fineract.apache.org, or using e.g. the https://hub.docker.com/r/apache/fineract container image, or on https://www.fineract.dev, this will not work, because they have not been built using this flag.
|
||||
|
||||
=== Invoke `/fineract-provider/api/oauth/token`
|
||||
Previous versions of Fineract included a built-in authorisation server for issuing OAuth tokens. However, as the spring-security-oauth2 package was deprecated and replaced by built-in OAuth support in Spring Security, this is no longer supported as part of the package. Instead, you need to run a separate OAuth authorization server (e.g. https://github.com/spring-projects/spring-authorization-server) or use a 3rd-party OAuth authorization provider (https://en.wikipedia.org/wiki/List_of_OAuth_providers)
|
||||
|
||||
This instruction describes how to get Fineract OAuth working with a Keycloak (http://keycloak.org) based authentication provider running in a Docker container. The steps required for other OAuth providers will be similar.
|
||||
|
||||
=== Set up Keycloak
|
||||
|
||||
1. From terminal, run: 'docker run -p 9000:8080 -e KEYCLOAK_USER=admin -e KEYCLOAK_PASSWORD=admin quay.io/keycloak/keycloak:15.0.2'
|
||||
1. Go to URL 'http://localhost:9000/auth/admin' and login with admin/admin
|
||||
1. Hover your mouse over text "Master" and click on "Add realm"
|
||||
1. Enter name "fineract" for your realm
|
||||
1. Click on tab "Users" on the left, then "Add user" and create user with username "mifos"
|
||||
1. Click on tab "Credentials" at the top, and set password to "password", turning "temporary" setting to off
|
||||
1. Click on tab "Clients" on the left, and create client with ID 'community-app'
|
||||
1. In settings tab, set 'access-type' to 'confidential' and enter 'localhost' in the valid redirect URIs.
|
||||
1. In credentials tab, copy string in field 'secret' as this will be needed in the step to request the access token
|
||||
|
||||
Finally we need to change Keycloak configuration so that it uses the username as a subject of the token:
|
||||
|
||||
1. Choose client 'community-app' in the tab 'Clients'
|
||||
1. Go to tab 'Mappers' and click on 'Create'
|
||||
1. Enter 'usernameInSub' as 'Name'
|
||||
1. Choose mapper type 'User Property'
|
||||
1. Enter 'username' into the field 'Property' and 'sub' into the field 'Token Claim Name'. Choose 'String' as 'Claim JSON Type'
|
||||
|
||||
You are now ready to test out OAuth:
|
||||
|
||||
=== Retrieve an access token from Keycloak
|
||||
|
||||
----
|
||||
curl [--insecure] --location --request POST \
|
||||
'https://localhost:8443/fineract-provider/api/oauth/token' \
|
||||
--header 'Fineract-Platform-TenantId: default' \
|
||||
curl --location --request POST \
|
||||
'http://localhost:9000/auth/realms/fineract/protocol/openid-connect/token' \
|
||||
--header 'Content-Type: application/x-www-form-urlencoded' \
|
||||
--data-urlencode 'username=mifos' \
|
||||
--data-urlencode 'password=password' \
|
||||
--data-urlencode 'client_id=community-app' \
|
||||
--data-urlencode 'grant_type=password' \
|
||||
--data-urlencode 'client_secret=123'
|
||||
--data-urlencode 'client_secret=<enter the client secret from credentials tab>'
|
||||
----
|
||||
|
||||
Note that the `client_id` and `client_secret` are stored in the `oauth_client_details` table in the database.
|
||||
The reply should contain a field 'access_token'. Copy the field's value and use it in the API call below:
|
||||
|
||||
=== Invoke APIs and pass `Authorization: bearer ...` header
|
||||
|
||||
----
|
||||
curl --location --request GET \
|
||||
'https://localhost:8443/fineract-provider/api/v1/clients' \
|
||||
'https://localhost:8443/fineract-provider/api/v1/offices' \
|
||||
--header 'Fineract-Platform-TenantId: default' \
|
||||
--header 'Authorization: bearer RzfUyQ0wEnxxq4PyFCF1J-XGFCI'
|
||||
--header 'Authorization: bearer <enter the value of the access_token field>'
|
||||
|
||||
----
|
||||
|
||||
NOTE: See also https://demo.fineract.dev/fineract-provider/api-docs/apiLive.htm#authentication_oauth
|
||||
NOTE: See also https://demo.fineract.dev/fineract-provider/api-docs/apiLive.htm#authentication_oauth
|
||||
|
||||
@@ -6,7 +6,7 @@ Apache Fineract supports client code generation using https://openapi-generator.
|
||||
|
||||
The `fineract-client.jar` will eventually be available on Maven Central (watch https://issues.apache.org/jira/browse/FINERACT-1102[FINERACT-1102]). Until it is, you can quite easily build the latest and greatest version locally from source, see below.
|
||||
|
||||
The https://github.com/apache/fineract/search?q=FineractClient.java[`FineractClient`] is the entry point to the _Fineract SDK Java API Client_. https://github.com/apache/fineract/search?q=Calls.java[`Calls`] is a convenient and recommended utility to simplify the use of the https://square.github.io/retrofit/2.x/retrofit/retrofit2/Call.html[`retrofit2.Call`] type which all API operations return. This permits you to use the API like the https://github.com/apache/fineract/search?q=FineractClientDemo.java[`FineractClientDemo`] illustrates:
|
||||
The https://github.com/apache/fineract/search?q=FineractClient.java[`FineractClient`] is the entry point to the _Fineract SDK Java API Client_. https://github.com/apache/fineract/search?q=Calls.java[`Calls`] is a convenient and recommended utility to simplify the use of the https://square.github.io/retrofit/2.x/retrofit/retrofit2/Call.html[`retrofit2.Call`] type which all API operations return. This permits you to use the API like the https://github.com/search?l=&q=repo%3Aapache%2Ffineract+filename%3AFineractClientDemo.java&type=code[`FineractClientDemo`] illustrates:
|
||||
|
||||
[source,java]
|
||||
----
|
||||
|
||||
@@ -18,6 +18,7 @@
|
||||
|
||||
| Michael Vorburger | mailto:mike@vorburger.ch[]
|
||||
| Aleksandar Vidakovic | mailto:aleks@apache.org[]
|
||||
| Arnold Galovics | mailto:arnold@apache.org[]
|
||||
|===
|
||||
|
||||
//ifdef::backend-pdf[]
|
||||
@@ -30,6 +31,7 @@
|
||||
^| Authors ^| Description ^| Date ^| Version
|
||||
|
||||
| Aleksandar Vidakovic | Initial version | 2020-10-26 | 1.4.0
|
||||
| Arnold Galovics | Database architecture section | 2022-03-11 | 1.7.0
|
||||
|===
|
||||
|
||||
toc::[]
|
||||
|
||||
@@ -15,7 +15,7 @@
|
||||
:source-language: java
|
||||
:diagramsdir: diagrams
|
||||
:imagesdir: images
|
||||
:years: 2017-2020
|
||||
:years: 2017-2022
|
||||
:lang: en
|
||||
:encoding: utf-8
|
||||
:linkattrs:
|
||||
|
||||
@@ -1,5 +1,23 @@
|
||||
== Deployment
|
||||
|
||||
=== Plugins
|
||||
|
||||
Apache Fineract is extensible through plugin JARs (https://issues.apache.org/jira/browse/FINERACT-1177[FINERACT-1177]; based on
|
||||
https://docs.spring.io/spring-boot/docs/current/reference/html/appendix-executable-jar-format.html[Spring Boot's support]). To launch Fineract with plugin JARs in `libs/*.jar`, use:
|
||||
|
||||
----
|
||||
java -Dloader.path=libs/ -jar fineract-provider.jar
|
||||
----
|
||||
|
||||
The Fineract "Docker" container image's `ENTRYPOINT` uses this, see our `Dockerfile`. You could therefore build your customized Fineract distribution container image with your own `Dockerfile` using e.g. `FROM apache/fineract:latest` and then drop some plugin JARs into `/app/libs/`.
|
||||
|
||||
The WAR distribution does not directly support such plugins, but one could "explode" the WAR and drop JARs into `WEB-INF/lib`; if you know what you are doing, and feel nostalgic of the 1990s still using WARs, instead of the recommended modern Spring Boot distribution.
|
||||
|
||||
Here is a list of known 3rd-party plugin projects which can be dropped into `libs/`:
|
||||
|
||||
* https://github.com/vorburger/fineract-pentaho
|
||||
|
||||
|
||||
=== HTTPS
|
||||
|
||||
Because Apache Fineract deals with customer sensitive personally identifiable information (PII), it very strongly encourages all developers, implementors and end-users to always only use HTTPS. This is why it does not run on HTTP even for local development and enforces use of HTTPS.
|
||||
|
||||
@@ -1,47 +0,0 @@
|
||||
@startuml
|
||||
!include <awslib/AWSCommon>
|
||||
|
||||
' Uncomment the following line to create simplified view
|
||||
!include <awslib/AWSSimplified>
|
||||
|
||||
!include <awslib/General/Users>
|
||||
!include <awslib/Mobile/APIGateway>
|
||||
!include <awslib/SecurityIdentityAndCompliance/Cognito>
|
||||
!include <awslib/Compute/Lambda>
|
||||
!include <awslib/Database/DynamoDB>
|
||||
!include <awslib/Storage/SimpleStorageServiceS3>
|
||||
!include <awslib/InternetOfThings/IoTRule>
|
||||
!include <awslib/InternetOfThings/IoTAction>
|
||||
!include <awslib/Analytics/KinesisDataStreams>
|
||||
!include <awslib/ApplicationIntegration/SQSQueue>
|
||||
|
||||
left to right direction
|
||||
|
||||
agent "Published Event" as event #fff
|
||||
|
||||
IoTRule(iotRule, "Action Error Rule", "error if Kinesis fails")
|
||||
KinesisDataStreams(eventStream, "IoT Events", "2 shards")
|
||||
SQSQueue(errorQueue, "Rule Error Queue", "failed Rule actions")
|
||||
|
||||
event --> iotRule : JSON message
|
||||
iotRule --> eventStream : messages
|
||||
iotRule --> errorQueue : Failed action message
|
||||
|
||||
Users(sources, "Events", "millions of users")
|
||||
APIGateway(votingAPI, "Voting API", "user votes")
|
||||
Cognito(userAuth, "User Authentication", "jwt to submit votes")
|
||||
Lambda(generateToken, "User Credentials", "return jwt")
|
||||
Lambda(recordVote, "Record Vote", "enter or update vote per user")
|
||||
DynamoDB(voteDb, "Vote Database", "one entry per user")
|
||||
|
||||
SimpleStorageServiceS3(s3_partner, "Vendor's S3", "Technology", "Optional Description")
|
||||
SimpleStorageServiceS3(s3_internal, "Internal", "Technology", "Optional Description")
|
||||
|
||||
s3_internal <- s3_partner
|
||||
|
||||
sources --> userAuth
|
||||
sources --> votingAPI
|
||||
userAuth <--> generateToken
|
||||
votingAPI --> recordVote
|
||||
recordVote --> voteDb
|
||||
@enduml
|
||||
@@ -1,64 +0,0 @@
|
||||
@startuml
|
||||
!includeurl https://raw.githubusercontent.com/ebbypeter/Archimate-PlantUML/master/Archimate.puml
|
||||
'!include <archimate/Archimate.puml>
|
||||
|
||||
title Archimate Example - Relationships
|
||||
|
||||
'LAYOUT_AS_SKETCH
|
||||
'LAYOUT_LEFT_RIGHT
|
||||
'LAYOUT_TOP_DOWN
|
||||
|
||||
Business_Service(Service01, "Service 01")
|
||||
Application_Service(Service02, "Service 02")
|
||||
Technology_Service(Service03, "Service03")
|
||||
|
||||
Rel_Composition_Right(Service01, Service02, "Composition")
|
||||
Rel_Aggregation(Service01, Service02, "Aggregation")
|
||||
Rel_Assignment(Service01, Service02, "Assignment")
|
||||
Rel_Specialization(Service01, Service02, "Specialization")
|
||||
Rel_Serving(Service01, Service02, "Serving")
|
||||
Rel_Association(Service02, Service03, "Association")
|
||||
Rel_Flow(Service02, Service03, "Flow")
|
||||
Rel_Realization(Service02, Service03, "Realization")
|
||||
Rel_Triggering(Service02, Service03, "Triggering")
|
||||
Rel_Access(Service02, Service03, "Access")
|
||||
Rel_Influence(Service02, Service03, " + Influence")
|
||||
|
||||
Grouping(Example01, "Example 01"){
|
||||
Strategy_Capability(TestCapability01, "Test Capability")
|
||||
Business_Product(TestProduct01, "Test Product")
|
||||
Application_Service(TestService01, "Test Service")
|
||||
Technology_Device(TestDevice01, "Test Device")
|
||||
|
||||
Rel_Composition(TestCapability01, TestProduct01, "C-P")
|
||||
Rel_Composition_Down(TestProduct01, TestService01, "P-S")
|
||||
Rel_Composition_Left(TestService01, TestDevice01, "S-D")
|
||||
Rel_Composition_Up(TestDevice01, TestCapability01, "D-C")
|
||||
}
|
||||
|
||||
Lay_D(Service01, Example01)
|
||||
|
||||
Group(Example02, "Group Type 02"){
|
||||
Motivation_Stakeholder(StakeholderElement, "Stakeholder Description")
|
||||
Business_Service(BService, "Business Service")
|
||||
}
|
||||
|
||||
Motivation_Requirement(ReqPayrollStandard, "Do Payroll with a standard system")
|
||||
Motivation_Requirement(ReqBudgetPlanning, "Do budget planning within the ERP system")
|
||||
|
||||
Application_Service(ASPayroll,"Payroll Service")
|
||||
Application_Service(ASBudgetPlanning,"Budget Planning Service")
|
||||
Application_Component(ACSAPFinanceAccRec, "SAP Finance - Accounts Recievables")
|
||||
Application_Component(ACSAPHR, "SAP Human Resources")
|
||||
Application_Component(ACSAPFin, "SAP Finance")
|
||||
Application_Component(ACSAP,"SAP")
|
||||
|
||||
Rel_Realization_Up(ASPayroll, ReqPayrollStandard)
|
||||
Rel_Realization_Up(ASBudgetPlanning, ReqBudgetPlanning)
|
||||
Rel_Realization_Up(ACSAPFinanceAccRec, ASBudgetPlanning)
|
||||
Rel_Realization_Up(ACSAPHR, ASPayroll)
|
||||
|
||||
Rel_Composition_Up(ACSAPFin, ACSAPFinanceAccRec)
|
||||
Rel_Composition_Up(ACSAP, ACSAPHR)
|
||||
Rel_Composition_Up(ACSAP, ACSAPFin)
|
||||
@enduml
|
||||
@@ -1,49 +0,0 @@
|
||||
@startuml
|
||||
' see: https://github.com/RicardoNiepel/C4-PlantUML
|
||||
'!includeurl https://raw.githubusercontent.com/RicardoNiepel/C4-PlantUML/master/C4_Container.puml
|
||||
!include <c4/C4_Container.puml>
|
||||
|
||||
LAYOUT_TOP_DOWN
|
||||
' LAYOUT_WITH_LEGEND
|
||||
|
||||
Person_Ext(anonymous_user, "Anonymous User")
|
||||
Person(aggregated_user, "Aggregated User")
|
||||
Person(administration_user, "Administration User")
|
||||
|
||||
System_Boundary(c1, "techtribes.js"){
|
||||
|
||||
Container(web_app, "Web Application", "Java, Spring MVC, Tomcat 7.x", "Allows users to view people, tribes, content, events, jobs, etc. from the local tech, digital and IT sector")
|
||||
|
||||
ContainerDb(rel_db, "Relational Database", "MySQL 5.5.x", "Stores people, tribes, tribe membership, talks, events, jobs, badges, GitHub repos, etc.")
|
||||
|
||||
Container(filesystem, "File System", "FAT32", "Stores search indexes")
|
||||
|
||||
ContainerDb(nosql, "NoSQL Data Store", "MongoDB 2.2.x", "Stores from RSS/Atom feeds (blog posts) and tweets")
|
||||
|
||||
Container(updater, "Updater", "Java 7 Console App", "Updates profiles, tweets, GitHub repos and content on a scheduled basis")
|
||||
}
|
||||
|
||||
System_Ext(twitter, "Twitter")
|
||||
System_Ext(github, "GitHub")
|
||||
System_Ext(blogs, "Blogs")
|
||||
|
||||
|
||||
Rel(anonymous_user, web_app, "Uses", "HTTPS")
|
||||
Rel(aggregated_user, web_app, "Uses", "HTTPS")
|
||||
Rel(administration_user, web_app, "Uses", "HTTPS")
|
||||
|
||||
Rel(web_app, rel_db, "Reads from and writes to", "SQL/JDBC, post 3306")
|
||||
Rel(web_app, filesystem, "Reads from")
|
||||
Rel(web_app, nosql, "Reads from", "MongoDB wire protocol, port 27017")
|
||||
|
||||
Rel_U(updater, rel_db, "Reads from and writes data to", "SQL/JDBC, post 3306")
|
||||
Rel_U(updater, filesystem, "Writes to")
|
||||
Rel_U(updater, nosql, "Reads from and writes to", "MongoDB wire protocol, port 27017")
|
||||
|
||||
Rel(updater, twitter, "Gets profile information and tweets from", "HTTPS")
|
||||
Rel(updater, github, "Gets information about public code repositories from", "HTTPS")
|
||||
Rel(updater, blogs, "Gets content using RSS and Atom feeds from", "HTTP")
|
||||
|
||||
Lay_R(rel_db, filesystem)
|
||||
|
||||
@enduml
|
||||
@@ -1,104 +0,0 @@
|
||||
@startuml
|
||||
' see: https://github.com/awslabs/aws-icons-for-plantuml
|
||||
!define AWSPuml https://raw.githubusercontent.com/awslabs/aws-icons-for-plantuml/master/dist
|
||||
!includeurl AWSPuml/AWSCommon.puml
|
||||
!includeurl AWSPuml/EndUserComputing/all.puml
|
||||
!includeurl AWSPuml/Storage/SimpleStorageServiceS3.puml
|
||||
|
||||
' see: https://github.com/aheil/EIP-PlantUML
|
||||
!includeurl https://raw.githubusercontent.com/aheil/EIP-PlantUML/main/dist/EIP-PlantUML.puml
|
||||
|
||||
' see: https://github.com/Roemer/plantuml-office
|
||||
!define ICONURL https://raw.githubusercontent.com/Roemer/plantuml-office/master/office2014
|
||||
!includeurl ICONURL/Servers/database_server.puml
|
||||
!includeurl ICONURL/Servers/application_server.puml
|
||||
!includeurl ICONURL/Concepts/firewall_orange.puml
|
||||
!includeurl ICONURL/Clouds/cloud_disaster_red.puml
|
||||
|
||||
' https://github.com/tupadr3/plantuml-icon-font-sprites
|
||||
!define ICONURL https://raw.githubusercontent.com/tupadr3/plantuml-icon-font-sprites/v2.1.0
|
||||
!includeurl ICONURL/common.puml
|
||||
!includeurl ICONURL/common.puml
|
||||
!includeurl ICONURL/devicons/mysql.puml
|
||||
!includeurl ICONURL/font-awesome/database.puml
|
||||
!includeurl ICONURL/font-awesome-5/database.puml
|
||||
|
||||
' https://github.com/rabelenda/cicon-plantuml-sprites
|
||||
!define SPRITESURL https://raw.githubusercontent.com/rabelenda/cicon-plantuml-sprites/v1.0/sprites
|
||||
!includeurl SPRITESURL/tomcat.puml
|
||||
!includeurl SPRITESURL/kafka.puml
|
||||
!includeurl SPRITESURL/java.puml
|
||||
!includeurl SPRITESURL/cassandra.puml
|
||||
|
||||
' https://github.com/RicardoNiepel/Azure-PlantUML
|
||||
!define AzurePuml https://raw.githubusercontent.com/RicardoNiepel/Azure-PlantUML/release/2-1/dist
|
||||
!includeurl AzurePuml/AzureCommon.puml
|
||||
!includeurl AzurePuml/Databases/all.puml
|
||||
!includeurl AzurePuml/Compute/AzureFunction.puml
|
||||
|
||||
' Remove shadows
|
||||
skinparam shadowing true
|
||||
|
||||
actor "Person" as personAlias1
|
||||
AzureFunction(functionAlias, "Label", "Technology", "Optional Description")
|
||||
AzureCosmosDb(cosmosDbAlias, "Label", "Technology", "Optional Description")
|
||||
|
||||
personAlias1 --> functionAlias
|
||||
functionAlias --> cosmosDbAlias
|
||||
|
||||
rectangle "<$tomcat>\nwebapp" as webapp
|
||||
queue "<$kafka>" as kafka
|
||||
rectangle "<$java>\ndaemon" as daemon
|
||||
database "<$cassandra>" as cassandra
|
||||
|
||||
webapp -> kafka
|
||||
kafka -> daemon
|
||||
daemon --> cassandra
|
||||
|
||||
DEV_MYSQL(db)
|
||||
DEV_MYSQL(db4,label of db4,database,red) #DeepSkyBlue
|
||||
|
||||
MsgChannel(channel1, "Channel 1")
|
||||
MsgChannel(channel2, "Channel 2")
|
||||
Message(msg, "Message")
|
||||
|
||||
Send(channel1, msg)
|
||||
Send(msg, channel2)
|
||||
|
||||
rectangle System1
|
||||
rectangle System2
|
||||
rectangle System3
|
||||
|
||||
Message(source)
|
||||
Message(target)
|
||||
|
||||
ControlBus("cb")
|
||||
|
||||
Send(source, System1)
|
||||
Send(System1, System2)
|
||||
Send(System2, System3)
|
||||
Send(System3, target)
|
||||
|
||||
System1 <--> cb
|
||||
System2 <--> cb
|
||||
System3 <--> cb
|
||||
|
||||
SimpleStorageServiceS3(storageAlias, "Label", "Technology", "Optional Description")
|
||||
|
||||
actor User
|
||||
[Third party application] as ThirdPartyApp
|
||||
|
||||
package "Spring Boot Application" {
|
||||
rectangle Controllers <<Spring REST controllers>>
|
||||
rectangle DataStoreService <<Spring service>>
|
||||
rectangle Repository <<Spring repository>>
|
||||
}
|
||||
|
||||
User --> Controllers
|
||||
ThirdPartyApp --> Controllers
|
||||
storageAlias --> Controllers
|
||||
|
||||
Controllers --> DataStoreService
|
||||
DataStoreService --> Repository
|
||||
|
||||
@enduml
|
||||
@@ -1,3 +0,0 @@
|
||||
@startuml
|
||||
listopeniconic
|
||||
@enduml
|
||||
@@ -1,27 +0,0 @@
|
||||
@startuml
|
||||
!includeurl https://raw.githubusercontent.com/inthepocket/plantuml-styles/master/styles.plantuml!0
|
||||
|
||||
!include <logos/flask>
|
||||
!include <logos/kafka>
|
||||
!include <logos/kotlin>
|
||||
!include <logos/cassandra>
|
||||
|
||||
title Gil Barbara's logos example
|
||||
|
||||
' skinparam monochrome true
|
||||
|
||||
rectangle "<$flask>\nwebapp" as webapp
|
||||
queue "<$kafka>" as kafka
|
||||
rectangle "<$kotlin>\ndaemon" as daemon
|
||||
database "<$cassandra>" as cassandra
|
||||
|
||||
webapp -> kafka
|
||||
kafka -> daemon
|
||||
daemon --> cassandra
|
||||
|
||||
database "Database"
|
||||
package "Package"
|
||||
node "ParentNode" {
|
||||
component "Subcomponent"
|
||||
}
|
||||
@enduml
|
||||
@@ -1,41 +0,0 @@
|
||||
@startmindmap
|
||||
!includeurl https://cdn.jsdelivr.net/gh/HSLdevcom/hsl-plantuml-theme/hsl-theme.iuml
|
||||
|
||||
title Crosscutting Concepts
|
||||
|
||||
+ Crosscutting Concepts
|
||||
++ Under the hood
|
||||
+++ Persistence
|
||||
+++ Process Control
|
||||
+++ Transaction handling
|
||||
+++ Session handling
|
||||
+++ Communication and Integration
|
||||
+++ Exception and error handling
|
||||
+++ Parallelization / Threading
|
||||
+++ Plausibility checks and validation
|
||||
+++ Business Rules
|
||||
+++ Batch
|
||||
+++ Reporting
|
||||
++ Operation Concepts
|
||||
+++ Administration
|
||||
+++ Management
|
||||
+++ Disaster-Recovery
|
||||
+++ Skalierung
|
||||
+++ Clusterring
|
||||
+++ Monitoring, Logging, Protocolling
|
||||
+++ High Availability
|
||||
-- Domain Concepts
|
||||
-- Architecture and Design Patterns
|
||||
-- User Experience (UX)
|
||||
--- User Interface
|
||||
--- Ergonomics
|
||||
--- Internationalization
|
||||
-- Security and Safety
|
||||
--- Security
|
||||
--- Safety
|
||||
-- Development Concepts
|
||||
--- Build, Test, Deploy
|
||||
--- Code generation
|
||||
--- Migration
|
||||
--- Configurability
|
||||
@endmindmap
|
||||
@@ -1,35 +0,0 @@
|
||||
@startuml
|
||||
'!includeurl https://cdn.jsdelivr.net/gh/HSLdevcom/hsl-plantuml-theme/hsl-theme.iuml
|
||||
'!define LIGHTBLUE
|
||||
'!includeurl https://raw.githubusercontent.com/Drakemor/RedDress-PlantUML/master/style.puml
|
||||
|
||||
'!includeurl https://github.com/rbkmoney/plantuml-toolset/raw/master/skin.iwsd
|
||||
'!includeurl https://raw.githubusercontent.com/inthepocket/plantuml-styles/master/styles.plantuml!0
|
||||
|
||||
!includeurl https://github.com/rbkmoney/plantuml-toolset/raw/master/super-serious-skin.iwsd
|
||||
|
||||
skinparam BackgroundColor #ffffff
|
||||
|
||||
title Publish(er) Jobs Workers (Successful Block Copy)
|
||||
|
||||
hide footbox
|
||||
|
||||
Alice -> Bob: Authentication Request
|
||||
Bob --> Alice: Authentication Response
|
||||
|
||||
Alice -> Bob: Another authentication Request
|
||||
Alice <-- Bob: Another authentication Response
|
||||
|
||||
Alice -> Bob: Authentication Request
|
||||
...
|
||||
Bob --> Alice: Authentication Response
|
||||
activate Alice
|
||||
note left of Alice
|
||||
Drink that potion!
|
||||
end note
|
||||
deactivate Alice
|
||||
activate Bob
|
||||
... 5 minutes later ...
|
||||
Bob --> Alice: Bye!
|
||||
deactivate Bob
|
||||
@enduml
|
||||
@@ -1,3 +0,0 @@
|
||||
@startuml
|
||||
listsprites
|
||||
@enduml
|
||||
@@ -1,3 +0,0 @@
|
||||
@startuml
|
||||
testdot
|
||||
@enduml
|
||||
@@ -1,25 +0,0 @@
|
||||
:doctitle: Fineract Documentation
|
||||
|
||||
include::config.adoc[]
|
||||
|
||||
= Fineract Documentation
|
||||
|
||||
IMPORTANT: @vidakovic migrate old documentation!
|
||||
|
||||
.Amazon
|
||||
[plantuml,amazon,svg]
|
||||
----
|
||||
include::diagrams/samples/amazon.puml[]
|
||||
----
|
||||
|
||||
.C4 Diagram
|
||||
[plantuml,c4,svg]
|
||||
----
|
||||
include::diagrams/samples/c4.puml[]
|
||||
----
|
||||
|
||||
.Mindmap
|
||||
[plantuml,mindmap,svg]
|
||||
----
|
||||
include::diagrams/samples/mindmap.puml[]
|
||||
----
|
||||
@@ -1,10 +1,10 @@
|
||||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||
<launchConfiguration type="org.eclipse.ui.externaltools.ProgramBuilderLaunchConfigurationType">
|
||||
<booleanAttribute key="org.eclipse.debug.ui.ATTR_LAUNCH_IN_BACKGROUND" value="false"/>
|
||||
<stringAttribute key="org.eclipse.ui.externaltools.ATTR_BUILD_SCOPE" value="${working_set:<?xml version="1.0" encoding="UTF-8"?> <resources> <item path="/fineract-provider/bin/main" type="2"/> </resources>}"/>
|
||||
<stringAttribute key="org.eclipse.ui.externaltools.ATTR_LOCATION" value="${workspace_loc:/fineract/gradlew}"/>
|
||||
<stringAttribute key="org.eclipse.ui.externaltools.ATTR_RUN_BUILD_KINDS" value="incremental,auto,"/>
|
||||
<stringAttribute key="org.eclipse.ui.externaltools.ATTR_TOOL_ARGUMENTS" value="-x rat -x compileJava -x sql -x processResources -x generateGitProperties -Penv=eclipse enhance"/>
|
||||
<booleanAttribute key="org.eclipse.ui.externaltools.ATTR_TRIGGERS_CONFIGURED" value="true"/>
|
||||
<stringAttribute key="org.eclipse.ui.externaltools.ATTR_WORKING_DIRECTORY" value="${workspace_loc:/fineract}"/>
|
||||
<booleanAttribute key="org.eclipse.debug.ui.ATTR_LAUNCH_IN_BACKGROUND" value="false"/>
|
||||
<stringAttribute key="org.eclipse.ui.externaltools.ATTR_BUILD_SCOPE" value="${working_set:<?xml version="1.0" encoding="UTF-8"?> <resources> <item path="/fineract-provider/bin/main" type="2"/> </resources>}"/>
|
||||
<stringAttribute key="org.eclipse.ui.externaltools.ATTR_LOCATION" value="${build_project}/../gradlew"/>
|
||||
<stringAttribute key="org.eclipse.ui.externaltools.ATTR_RUN_BUILD_KINDS" value="incremental,auto,"/>
|
||||
<stringAttribute key="org.eclipse.ui.externaltools.ATTR_TOOL_ARGUMENTS" value="-x rat -x compileJava -x sql -x processResources -x generateGitProperties -Penv=eclipse enhance"/>
|
||||
<booleanAttribute key="org.eclipse.ui.externaltools.ATTR_TRIGGERS_CONFIGURED" value="true"/>
|
||||
<stringAttribute key="org.eclipse.ui.externaltools.ATTR_WORKING_DIRECTORY" value="${build_project}"/>
|
||||
</launchConfiguration>
|
||||
|
||||
+158
-162
@@ -18,26 +18,28 @@
|
||||
*/
|
||||
description = 'Fineract Provider'
|
||||
|
||||
apply plugin: 'rebel'
|
||||
apply plugin: 'war'
|
||||
apply plugin: 'org.zeroturnaround.gradle.jrebel'
|
||||
apply plugin: 'java'
|
||||
apply plugin: 'eclipse'
|
||||
apply plugin: 'org.springframework.boot'
|
||||
apply plugin: 'openjpa'
|
||||
apply plugin: 'com.gorylenko.gradle-git-properties'
|
||||
apply plugin: 'io.swagger.core.v3.swagger-gradle-plugin'
|
||||
apply plugin: 'distribution'
|
||||
apply plugin: 'signing'
|
||||
apply plugin: 'com.google.cloud.tools.jib'
|
||||
|
||||
// Configuration for the OpenJPA enhance task
|
||||
// https://github.com/radcortez/openjpa-gradle-plugin
|
||||
System.setProperty("openjpa.Log", "commons")
|
||||
|
||||
openjpa {
|
||||
includes = [
|
||||
'**/AbstractPersistableCustom.class',
|
||||
'**/domain/*.class'
|
||||
]
|
||||
enhance {
|
||||
enforcePropertyRestrictions true
|
||||
compileJava.doLast {
|
||||
def mainSS = sourceSets.main
|
||||
def source = mainSS.java.classesDirectory.get()
|
||||
copy {
|
||||
from "src/main/resources/"
|
||||
into source
|
||||
}
|
||||
javaexec {
|
||||
description = 'Performs EclipseLink static weaving of entity classes'
|
||||
def target = source
|
||||
main 'org.eclipse.persistence.tools.weaving.jpa.StaticWeave'
|
||||
args '-persistenceinfo', source, '-classpath', configurations.runtimeClasspath, source, target
|
||||
classpath configurations.runtimeClasspath
|
||||
}
|
||||
}
|
||||
|
||||
@@ -45,32 +47,28 @@ openjpa {
|
||||
// https://github.com/swagger-api/swagger-core/tree/master/modules/swagger-gradle-plugin
|
||||
import org.apache.tools.ant.filters.ReplaceTokens
|
||||
|
||||
task prepareInputYaml(dependsOn: 'generateGitProperties') {
|
||||
task prepareInputYaml {
|
||||
outputs.file('config/swagger/fineract-input.yaml')
|
||||
|
||||
doLast {
|
||||
def versionForSwagger
|
||||
|
||||
if(project.ext.properties.containsKey("gitProps"))
|
||||
versionForSwagger = project.ext.gitProps['git.commit.id.describe']
|
||||
else
|
||||
versionForSwagger = "unknown"
|
||||
|
||||
copy {
|
||||
from file('config/swagger/fineract-input.yaml.template')
|
||||
into file('config/swagger')
|
||||
rename { String filename -> return 'fineract-input.yaml' }
|
||||
filter(ReplaceTokens, tokens: [VERSION: versionForSwagger])
|
||||
filter(ReplaceTokens, tokens: [VERSION: "${project.version}".toString()])
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
rat.dependsOn prepareInputYaml
|
||||
|
||||
resolve {
|
||||
logging.captureStandardOutput LogLevel.INFO
|
||||
outputFileName = 'fineract'
|
||||
outputFormat = 'YAML'
|
||||
prettyPrint = 'TRUE'
|
||||
prettyPrint = true
|
||||
classpath = sourceSets.main.runtimeClasspath
|
||||
outputDir = file("${buildDir}/classes/java/main/static/swagger-ui")
|
||||
outputDir = file("${buildDir}/generated/swagger-ui")
|
||||
openApiFile = file("config/swagger/fineract-input.yaml")
|
||||
}
|
||||
|
||||
@@ -98,52 +96,14 @@ configurations {
|
||||
}
|
||||
|
||||
apply from: 'dependencies.gradle'
|
||||
/* TODO https://issues.apache.org/jira/browse/FINERACT-939 (dev-dependencies.gradle has been removed, as totally broken)
|
||||
// Pick up dependencies based on the environment, defaults to production
|
||||
if (project.hasProperty('env') && project.getProperty('env') == 'dev') {
|
||||
apply from: 'dev-dependencies.gradle'
|
||||
} else {
|
||||
apply from: 'dependencies.gradle'
|
||||
}
|
||||
*/
|
||||
|
||||
/* Enable Oauth2 authentication based on environment, default to HTTP basic auth */
|
||||
if (project.hasProperty('security') && project.getProperty('security') == 'oauth') {
|
||||
if(project.hasProperty('twofactor') && project.getProperty('twofactor') == 'enabled') {
|
||||
copy {
|
||||
from './properties/oauth/twofactor/'
|
||||
into 'src/main/resources/'
|
||||
include '*.properties'
|
||||
}
|
||||
} else {
|
||||
copy {
|
||||
from './properties/oauth/'
|
||||
into 'src/main/resources/'
|
||||
include '*.properties'
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if(project.hasProperty('twofactor') && project.getProperty('twofactor') == 'enabled') {
|
||||
copy {
|
||||
from './properties/basicauth/twofactor/'
|
||||
into 'src/main/resources/'
|
||||
include '*.properties'
|
||||
}
|
||||
} else {
|
||||
copy {
|
||||
from './properties/basicauth/'
|
||||
into 'src/main/resources/'
|
||||
include '*.properties'
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Configuration for the modernizer plugin
|
||||
// https://github.com/andygoossens/gradle-modernizer-plugin
|
||||
modernizer {
|
||||
ignoreClassNamePatterns = [
|
||||
'.*AbstractPersistableCustom',
|
||||
'.*EntityTables'
|
||||
'.*EntityTables',
|
||||
'.*domain.*'
|
||||
]
|
||||
}
|
||||
|
||||
@@ -152,42 +112,26 @@ compileJava {
|
||||
finalizedBy resolve
|
||||
}
|
||||
|
||||
war {
|
||||
from("$rootDir/licenses/binary/") {
|
||||
// notice the parens
|
||||
into "WEB-INF/licenses/binary/" // no leading slash
|
||||
}
|
||||
from("$rootDir/LICENSE_RELEASE") {
|
||||
// notice the parens
|
||||
into "WEB-INF/" // no leading slash
|
||||
}
|
||||
from("$rootDir/NOTICE_RELEASE") {
|
||||
// notice the parens
|
||||
into "WEB-INF/" // no leading slash
|
||||
}
|
||||
rename ('LICENSE_RELEASE', 'LICENSE')
|
||||
rename ('NOTICE_RELEASE', 'NOTICE')
|
||||
// If we are running Gradle within Eclipse to enhance classes with OpenJPA,
|
||||
// set the classes directory to point to Eclipse's default build directory
|
||||
if (project.hasProperty('env') && project.getProperty('env') == 'eclipse')
|
||||
{
|
||||
sourceSets.main.java.outputDir = new File(rootProject.projectDir, "fineract-provider/bin/main")
|
||||
}
|
||||
|
||||
from("$rootDir/DISCLAIMER") {
|
||||
// notice the parens
|
||||
into "WEB-INF/" // no leading slash
|
||||
eclipse
|
||||
{
|
||||
project {
|
||||
buildCommand([ LaunchConfigHandle: "<project>/.externalToolBuilders/OpenJPA Enhance Builder.launch" ], 'org.eclipse.ui.externaltools.ExternalToolBuilder')
|
||||
}
|
||||
enabled = true
|
||||
}
|
||||
|
||||
/* http://stackoverflow.com/questions/19653311/jpa-repository-works-in-idea-and-production-but-not-in-gradle */
|
||||
sourceSets.main.output.resourcesDir = sourceSets.main.java.outputDir
|
||||
sourceSets.test.output.resourcesDir = sourceSets.test.java.outputDir
|
||||
|
||||
/* Exclude maria db related files for non dev builds */
|
||||
if (!(project.hasProperty('env') && project.getProperty('env') == 'dev')) {
|
||||
sourceSets {
|
||||
main {
|
||||
java {
|
||||
exclude '**/ServerWithMariaDB*'
|
||||
exclude '**/MariaDB4j*'
|
||||
}
|
||||
}
|
||||
test {
|
||||
java {
|
||||
exclude '**/core/boot/tests/**'
|
||||
@@ -202,12 +146,15 @@ import groovy.sql.Sql
|
||||
|
||||
project.ext.mysqlUser='root'
|
||||
project.ext.mysqlPassword='mysql'
|
||||
project.ext.pgUser='root'
|
||||
project.ext.pgPassword='postgres'
|
||||
|
||||
configurations {
|
||||
driver
|
||||
}
|
||||
dependencies {
|
||||
driver 'org.drizzle.jdbc:drizzle-jdbc:1.4'
|
||||
driver 'org.mariadb.jdbc:mariadb-java-client:2.7.5'
|
||||
driver 'org.postgresql:postgresql:42.3.3'
|
||||
}
|
||||
|
||||
URLClassLoader loader = GroovyObject.class.classLoader
|
||||
@@ -216,23 +163,40 @@ configurations.driver.each {File file ->
|
||||
}
|
||||
|
||||
task createDB {
|
||||
description= "Creates the Database. Needs database name to be passed (like: -PdbName=someDBname)"
|
||||
description= "Creates the MySQL Database. Needs database name to be passed (like: -PdbName=someDBname)"
|
||||
doLast {
|
||||
def sql = Sql.newInstance( 'jdbc:mysql:thin://localhost:3306/', mysqlUser, mysqlPassword, 'org.drizzle.jdbc.DrizzleDriver' )
|
||||
def sql = Sql.newInstance( 'jdbc:mariadb://localhost:3306/', mysqlUser, mysqlPassword, 'org.mariadb.jdbc.Driver' )
|
||||
sql.execute( 'create database '+"`$dbName`" )
|
||||
}
|
||||
}
|
||||
|
||||
task dropDB {
|
||||
description= "Drops the specified database. The database name has to be passed (like: -PdbName=someDBname)"
|
||||
description= "Drops the specified MySQL database. The database name has to be passed (like: -PdbName=someDBname)"
|
||||
doLast {
|
||||
def sql = Sql.newInstance( 'jdbc:mysql:thin://localhost:3306/', mysqlUser, mysqlPassword, 'org.drizzle.jdbc.DrizzleDriver' )
|
||||
def sql = Sql.newInstance( 'jdbc:mariadb://localhost:3306/', mysqlUser, mysqlPassword, 'org.mariadb.jdbc.Driver' )
|
||||
sql.execute( 'DROP DATABASE '+"`$dbName`")
|
||||
}
|
||||
}
|
||||
|
||||
task createPGDB {
|
||||
description= "Creates the PostgreSQL Database. Needs database name to be passed (like: -PdbName=someDBname)"
|
||||
doLast {
|
||||
def sql = Sql.newInstance( 'jdbc:postgresql://localhost:5432/', pgUser, pgPassword, 'org.postgresql.Driver' )
|
||||
sql.execute( 'create database '+"$dbName" )
|
||||
}
|
||||
}
|
||||
|
||||
task dropPGDB {
|
||||
description= "Drops the specified PostgreSQL database. The database name has to be passed (like: -PdbName=someDBname)"
|
||||
doLast {
|
||||
def sql = Sql.newInstance( 'jdbc:postgresql://localhost:5432/', pgUser, pgPassword, 'org.postgresql.Driver' )
|
||||
sql.execute( 'DROP DATABASE '+ "$dbName")
|
||||
}
|
||||
}
|
||||
|
||||
task setBlankPassword {
|
||||
doLast {
|
||||
def sql = Sql.newInstance( 'jdbc:mysql:thin://localhost:3306/', mysqlUser, mysqlPassword, 'org.drizzle.jdbc.DrizzleDriver' )
|
||||
def sql = Sql.newInstance( 'jdbc:mariadb://localhost:3306/', mysqlUser, mysqlPassword, 'org.mariadb.jdbc.Driver' )
|
||||
sql.execute('USE `fineract_tenants`')
|
||||
sql.execute('UPDATE fineract_tenants.tenants SET schema_server = \'localhost\', schema_server_port = \'3306\', schema_username = \'mifos\', schema_password = \'mysql\' WHERE id=1;')
|
||||
}
|
||||
@@ -242,84 +206,108 @@ bootRun {
|
||||
jvmArgs = [
|
||||
"-Dspring.output.ansi.enabled=ALWAYS"
|
||||
]
|
||||
|
||||
dependencies {
|
||||
implementation 'org.mariadb.jdbc:mariadb-java-client:2.7.5'
|
||||
implementation 'org.postgresql:postgresql:42.3.3'
|
||||
}
|
||||
|
||||
classpath += files("build/generated/swagger-ui")
|
||||
}
|
||||
|
||||
springBoot {
|
||||
mainClassName = 'org.apache.fineract.ServerApplication'
|
||||
mainClass = 'org.apache.fineract.ServerApplication'
|
||||
}
|
||||
|
||||
bootJar {
|
||||
duplicatesStrategy = DuplicatesStrategy.EXCLUDE
|
||||
manifest {
|
||||
attributes 'Main-Class': 'org.springframework.boot.loader.PropertiesLauncher', 'Implementation-Title': 'Apache Fineract', 'Implementation-Version': archiveVersion
|
||||
}
|
||||
dependsOn resolve
|
||||
classifier = ''
|
||||
|
||||
from('build/generated/swagger-ui') {
|
||||
into 'BOOT-INF/classes/static/swagger-ui'
|
||||
}
|
||||
}
|
||||
|
||||
bootWar {
|
||||
enabled = false
|
||||
jar {
|
||||
from('build/generated/swagger-ui') {
|
||||
include '*'
|
||||
}
|
||||
}
|
||||
|
||||
tasks.withType(Tar) {
|
||||
compression Compression.GZIP
|
||||
extension 'tar.gz'
|
||||
}
|
||||
jar.dependsOn resolve
|
||||
jar.dependsOn bootJar
|
||||
|
||||
distributions {
|
||||
binary {
|
||||
baseName "apache-fineract-$releaseVersion-binary"
|
||||
contents {
|
||||
from bootJar
|
||||
from war
|
||||
// TODO: @vidakovic add client library
|
||||
from("$rootDir/licenses/binary/") {
|
||||
into "licenses/binary/"
|
||||
jib {
|
||||
from {
|
||||
image = 'azul/zulu-openjdk-alpine:17'
|
||||
}
|
||||
|
||||
to {
|
||||
image = 'fineract'
|
||||
tags = [
|
||||
"${version}",
|
||||
'latest'
|
||||
]
|
||||
}
|
||||
|
||||
container {
|
||||
creationTime = 'USE_CURRENT_TIMESTAMP'
|
||||
mainClass = 'org.apache.fineract.ServerApplication'
|
||||
jvmFlags = [
|
||||
'-Xmx1G',
|
||||
'-Xms1G',
|
||||
'-XshowSettings:vm',
|
||||
'-XX:+UseContainerSupport',
|
||||
'-XX:+UseStringDeduplication',
|
||||
'-XX:MinRAMPercentage=25',
|
||||
'-XX:MaxRAMPercentage=80',
|
||||
'--add-exports=java.naming/com.sun.jndi.ldap=ALL-UNNAMED',
|
||||
'--add-opens=java.base/java.lang=ALL-UNNAMED',
|
||||
'--add-opens=java.base/java.lang.invoke=ALL-UNNAMED',
|
||||
'--add-opens=java.base/java.io=ALL-UNNAMED',
|
||||
'--add-opens=java.base/java.security=ALL-UNNAMED',
|
||||
'--add-opens=java.base/java.util=ALL-UNNAMED',
|
||||
'--add-opens=java.management/javax.management=ALL-UNNAMED',
|
||||
'--add-opens=java.naming/javax.naming=ALL-UNNAMED'
|
||||
]
|
||||
args = [
|
||||
'-Duser.home=/tmp',
|
||||
'-Dfile.encoding=UTF-8',
|
||||
'-Duser.timezone=UTC',
|
||||
'-Djava.security.egd=file:/dev/./urandom'
|
||||
]
|
||||
ports = ['8080/tcp', '8443/tcp']
|
||||
labels = [maintainer: 'Aleksandar Vidakovic <aleks@apache.org>']
|
||||
user = 'nobody:nogroup'
|
||||
}
|
||||
|
||||
allowInsecureRegistries = true
|
||||
|
||||
dependencies {
|
||||
implementation 'org.mariadb.jdbc:mariadb-java-client:2.7.5'
|
||||
implementation 'org.postgresql:postgresql:42.3.3'
|
||||
}
|
||||
|
||||
extraDirectories {
|
||||
paths {
|
||||
path {
|
||||
from = file('build/generated/swagger-ui')
|
||||
into = "/app/classes"
|
||||
}
|
||||
from "$rootDir/LICENSE_RELEASE"
|
||||
from "$rootDir/NOTICE_RELEASE"
|
||||
rename ('LICENSE_RELEASE', 'LICENSE')
|
||||
rename ('NOTICE_RELEASE', 'NOTICE')
|
||||
|
||||
from "$rootDir/DISCLAIMER"
|
||||
from "$rootDir/README.md"
|
||||
}
|
||||
}
|
||||
src {
|
||||
baseName "apache-fineract-$releaseVersion-src"
|
||||
contents {
|
||||
from "$rootDir/"
|
||||
exclude '**/build' , '.git', '.gradle', '.github', '.settings', '.project', '.classpath', '.idea', 'out', '._.DS_Store', '.DS_Store', 'WebContent', '.externalToolbuilders', '.theia', '.gitpod.yml', '.travis.yml', 'LICENSE_RELEASE', 'NOTICE_RELEASE', '**/licenses/binary'
|
||||
rename ('LICENSE_SOURCE', 'LICENSE')
|
||||
rename ('NOTICE_SOURCE', 'NOTICE')
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
tasks.binaryDistZip.enabled false
|
||||
tasks.srcDistZip.enabled false
|
||||
|
||||
// create signatures and checksums only if project parameter "fineract.release" is provided on the command line
|
||||
if( project.hasProperty("fineract.release") ) {
|
||||
signing {
|
||||
useGpgCmd()
|
||||
sign (binaryDistTar, srcDistTar)
|
||||
}
|
||||
tasks.withType(Tar) { task ->
|
||||
task.doLast {
|
||||
ant.checksum file: task.archivePath, algorithm: 'SHA-512', fileext: '.sha512'
|
||||
}
|
||||
}
|
||||
tasks.withType(Sign) { task ->
|
||||
task.doLast {
|
||||
task.getFilesToSign().each { f ->
|
||||
new ByteArrayOutputStream().withStream { os ->
|
||||
def result = exec {
|
||||
workingDir "$buildDir/distributions"
|
||||
executable 'sh'
|
||||
args '-c', "gpg --verify ${f}.asc"
|
||||
standardOutput = os
|
||||
}
|
||||
if(result.exitValue==0) {
|
||||
println '+++ GPG signature correct!'
|
||||
} else {
|
||||
println '--- GPG signature incorrect!'
|
||||
throw new RuntimeException('--- GPG signature incorrect!')
|
||||
pluginExtensions {
|
||||
pluginExtension {
|
||||
implementation = 'com.google.cloud.tools.jib.gradle.extension.layerfilter.JibLayerFilterExtension'
|
||||
configuration {
|
||||
filters {
|
||||
filter {
|
||||
glob = '/app/resources/**'
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -327,15 +315,23 @@ if( project.hasProperty("fineract.release") ) {
|
||||
}
|
||||
}
|
||||
|
||||
tasks.jibDockerBuild.dependsOn = ["bootJar"]
|
||||
|
||||
// Configuration for git properties gradle plugin
|
||||
// https://github.com/n0mer/gradle-git-properties
|
||||
gitProperties {
|
||||
gitPropertiesResourceDir = "$buildDir/classes/java/main/resources"
|
||||
gitPropertiesResourceDir = file("$buildDir/classes/java/main")
|
||||
dateFormat = "yyyy-MM-dd'T'HH:mmZ"
|
||||
dateFormatTimeZone = "GMT"
|
||||
failOnNoGitDirectory = false
|
||||
extProperty = 'gitProps'
|
||||
}
|
||||
|
||||
// make sure the generateGitProperties task always executes (even when git.properties is not changed)
|
||||
generateGitProperties.outputs.upToDateWhen { false }
|
||||
|
||||
// Gradle 7.x asks for explicit dependencies between tasks
|
||||
checkstyleMain.dependsOn resolve
|
||||
checkstyleTest.dependsOn resolve
|
||||
licenseMain.dependsOn processResources, generateGitProperties
|
||||
spotbugsTest.dependsOn resolve
|
||||
test.dependsOn resolve
|
||||
|
||||
@@ -22,7 +22,7 @@ info:
|
||||
name: Apache 2.0
|
||||
url: 'http://www.apache.org/licenses/LICENSE-2.0.html'
|
||||
servers:
|
||||
- url: https://localhost:8443/fineract-provider/api/v1
|
||||
- url: /fineract-provider/api/v1
|
||||
- url: https://demo.fineract.dev/fineract-provider/api/v1
|
||||
components:
|
||||
securitySchemes:
|
||||
|
||||
@@ -16,6 +16,7 @@
|
||||
* specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*/
|
||||
|
||||
dependencies {
|
||||
providedRuntime("org.springframework.boot:spring-boot-starter-tomcat")
|
||||
|
||||
@@ -26,34 +27,26 @@ dependencies {
|
||||
// implementation dependencies are directly used (compiled against) in src/main (and src/test)
|
||||
//
|
||||
implementation(
|
||||
//'ch.vorburger.mariaDB4j:mariaDB4j:2.4.0',
|
||||
|
||||
'org.springframework.boot:spring-boot-starter-web',
|
||||
'org.springframework.boot:spring-boot-starter-security',
|
||||
'org.springframework.boot:spring-boot-starter-cache',
|
||||
'org.springframework.boot:spring-boot-starter-oauth2-resource-server',
|
||||
|
||||
'org.glassfish.jersey.media:jersey-media-multipart:2.35',
|
||||
|
||||
'org.springframework:spring-jms',
|
||||
'org.springframework:spring-context-support',
|
||||
'org.springframework.security.oauth:spring-security-oauth2',
|
||||
|
||||
'com.sun.jersey:jersey-servlet',
|
||||
'com.sun.jersey:jersey-server',
|
||||
'com.sun.jersey:jersey-json',
|
||||
'com.sun.jersey.contribs:jersey-spring',
|
||||
'com.sun.jersey.contribs:jersey-multipart',
|
||||
|
||||
'com.google.guava:guava',
|
||||
'com.google.code.gson:gson',
|
||||
'com.sun.jersey:jersey-core',
|
||||
|
||||
'jakarta.jms:jakarta.jms-api',
|
||||
'jakarta.management.j2ee:jakarta.management.j2ee-api',
|
||||
'jakarta.validation:jakarta.validation-api',
|
||||
|
||||
'com.squareup.retrofit2:retrofit',
|
||||
'com.squareup.okhttp3:okhttp',
|
||||
'com.squareup.okhttp3:okhttp-urlconnection',
|
||||
|
||||
'org.apache.commons:commons-email',
|
||||
'org.apache.commons:commons-lang3',
|
||||
'commons-io:commons-io',
|
||||
'org.apache.poi:poi',
|
||||
@@ -61,36 +54,43 @@ dependencies {
|
||||
'org.apache.poi:poi-ooxml-schemas',
|
||||
'org.apache.tika:tika-core',
|
||||
|
||||
'org.drizzle.jdbc:drizzle-jdbc',
|
||||
'org.flywaydb:flyway-core',
|
||||
'org.liquibase:liquibase-core',
|
||||
|
||||
'com.github.librepdf:openpdf',
|
||||
'com.github.spullara.mustache.java:compiler',
|
||||
'com.jayway.jsonpath:json-path',
|
||||
|
||||
// JAX-B dependencies for JDK 9+
|
||||
'jakarta.xml.bind:jakarta.xml.bind-api',
|
||||
|
||||
'org.dom4j:dom4j',
|
||||
|
||||
'javax.cache:cache-api',
|
||||
|
||||
'com.github.spotbugs:spotbugs-annotations',
|
||||
'io.swagger.core.v3:swagger-annotations',
|
||||
'org.webjars:webjars-locator-core',
|
||||
|
||||
'com.google.cloud.sql:mysql-socket-factory-connector-j-8:1.2.0',
|
||||
'com.squareup.retrofit2:converter-gson'
|
||||
'com.google.cloud.sql:mysql-socket-factory-connector-j-8:1.4.4',
|
||||
'com.squareup.retrofit2:converter-gson',
|
||||
'org.apache.commons:commons-email'
|
||||
)
|
||||
|
||||
implementation('org.springframework.boot:spring-boot-starter-jersey') {
|
||||
exclude group: 'org.glassfish.hk2.external', module: 'aopalliance-repackaged'
|
||||
exclude group: 'org.glassfish.hk2', module: 'hk2-runlevel'
|
||||
exclude group: 'org.hibernate.validator', module: 'hibernate-validator'
|
||||
exclude group: 'jakarta.activation', module: 'jakarta.activation-api'
|
||||
}
|
||||
implementation('org.dom4j:dom4j') {
|
||||
exclude group: 'javax.xml.bind'
|
||||
}
|
||||
implementation ('jakarta.xml.bind:jakarta.xml.bind-api') {
|
||||
exclude group: 'jakarta.activation'
|
||||
}
|
||||
implementation ('org.apache.activemq:activemq-broker') {
|
||||
exclude group: 'org.apache.geronimo.specs'
|
||||
}
|
||||
implementation ('org.springframework.boot:spring-boot-starter-data-jpa') {
|
||||
exclude group: 'org.hibernate'
|
||||
}
|
||||
implementation ('org.apache.openjpa:openjpa') {
|
||||
exclude group: 'org.eclipse.persistence'
|
||||
exclude group: 'org.apache.geronimo.specs'
|
||||
implementation('org.eclipse.persistence:org.eclipse.persistence.jpa:2.7.10') {
|
||||
exclude group: 'org.eclipse.persistence', module: 'jakarta.persistence'
|
||||
}
|
||||
implementation ('org.quartz-scheduler:quartz') {
|
||||
exclude group: 'com.zaxxer', module: 'HikariCP-java7'
|
||||
@@ -100,9 +100,14 @@ dependencies {
|
||||
}
|
||||
implementation ('org.mnode.ical4j:ical4j') {
|
||||
exclude group: 'commons-logging'
|
||||
exclude group: 'javax.activation'
|
||||
}
|
||||
|
||||
runtimeOnly('org.ehcache:ehcache') {
|
||||
implementation ('org.ehcache:ehcache') {
|
||||
exclude group: 'com.sun.activation'
|
||||
}
|
||||
|
||||
runtimeOnly('org.glassfish.jaxb:jaxb-runtime') {
|
||||
exclude group: 'com.sun.activation'
|
||||
}
|
||||
|
||||
@@ -114,7 +119,7 @@ dependencies {
|
||||
|
||||
// Although fineract (at the time of writing) doesn't have any compile time dep. on httpclient,
|
||||
// it's useful to have this for the Spring Boot TestRestTemplate http://docs.spring.io/spring-boot/docs/current-SNAPSHOT/reference/htmlsingle/#boot-features-rest-templates-test-utility
|
||||
'org.apache.httpcomponents:httpclient',
|
||||
'org.apache.httpcomponents:httpclient'
|
||||
)
|
||||
|
||||
// testCompile dependencies are ONLY used in src/test, not src/main.
|
||||
@@ -128,5 +133,9 @@ dependencies {
|
||||
testImplementation ('org.springframework.boot:spring-boot-starter-test') {
|
||||
exclude group: 'com.jayway.jsonpath', module: 'json-path'
|
||||
exclude group: 'org.junit.vintage', module: 'junit-vintage-engine'
|
||||
exclude group: 'jakarta.activation'
|
||||
exclude group: 'javax.activation'
|
||||
exclude group: 'org.skyscreamer'
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -1,29 +0,0 @@
|
||||
#
|
||||
# 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.
|
||||
#
|
||||
|
||||
spring.profiles.default=basicauth
|
||||
spring.profiles.active=oauth,twofactor
|
||||
management.health.jms.enabled=false
|
||||
|
||||
# FINERACT-883
|
||||
management.info.git.mode=FULL
|
||||
|
||||
# FINERACT-914
|
||||
server.forward-headers-strategy=framework
|
||||
spring.cache.jcache.config=classpath:/META-INF/spring/ehcache.xml
|
||||
@@ -20,13 +20,10 @@ package org.apache.fineract;
|
||||
|
||||
import java.io.IOException;
|
||||
import org.apache.fineract.infrastructure.core.boot.AbstractApplicationConfiguration;
|
||||
import org.apache.fineract.infrastructure.core.boot.EmbeddedTomcatWithSSLConfiguration;
|
||||
import org.springframework.boot.autoconfigure.jdbc.DataSourceProperties;
|
||||
import org.springframework.boot.builder.SpringApplicationBuilder;
|
||||
import org.springframework.boot.web.servlet.support.SpringBootServletInitializer;
|
||||
import org.springframework.context.ConfigurableApplicationContext;
|
||||
import org.springframework.context.annotation.Import;
|
||||
import org.springframework.context.annotation.ImportResource;
|
||||
|
||||
/**
|
||||
* Fineract main() application which launches Fineract in an embedded Tomcat HTTP (using Spring Boot).
|
||||
@@ -39,13 +36,10 @@ import org.springframework.context.annotation.ImportResource;
|
||||
*
|
||||
* It's the old/classic Mifos (non-X) Workspace 2.0 reborn for Fineract! ;-)
|
||||
*
|
||||
* @see ServerWithMariaDB4jApplication for an alternative with an embedded DB
|
||||
*/
|
||||
|
||||
public class ServerApplication extends SpringBootServletInitializer {
|
||||
|
||||
@Import({ EmbeddedTomcatWithSSLConfiguration.class })
|
||||
@ImportResource({ "classpath*:META-INF/spring/hikariDataSource.xml" })
|
||||
private static class Configuration extends AbstractApplicationConfiguration {}
|
||||
|
||||
@Override
|
||||
|
||||
-105
@@ -1,105 +0,0 @@
|
||||
/**
|
||||
* 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;
|
||||
|
||||
import java.awt.Desktop;
|
||||
import java.io.IOException;
|
||||
import java.net.URI;
|
||||
|
||||
import org.apache.fineract.infrastructure.core.boot.AbstractApplicationConfiguration;
|
||||
import org.apache.fineract.infrastructure.core.boot.ApplicationExitUtil;
|
||||
import org.apache.fineract.infrastructure.core.boot.EmbeddedTomcatWithSSLConfiguration;
|
||||
import org.apache.fineract.infrastructure.core.boot.db.MariaDB4jDataSourceConfiguration;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.springframework.boot.SpringApplication;
|
||||
import org.springframework.context.ConfigurableApplicationContext;
|
||||
import org.springframework.context.annotation.Import;
|
||||
import org.springframework.core.io.Resource;
|
||||
|
||||
/**
|
||||
* Fineract main() application which launches Fineract in an embedded Tomcat HTTP
|
||||
* server (using Spring Boot), as well as an embedded database (using
|
||||
* MariaDB4j).
|
||||
*
|
||||
* You can easily launch this via Debug as Java Application in your IDE -
|
||||
* without needing command line Gradle stuff, no need to build and deploy a WAR,
|
||||
* remote attachment etc.
|
||||
*
|
||||
* It's the old/classic Mifos (non-X) Workspace 2.0 reborn for Fineract! ;-)
|
||||
*
|
||||
* @see ServerApplication for the same without the embedded MariaDB4j database
|
||||
*/
|
||||
public class ServerWithMariaDB4jApplication {
|
||||
private final static Logger LOG = LoggerFactory.getLogger(ServerWithMariaDB4jApplication.class);
|
||||
|
||||
@Import({ MariaDB4jDataSourceConfiguration.class, EmbeddedTomcatWithSSLConfiguration.class })
|
||||
public static class Configuration extends AbstractApplicationConfiguration { }
|
||||
|
||||
public static void main(String[] args) throws Exception {
|
||||
ConfigurableApplicationContext ctx = SpringApplication.run(Configuration.class, args);
|
||||
if (!Desktop.isDesktopSupported()) {
|
||||
LOG.info("Not going to open UI homepage in local web browser, because !Desktop.isDesktopSupported()");
|
||||
|
||||
} else {
|
||||
// apps/community-app/dist/community-app/index.html
|
||||
Resource distResource = ctx.getResource("file:" + System.getProperty("user.dir") +
|
||||
System.getProperty("file.separator") + "apps" +
|
||||
System.getProperty("file.separator") + "community-app" +
|
||||
System.getProperty("file.separator") + "dist" +
|
||||
System.getProperty("file.separator") + "community-app" +
|
||||
System.getProperty("file.separator") + "index.html");
|
||||
URI distURI = URI.create("https://localhost:8443/fineract-provider" +
|
||||
"/apps/community-app/index.html?baseApiUrl=https://localhost:8443" +
|
||||
"&tenantIdentifier=default#/");
|
||||
|
||||
// apps/community-app/app/index.html
|
||||
Resource devResource = ctx.getResource("file:" + System.getProperty("user.dir") +
|
||||
System.getProperty("file.separator") + "apps" +
|
||||
System.getProperty("file.separator") + "community-app" +
|
||||
System.getProperty("file.separator") + "app" +
|
||||
System.getProperty("file.separator") + "index.html");
|
||||
URI devURI = URI.create("https://localhost:8443/fineract-provider" +
|
||||
"/apps/community-app/app/index.html?baseApiUrl=https://localhost:8443" +
|
||||
"&tenantIdentifier=default#/");
|
||||
|
||||
if (distResource.exists()) {
|
||||
openWebBrowser(distURI);
|
||||
} else if (devResource.exists()) {
|
||||
openWebBrowser(devURI);
|
||||
} else {
|
||||
LOG.error("Cannot open Fineract UI in browser; not found: " + distResource.toString());
|
||||
}
|
||||
}
|
||||
|
||||
// TODO Tray Icon stuff; dig out my very own old @see https://github.com/mifos/head/tree/hudsonBuild-MIFOS-5157_Launch4j-EXE_NewDist-squash1/server-jetty/src/main/java/org/mifos/server/tray
|
||||
|
||||
ApplicationExitUtil.waitForKeyPressToCleanlyExit(ctx);
|
||||
}
|
||||
|
||||
private static void openWebBrowser(URI uri) {
|
||||
try {
|
||||
LOG.info("Opening Fineract UI in browser: " + uri.toString());
|
||||
Desktop.getDesktop().browse(uri);
|
||||
} catch (IOException e) {
|
||||
LOG.error("IOException when opening Fineract UI in browser: " + uri.toString(), e);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
+1
@@ -35,6 +35,7 @@ public enum GLClosureJsonInputParams {
|
||||
}
|
||||
|
||||
private static final Set<String> values = new HashSet<>();
|
||||
|
||||
static {
|
||||
for (final GLClosureJsonInputParams type : GLClosureJsonInputParams.values()) {
|
||||
values.add(type.value);
|
||||
|
||||
+1
-1
@@ -80,7 +80,7 @@ public class GLClosureReadPlatformServiceImpl implements GLClosureReadPlatformSe
|
||||
public List<GLClosureData> retrieveAllGLClosures(final Long officeId) {
|
||||
final GLClosureMapper rm = new GLClosureMapper();
|
||||
|
||||
String sql = "select " + rm.schema() + " and glClosure.is_deleted = 0";
|
||||
String sql = "select " + rm.schema() + " and glClosure.is_deleted = false";
|
||||
final Object[] objectArray = new Object[1];
|
||||
int arrayPos = 0;
|
||||
if (officeId != null && officeId != 0) {
|
||||
|
||||
+6
@@ -55,6 +55,7 @@ public final class AccountingConstants {
|
||||
}
|
||||
|
||||
private static final Map<Integer, CashAccountsForLoan> intToEnumMap = new HashMap<>();
|
||||
|
||||
static {
|
||||
for (final CashAccountsForLoan type : CashAccountsForLoan.values()) {
|
||||
intToEnumMap.put(type.value, type);
|
||||
@@ -92,6 +93,7 @@ public final class AccountingConstants {
|
||||
}
|
||||
|
||||
private static final Map<Integer, AccrualAccountsForLoan> intToEnumMap = new HashMap<>();
|
||||
|
||||
static {
|
||||
for (final AccrualAccountsForLoan type : AccrualAccountsForLoan.values()) {
|
||||
intToEnumMap.put(type.value, type);
|
||||
@@ -191,6 +193,7 @@ public final class AccountingConstants {
|
||||
}
|
||||
|
||||
private static final Map<Integer, CashAccountsForSavings> intToEnumMap = new HashMap<>();
|
||||
|
||||
static {
|
||||
for (final CashAccountsForSavings type : CashAccountsForSavings.values()) {
|
||||
intToEnumMap.put(type.value, type);
|
||||
@@ -278,6 +281,7 @@ public final class AccountingConstants {
|
||||
private final GLAccountType mappedGLAccountType;
|
||||
|
||||
private static List<FinancialActivityData> financialActivities;
|
||||
|
||||
static {
|
||||
financialActivities = new ArrayList<>();
|
||||
for (final FinancialActivity type : FinancialActivity.values()) {
|
||||
@@ -314,6 +318,7 @@ public final class AccountingConstants {
|
||||
}
|
||||
|
||||
private static final Map<Integer, FinancialActivity> intToEnumMap = new HashMap<>();
|
||||
|
||||
static {
|
||||
for (final FinancialActivity type : FinancialActivity.values()) {
|
||||
intToEnumMap.put(type.value, type);
|
||||
@@ -363,6 +368,7 @@ public final class AccountingConstants {
|
||||
}
|
||||
|
||||
private static final Map<Integer, CashAccountsForShares> intToEnumMap = new HashMap<>();
|
||||
|
||||
static {
|
||||
for (final CashAccountsForShares type : CashAccountsForShares.values()) {
|
||||
intToEnumMap.put(type.value, type);
|
||||
|
||||
+4
@@ -43,4 +43,8 @@ public interface AccountingDropdownReadPlatformService {
|
||||
|
||||
Map<String, List<GLAccountData>> retrieveAccountMappingOptionsForShareProducts();
|
||||
|
||||
List<GLAccountData> retrieveExpenseAccountOptions();
|
||||
|
||||
List<GLAccountData> retrieveAssetAccountOptions();
|
||||
|
||||
}
|
||||
|
||||
+10
@@ -95,6 +95,16 @@ public class AccountingDropdownReadPlatformServiceImpl implements AccountingDrop
|
||||
includeEquityAccounts);
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<GLAccountData> retrieveExpenseAccountOptions() {
|
||||
return accountReadPlatformService.retrieveAllEnabledDetailGLAccounts(GLAccountType.EXPENSE);
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<GLAccountData> retrieveAssetAccountOptions() {
|
||||
return accountReadPlatformService.retrieveAllEnabledDetailGLAccounts(GLAccountType.ASSET);
|
||||
}
|
||||
|
||||
private Map<String, List<GLAccountData>> retrieveAccountMappingOptions(boolean includeAssetAccounts, boolean includeIncomeAccounts,
|
||||
boolean includeExpenseAccounts, boolean includeLiabilityAccounts, boolean includeEquityAccounts) {
|
||||
final Map<String, List<GLAccountData>> accountOptions = new HashMap<>();
|
||||
|
||||
+1
@@ -32,6 +32,7 @@ public enum AccountingRuleType {
|
||||
private final String code;
|
||||
|
||||
private static final Map<Integer, AccountingRuleType> intToEnumMap = new HashMap<>();
|
||||
|
||||
static {
|
||||
for (final AccountingRuleType type : AccountingRuleType.values()) {
|
||||
intToEnumMap.put(type.value, type);
|
||||
|
||||
+1
@@ -35,6 +35,7 @@ public enum FinancialActivityAccountsJsonInputParams {
|
||||
}
|
||||
|
||||
private static final Set<String> values = new HashSet<>();
|
||||
|
||||
static {
|
||||
for (final FinancialActivityAccountsJsonInputParams type : FinancialActivityAccountsJsonInputParams.values()) {
|
||||
values.add(type.value);
|
||||
|
||||
+2
-2
@@ -74,7 +74,7 @@ public class FinancialActivityAccountWritePlatformServiceImpl implements Financi
|
||||
FinancialActivityAccount financialActivityAccount = FinancialActivityAccount.createNew(glAccount, financialActivityId);
|
||||
|
||||
validateFinancialActivityAndAccountMapping(financialActivityAccount);
|
||||
this.financialActivityAccountRepository.save(financialActivityAccount);
|
||||
this.financialActivityAccountRepository.saveAndFlush(financialActivityAccount);
|
||||
return new CommandProcessingResultBuilder() //
|
||||
.withCommandId(command.commandId()) //
|
||||
.withEntityId(financialActivityAccount.getId()) //
|
||||
@@ -122,7 +122,7 @@ public class FinancialActivityAccountWritePlatformServiceImpl implements Financi
|
||||
|
||||
if (!changes.isEmpty()) {
|
||||
validateFinancialActivityAndAccountMapping(financialActivityAccount);
|
||||
this.financialActivityAccountRepository.save(financialActivityAccount);
|
||||
this.financialActivityAccountRepository.saveAndFlush(financialActivityAccount);
|
||||
}
|
||||
return new CommandProcessingResultBuilder() //
|
||||
.withCommandId(command.commandId()) //
|
||||
|
||||
+1
@@ -36,6 +36,7 @@ public enum GLAccountJsonInputParams {
|
||||
}
|
||||
|
||||
private static final Set<String> values = new HashSet<>();
|
||||
|
||||
static {
|
||||
for (final GLAccountJsonInputParams type : GLAccountJsonInputParams.values()) {
|
||||
values.add(type.value);
|
||||
|
||||
+2
-2
@@ -18,8 +18,6 @@
|
||||
*/
|
||||
package org.apache.fineract.accounting.glaccount.api;
|
||||
|
||||
import com.sun.jersey.core.header.FormDataContentDisposition;
|
||||
import com.sun.jersey.multipart.FormDataParam;
|
||||
import io.swagger.v3.oas.annotations.Operation;
|
||||
import io.swagger.v3.oas.annotations.Parameter;
|
||||
import io.swagger.v3.oas.annotations.media.ArraySchema;
|
||||
@@ -68,6 +66,8 @@ import org.apache.fineract.infrastructure.core.data.EnumOptionData;
|
||||
import org.apache.fineract.infrastructure.core.serialization.ApiRequestJsonSerializationSettings;
|
||||
import org.apache.fineract.infrastructure.core.serialization.DefaultToApiJsonSerializer;
|
||||
import org.apache.fineract.infrastructure.security.service.PlatformSecurityContext;
|
||||
import org.glassfish.jersey.media.multipart.FormDataContentDisposition;
|
||||
import org.glassfish.jersey.media.multipart.FormDataParam;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.context.annotation.Scope;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
+33
@@ -69,6 +69,39 @@ public class GLAccountData implements Serializable {
|
||||
return new GLAccountData(name, parentId, glCode, manualEntriesAllowed, type, usage, description, tagId, rowIndex);
|
||||
}
|
||||
|
||||
public static GLAccountData createFrom(final Long id) {
|
||||
return new GLAccountData(id);
|
||||
}
|
||||
|
||||
private GLAccountData(final Long id) {
|
||||
|
||||
this.name = null;
|
||||
this.parentId = null;
|
||||
this.glCode = null;
|
||||
this.manualEntriesAllowed = null;
|
||||
this.type = null;
|
||||
this.usage = null;
|
||||
this.description = null;
|
||||
this.tagId = null;
|
||||
this.rowIndex = null;
|
||||
this.id = id;
|
||||
this.disabled = null;
|
||||
this.nameDecorated = null;
|
||||
this.organizationRunningBalance = null;
|
||||
this.accountTypeOptions = null;
|
||||
this.usageOptions = null;
|
||||
this.assetHeaderAccountOptions = null;
|
||||
this.liabilityHeaderAccountOptions = null;
|
||||
this.equityHeaderAccountOptions = null;
|
||||
this.incomeHeaderAccountOptions = null;
|
||||
this.expenseHeaderAccountOptions = null;
|
||||
this.allowedAssetsTagOptions = null;
|
||||
this.allowedLiabilitiesTagOptions = null;
|
||||
this.allowedEquityTagOptions = null;
|
||||
this.allowedIncomeTagOptions = null;
|
||||
this.allowedExpensesTagOptions = null;
|
||||
}
|
||||
|
||||
private GLAccountData(String name, Long parentId, String glCode, Boolean manualEntriesAllowed, EnumOptionData type,
|
||||
EnumOptionData usage, String description, CodeValueData tagId, Integer rowIndex) {
|
||||
|
||||
|
||||
+4
@@ -18,9 +18,13 @@
|
||||
*/
|
||||
package org.apache.fineract.accounting.glaccount.domain;
|
||||
|
||||
import java.util.Optional;
|
||||
import org.springframework.data.jpa.repository.JpaRepository;
|
||||
import org.springframework.data.jpa.repository.JpaSpecificationExecutor;
|
||||
|
||||
public interface GLAccountRepository extends JpaRepository<GLAccount, Long>, JpaSpecificationExecutor<GLAccount> {
|
||||
|
||||
// no added behaviour
|
||||
// adding behaviour to fetch id by glcode for opening balance bulk import
|
||||
Optional<GLAccount> findOneByGlCode(String glCode);
|
||||
}
|
||||
|
||||
+5
@@ -41,4 +41,9 @@ public class GLAccountRepositoryWrapper {
|
||||
return this.repository.findById(id).orElseThrow(() -> new GLAccountNotFoundException(id));
|
||||
}
|
||||
|
||||
// finding account id by glcode for opening balance bulk import
|
||||
public GLAccount findOneByGlCodeWithNotFoundDetection(final String glCode) {
|
||||
return this.repository.findOneByGlCode(glCode).orElseThrow(() -> new GLAccountNotFoundException(glCode));
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
+1
@@ -46,6 +46,7 @@ public enum GLAccountType {
|
||||
private static final Map<Integer, GLAccountType> intToEnumMap = new HashMap<>();
|
||||
private static int minValue;
|
||||
private static int maxValue;
|
||||
|
||||
static {
|
||||
int i = 0;
|
||||
for (final GLAccountType type : GLAccountType.values()) {
|
||||
|
||||
+1
@@ -44,6 +44,7 @@ public enum GLAccountUsage {
|
||||
private static final Map<Integer, GLAccountUsage> intToEnumMap = new HashMap<>();
|
||||
private static int minValue;
|
||||
private static int maxValue;
|
||||
|
||||
static {
|
||||
int i = 0;
|
||||
for (final GLAccountUsage type : GLAccountUsage.values()) {
|
||||
|
||||
+4
@@ -33,4 +33,8 @@ public class GLAccountNotFoundException extends AbstractPlatformResourceNotFound
|
||||
public GLAccountNotFoundException(final Long id, EmptyResultDataAccessException e) {
|
||||
super("error.msg.glaccount.id.invalid", "General Ledger account with identifier " + id + " does not exist ", id, e);
|
||||
}
|
||||
|
||||
public GLAccountNotFoundException(final String glCode) {
|
||||
super("error.msg.glaccount.code.invalid", "General Ledger account with GlCode " + glCode + " does not exist ", glCode);
|
||||
}
|
||||
}
|
||||
|
||||
+2
-2
@@ -130,7 +130,7 @@ public class GLAccountReadPlatformServiceImpl implements GLAccountReadPlatformSe
|
||||
if (associationParametersData != null) {
|
||||
if (associationParametersData.isRunningBalanceRequired()) {
|
||||
sql = sql + " and gl_j.id in (select t1.id from (select t2.account_id, max(t2.id) as id from "
|
||||
+ "(select id, max(entry_date) as entry_date, account_id from acc_gl_journal_entry where is_running_balance_calculated = 1 "
|
||||
+ "(select id, max(entry_date) as entry_date, account_id from acc_gl_journal_entry where is_running_balance_calculated = true "
|
||||
+ "group by account_id desc, id) t3 inner join acc_gl_journal_entry t2 on t2.account_id = t3.account_id and t2.entry_date = t3.entry_date "
|
||||
+ "group by t2.account_id desc) t1)";
|
||||
}
|
||||
@@ -214,7 +214,7 @@ public class GLAccountReadPlatformServiceImpl implements GLAccountReadPlatformSe
|
||||
final StringBuilder sql = new StringBuilder();
|
||||
sql.append("select ").append(rm.schema());
|
||||
if (associationParametersData.isRunningBalanceRequired()) {
|
||||
sql.append(" and gl_j.is_running_balance_calculated = 1 ");
|
||||
sql.append(" and gl_j.is_running_balance_calculated = true ");
|
||||
}
|
||||
sql.append("where gl.id = ?");
|
||||
if (associationParametersData.isRunningBalanceRequired()) {
|
||||
|
||||
+1
-1
@@ -107,7 +107,7 @@ public class GLAccountWritePlatformServiceJpaRepositoryImpl implements GLAccount
|
||||
|
||||
glAccount.generateHierarchy();
|
||||
|
||||
this.glAccountRepository.save(glAccount);
|
||||
this.glAccountRepository.saveAndFlush(glAccount);
|
||||
|
||||
return new CommandProcessingResultBuilder().withCommandId(command.commandId()).withEntityId(glAccount.getId()).build();
|
||||
} catch (final JpaSystemException | DataIntegrityViolationException dve) {
|
||||
|
||||
+2
-2
@@ -19,11 +19,11 @@
|
||||
package org.apache.fineract.accounting.journalentry.api;
|
||||
|
||||
import java.time.LocalDate;
|
||||
import java.time.ZoneId;
|
||||
import java.util.Date;
|
||||
import java.util.Locale;
|
||||
import javax.ws.rs.WebApplicationException;
|
||||
import org.apache.fineract.infrastructure.core.serialization.JsonParserHelper;
|
||||
import org.apache.fineract.infrastructure.core.service.DateUtils;
|
||||
|
||||
/**
|
||||
* Class for parsing dates sent as query parameters
|
||||
@@ -41,6 +41,6 @@ public class DateParam {
|
||||
public Date getDate(final String parameterName, final String dateFormat, final String localeAsString) {
|
||||
final Locale locale = JsonParserHelper.localeFromString(localeAsString);
|
||||
final LocalDate localDate = JsonParserHelper.convertFrom(this.dateAsString, parameterName, dateFormat, locale);
|
||||
return Date.from(localDate.atStartOfDay(DateUtils.getDateTimeZoneOfTenant()).toInstant());
|
||||
return Date.from(localDate.atStartOfDay(ZoneId.systemDefault()).toInstant());
|
||||
}
|
||||
}
|
||||
|
||||
+2
-2
@@ -18,8 +18,6 @@
|
||||
*/
|
||||
package org.apache.fineract.accounting.journalentry.api;
|
||||
|
||||
import com.sun.jersey.core.header.FormDataContentDisposition;
|
||||
import com.sun.jersey.multipart.FormDataParam;
|
||||
import io.swagger.v3.oas.annotations.Operation;
|
||||
import io.swagger.v3.oas.annotations.Parameter;
|
||||
import io.swagger.v3.oas.annotations.media.ArraySchema;
|
||||
@@ -66,6 +64,8 @@ import org.apache.fineract.infrastructure.core.serialization.DefaultToApiJsonSer
|
||||
import org.apache.fineract.infrastructure.core.service.Page;
|
||||
import org.apache.fineract.infrastructure.core.service.SearchParameters;
|
||||
import org.apache.fineract.infrastructure.security.service.PlatformSecurityContext;
|
||||
import org.glassfish.jersey.media.multipart.FormDataContentDisposition;
|
||||
import org.glassfish.jersey.media.multipart.FormDataParam;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.context.annotation.Scope;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
+1
@@ -39,6 +39,7 @@ public enum JournalEntryJsonInputParams {
|
||||
}
|
||||
|
||||
private static final Set<String> values = new HashSet<>();
|
||||
|
||||
static {
|
||||
for (final JournalEntryJsonInputParams type : JournalEntryJsonInputParams.values()) {
|
||||
values.add(type.value);
|
||||
|
||||
+1
@@ -30,6 +30,7 @@ public class ChargePaymentDTO {
|
||||
this.chargeId = chargeId;
|
||||
this.amount = amount;
|
||||
this.loanChargeId = loanChargeId;
|
||||
|
||||
}
|
||||
|
||||
public Long getChargeId() {
|
||||
|
||||
+111
@@ -90,6 +90,49 @@ public class JournalEntryData {
|
||||
private String routingCode;
|
||||
private String receiptNumber;
|
||||
private String bankNumber;
|
||||
private transient Long savingTransactionId;
|
||||
|
||||
// for opening bal bulk import
|
||||
public JournalEntryData(Long officeId, LocalDate transactionDate, String currencyCode, List<CreditDebit> credits,
|
||||
List<CreditDebit> debits, String locale, String dateFormat) {
|
||||
this.officeId = officeId;
|
||||
this.dateFormat = dateFormat;
|
||||
this.locale = locale;
|
||||
this.transactionDate = transactionDate;
|
||||
this.currencyCode = currencyCode;
|
||||
this.credits = credits;
|
||||
this.debits = debits;
|
||||
this.rowIndex = null;
|
||||
this.paymentTypeId = null;
|
||||
this.accountNumber = null;
|
||||
this.checkNumber = null;
|
||||
this.routingCode = null;
|
||||
this.receiptNumber = null;
|
||||
this.bankNumber = null;
|
||||
this.comments = null;
|
||||
this.id = null;
|
||||
this.officeName = null;
|
||||
this.glAccountName = null;
|
||||
this.glAccountId = null;
|
||||
this.glAccountCode = null;
|
||||
this.glAccountType = null;
|
||||
this.entryType = null;
|
||||
this.amount = null;
|
||||
this.currency = null;
|
||||
this.transactionId = null;
|
||||
this.manualEntry = null;
|
||||
this.entityType = null;
|
||||
this.entityId = null;
|
||||
this.createdByUserId = null;
|
||||
this.createdDate = null;
|
||||
this.createdByUserName = null;
|
||||
this.reversed = null;
|
||||
this.referenceNumber = null;
|
||||
this.officeRunningBalance = null;
|
||||
this.organizationRunningBalance = null;
|
||||
this.runningBalanceComputed = null;
|
||||
this.transactionDetails = null;
|
||||
}
|
||||
|
||||
public static JournalEntryData importInstance(Long officeId, LocalDate transactionDate, String currencyCode, Long paymentTypeId,
|
||||
Integer rowIndex, List<CreditDebit> credits, List<CreditDebit> debits, String accountNumber, String checkNumber,
|
||||
@@ -98,6 +141,11 @@ public class JournalEntryData {
|
||||
checkNumber, routingCode, receiptNumber, bankNumber, comments, locale, dateFormat);
|
||||
}
|
||||
|
||||
public static JournalEntryData importInstance1(Long officeId, LocalDate transactionDate, String currencyCode, List<CreditDebit> credits,
|
||||
List<CreditDebit> debits, String locale, String dateFormat) {
|
||||
return new JournalEntryData(officeId, transactionDate, currencyCode, credits, debits, locale, dateFormat);
|
||||
}
|
||||
|
||||
private JournalEntryData(Long officeId, LocalDate transactionDate, String currencyCode, Long paymentTypeId, Integer rowIndex,
|
||||
List<CreditDebit> credits, List<CreditDebit> debits, String accountNumber, String checkNumber, String routingCode,
|
||||
String receiptNumber, String bankNumber, String comments, String locale, String dateFormat) {
|
||||
@@ -192,6 +240,40 @@ public class JournalEntryData {
|
||||
this.currency = currency;
|
||||
}
|
||||
|
||||
public JournalEntryData(final Long id, final Long officeId, final String glAccountName, final Long glAccountId,
|
||||
final String glAccountCode, final EnumOptionData glAccountClassification, final LocalDate transactionDate,
|
||||
final EnumOptionData entryType, final BigDecimal amount, final String transactionId, final Boolean manualEntry,
|
||||
final EnumOptionData entityType, final Long entityId, final LocalDate createdDate, final String currencyCode,
|
||||
final Long savingTransactionId) {
|
||||
this.id = id;
|
||||
this.officeId = officeId;
|
||||
this.officeName = null;
|
||||
this.glAccountName = glAccountName;
|
||||
this.glAccountId = glAccountId;
|
||||
this.glAccountCode = glAccountCode;
|
||||
this.glAccountType = glAccountClassification;
|
||||
this.transactionDate = transactionDate;
|
||||
this.entryType = entryType;
|
||||
this.amount = amount;
|
||||
this.transactionId = transactionId;
|
||||
this.savingTransactionId = savingTransactionId;
|
||||
this.manualEntry = manualEntry;
|
||||
this.entityType = entityType;
|
||||
this.entityId = entityId;
|
||||
this.createdByUserId = null;
|
||||
this.createdDate = createdDate;
|
||||
this.createdByUserName = null;
|
||||
this.comments = null;
|
||||
this.reversed = false;
|
||||
this.referenceNumber = null;
|
||||
this.officeRunningBalance = null;
|
||||
this.organizationRunningBalance = null;
|
||||
this.runningBalanceComputed = null;
|
||||
this.transactionDetails = null;
|
||||
this.currency = null;
|
||||
this.currencyCode = currencyCode;
|
||||
}
|
||||
|
||||
public static JournalEntryData fromGLAccountData(final GLAccountData glAccountData) {
|
||||
|
||||
final Long id = null;
|
||||
@@ -252,4 +334,33 @@ public class JournalEntryData {
|
||||
public String getTransactionId() {
|
||||
return transactionId;
|
||||
}
|
||||
|
||||
public Long getSavingTransactionId() {
|
||||
return this.savingTransactionId;
|
||||
}
|
||||
|
||||
public String getCurrencyCode() {
|
||||
return this.currencyCode;
|
||||
}
|
||||
|
||||
public boolean isManualEntry() {
|
||||
return this.manualEntry;
|
||||
}
|
||||
|
||||
public EnumOptionData getEntityType() {
|
||||
return this.entityType;
|
||||
}
|
||||
|
||||
public Long getEntityId() {
|
||||
return this.entityId;
|
||||
}
|
||||
|
||||
public LocalDate getCreatedDate() {
|
||||
return this.createdDate;
|
||||
}
|
||||
|
||||
public Long getPaymentTypeId() {
|
||||
return this.paymentTypeId;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
+8
@@ -222,4 +222,12 @@ public class JournalEntry extends AbstractAuditableCustom {
|
||||
return this.shareTransactionId;
|
||||
}
|
||||
|
||||
public boolean isReversed() {
|
||||
return this.reversed;
|
||||
}
|
||||
|
||||
public String getDescription() {
|
||||
return this.description;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
+1
@@ -42,6 +42,7 @@ public enum JournalEntryType {
|
||||
}
|
||||
|
||||
private static final Map<Integer, JournalEntryType> intToEnumMap = new HashMap<>();
|
||||
|
||||
static {
|
||||
for (final JournalEntryType type : JournalEntryType.values()) {
|
||||
intToEnumMap.put(type.value, type);
|
||||
|
||||
-1
@@ -23,5 +23,4 @@ import org.apache.fineract.accounting.journalentry.data.SavingsDTO;
|
||||
public interface AccountingProcessorForSavings {
|
||||
|
||||
void createJournalEntriesForSavings(SavingsDTO savingsDTO);
|
||||
|
||||
}
|
||||
|
||||
+38
-15
@@ -20,11 +20,13 @@ package org.apache.fineract.accounting.journalentry.service;
|
||||
|
||||
import java.math.BigDecimal;
|
||||
import java.time.LocalDate;
|
||||
import java.time.ZoneId;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Date;
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import javax.sql.DataSource;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
import org.apache.fineract.accounting.closure.domain.GLClosure;
|
||||
import org.apache.fineract.accounting.closure.domain.GLClosureRepository;
|
||||
@@ -58,12 +60,13 @@ import org.apache.fineract.accounting.producttoaccountmapping.domain.ProductToGL
|
||||
import org.apache.fineract.accounting.producttoaccountmapping.exception.ProductToGLAccountMappingNotFoundException;
|
||||
import org.apache.fineract.infrastructure.core.data.EnumOptionData;
|
||||
import org.apache.fineract.infrastructure.core.exception.PlatformDataIntegrityException;
|
||||
import org.apache.fineract.infrastructure.core.service.DateUtils;
|
||||
import org.apache.fineract.infrastructure.core.service.RoutingDataSource;
|
||||
import org.apache.fineract.organisation.monetary.data.CurrencyData;
|
||||
import org.apache.fineract.organisation.office.domain.Office;
|
||||
import org.apache.fineract.organisation.office.domain.OfficeRepositoryWrapper;
|
||||
import org.apache.fineract.portfolio.account.PortfolioAccountType;
|
||||
import org.apache.fineract.portfolio.account.service.AccountTransfersReadPlatformService;
|
||||
import org.apache.fineract.portfolio.charge.domain.ChargeRepositoryWrapper;
|
||||
import org.apache.fineract.portfolio.client.domain.ClientTransaction;
|
||||
import org.apache.fineract.portfolio.client.domain.ClientTransactionRepositoryWrapper;
|
||||
import org.apache.fineract.portfolio.loanaccount.data.LoanTransactionEnumData;
|
||||
@@ -74,7 +77,11 @@ import org.apache.fineract.portfolio.savings.data.SavingsAccountTransactionEnumD
|
||||
import org.apache.fineract.portfolio.savings.domain.SavingsAccountTransaction;
|
||||
import org.apache.fineract.portfolio.savings.domain.SavingsAccountTransactionRepository;
|
||||
import org.apache.fineract.portfolio.shareaccounts.data.ShareAccountTransactionEnumData;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.dao.DataAccessException;
|
||||
import org.springframework.jdbc.core.JdbcTemplate;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
@Service
|
||||
@@ -95,6 +102,10 @@ public class AccountingProcessorHelper {
|
||||
private final ClientTransactionRepositoryWrapper clientTransactionRepository;
|
||||
private final SavingsAccountTransactionRepository savingsAccountTransactionRepository;
|
||||
private final AccountTransfersReadPlatformService accountTransfersReadPlatformService;
|
||||
private final ChargeRepositoryWrapper chargeRepositoryWrapper;
|
||||
private final JdbcTemplate jdbcTemplate;
|
||||
private final DataSource dataSource;
|
||||
private static final Logger LOG = LoggerFactory.getLogger(AccountingProcessorHelper.class);
|
||||
|
||||
@Autowired
|
||||
public AccountingProcessorHelper(final JournalEntryRepository glJournalEntryRepository,
|
||||
@@ -104,8 +115,10 @@ public class AccountingProcessorHelper {
|
||||
final FinancialActivityAccountRepositoryWrapper financialActivityAccountRepository,
|
||||
final AccountTransfersReadPlatformService accountTransfersReadPlatformService,
|
||||
final GLAccountRepositoryWrapper accountRepositoryWrapper,
|
||||
final ClientTransactionRepositoryWrapper clientTransactionRepositoryWrapper) {
|
||||
final ClientTransactionRepositoryWrapper clientTransactionRepositoryWrapper,
|
||||
final ChargeRepositoryWrapper chargeRepositoryWrapper, final RoutingDataSource dataSource) {
|
||||
this.glJournalEntryRepository = glJournalEntryRepository;
|
||||
this.dataSource = dataSource;
|
||||
this.accountMappingRepository = accountMappingRepository;
|
||||
this.closureRepository = closureRepository;
|
||||
this.officeRepositoryWrapper = officeRepositoryWrapper;
|
||||
@@ -115,6 +128,8 @@ public class AccountingProcessorHelper {
|
||||
this.accountTransfersReadPlatformService = accountTransfersReadPlatformService;
|
||||
this.accountRepositoryWrapper = accountRepositoryWrapper;
|
||||
this.clientTransactionRepository = clientTransactionRepositoryWrapper;
|
||||
this.chargeRepositoryWrapper = chargeRepositoryWrapper;
|
||||
this.jdbcTemplate = new JdbcTemplate(this.dataSource);
|
||||
}
|
||||
|
||||
public LoanDTO populateLoanDtoFromMap(final Map<String, Object> accountingBridgeData, final boolean cashBasedAccountingEnabled,
|
||||
@@ -132,8 +147,7 @@ public class AccountingProcessorHelper {
|
||||
for (final Map<String, Object> map : newTransactionsMap) {
|
||||
final Long transactionOfficeId = (Long) map.get("officeId");
|
||||
final String transactionId = ((Long) map.get("id")).toString();
|
||||
final Date transactionDate = Date
|
||||
.from(((LocalDate) map.get("date")).atStartOfDay(DateUtils.getDateTimeZoneOfTenant()).toInstant());
|
||||
final Date transactionDate = Date.from(((LocalDate) map.get("date")).atStartOfDay(ZoneId.systemDefault()).toInstant());
|
||||
final LoanTransactionEnumData transactionType = (LoanTransactionEnumData) map.get("type");
|
||||
final BigDecimal amount = (BigDecimal) map.get("amount");
|
||||
final BigDecimal principal = (BigDecimal) map.get("principalPortion");
|
||||
@@ -200,8 +214,7 @@ public class AccountingProcessorHelper {
|
||||
for (final Map<String, Object> map : newTransactionsMap) {
|
||||
final Long transactionOfficeId = (Long) map.get("officeId");
|
||||
final String transactionId = ((Long) map.get("id")).toString();
|
||||
final Date transactionDate = Date
|
||||
.from(((LocalDate) map.get("date")).atStartOfDay(DateUtils.getDateTimeZoneOfTenant()).toInstant());
|
||||
final Date transactionDate = Date.from(((LocalDate) map.get("date")).atStartOfDay(ZoneId.systemDefault()).toInstant());
|
||||
final SavingsAccountTransactionEnumData transactionType = (SavingsAccountTransactionEnumData) map.get("type");
|
||||
final BigDecimal amount = (BigDecimal) map.get("amount");
|
||||
final boolean reversed = (Boolean) map.get("reversed");
|
||||
@@ -270,8 +283,7 @@ public class AccountingProcessorHelper {
|
||||
for (final Map<String, Object> map : newTransactionsMap) {
|
||||
final Long transactionOfficeId = (Long) map.get("officeId");
|
||||
final String transactionId = ((Long) map.get("id")).toString();
|
||||
final Date transactionDate = Date
|
||||
.from(((LocalDate) map.get("date")).atStartOfDay(DateUtils.getDateTimeZoneOfTenant()).toInstant());
|
||||
final Date transactionDate = Date.from(((LocalDate) map.get("date")).atStartOfDay(ZoneId.systemDefault()).toInstant());
|
||||
final ShareAccountTransactionEnumData transactionType = (ShareAccountTransactionEnumData) map.get("type");
|
||||
final ShareAccountTransactionEnumData transactionStatus = (ShareAccountTransactionEnumData) map.get("status");
|
||||
final BigDecimal amount = (BigDecimal) map.get("amount");
|
||||
@@ -308,7 +320,7 @@ public class AccountingProcessorHelper {
|
||||
final Long clientId = (Long) accountingBridgeData.get("clientId");
|
||||
final Long transactionId = (Long) accountingBridgeData.get("id");
|
||||
final Date transactionDate = Date
|
||||
.from(((LocalDate) accountingBridgeData.get("date")).atStartOfDay(DateUtils.getDateTimeZoneOfTenant()).toInstant());
|
||||
.from(((LocalDate) accountingBridgeData.get("date")).atStartOfDay(ZoneId.systemDefault()).toInstant());
|
||||
final EnumOptionData transactionType = (EnumOptionData) accountingBridgeData.get("type");
|
||||
final BigDecimal amount = (BigDecimal) accountingBridgeData.get("amount");
|
||||
final boolean reversed = (Boolean) accountingBridgeData.get("reversed");
|
||||
@@ -761,7 +773,7 @@ public class AccountingProcessorHelper {
|
||||
* chargePaymentDTOs
|
||||
*/
|
||||
public void createCashBasedJournalEntriesAndReversalsForSavingsCharges(final Office office, final String currencyCode,
|
||||
final CashAccountsForSavings accountTypeToBeDebited, final CashAccountsForSavings accountTypeToBeCredited,
|
||||
final CashAccountsForSavings accountTypeToBeDebited, CashAccountsForSavings accountTypeToBeCredited,
|
||||
final Long savingsProductId, final Long paymentTypeId, final Long loanId, final String transactionId,
|
||||
final Date transactionDate, final BigDecimal totalAmount, final Boolean isReversal,
|
||||
final List<ChargePaymentDTO> chargePaymentDTOs) {
|
||||
@@ -777,9 +789,9 @@ public class AccountingProcessorHelper {
|
||||
"Recent Portfolio changes w.r.t Charges for Savings have Broken the accounting code");
|
||||
}
|
||||
ChargePaymentDTO chargePaymentDTO = chargePaymentDTOs.get(0);
|
||||
|
||||
final GLAccount chargeSpecificAccount = getLinkedGLAccountForSavingsCharges(savingsProductId, accountTypeToBeCredited.getValue(),
|
||||
GLAccount chargeSpecificAccount = getLinkedGLAccountForSavingsCharges(savingsProductId, accountTypeToBeCredited.getValue(),
|
||||
chargePaymentDTO.getChargeId());
|
||||
|
||||
final GLAccount savingsControlAccount = getLinkedGLAccountForSavingsProduct(savingsProductId, accountTypeToBeDebited.getValue(),
|
||||
paymentTypeId);
|
||||
if (isReversal) {
|
||||
@@ -841,7 +853,8 @@ public class AccountingProcessorHelper {
|
||||
}
|
||||
|
||||
private void createCreditJournalEntryForSavings(final Office office, final String currencyCode, final GLAccount account,
|
||||
final Long savingsId, final String transactionId, final Date transactionDate, final BigDecimal amount) {
|
||||
final Long savingsId, final String transactionId, final Date transactionDate, final BigDecimal amount)
|
||||
throws DataAccessException {
|
||||
final boolean manualEntry = false;
|
||||
LoanTransaction loanTransaction = null;
|
||||
SavingsAccountTransaction savingsAccountTransaction = null;
|
||||
@@ -857,6 +870,7 @@ public class AccountingProcessorHelper {
|
||||
final JournalEntry journalEntry = JournalEntry.createNew(office, paymentDetail, account, currencyCode, modifiedTransactionId,
|
||||
manualEntry, transactionDate, JournalEntryType.CREDIT, amount, null, PortfolioProductType.SAVING.getValue(), savingsId,
|
||||
null, loanTransaction, savingsAccountTransaction, clientTransaction, shareTransactionId);
|
||||
|
||||
this.glJournalEntryRepository.saveAndFlush(journalEntry);
|
||||
}
|
||||
|
||||
@@ -947,6 +961,7 @@ public class AccountingProcessorHelper {
|
||||
final JournalEntry journalEntry = JournalEntry.createNew(office, paymentDetail, account, currencyCode, modifiedTransactionId,
|
||||
manualEntry, transactionDate, JournalEntryType.DEBIT, amount, null, PortfolioProductType.SAVING.getValue(), savingsId, null,
|
||||
loanTransaction, savingsAccountTransaction, clientTransaction, shareTransactionId);
|
||||
|
||||
this.glJournalEntryRepository.saveAndFlush(journalEntry);
|
||||
}
|
||||
|
||||
@@ -1083,7 +1098,7 @@ public class AccountingProcessorHelper {
|
||||
final JournalEntry journalEntry = JournalEntry.createNew(office, paymentDetail, account, currencyCode, modifiedTransactionId,
|
||||
manualEntry, transactionDate, JournalEntryType.DEBIT, amount, null, PortfolioProductType.SHARES.getValue(), shareAccountId,
|
||||
null, loanTransaction, savingsAccountTransaction, clientTransaction, shareTransactionId);
|
||||
this.glJournalEntryRepository.save(journalEntry);
|
||||
this.glJournalEntryRepository.saveAndFlush(journalEntry);
|
||||
}
|
||||
|
||||
private void createCreditJournalEntryForShares(final Office office, final String currencyCode, final GLAccount account,
|
||||
@@ -1102,7 +1117,7 @@ public class AccountingProcessorHelper {
|
||||
final JournalEntry journalEntry = JournalEntry.createNew(office, paymentDetail, account, currencyCode, modifiedTransactionId,
|
||||
manualEntry, transactionDate, JournalEntryType.CREDIT, amount, null, PortfolioProductType.SHARES.getValue(), shareAccountId,
|
||||
null, loanTransaction, savingsAccountTransaction, clientTransaction, shareTransactionId);
|
||||
this.glJournalEntryRepository.save(journalEntry);
|
||||
this.glJournalEntryRepository.saveAndFlush(journalEntry);
|
||||
}
|
||||
|
||||
public GLAccount getLinkedGLAccountForLoanProduct(final Long loanProductId, final int accountMappingTypeId, final Long paymentTypeId) {
|
||||
@@ -1161,6 +1176,7 @@ public class AccountingProcessorHelper {
|
||||
|
||||
private GLAccount getLinkedGLAccountForSavingsCharges(final Long savingsProductId, final int accountMappingTypeId,
|
||||
final Long chargeId) {
|
||||
|
||||
ProductToGLAccountMapping accountMapping = this.accountMappingRepository.findCoreProductToFinAccountMapping(savingsProductId,
|
||||
PortfolioProductType.SAVING.getValue(), accountMappingTypeId);
|
||||
/*****
|
||||
@@ -1170,15 +1186,22 @@ public class AccountingProcessorHelper {
|
||||
*****/
|
||||
|
||||
// Vishwas TODO: remove this condition as it should always be true
|
||||
|
||||
if (accountMappingTypeId == CashAccountsForSavings.INCOME_FROM_FEES.getValue()
|
||||
|| accountMappingTypeId == CashAccountsForLoan.INCOME_FROM_PENALTIES.getValue()) {
|
||||
GLAccount glAccount = chargeRepositoryWrapper.findOneWithNotFoundDetection(chargeId).getAccount();
|
||||
if (glAccount != null) {
|
||||
return glAccount;
|
||||
}
|
||||
final ProductToGLAccountMapping chargeSpecificIncomeAccountMapping = this.accountMappingRepository
|
||||
.findProductIdAndProductTypeAndFinancialAccountTypeAndChargeId(savingsProductId, PortfolioProductType.SAVING.getValue(),
|
||||
accountMappingTypeId, chargeId);
|
||||
if (chargeSpecificIncomeAccountMapping != null) {
|
||||
|
||||
accountMapping = chargeSpecificIncomeAccountMapping;
|
||||
}
|
||||
}
|
||||
|
||||
return accountMapping.getGlAccount();
|
||||
}
|
||||
|
||||
|
||||
+4
-8
@@ -215,17 +215,13 @@ public class AccrualBasedAccountingProcessorForLoan implements AccountingProcess
|
||||
|
||||
// handle fees payment of writeOff (and reversals)
|
||||
if (feesAmount != null && !(feesAmount.compareTo(BigDecimal.ZERO) == 0)) {
|
||||
|
||||
totalDebitAmount = totalDebitAmount.add(feesAmount);
|
||||
|
||||
if (isIncomeFromFee) {
|
||||
GLAccount account = this.helper.getLinkedGLAccountForLoanProduct(loanProductId,
|
||||
AccrualAccountsForLoan.INCOME_FROM_FEES.getValue(), paymentTypeId);
|
||||
if (accountMap.containsKey(account)) {
|
||||
BigDecimal amount = accountMap.get(account).add(feesAmount);
|
||||
accountMap.put(account, amount);
|
||||
} else {
|
||||
accountMap.put(account, feesAmount);
|
||||
}
|
||||
this.helper.createCreditJournalEntryOrReversalForLoanCharges(office, currencyCode,
|
||||
AccrualAccountsForLoan.INCOME_FROM_FEES.getValue(), loanProductId, loanId, transactionId, transactionDate,
|
||||
feesAmount, isReversal, loanTransactionDTO.getFeePayments());
|
||||
} else {
|
||||
GLAccount account = this.helper.getLinkedGLAccountForLoanProduct(loanProductId,
|
||||
AccrualAccountsForLoan.FEES_RECEIVABLE.getValue(), paymentTypeId);
|
||||
|
||||
+20
-24
@@ -49,6 +49,7 @@ import org.apache.fineract.infrastructure.core.service.Page;
|
||||
import org.apache.fineract.infrastructure.core.service.PaginationHelper;
|
||||
import org.apache.fineract.infrastructure.core.service.RoutingDataSource;
|
||||
import org.apache.fineract.infrastructure.core.service.SearchParameters;
|
||||
import org.apache.fineract.infrastructure.core.service.database.DatabaseSpecificSQLGenerator;
|
||||
import org.apache.fineract.infrastructure.security.utils.ColumnValidator;
|
||||
import org.apache.fineract.organisation.monetary.data.CurrencyData;
|
||||
import org.apache.fineract.organisation.office.data.OfficeData;
|
||||
@@ -77,18 +78,22 @@ public class JournalEntryReadPlatformServiceImpl implements JournalEntryReadPlat
|
||||
private final ColumnValidator columnValidator;
|
||||
private final FinancialActivityAccountRepositoryWrapper financialActivityAccountRepositoryWrapper;
|
||||
|
||||
private final PaginationHelper<JournalEntryData> paginationHelper = new PaginationHelper<>();
|
||||
private final PaginationHelper paginationHelper;
|
||||
private final DatabaseSpecificSQLGenerator sqlGenerator;
|
||||
|
||||
@Autowired
|
||||
public JournalEntryReadPlatformServiceImpl(final RoutingDataSource dataSource,
|
||||
final GLAccountReadPlatformService glAccountReadPlatformService, final ColumnValidator columnValidator,
|
||||
final OfficeReadPlatformService officeReadPlatformService,
|
||||
final FinancialActivityAccountRepositoryWrapper financialActivityAccountRepositoryWrapper) {
|
||||
final FinancialActivityAccountRepositoryWrapper financialActivityAccountRepositoryWrapper,
|
||||
DatabaseSpecificSQLGenerator sqlGenerator, PaginationHelper paginationHelper) {
|
||||
this.jdbcTemplate = new JdbcTemplate(dataSource);
|
||||
this.glAccountReadPlatformService = glAccountReadPlatformService;
|
||||
this.officeReadPlatformService = officeReadPlatformService;
|
||||
this.financialActivityAccountRepositoryWrapper = financialActivityAccountRepositoryWrapper;
|
||||
this.columnValidator = columnValidator;
|
||||
this.paginationHelper = paginationHelper;
|
||||
this.sqlGenerator = sqlGenerator;
|
||||
}
|
||||
|
||||
private static final class GLJournalEntryMapper implements RowMapper<JournalEntryData> {
|
||||
@@ -250,7 +255,7 @@ public class JournalEntryReadPlatformServiceImpl implements JournalEntryReadPlat
|
||||
|
||||
GLJournalEntryMapper rm = new GLJournalEntryMapper(associationParametersData);
|
||||
final StringBuilder sqlBuilder = new StringBuilder(200);
|
||||
sqlBuilder.append("select SQL_CALC_FOUND_ROWS ");
|
||||
sqlBuilder.append("select " + sqlGenerator.calcFoundRows() + " ");
|
||||
sqlBuilder.append(rm.schema());
|
||||
|
||||
final Object[] objectArray = new Object[15];
|
||||
@@ -304,28 +309,19 @@ public class JournalEntryReadPlatformServiceImpl implements JournalEntryReadPlat
|
||||
String fromDateString = null;
|
||||
String toDateString = null;
|
||||
if (fromDate != null && toDate != null) {
|
||||
sqlBuilder.append(whereClose + " journalEntry.entry_date between ? and ? ");
|
||||
|
||||
whereClose = " and ";
|
||||
|
||||
fromDateString = df.format(fromDate);
|
||||
toDateString = df.format(toDate);
|
||||
objectArray[arrayPos] = fromDateString;
|
||||
arrayPos = arrayPos + 1;
|
||||
objectArray[arrayPos] = toDateString;
|
||||
arrayPos = arrayPos + 1;
|
||||
sqlBuilder.append(whereClose + " journalEntry.entry_date between '" + fromDateString + "' and '" + toDateString + "' ");
|
||||
|
||||
whereClose = " and ";
|
||||
} else if (fromDate != null) {
|
||||
sqlBuilder.append(whereClose + " journalEntry.entry_date >= ? ");
|
||||
fromDateString = df.format(fromDate);
|
||||
objectArray[arrayPos] = fromDateString;
|
||||
arrayPos = arrayPos + 1;
|
||||
sqlBuilder.append(whereClose + " journalEntry.entry_date >= '" + fromDateString + "' ");
|
||||
whereClose = " and ";
|
||||
|
||||
} else if (toDate != null) {
|
||||
sqlBuilder.append(whereClose + " journalEntry.entry_date <= ? ");
|
||||
toDateString = df.format(toDate);
|
||||
objectArray[arrayPos] = toDateString;
|
||||
arrayPos = arrayPos + 1;
|
||||
sqlBuilder.append(whereClose + " journalEntry.entry_date <= '" + toDateString + "' ");
|
||||
|
||||
whereClose = " and ";
|
||||
}
|
||||
@@ -333,7 +329,7 @@ public class JournalEntryReadPlatformServiceImpl implements JournalEntryReadPlat
|
||||
|
||||
if (onlyManualEntries != null) {
|
||||
if (onlyManualEntries) {
|
||||
sqlBuilder.append(whereClose + " journalEntry.manual_entry = 1");
|
||||
sqlBuilder.append(whereClose + " journalEntry.manual_entry = true");
|
||||
|
||||
whereClose = " and ";
|
||||
}
|
||||
@@ -368,15 +364,16 @@ public class JournalEntryReadPlatformServiceImpl implements JournalEntryReadPlat
|
||||
}
|
||||
|
||||
if (searchParameters.isLimited()) {
|
||||
sqlBuilder.append(" limit ").append(searchParameters.getLimit());
|
||||
sqlBuilder.append(" ");
|
||||
if (searchParameters.isOffset()) {
|
||||
sqlBuilder.append(" offset ").append(searchParameters.getOffset());
|
||||
sqlBuilder.append(sqlGenerator.limit(searchParameters.getLimit(), searchParameters.getOffset()));
|
||||
} else {
|
||||
sqlBuilder.append(sqlGenerator.limit(searchParameters.getLimit()));
|
||||
}
|
||||
}
|
||||
|
||||
final Object[] finalObjectArray = Arrays.copyOf(objectArray, arrayPos);
|
||||
final String sqlCountRows = "SELECT FOUND_ROWS()";
|
||||
return this.paginationHelper.fetchPage(this.jdbcTemplate, sqlCountRows, sqlBuilder.toString(), finalObjectArray, rm);
|
||||
return this.paginationHelper.fetchPage(this.jdbcTemplate, sqlBuilder.toString(), finalObjectArray, rm);
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -530,9 +527,8 @@ public class JournalEntryReadPlatformServiceImpl implements JournalEntryReadPlat
|
||||
final GLJournalEntryMapper rm = new GLJournalEntryMapper(associationParametersData);
|
||||
final String sql = "select " + rm.schema()
|
||||
+ " where journalEntry.transaction_id = ? and journalEntry.entity_id = ? and journalEntry.entity_type_enum = ?";
|
||||
final String sqlCountRows = "SELECT FOUND_ROWS()";
|
||||
Object[] data = { transactionId, entityId, entityType };
|
||||
return this.paginationHelper.fetchPage(this.jdbcTemplate, sqlCountRows, sql, data, rm);
|
||||
return this.paginationHelper.fetchPage(this.jdbcTemplate, sql, data, rm);
|
||||
} catch (final EmptyResultDataAccessException e) {
|
||||
throw new JournalEntriesNotFoundException(entityId, e);
|
||||
}
|
||||
|
||||
+27
-34
@@ -39,6 +39,7 @@ import org.apache.fineract.infrastructure.core.data.EnumOptionData;
|
||||
import org.apache.fineract.infrastructure.core.domain.JdbcSupport;
|
||||
import org.apache.fineract.infrastructure.core.serialization.FromJsonHelper;
|
||||
import org.apache.fineract.infrastructure.core.service.RoutingDataSource;
|
||||
import org.apache.fineract.infrastructure.core.service.database.DatabaseSpecificSQLGenerator;
|
||||
import org.apache.fineract.infrastructure.jobs.annotation.CronTarget;
|
||||
import org.apache.fineract.infrastructure.jobs.service.JobName;
|
||||
import org.apache.fineract.organisation.office.domain.OfficeRepositoryWrapper;
|
||||
@@ -62,48 +63,26 @@ public class JournalEntryRunningBalanceUpdateServiceImpl implements JournalEntry
|
||||
private final JournalEntryDataValidator dataValidator;
|
||||
|
||||
private final FromJsonHelper fromApiJsonHelper;
|
||||
private final DatabaseSpecificSQLGenerator sqlGenerator;
|
||||
|
||||
private final GLJournalEntryMapper entryMapper = new GLJournalEntryMapper();
|
||||
|
||||
// if a limit is not added to the running balance select statements below
|
||||
// and the resultset is more than 400,000,
|
||||
// the script will eat up all of the server memory
|
||||
private final String selectRunningBalanceSqlLimit = "limit 0, 10000";
|
||||
|
||||
private final String officeRunningBalanceSql = "select je.office_running_balance as runningBalance,je.account_id as accountId from acc_gl_journal_entry je "
|
||||
+ "inner join (select max(id) as id from acc_gl_journal_entry where office_id=? and entry_date < ? group by account_id,entry_date) je2 "
|
||||
+ "inner join (select max(entry_date) as date from acc_gl_journal_entry where office_id=? and entry_date < ? group by account_id) je3 "
|
||||
+ "where je2.id = je.id and je.entry_date = je3.date group by je.id order by je.entry_date DESC "
|
||||
+ selectRunningBalanceSqlLimit;
|
||||
|
||||
private final String organizationRunningBalanceSql = "select je.organization_running_balance as runningBalance,je.account_id as accountId from acc_gl_journal_entry je "
|
||||
+ "inner join (select max(id) as id from acc_gl_journal_entry where entry_date < ? group by account_id,entry_date) je2 "
|
||||
+ "inner join (select max(entry_date) as date from acc_gl_journal_entry where entry_date < ? group by account_id) je3 "
|
||||
+ "where je2.id = je.id and je.entry_date = je3.date group by je.id order by je.entry_date DESC "
|
||||
+ selectRunningBalanceSqlLimit;
|
||||
|
||||
private final String officesRunningBalanceSql = "select je.office_running_balance as runningBalance,je.account_id as accountId,je.office_id as officeId "
|
||||
+ "from acc_gl_journal_entry je "
|
||||
+ "inner join (select max(id) as id from acc_gl_journal_entry where entry_date < ? group by office_id,account_id,entry_date) je2 "
|
||||
+ "inner join (select max(entry_date) as date from acc_gl_journal_entry where entry_date < ? group by office_id,account_id) je3 "
|
||||
+ "where je2.id = je.id and je.entry_date = je3.date group by je.id order by je.entry_date DESC "
|
||||
+ selectRunningBalanceSqlLimit;
|
||||
|
||||
@Autowired
|
||||
public JournalEntryRunningBalanceUpdateServiceImpl(final RoutingDataSource dataSource,
|
||||
final OfficeRepositoryWrapper officeRepositoryWrapper, final JournalEntryDataValidator dataValidator,
|
||||
final FromJsonHelper fromApiJsonHelper) {
|
||||
final FromJsonHelper fromApiJsonHelper, DatabaseSpecificSQLGenerator sqlGenerator) {
|
||||
this.jdbcTemplate = new JdbcTemplate(dataSource);
|
||||
this.officeRepositoryWrapper = officeRepositoryWrapper;
|
||||
this.dataValidator = dataValidator;
|
||||
this.fromApiJsonHelper = fromApiJsonHelper;
|
||||
this.sqlGenerator = sqlGenerator;
|
||||
}
|
||||
|
||||
@Override
|
||||
@CronTarget(jobName = JobName.ACCOUNTING_RUNNING_BALANCE_UPDATE)
|
||||
public void updateRunningBalance() {
|
||||
String dateFinder = "select MIN(je.entry_date) as entityDate from acc_gl_journal_entry je "
|
||||
+ "where je.is_running_balance_calculated=0 ";
|
||||
+ "where je.is_running_balance_calculated=false ";
|
||||
try {
|
||||
Date entityDate = this.jdbcTemplate.queryForObject(dateFinder, Date.class);
|
||||
updateOrganizationRunningBalance(entityDate);
|
||||
@@ -124,7 +103,7 @@ public class JournalEntryRunningBalanceUpdateServiceImpl implements JournalEntry
|
||||
} else {
|
||||
this.officeRepositoryWrapper.findOneWithNotFoundDetection(officeId);
|
||||
String dateFinder = "select MIN(je.entry_date) as entityDate " + "from acc_gl_journal_entry je "
|
||||
+ "where je.is_running_balance_calculated=0 and je.office_id=?";
|
||||
+ "where je.is_running_balance_calculated=false and je.office_id=?";
|
||||
try {
|
||||
Date entityDate = this.jdbcTemplate.queryForObject(dateFinder, Date.class, officeId);
|
||||
updateRunningBalance(officeId, entityDate);
|
||||
@@ -140,7 +119,12 @@ public class JournalEntryRunningBalanceUpdateServiceImpl implements JournalEntry
|
||||
Map<Long, BigDecimal> runningBalanceMap = new HashMap<>(5);
|
||||
Map<Long, Map<Long, BigDecimal>> officesRunningBalance = new HashMap<>();
|
||||
|
||||
List<Map<String, Object>> list = jdbcTemplate.queryForList(organizationRunningBalanceSql, entityDate, entityDate);
|
||||
List<Map<String, Object>> list = jdbcTemplate.queryForList(
|
||||
"select je.organization_running_balance as runningBalance,je.account_id as accountId from acc_gl_journal_entry je "
|
||||
+ "inner join (select max(id) as id from acc_gl_journal_entry where entry_date < ? group by account_id,entry_date) je2 ON je2.id = je.id "
|
||||
+ "inner join (select max(entry_date) as date from acc_gl_journal_entry where entry_date < ? group by account_id) je3 ON je.entry_date = je3.date "
|
||||
+ "group by je.id order by je.entry_date DESC " + sqlGenerator.limit(10000, 0),
|
||||
entityDate, entityDate);
|
||||
for (Map<String, Object> entries : list) {
|
||||
Long accountId = Long.parseLong(entries.get("accountId").toString()); // Drizzle
|
||||
// is
|
||||
@@ -157,7 +141,12 @@ public class JournalEntryRunningBalanceUpdateServiceImpl implements JournalEntry
|
||||
}
|
||||
}
|
||||
|
||||
List<Map<String, Object>> officesRunningBalanceList = jdbcTemplate.queryForList(officesRunningBalanceSql, entityDate, entityDate);
|
||||
List<Map<String, Object>> officesRunningBalanceList = jdbcTemplate
|
||||
.queryForList("select je.office_running_balance as runningBalance,je.account_id as accountId,je.office_id as officeId "
|
||||
+ "from acc_gl_journal_entry je "
|
||||
+ "inner join (select max(id) as id from acc_gl_journal_entry where entry_date < ? group by office_id,account_id,entry_date) je2 ON je2.id = je.id "
|
||||
+ "inner join (select max(entry_date) as date from acc_gl_journal_entry where entry_date < ? group by office_id,account_id) je3 ON je.entry_date = je3.date "
|
||||
+ "group by je.id order by je.entry_date DESC " + sqlGenerator.limit(10000, 0), entityDate, entityDate);
|
||||
for (Map<String, Object> entries : officesRunningBalanceList) {
|
||||
Long accountId = Long.parseLong(entries.get("accountId").toString());
|
||||
Long officeId = Long.parseLong(entries.get("officeId").toString());
|
||||
@@ -191,8 +180,8 @@ public class JournalEntryRunningBalanceUpdateServiceImpl implements JournalEntry
|
||||
}
|
||||
BigDecimal officeRunningBalance = calculateRunningBalance(entryData, officeRunningBalanceMap);
|
||||
BigDecimal runningBalance = calculateRunningBalance(entryData, runningBalanceMap);
|
||||
String sql = "UPDATE acc_gl_journal_entry je SET je.is_running_balance_calculated=1, je.organization_running_balance="
|
||||
+ runningBalance + ",je.office_running_balance=" + officeRunningBalance + " WHERE je.id=" + entryData.getId();
|
||||
String sql = "UPDATE acc_gl_journal_entry SET is_running_balance_calculated=true, organization_running_balance="
|
||||
+ runningBalance + ",office_running_balance=" + officeRunningBalance + " WHERE id=" + entryData.getId();
|
||||
updateSql.add(sql);
|
||||
batchIndex++;
|
||||
if (batchIndex == batchUpdateSize || index == entryDatas.size() - 1) {
|
||||
@@ -212,7 +201,12 @@ public class JournalEntryRunningBalanceUpdateServiceImpl implements JournalEntry
|
||||
private void updateRunningBalance(Long officeId, Date entityDate) {
|
||||
Map<Long, BigDecimal> runningBalanceMap = new HashMap<>(5);
|
||||
|
||||
List<Map<String, Object>> list = jdbcTemplate.queryForList(officeRunningBalanceSql, officeId, entityDate, officeId, entityDate);
|
||||
List<Map<String, Object>> list = jdbcTemplate.queryForList(
|
||||
"select je.office_running_balance as runningBalance,je.account_id as accountId from acc_gl_journal_entry je "
|
||||
+ "inner join (select max(id) as id from acc_gl_journal_entry where office_id=? and entry_date < ? group by account_id,entry_date) je2 ON je2.id = je.id "
|
||||
+ "inner join (select max(entry_date) as date from acc_gl_journal_entry where office_id=? and entry_date < ? group by account_id) je3 ON je.entry_date = je3.date "
|
||||
+ "group by je.id order by je.entry_date DESC " + sqlGenerator.limit(10000, 0),
|
||||
officeId, entityDate, officeId, entityDate);
|
||||
for (Map<String, Object> entries : list) {
|
||||
Long accountId = (Long) entries.get("accountId");
|
||||
if (!runningBalanceMap.containsKey(accountId)) {
|
||||
@@ -225,8 +219,7 @@ public class JournalEntryRunningBalanceUpdateServiceImpl implements JournalEntry
|
||||
int i = 0;
|
||||
for (JournalEntryData entryData : entryDatas) {
|
||||
BigDecimal runningBalance = calculateRunningBalance(entryData, runningBalanceMap);
|
||||
String sql = "UPDATE acc_gl_journal_entry je SET je.office_running_balance=" + runningBalance + " WHERE je.id="
|
||||
+ entryData.getId();
|
||||
String sql = "UPDATE acc_gl_journal_entry SET office_running_balance=" + runningBalance + " WHERE id=" + entryData.getId();
|
||||
updateSql[i++] = sql;
|
||||
}
|
||||
this.jdbcTemplate.batchUpdate(updateSql);
|
||||
|
||||
+1
@@ -46,4 +46,5 @@ public interface JournalEntryWritePlatformService {
|
||||
void createJournalEntriesForShares(Map<String, Object> accountingBridgeData);
|
||||
|
||||
void revertShareAccountJournalEntries(ArrayList<Long> transactionId, Date transactionDate);
|
||||
|
||||
}
|
||||
|
||||
+6
-7
@@ -20,6 +20,7 @@ package org.apache.fineract.accounting.journalentry.service;
|
||||
|
||||
import java.math.BigDecimal;
|
||||
import java.time.LocalDate;
|
||||
import java.time.ZoneId;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.Date;
|
||||
@@ -69,7 +70,6 @@ import org.apache.fineract.infrastructure.core.data.DataValidatorBuilder;
|
||||
import org.apache.fineract.infrastructure.core.exception.GeneralPlatformDomainRuleException;
|
||||
import org.apache.fineract.infrastructure.core.exception.PlatformApiDataValidationException;
|
||||
import org.apache.fineract.infrastructure.core.exception.PlatformDataIntegrityException;
|
||||
import org.apache.fineract.infrastructure.core.service.DateUtils;
|
||||
import org.apache.fineract.infrastructure.security.service.PlatformSecurityContext;
|
||||
import org.apache.fineract.organisation.office.domain.Office;
|
||||
import org.apache.fineract.organisation.office.domain.OfficeRepositoryWrapper;
|
||||
@@ -412,11 +412,11 @@ public class JournalEntryWritePlatformServiceJpaRepositoryImpl implements Journa
|
||||
journalEntry.getShareTransactionId());
|
||||
}
|
||||
// save the reversal entry
|
||||
this.glJournalEntryRepository.save(reversalJournalEntry);
|
||||
this.glJournalEntryRepository.saveAndFlush(reversalJournalEntry);
|
||||
journalEntry.setReversalJournalEntry(reversalJournalEntry);
|
||||
journalEntry.setReversed(true);
|
||||
// save the updated journal entry
|
||||
this.glJournalEntryRepository.save(journalEntry);
|
||||
this.glJournalEntryRepository.saveAndFlush(journalEntry);
|
||||
}
|
||||
return reversalTransactionId;
|
||||
|
||||
@@ -530,7 +530,6 @@ public class JournalEntryWritePlatformServiceJpaRepositoryImpl implements Journa
|
||||
.determineProcessor(savingsDTO);
|
||||
accountingProcessorForSavings.createJournalEntriesForSavings(savingsDTO);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@Transactional
|
||||
@@ -581,11 +580,11 @@ public class JournalEntryWritePlatformServiceJpaRepositoryImpl implements Journa
|
||||
journalEntry.getShareTransactionId());
|
||||
}
|
||||
// save the reversal entry
|
||||
this.glJournalEntryRepository.save(reversalJournalEntry);
|
||||
this.glJournalEntryRepository.saveAndFlush(reversalJournalEntry);
|
||||
journalEntry.setReversalJournalEntry(reversalJournalEntry);
|
||||
journalEntry.setReversed(true);
|
||||
// save the updated journal entry
|
||||
this.glJournalEntryRepository.save(journalEntry);
|
||||
this.glJournalEntryRepository.saveAndFlush(journalEntry);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -593,7 +592,7 @@ public class JournalEntryWritePlatformServiceJpaRepositoryImpl implements Journa
|
||||
private void validateBusinessRulesForJournalEntries(final JournalEntryCommand command) {
|
||||
/** check if date of Journal entry is valid ***/
|
||||
final LocalDate entryLocalDate = command.getTransactionDate();
|
||||
final Date transactionDate = Date.from(entryLocalDate.atStartOfDay(DateUtils.getDateTimeZoneOfTenant()).toInstant());
|
||||
final Date transactionDate = Date.from(entryLocalDate.atStartOfDay(ZoneId.systemDefault()).toInstant());
|
||||
// shouldn't be in the future
|
||||
final Date todaysDate = new Date();
|
||||
if (transactionDate.after(todaysDate)) {
|
||||
|
||||
+2
-2
@@ -115,8 +115,8 @@ public class LoanProductToGLAccountMappingHelper extends ProductToGLAccountMappi
|
||||
public void saveChargesToIncomeAccountMappings(final JsonCommand command, final JsonElement element, final Long productId,
|
||||
final Map<String, Object> changes) {
|
||||
// save both fee and penalty charges
|
||||
saveChargesToIncomeOrLiabilityAccountMappings(command, element, productId, changes, PortfolioProductType.LOAN, true);
|
||||
saveChargesToIncomeOrLiabilityAccountMappings(command, element, productId, changes, PortfolioProductType.LOAN, false);
|
||||
saveChargesToGLAccountMappings(command, element, productId, changes, PortfolioProductType.LOAN, true);
|
||||
saveChargesToGLAccountMappings(command, element, productId, changes, PortfolioProductType.LOAN, false);
|
||||
}
|
||||
|
||||
public void updateChargesToIncomeAccountMappings(final JsonCommand command, final JsonElement element, final Long productId,
|
||||
|
||||
+19
-16
@@ -78,7 +78,7 @@ public class ProductToGLAccountMappingHelper {
|
||||
|
||||
final ProductToGLAccountMapping accountMapping = new ProductToGLAccountMapping(glAccount, productId,
|
||||
portfolioProductType.getValue(), placeHolderTypeId);
|
||||
this.accountMappingRepository.save(accountMapping);
|
||||
this.accountMappingRepository.saveAndFlush(accountMapping);
|
||||
}
|
||||
|
||||
public void mergeProductToAccountMappingChanges(final JsonElement element, final String paramName, final Long productId,
|
||||
@@ -97,7 +97,7 @@ public class ProductToGLAccountMappingHelper {
|
||||
final GLAccount glAccount = getAccountByIdAndType(paramName, expectedAccountType, accountId);
|
||||
changes.put(paramName, accountId);
|
||||
accountMapping.setGlAccount(glAccount);
|
||||
this.accountMappingRepository.save(accountMapping);
|
||||
this.accountMappingRepository.saveAndFlush(accountMapping);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -116,12 +116,12 @@ public class ProductToGLAccountMappingHelper {
|
||||
changes.put(paramName, accountId);
|
||||
ProductToGLAccountMapping newAccountMapping = new ProductToGLAccountMapping(glAccount, productId,
|
||||
portfolioProductType.getValue(), accountTypeId);
|
||||
this.accountMappingRepository.save(newAccountMapping);
|
||||
this.accountMappingRepository.saveAndFlush(newAccountMapping);
|
||||
} else if (!accountMapping.getGlAccount().getId().equals(accountId)) {
|
||||
final GLAccount glAccount = getAccountByIdAndType(paramName, expectedAccountType, accountId);
|
||||
changes.put(paramName, accountId);
|
||||
accountMapping.setGlAccount(glAccount);
|
||||
this.accountMappingRepository.save(accountMapping);
|
||||
this.accountMappingRepository.saveAndFlush(accountMapping);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -162,7 +162,7 @@ public class ProductToGLAccountMappingHelper {
|
||||
* @param productId
|
||||
* @param changes
|
||||
*/
|
||||
public void saveChargesToIncomeOrLiabilityAccountMappings(final JsonCommand command, final JsonElement element, final Long productId,
|
||||
public void saveChargesToGLAccountMappings(final JsonCommand command, final JsonElement element, final Long productId,
|
||||
final Map<String, Object> changes, final PortfolioProductType portfolioProductType, final boolean isPenalty) {
|
||||
String arrayName;
|
||||
if (isPenalty) {
|
||||
@@ -232,7 +232,7 @@ public class ProductToGLAccountMappingHelper {
|
||||
|
||||
// If input map is empty, delete all existing mappings
|
||||
if (inputChargeToIncomeAccountMap.size() == 0) {
|
||||
this.accountMappingRepository.deleteInBatch(existingChargeToIncomeAccountMappings);
|
||||
this.accountMappingRepository.deleteAllInBatch(existingChargeToIncomeAccountMappings);
|
||||
} /**
|
||||
* Else, <br/>
|
||||
* update existing mappings OR <br/>
|
||||
@@ -258,7 +258,7 @@ public class ProductToGLAccountMappingHelper {
|
||||
allowedAccountTypes, newGLAccountId);
|
||||
}
|
||||
chargeToIncomeAccountMapping.setGlAccount(glAccount);
|
||||
this.accountMappingRepository.save(chargeToIncomeAccountMapping);
|
||||
this.accountMappingRepository.saveAndFlush(chargeToIncomeAccountMapping);
|
||||
}
|
||||
} // deleted payment type
|
||||
else {
|
||||
@@ -315,7 +315,7 @@ public class ProductToGLAccountMappingHelper {
|
||||
|
||||
// If input map is empty, delete all existing mappings
|
||||
if (inputPaymentChannelFundSourceMap.size() == 0) {
|
||||
this.accountMappingRepository.deleteInBatch(existingPaymentChannelToFundSourceMappings);
|
||||
this.accountMappingRepository.deleteAllInBatch(existingPaymentChannelToFundSourceMappings);
|
||||
} /**
|
||||
* Else, <br/>
|
||||
* update existing mappings OR <br/>
|
||||
@@ -332,10 +332,9 @@ public class ProductToGLAccountMappingHelper {
|
||||
if (inputPaymentChannelFundSourceMap.containsKey(currentPaymentChannelId)) {
|
||||
final Long newGLAccountId = inputPaymentChannelFundSourceMap.get(currentPaymentChannelId);
|
||||
if (!newGLAccountId.equals(existingPaymentChannelToFundSourceMapping.getGlAccount().getId())) {
|
||||
final GLAccount glAccount = getAccountByIdAndType(LoanProductAccountingParams.FUND_SOURCE.getValue(),
|
||||
GLAccountType.ASSET, newGLAccountId);
|
||||
final GLAccount glAccount = getAccountById(LoanProductAccountingParams.FUND_SOURCE.getValue(), newGLAccountId);
|
||||
existingPaymentChannelToFundSourceMapping.setGlAccount(glAccount);
|
||||
this.accountMappingRepository.save(existingPaymentChannelToFundSourceMapping);
|
||||
this.accountMappingRepository.saveAndFlush(existingPaymentChannelToFundSourceMapping);
|
||||
}
|
||||
} // deleted payment type
|
||||
else {
|
||||
@@ -362,11 +361,10 @@ public class ProductToGLAccountMappingHelper {
|
||||
private void savePaymentChannelToFundSourceMapping(final Long productId, final Long paymentTypeId,
|
||||
final Long paymentTypeSpecificFundAccountId, final PortfolioProductType portfolioProductType) {
|
||||
final PaymentType paymentType = this.paymentTypeRepositoryWrapper.findOneWithNotFoundDetection(paymentTypeId);
|
||||
final GLAccount glAccount = getAccountByIdAndType(LoanProductAccountingParams.FUND_SOURCE.getValue(), GLAccountType.ASSET,
|
||||
paymentTypeSpecificFundAccountId);
|
||||
final GLAccount glAccount = getAccountById(LoanProductAccountingParams.FUND_SOURCE.getValue(), paymentTypeSpecificFundAccountId);
|
||||
final ProductToGLAccountMapping accountMapping = new ProductToGLAccountMapping(glAccount, productId,
|
||||
portfolioProductType.getValue(), CashAccountsForLoan.FUND_SOURCE.getValue(), paymentType);
|
||||
this.accountMappingRepository.save(accountMapping);
|
||||
this.accountMappingRepository.saveAndFlush(accountMapping);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -397,7 +395,7 @@ public class ProductToGLAccountMappingHelper {
|
||||
}
|
||||
final ProductToGLAccountMapping accountMapping = new ProductToGLAccountMapping(glAccount, productId,
|
||||
portfolioProductType.getValue(), placeHolderAccountType.getValue(), charge);
|
||||
this.accountMappingRepository.save(accountMapping);
|
||||
this.accountMappingRepository.saveAndFlush(accountMapping);
|
||||
}
|
||||
|
||||
private List<GLAccountType> getAllowedAccountTypesForFeeMapping() {
|
||||
@@ -427,6 +425,11 @@ public class ProductToGLAccountMappingHelper {
|
||||
return glAccount;
|
||||
}
|
||||
|
||||
public GLAccount getAccountById(final String paramName, final Long accountId) {
|
||||
final GLAccount glAccount = this.accountRepositoryWrapper.findOneWithNotFoundDetection(accountId);
|
||||
return glAccount;
|
||||
}
|
||||
|
||||
public GLAccount getAccountByIdAndType(final String paramName, final List<GLAccountType> expectedAccountTypes, final Long accountId) {
|
||||
final GLAccount glAccount = this.accountRepositoryWrapper.findOneWithNotFoundDetection(accountId);
|
||||
// validate account is of the expected Type
|
||||
@@ -445,7 +448,7 @@ public class ProductToGLAccountMappingHelper {
|
||||
final List<ProductToGLAccountMapping> productToGLAccountMappings = this.accountMappingRepository
|
||||
.findByProductIdAndProductType(loanProductId, portfolioProductType.getValue());
|
||||
if (productToGLAccountMappings != null && productToGLAccountMappings.size() > 0) {
|
||||
this.accountMappingRepository.deleteInBatch(productToGLAccountMappings);
|
||||
this.accountMappingRepository.deleteAllInBatch(productToGLAccountMappings);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+1
-1
@@ -29,7 +29,7 @@ public interface ProductToGLAccountMappingReadPlatformService {
|
||||
|
||||
List<PaymentTypeToGLAccountMapper> fetchPaymentTypeToFundSourceMappingsForLoanProduct(Long loanProductId);
|
||||
|
||||
List<ChargeToGLAccountMapper> fetchFeeToIncomeOrLiabilityAccountMappingsForLoanProduct(Long loanProductId);
|
||||
List<ChargeToGLAccountMapper> fetchFeeToGLAccountMappingsForLoanProduct(Long loanProductId);
|
||||
|
||||
List<ChargeToGLAccountMapper> fetchPenaltyToIncomeAccountMappingsForLoanProduct(Long loanProductId);
|
||||
|
||||
|
||||
+3
-3
@@ -279,7 +279,7 @@ public class ProductToGLAccountMappingReadPlatformServiceImpl implements Product
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<ChargeToGLAccountMapper> fetchFeeToIncomeOrLiabilityAccountMappingsForLoanProduct(final Long loanProductId) {
|
||||
public List<ChargeToGLAccountMapper> fetchFeeToGLAccountMappingsForLoanProduct(final Long loanProductId) {
|
||||
return fetchChargeToIncomeAccountMappings(PortfolioProductType.LOAN, loanProductId, false);
|
||||
}
|
||||
|
||||
@@ -303,9 +303,9 @@ public class ProductToGLAccountMappingReadPlatformServiceImpl implements Product
|
||||
final ProductToGLAccountMappingMapper rm = new ProductToGLAccountMappingMapper();
|
||||
String sql = "select " + rm.schema() + " and product_id = ? and mapping.charge_id is not null and charge.is_penalty=";
|
||||
if (penalty) {
|
||||
sql = sql + " 1";
|
||||
sql = sql + " true";
|
||||
} else {
|
||||
sql = sql + " 0";
|
||||
sql = sql + " false";
|
||||
}
|
||||
|
||||
final List<Map<String, Object>> chargeToFundSourceMappingsList = this.jdbcTemplate.query(sql, rm,
|
||||
|
||||
+2
-2
@@ -121,8 +121,8 @@ public class SavingsProductToGLAccountMappingHelper extends ProductToGLAccountMa
|
||||
public void saveChargesToIncomeAccountMappings(final JsonCommand command, final JsonElement element, final Long productId,
|
||||
final Map<String, Object> changes) {
|
||||
// save both fee and penalty charges
|
||||
saveChargesToIncomeOrLiabilityAccountMappings(command, element, productId, changes, PortfolioProductType.SAVING, true);
|
||||
saveChargesToIncomeOrLiabilityAccountMappings(command, element, productId, changes, PortfolioProductType.SAVING, false);
|
||||
saveChargesToGLAccountMappings(command, element, productId, changes, PortfolioProductType.SAVING, true);
|
||||
saveChargesToGLAccountMappings(command, element, productId, changes, PortfolioProductType.SAVING, false);
|
||||
}
|
||||
|
||||
public void updateChargesToIncomeAccountMappings(final JsonCommand command, final JsonElement element, final Long productId,
|
||||
|
||||
+2
-2
@@ -114,8 +114,8 @@ public class ShareProductToGLAccountMappingHelper extends ProductToGLAccountMapp
|
||||
|
||||
public void saveChargesToIncomeAccountMappings(final JsonCommand command, final JsonElement element, final Long productId,
|
||||
final Map<String, Object> changes) {
|
||||
saveChargesToIncomeOrLiabilityAccountMappings(command, element, productId, changes, PortfolioProductType.SHARES, true);
|
||||
saveChargesToIncomeOrLiabilityAccountMappings(command, element, productId, changes, PortfolioProductType.SHARES, false);
|
||||
saveChargesToGLAccountMappings(command, element, productId, changes, PortfolioProductType.SHARES, true);
|
||||
saveChargesToGLAccountMappings(command, element, productId, changes, PortfolioProductType.SHARES, false);
|
||||
}
|
||||
|
||||
public void updateChargesToIncomeAccountMappings(final JsonCommand command, final JsonElement element, final Long productId,
|
||||
|
||||
+7
@@ -143,4 +143,11 @@ public class LoanProductProvisioningEntry extends AbstractPersistableCustom {
|
||||
return Objects.hash(entry.getId(), criteriaId, office.getId(), currencyCode, loanProduct.getId(), provisioningCategory.getId(),
|
||||
overdueInDays, reservedAmount, liabilityAccount.getId(), expenseAccount.getId());
|
||||
}
|
||||
|
||||
public int partialHashCode() {
|
||||
// this is used to group together all the entries that have similar parameters (excluding the amount reserved)
|
||||
// rather than a check for if the objects are the same based on their values, this tells if they are similar
|
||||
return Objects.hash(entry.getId(), criteriaId, office.getId(), currencyCode, loanProduct.getId(), provisioningCategory.getId(),
|
||||
overdueInDays, liabilityAccount.getId(), expenseAccount.getId());
|
||||
}
|
||||
}
|
||||
|
||||
+24
-21
@@ -32,6 +32,7 @@ import org.apache.fineract.infrastructure.core.service.Page;
|
||||
import org.apache.fineract.infrastructure.core.service.PaginationHelper;
|
||||
import org.apache.fineract.infrastructure.core.service.RoutingDataSource;
|
||||
import org.apache.fineract.infrastructure.core.service.SearchParameters;
|
||||
import org.apache.fineract.infrastructure.core.service.database.DatabaseSpecificSQLGenerator;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
@@ -46,39 +47,43 @@ public class ProvisioningEntriesReadPlatformServiceImpl implements ProvisioningE
|
||||
private static final Logger LOG = LoggerFactory.getLogger(ProvisioningEntriesReadPlatformServiceImpl.class);
|
||||
private final JdbcTemplate jdbcTemplate;
|
||||
|
||||
private final PaginationHelper<LoanProductProvisioningEntryData> loanProductProvisioningEntryDataPaginationHelper = new PaginationHelper<>();
|
||||
private final PaginationHelper<ProvisioningEntryData> provisioningEntryDataPaginationHelper = new PaginationHelper<>();
|
||||
private final PaginationHelper loanProductProvisioningEntryDataPaginationHelper;
|
||||
private final PaginationHelper provisioningEntryDataPaginationHelper;
|
||||
private final DatabaseSpecificSQLGenerator sqlGenerator;
|
||||
|
||||
@Autowired
|
||||
public ProvisioningEntriesReadPlatformServiceImpl(final RoutingDataSource dataSource) {
|
||||
public ProvisioningEntriesReadPlatformServiceImpl(final RoutingDataSource dataSource, DatabaseSpecificSQLGenerator sqlGenerator,
|
||||
PaginationHelper paginationHelper) {
|
||||
this.jdbcTemplate = new JdbcTemplate(dataSource);
|
||||
this.loanProductProvisioningEntryDataPaginationHelper = paginationHelper;
|
||||
this.provisioningEntryDataPaginationHelper = paginationHelper;
|
||||
this.sqlGenerator = sqlGenerator;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Collection<LoanProductProvisioningEntryData> retrieveLoanProductsProvisioningData(Date date) {
|
||||
String formattedDate = new SimpleDateFormat("yyyy-MM-dd").format(date);
|
||||
formattedDate = "'" + formattedDate + "'";
|
||||
LoanProductProvisioningEntryMapper mapper = new LoanProductProvisioningEntryMapper(formattedDate);
|
||||
LoanProductProvisioningEntryMapper mapper = new LoanProductProvisioningEntryMapper(sqlGenerator);
|
||||
final String sql = mapper.schema();
|
||||
return this.jdbcTemplate.query(sql, mapper, new Object[] {});
|
||||
return this.jdbcTemplate.query(sql, mapper, new Object[] { formattedDate, formattedDate, formattedDate });
|
||||
}
|
||||
|
||||
private static final class LoanProductProvisioningEntryMapper implements RowMapper<LoanProductProvisioningEntryData> {
|
||||
|
||||
private final StringBuilder sqlQuery;
|
||||
|
||||
private LoanProductProvisioningEntryMapper(String formattedDate) {
|
||||
private LoanProductProvisioningEntryMapper(DatabaseSpecificSQLGenerator sqlGenerator) {
|
||||
sqlQuery = new StringBuilder().append(
|
||||
"select if(loan.loan_type_enum=1, mclient.office_id, mgroup.office_id) as office_id, loan.loan_type_enum, pcd.criteria_id as criteriaid, loan.product_id,loan.currency_code,")
|
||||
.append("GREATEST(datediff(").append(formattedDate)
|
||||
.append(",sch.duedate),0) as numberofdaysoverdue,sch.duedate, pcd.category_id, pcd.provision_percentage,")
|
||||
"select (CASE WHEN loan.loan_type_enum=1 THEN mclient.office_id ELSE mgroup.office_id END) as office_id, loan.loan_type_enum, pcd.criteria_id as criteriaid, loan.product_id,loan.currency_code,")
|
||||
.append("GREATEST(" + sqlGenerator.dateDiff("?", "sch.duedate")
|
||||
+ ", 0) as numberofdaysoverdue,sch.duedate, pcd.category_id, pcd.provision_percentage,")
|
||||
.append("loan.total_outstanding_derived as outstandingbalance, pcd.liability_account, pcd.expense_account from m_loan_repayment_schedule sch")
|
||||
.append(" LEFT JOIN m_loan loan on sch.loan_id = loan.id")
|
||||
.append(" JOIN m_loanproduct_provisioning_mapping lpm on lpm.product_id = loan.product_id")
|
||||
.append(" JOIN m_provisioning_criteria_definition pcd on pcd.criteria_id = lpm.criteria_id and ")
|
||||
.append("(pcd.min_age <= GREATEST(datediff(").append(formattedDate).append(",sch.duedate),0) and ")
|
||||
.append("GREATEST(datediff(").append(formattedDate).append(",sch.duedate),0) <= pcd.max_age) and ")
|
||||
.append("pcd.criteria_id is not null ").append("LEFT JOIN m_client mclient ON mclient.id = loan.client_id ")
|
||||
.append("(pcd.min_age <= GREATEST(" + sqlGenerator.dateDiff("?", "sch.duedate") + ",0) and GREATEST("
|
||||
+ sqlGenerator.dateDiff("?", "sch.duedate") + ",0) <= pcd.max_age) and pcd.criteria_id is not null ")
|
||||
.append("LEFT JOIN m_client mclient ON mclient.id = loan.client_id ")
|
||||
.append("LEFT JOIN m_group mgroup ON mgroup.id = loan.group_id ")
|
||||
.append("where loan.loan_status_id=300 and sch.duedate = ")
|
||||
.append("(select MIN(sch1.duedate) from m_loan_repayment_schedule sch1 where sch1.loan_id=loan.id and sch1.completed_derived=false)");
|
||||
@@ -111,7 +116,7 @@ public class ProvisioningEntriesReadPlatformServiceImpl implements ProvisioningE
|
||||
@Override
|
||||
public ProvisioningEntryData retrieveProvisioningEntryData(Long entryId) {
|
||||
ProvisioningEntryDataMapperWithSumReserved mapper1 = new ProvisioningEntryDataMapperWithSumReserved();
|
||||
final String sql1 = "select" + mapper1.getSchema() + " where entry.id = ?";
|
||||
final String sql1 = "select" + mapper1.getSchema() + " where entry.id = ? group by entry.id, created.username, modified.username";
|
||||
ProvisioningEntryData data = this.jdbcTemplate.queryForObject(sql1, mapper1, new Object[] { entryId });
|
||||
return data;
|
||||
}
|
||||
@@ -222,7 +227,7 @@ public class ProvisioningEntriesReadPlatformServiceImpl implements ProvisioningE
|
||||
public Page<ProvisioningEntryData> retrieveAllProvisioningEntries(Integer offset, Integer limit) {
|
||||
ProvisioningEntryDataMapper mapper = new ProvisioningEntryDataMapper();
|
||||
StringBuilder sqlBuilder = new StringBuilder();
|
||||
sqlBuilder.append("select SQL_CALC_FOUND_ROWS ");
|
||||
sqlBuilder.append("select " + sqlGenerator.calcFoundRows() + " ");
|
||||
sqlBuilder.append(mapper.getSchema());
|
||||
sqlBuilder.append(" order by entry.created_date");
|
||||
if (limit != null) {
|
||||
@@ -232,10 +237,9 @@ public class ProvisioningEntriesReadPlatformServiceImpl implements ProvisioningE
|
||||
sqlBuilder.append(" offset ").append(offset);
|
||||
}
|
||||
|
||||
final String sqlCountRows = "SELECT FOUND_ROWS()";
|
||||
Object[] whereClauseItemsitems = new Object[] {};
|
||||
return this.provisioningEntryDataPaginationHelper.fetchPage(this.jdbcTemplate, sqlCountRows, sqlBuilder.toString(),
|
||||
whereClauseItemsitems, mapper);
|
||||
return this.provisioningEntryDataPaginationHelper.fetchPage(this.jdbcTemplate, sqlBuilder.toString(), whereClauseItemsitems,
|
||||
mapper);
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -309,7 +313,7 @@ public class ProvisioningEntriesReadPlatformServiceImpl implements ProvisioningE
|
||||
public Page<LoanProductProvisioningEntryData> retrieveProvisioningEntries(SearchParameters searchParams) {
|
||||
LoanProductProvisioningEntryRowMapper mapper = new LoanProductProvisioningEntryRowMapper();
|
||||
final StringBuilder sqlBuilder = new StringBuilder(200);
|
||||
sqlBuilder.append("select SQL_CALC_FOUND_ROWS ");
|
||||
sqlBuilder.append("select " + sqlGenerator.calcFoundRows() + " ");
|
||||
sqlBuilder.append(mapper.getSchema());
|
||||
String whereClose = " where ";
|
||||
List<Object> items = new ArrayList<>();
|
||||
@@ -345,8 +349,7 @@ public class ProvisioningEntriesReadPlatformServiceImpl implements ProvisioningE
|
||||
}
|
||||
}
|
||||
Object[] whereClauseItemsitems = items.toArray();
|
||||
final String sqlCountRows = "SELECT FOUND_ROWS()";
|
||||
return this.loanProductProvisioningEntryDataPaginationHelper.fetchPage(this.jdbcTemplate, sqlCountRows, sqlBuilder.toString(),
|
||||
return this.loanProductProvisioningEntryDataPaginationHelper.fetchPage(this.jdbcTemplate, sqlBuilder.toString(),
|
||||
whereClauseItemsitems, mapper);
|
||||
}
|
||||
|
||||
|
||||
+11
-10
@@ -20,6 +20,7 @@ package org.apache.fineract.accounting.provisioning.service;
|
||||
|
||||
import com.google.gson.JsonObject;
|
||||
import java.time.LocalDate;
|
||||
import java.time.ZoneId;
|
||||
import java.util.Collection;
|
||||
import java.util.Date;
|
||||
import java.util.HashMap;
|
||||
@@ -127,7 +128,7 @@ public class ProvisioningEntriesWritePlatformServiceJpaRepositoryImpl implements
|
||||
requestedEntry.setJournalEntryCreated(Boolean.TRUE);
|
||||
}
|
||||
|
||||
this.provisioningEntryRepository.save(requestedEntry);
|
||||
this.provisioningEntryRepository.saveAndFlush(requestedEntry);
|
||||
this.journalEntryWritePlatformService.createProvisioningJournalEntries(requestedEntry);
|
||||
}
|
||||
|
||||
@@ -150,13 +151,13 @@ public class ProvisioningEntriesWritePlatformServiceJpaRepositoryImpl implements
|
||||
|
||||
private Date parseDate(JsonCommand command) {
|
||||
LocalDate localDate = this.fromApiJsonHelper.extractLocalDateNamed("date", command.parsedJson());
|
||||
return Date.from(localDate.atStartOfDay(DateUtils.getDateTimeZoneOfTenant()).toInstant());
|
||||
return Date.from(localDate.atStartOfDay(ZoneId.systemDefault()).toInstant());
|
||||
}
|
||||
|
||||
@Override
|
||||
@CronTarget(jobName = JobName.GENERATE_LOANLOSS_PROVISIONING)
|
||||
public void generateLoanLossProvisioningAmount() {
|
||||
Date currentDate = Date.from(DateUtils.getLocalDateOfTenant().atStartOfDay(DateUtils.getDateTimeZoneOfTenant()).toInstant());
|
||||
Date currentDate = Date.from(DateUtils.getLocalDateOfTenant().atStartOfDay(ZoneId.systemDefault()).toInstant());
|
||||
boolean addJournalEntries = true;
|
||||
try {
|
||||
Collection<ProvisioningCriteriaData> criteriaCollection = this.provisioningCriteriaReadPlatformService
|
||||
@@ -209,7 +210,7 @@ public class ProvisioningEntriesWritePlatformServiceJpaRepositoryImpl implements
|
||||
.retrieveExistingProvisioningIdDateWithJournals();
|
||||
revertAndAddJournalEntries(exisProvisioningEntryData, requestedEntry);
|
||||
} else {
|
||||
this.provisioningEntryRepository.save(requestedEntry);
|
||||
this.provisioningEntryRepository.saveAndFlush(requestedEntry);
|
||||
}
|
||||
return requestedEntry;
|
||||
}
|
||||
@@ -219,17 +220,17 @@ public class ProvisioningEntriesWritePlatformServiceJpaRepositoryImpl implements
|
||||
ProvisioningEntry requestedEntry = this.provisioningEntryRepository.findById(provisioningEntryId)
|
||||
.orElseThrow(() -> new ProvisioningEntryNotfoundException(provisioningEntryId));
|
||||
requestedEntry.getLoanProductProvisioningEntries().clear();
|
||||
this.provisioningEntryRepository.save(requestedEntry);
|
||||
this.provisioningEntryRepository.saveAndFlush(requestedEntry);
|
||||
Collection<LoanProductProvisioningEntry> entries = generateLoanProvisioningEntry(requestedEntry, requestedEntry.getCreatedDate());
|
||||
requestedEntry.setProvisioningEntries(entries);
|
||||
this.provisioningEntryRepository.save(requestedEntry);
|
||||
this.provisioningEntryRepository.saveAndFlush(requestedEntry);
|
||||
return new CommandProcessingResultBuilder().withCommandId(command.commandId()).withEntityId(requestedEntry.getId()).build();
|
||||
}
|
||||
|
||||
private Collection<LoanProductProvisioningEntry> generateLoanProvisioningEntry(ProvisioningEntry parent, Date date) {
|
||||
Collection<LoanProductProvisioningEntryData> entries = this.provisioningEntriesReadPlatformService
|
||||
.retrieveLoanProductsProvisioningData(date);
|
||||
Map<LoanProductProvisioningEntry, LoanProductProvisioningEntry> provisioningEntries = new HashMap<>();
|
||||
Map<Integer, LoanProductProvisioningEntry> provisioningEntries = new HashMap<>();
|
||||
for (LoanProductProvisioningEntryData data : entries) {
|
||||
LoanProduct loanProduct = this.loanProductRepository.findById(data.getProductId()).get();
|
||||
Office office = this.officeRepositoryWrapper.findOneWithNotFoundDetection(data.getOfficeId());
|
||||
@@ -244,10 +245,10 @@ public class ProvisioningEntriesWritePlatformServiceJpaRepositoryImpl implements
|
||||
provisioningCategory, data.getOverdueInDays(), amountToReserve.getAmount(), liabilityAccount, expenseAccount,
|
||||
criteraId);
|
||||
entry.setProvisioningEntry(parent);
|
||||
if (!provisioningEntries.containsKey(entry)) {
|
||||
provisioningEntries.put(entry, entry);
|
||||
if (!provisioningEntries.containsKey(entry.partialHashCode())) {
|
||||
provisioningEntries.put(entry.partialHashCode(), entry);
|
||||
} else {
|
||||
LoanProductProvisioningEntry entry1 = provisioningEntries.get(entry);
|
||||
LoanProductProvisioningEntry entry1 = provisioningEntries.get(entry.partialHashCode());
|
||||
entry1.addReservedAmount(entry.getReservedAmount());
|
||||
}
|
||||
}
|
||||
|
||||
+1
@@ -38,6 +38,7 @@ public enum AccountingRuleJsonInputParams {
|
||||
}
|
||||
|
||||
private static final Set<String> values = new HashSet<>();
|
||||
|
||||
static {
|
||||
for (final AccountingRuleJsonInputParams type : AccountingRuleJsonInputParams.values()) {
|
||||
values.add(type.value);
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user