Compare commits
494
Commits
872f97b6b6
...
1005b56d0f
@@ -4,21 +4,15 @@ Describe the changes made and why they were made.
|
||||
|
||||
Ignore if these details are present on the associated [Apache Fineract JIRA ticket](https://github.com/apache/fineract/pull/1284).
|
||||
|
||||
|
||||
## Checklist
|
||||
|
||||
Please make sure these boxes are checked before submitting your pull request - thanks!
|
||||
|
||||
- [ ] Write the commit message as per https://github.com/apache/fineract/#pull-requests
|
||||
|
||||
- [ ] Acknowledge that we will not review PRs that are not passing the build _("green")_ - it is your responsibility to get a proposed PR to pass the build, not primarily the project's maintainers.
|
||||
|
||||
- [ ] Create/update unit or integration tests for verifying the changes made.
|
||||
|
||||
- [ ] Follow coding conventions at https://cwiki.apache.org/confluence/display/FINERACT/Coding+Conventions.
|
||||
|
||||
- [ ] Add required Swagger annotation and update API documentation at fineract-provider/src/main/resources/static/legacy-docs/apiLive.htm with details of any API changes
|
||||
|
||||
- [ ] Submission is not a "code dump". (Large changes can be made "in repository" via a branch. Ask on the developer mailing list for guidance, if required.)
|
||||
|
||||
FYI our guidelines for code reviews are at https://cwiki.apache.org/confluence/display/FINERACT/Code+Review+Guide.
|
||||
@@ -0,0 +1,114 @@
|
||||
name: Fineract Build & Cucumber tests (without E2E tests)
|
||||
|
||||
on: [push, pull_request]
|
||||
|
||||
permissions:
|
||||
contents: read
|
||||
|
||||
jobs:
|
||||
verify:
|
||||
runs-on: ubuntu-24.04
|
||||
timeout-minutes: 60
|
||||
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
include:
|
||||
- task: build-core
|
||||
job_type: main
|
||||
- task: cucumber
|
||||
job_type: main
|
||||
- task: build-progressive-loan
|
||||
job_type: progressive-loan
|
||||
|
||||
env:
|
||||
TZ: Asia/Kolkata
|
||||
DEVELOCITY_ACCESS_KEY: ${{ secrets.DEVELOCITY_ACCESS_KEY }}
|
||||
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v4
|
||||
with:
|
||||
fetch-depth: 0
|
||||
fetch-tags: true
|
||||
|
||||
- name: Set up JDK 21
|
||||
uses: actions/setup-java@dded0888837ed1f317902acf8a20df0ad188d165 # v4
|
||||
with:
|
||||
java-version: '21'
|
||||
distribution: 'zulu'
|
||||
|
||||
- name: Cache Gradle dependencies
|
||||
uses: actions/cache@0057852bfaa89a56745cba8c7296529d2fc39830 # v4
|
||||
with:
|
||||
path: |
|
||||
~/.gradle/caches
|
||||
~/.gradle/wrapper
|
||||
key: gradle-${{ runner.os }}-${{ hashFiles('**/*.gradle*', '**/gradle-wrapper.properties') }}
|
||||
|
||||
- name: Setup Gradle and Validate Wrapper
|
||||
uses: gradle/actions/setup-gradle@ac638b010cf58a27ee6c972d7336334ccaf61c96 # v4.4.1
|
||||
with:
|
||||
validate-wrappers: true
|
||||
|
||||
- name: Run Gradle Task
|
||||
if: matrix.job_type == 'main'
|
||||
run: |
|
||||
set -e # Fail the script if any command fails
|
||||
|
||||
case "${{ matrix.task }}" in
|
||||
build-core)
|
||||
./gradlew --no-daemon build -x test -x cucumber -x doc
|
||||
;;
|
||||
cucumber)
|
||||
./gradlew --no-daemon cucumber -x :fineract-e2e-tests-runner:cucumber -x checkstyleJmh -x checkstyleMain -x checkstyleTest -x spotlessCheck -x spotlessApply -x spotbugsMain -x spotbugsTest -x javadoc -x javadocJar -x modernizer
|
||||
;;
|
||||
esac
|
||||
|
||||
- name: Build and Test Progressive Loan
|
||||
if: matrix.job_type == 'progressive-loan'
|
||||
run: |
|
||||
# Build the JAR
|
||||
./gradlew --no-daemon --console=plain :fineract-progressive-loan-embeddable-schedule-generator:shadowJar
|
||||
|
||||
# Store the JAR filename in an environment variable
|
||||
EMBEDDABLE_JAR_FILE=$(ls fineract-progressive-loan-embeddable-schedule-generator/build/libs/*-all.jar | head -n 1)
|
||||
echo "EMBEDDABLE_JAR_FILE=$EMBEDDABLE_JAR_FILE" >> $GITHUB_ENV
|
||||
echo "JAR file: $EMBEDDABLE_JAR_FILE"
|
||||
|
||||
# Run unit tests
|
||||
./gradlew --no-daemon --console=plain :fineract-progressive-loan-embeddable-schedule-generator:test
|
||||
|
||||
# Build and run sample application
|
||||
mkdir -p sample-app
|
||||
javac -cp "$EMBEDDABLE_JAR_FILE" -d sample-app fineract-progressive-loan-embeddable-schedule-generator/misc/Main.java
|
||||
java -cp "$EMBEDDABLE_JAR_FILE:sample-app" Main
|
||||
java -cp "$EMBEDDABLE_JAR_FILE:sample-app" Main 25
|
||||
|
||||
- name: Archive test results
|
||||
if: always()
|
||||
uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4
|
||||
with:
|
||||
name: test-results-${{ matrix.task }}
|
||||
path: |
|
||||
**/build/reports/
|
||||
**/fineract-progressive-loan-embeddable-schedule-generator/build/reports/
|
||||
if-no-files-found: ignore
|
||||
retention-days: 5
|
||||
|
||||
- name: Archive Progressive Loan JAR
|
||||
if: matrix.job_type == 'progressive-loan' && always()
|
||||
uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4
|
||||
with:
|
||||
name: progressive-loan-jar
|
||||
path: ${{ env.EMBEDDABLE_JAR_FILE }}
|
||||
retention-days: 5
|
||||
if-no-files-found: ignore
|
||||
|
||||
- name: Archive server logs
|
||||
if: always()
|
||||
uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4
|
||||
with:
|
||||
name: server-logs-${{ matrix.task }}
|
||||
path: '**/build/cargo/'
|
||||
retention-days: 5
|
||||
@@ -1,31 +0,0 @@
|
||||
name: Fineract Docker build - MariaDB
|
||||
on: [push, pull_request]
|
||||
permissions:
|
||||
contents: read
|
||||
jobs:
|
||||
build:
|
||||
runs-on: ubuntu-24.04
|
||||
env:
|
||||
DEVELOCITY_ACCESS_KEY: ${{ secrets.DEVELOCITY_ACCESS_KEY }}
|
||||
IMAGE_NAME: fineract
|
||||
steps:
|
||||
- uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4
|
||||
with:
|
||||
fetch-depth: 0
|
||||
- name: Set up JDK 17
|
||||
uses: actions/setup-java@3a4f6e1af504cf6a31855fa899c6aa5355ba6c12 # v4
|
||||
with:
|
||||
java-version: '17'
|
||||
distribution: 'zulu'
|
||||
- name: Setup Gradle
|
||||
uses: gradle/actions/setup-gradle@06832c7b30a0129d7fb559bcc6e43d26f6374244 # v4.3.1
|
||||
- name: Build the image
|
||||
run: ./gradlew --no-daemon --console=plain :fineract-provider:jibDockerBuild -Djib.to.image=$IMAGE_NAME -x test -x cucumber
|
||||
- name: Start the stack
|
||||
run: docker compose -f docker-compose.yml up -d
|
||||
- name: Check the stack
|
||||
run: docker ps
|
||||
- name: Check health
|
||||
run: curl -f -k --retry 60 --retry-all-errors --connect-timeout 30 --retry-delay 30 https://localhost:8443/fineract-provider/actuator/health
|
||||
- name: Check info
|
||||
run: (( $(curl -f -k --retry 5 --retry-all-errors --connect-timeout 30 --retry-delay 30 https://localhost:8443/fineract-provider/actuator/info | wc --chars) > 100 ))
|
||||
@@ -1,31 +0,0 @@
|
||||
name: Fineract Docker build - PostgreSQL
|
||||
on: [push, pull_request]
|
||||
permissions:
|
||||
contents: read
|
||||
jobs:
|
||||
build:
|
||||
runs-on: ubuntu-24.04
|
||||
env:
|
||||
DEVELOCITY_ACCESS_KEY: ${{ secrets.DEVELOCITY_ACCESS_KEY }}
|
||||
IMAGE_NAME: fineract
|
||||
steps:
|
||||
- uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4
|
||||
with:
|
||||
fetch-depth: 0
|
||||
- name: Set up JDK 17
|
||||
uses: actions/setup-java@3a4f6e1af504cf6a31855fa899c6aa5355ba6c12 # v4
|
||||
with:
|
||||
java-version: '17'
|
||||
distribution: 'zulu'
|
||||
- name: Setup Gradle
|
||||
uses: gradle/actions/setup-gradle@06832c7b30a0129d7fb559bcc6e43d26f6374244 # v4.3.1
|
||||
- name: Build the image
|
||||
run: ./gradlew --no-daemon --console=plain :fineract-provider:jibDockerBuild -Djib.to.image=$IMAGE_NAME -x test -x cucumber
|
||||
- name: Start the Standalone Stack
|
||||
run: docker compose -f docker-compose-postgresql.yml up -d
|
||||
- name: Check the stack
|
||||
run: docker ps
|
||||
- name: Check health
|
||||
run: curl -f -k --retry 60 --retry-all-errors --connect-timeout 30 --retry-delay 30 https://localhost:8443/fineract-provider/actuator/health
|
||||
- name: Check info
|
||||
run: (( $(curl -f -k --retry 5 --retry-all-errors --connect-timeout 30 --retry-delay 30 https://localhost:8443/fineract-provider/actuator/info | wc --chars) > 100 ))
|
||||
@@ -0,0 +1,55 @@
|
||||
name: Fineract Docker Builds
|
||||
|
||||
on: [push, pull_request]
|
||||
|
||||
permissions:
|
||||
contents: read
|
||||
|
||||
jobs:
|
||||
build:
|
||||
runs-on: ubuntu-24.04
|
||||
timeout-minutes: 60
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
db_type: [mariadb, postgresql]
|
||||
include:
|
||||
- db_type: mariadb
|
||||
compose_file: docker-compose.yml
|
||||
check_worker_health: true
|
||||
- db_type: postgresql
|
||||
compose_file: docker-compose-postgresql.yml
|
||||
check_worker_health: false
|
||||
|
||||
env:
|
||||
DEVELOCITY_ACCESS_KEY: ${{ secrets.DEVELOCITY_ACCESS_KEY }}
|
||||
IMAGE_NAME: fineract
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v4
|
||||
with:
|
||||
fetch-depth: 0
|
||||
|
||||
- name: Set up JDK 21
|
||||
uses: actions/setup-java@dded0888837ed1f317902acf8a20df0ad188d165 # v4
|
||||
with:
|
||||
java-version: '21'
|
||||
distribution: 'zulu'
|
||||
|
||||
- name: Setup Gradle
|
||||
uses: gradle/actions/setup-gradle@ac638b010cf58a27ee6c972d7336334ccaf61c96 # v4.4.1
|
||||
|
||||
- name: Build the image
|
||||
run: ./gradlew --no-daemon --console=plain :fineract-provider:jibDockerBuild -Djib.to.image=$IMAGE_NAME -x test -x cucumber
|
||||
|
||||
- name: Start the ${{ matrix.db_type }} stack
|
||||
run: docker compose -f ${{ matrix.compose_file }} up -d
|
||||
|
||||
- name: Check the stack
|
||||
run: docker ps
|
||||
|
||||
- name: Check health Manager
|
||||
run: curl -f -k --retry 60 --retry-all-errors --connect-timeout 30 --retry-delay 30 https://localhost:8443/fineract-provider/actuator/health
|
||||
|
||||
- name: Check info Manager
|
||||
run: (( $(curl -f -k --retry 5 --retry-all-errors --connect-timeout 30 --retry-delay 30 https://localhost:8443/fineract-provider/actuator/info | wc --chars) > 100 ))
|
||||
@@ -5,27 +5,28 @@ permissions:
|
||||
jobs:
|
||||
build:
|
||||
runs-on: ubuntu-24.04
|
||||
timeout-minutes: 60
|
||||
env:
|
||||
DEVELOCITY_ACCESS_KEY: ${{ secrets.DEVELOCITY_ACCESS_KEY }}
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4
|
||||
uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v4
|
||||
with:
|
||||
fetch-depth: 0
|
||||
- name: Set up JDK 17
|
||||
uses: actions/setup-java@3a4f6e1af504cf6a31855fa899c6aa5355ba6c12 # v4
|
||||
- name: Set up JDK 21
|
||||
uses: actions/setup-java@dded0888837ed1f317902acf8a20df0ad188d165 # v4
|
||||
with:
|
||||
java-version: '17'
|
||||
java-version: '21'
|
||||
distribution: 'zulu'
|
||||
- name: Setup Gradle
|
||||
uses: gradle/actions/setup-gradle@06832c7b30a0129d7fb559bcc6e43d26f6374244 # v4.3.1
|
||||
- uses: actions/setup-node@cdca7365b2dadb8aad0a33bc7601856ffabcc48e # v4
|
||||
uses: gradle/actions/setup-gradle@ac638b010cf58a27ee6c972d7336334ccaf61c96 # v4.4.1
|
||||
- uses: actions/setup-node@a0853c24544627f65ddf259abe73b1d18a591444 # v4
|
||||
with:
|
||||
node-version: 16
|
||||
node-version: 22
|
||||
- name: Congfigure vega-cli
|
||||
run: npm i -g vega-cli --unsafe
|
||||
- name: Validate Gradle wrapper
|
||||
uses: gradle/wrapper-validation-action@f9c9c575b8b21b6485636a91ffecd10e558c62f6
|
||||
uses: gradle/actions/wrapper-validation@v4
|
||||
- name: Install additional software
|
||||
run: |
|
||||
sudo apt-get update
|
||||
|
||||
@@ -0,0 +1,183 @@
|
||||
name: Fineract E2E Tests
|
||||
|
||||
on: [push, pull_request]
|
||||
|
||||
permissions:
|
||||
contents: read
|
||||
|
||||
jobs:
|
||||
test:
|
||||
name: E2E Tests (Shard ${{ matrix.shard_index }} of ${{ matrix.total_shards }})
|
||||
runs-on: ubuntu-24.04
|
||||
timeout-minutes: 60
|
||||
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
# Define the number of shards (1-based indexing)
|
||||
shard_index: [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
|
||||
total_shards: [10]
|
||||
|
||||
env:
|
||||
DEVELOCITY_ACCESS_KEY: ${{ secrets.DEVELOCITY_ACCESS_KEY }}
|
||||
IMAGE_NAME: fineract
|
||||
BASE_URL: https://localhost:8443
|
||||
TEST_USERNAME: mifos
|
||||
TEST_PASSWORD: password
|
||||
TEST_STRONG_PASSWORD: A1b2c3d4e5f$
|
||||
TEST_TENANT_ID: default
|
||||
INITIALIZATION_ENABLED: true
|
||||
EVENT_VERIFICATION_ENABLED: true
|
||||
ACTIVEMQ_BROKER_URL: tcp://localhost:61616
|
||||
ACTIVEMQ_TOPIC_NAME: events
|
||||
|
||||
steps:
|
||||
- name: Checkout code
|
||||
uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v4
|
||||
with:
|
||||
fetch-depth: 0
|
||||
|
||||
- name: Set up JDK 21
|
||||
uses: actions/setup-java@dded0888837ed1f317902acf8a20df0ad188d165 # v4
|
||||
with:
|
||||
java-version: '21'
|
||||
distribution: 'zulu'
|
||||
|
||||
- name: Setup Gradle
|
||||
uses: gradle/actions/setup-gradle@ac638b010cf58a27ee6c972d7336334ccaf61c96 # v4.4.1
|
||||
|
||||
- name: Make scripts executable
|
||||
run: chmod +x scripts/split-features.sh
|
||||
|
||||
- name: Split feature files into shards
|
||||
id: split-features
|
||||
run: |
|
||||
./scripts/split-features.sh ${{ matrix.total_shards }} ${{ matrix.shard_index }}
|
||||
echo "Shard ${{ matrix.shard_index }} feature files:"
|
||||
cat feature_shard_${{ matrix.shard_index }}.txt
|
||||
|
||||
- name: Build the image
|
||||
run: ./gradlew --no-daemon --console=plain :fineract-provider:jibDockerBuild -Djib.to.image=$IMAGE_NAME -x test -x cucumber
|
||||
|
||||
- name: Start the Fineract stack
|
||||
run: docker compose -f docker-compose-postgresql-test-activemq.yml up -d
|
||||
|
||||
- name: Check the stack
|
||||
run: docker ps
|
||||
|
||||
- name: Wait for Manager to be ready
|
||||
run: |
|
||||
# Wait for the container to be running
|
||||
echo "Waiting for Manager container to be ready..."
|
||||
timeout 300 bash -c 'until docker ps --filter "health=healthy" --filter "name=fineract" --format "{{.Status}}" | grep -q "healthy"; do
|
||||
if docker ps --filter "name=fineract" --format "{{.Status}}" | grep -q "unhealthy"; then
|
||||
echo "Container is unhealthy. Stopping..."
|
||||
docker ps -a
|
||||
docker logs $(docker ps -q --filter name=fineract) || true
|
||||
exit 1
|
||||
fi
|
||||
echo "Waiting for Manager to be ready..."
|
||||
sleep 5
|
||||
done'
|
||||
|
||||
# Check the health endpoint
|
||||
echo "Checking Manager health endpoint..."
|
||||
curl -f -k --retry 30 --retry-all-errors --connect-timeout 10 --retry-delay 10 \
|
||||
https://localhost:8443/fineract-provider/actuator/health
|
||||
|
||||
- name: Execute tests for shard ${{ matrix.shard_index }}
|
||||
id: tests
|
||||
run: |
|
||||
# Initialize failure flag
|
||||
FAILED=0
|
||||
|
||||
# Create necessary directories
|
||||
mkdir -p "allure-results-shard-${{ matrix.shard_index }}"
|
||||
mkdir -p "allure-results-merged"
|
||||
|
||||
# Read feature files from the shard file
|
||||
if [ ! -s "feature_shard_${{ matrix.shard_index }}.txt" ]; then
|
||||
echo "No features to test in this shard. Skipping..."
|
||||
exit 0
|
||||
fi
|
||||
|
||||
# Read each feature file path and run tests one by one
|
||||
while IFS= read -r feature_file || [ -n "$feature_file" ]; do
|
||||
# Skip empty lines
|
||||
[ -z "$feature_file" ] && continue
|
||||
|
||||
# Create a safe filename for the results
|
||||
safe_name=$(echo "$feature_file" | tr '/' '-' | tr ' ' '_')
|
||||
|
||||
echo "::group::Testing feature: $feature_file"
|
||||
|
||||
# Run tests with individual allure results directory
|
||||
if ! ./gradlew --no-daemon --console=plain \
|
||||
:fineract-e2e-tests-runner:cucumber \
|
||||
-Pcucumber.features="$feature_file" \
|
||||
-Dallure.results.directory="allure-results-shard-${{ matrix.shard_index }}/$safe_name" \
|
||||
allureReport; then
|
||||
|
||||
echo "::error::Test failed for $feature_file"
|
||||
FAILED=1
|
||||
fi
|
||||
|
||||
echo "::endgroup::"
|
||||
|
||||
# Copy the results to a merged directory
|
||||
if [ -d "allure-results-shard-${{ matrix.shard_index }}/$safe_name" ]; then
|
||||
cp -r "allure-results-shard-${{ matrix.shard_index }}/$safe_name/." "allure-results-merged/" || true
|
||||
fi
|
||||
done < "feature_shard_${{ matrix.shard_index }}.txt"
|
||||
|
||||
# Generate individual report for this shard
|
||||
if [ -d "allure-results-merged" ] && [ "$(ls -A allure-results-merged)" ]; then
|
||||
echo "Generating Allure report..."
|
||||
mkdir -p "allure-report-shard-${{ matrix.shard_index }}"
|
||||
./fineract-e2e-tests-runner/build/allure/commandline/bin/allure generate "allure-results-merged" --clean -o "allure-report-shard-${{ matrix.shard_index }}" || \
|
||||
echo "::warning::Failed to generate Allure report for shard ${{ matrix.shard_index }}"
|
||||
fi
|
||||
|
||||
# Exit with failure status if any test failed
|
||||
if [ "$FAILED" -eq 1 ]; then
|
||||
echo "::error::Some tests failed in this shard"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
- name: Upload test results
|
||||
if: always()
|
||||
uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4
|
||||
with:
|
||||
name: allure-results-shard-${{ matrix.shard_index }}
|
||||
path: |
|
||||
allure-results-shard-${{ matrix.shard_index }}
|
||||
allure-results-merged
|
||||
**/build/allure-results
|
||||
**/build/reports/tests/test
|
||||
**/build/test-results/test
|
||||
retention-days: 5
|
||||
|
||||
- name: Upload Allure Report
|
||||
if: always()
|
||||
uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4
|
||||
with:
|
||||
name: allure-report-shard-${{ matrix.shard_index }}
|
||||
path: allure-report-shard-${{ matrix.shard_index }}
|
||||
retention-days: 5
|
||||
|
||||
- name: Upload logs
|
||||
if: always()
|
||||
uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4
|
||||
with:
|
||||
name: logs-shard-${{ matrix.shard_index }}
|
||||
path: |
|
||||
**/build/reports/tests/
|
||||
**/logs/
|
||||
**/out/
|
||||
retention-days: 5
|
||||
|
||||
- name: Clean up
|
||||
if: always()
|
||||
run: |
|
||||
docker compose -f docker-compose-postgresql-test-activemq.yml down -v
|
||||
docker system prune -f
|
||||
@@ -1,47 +0,0 @@
|
||||
name: Fineract Build Progressive Loan Embeddable Jar & Test with a Sample Application
|
||||
on: [push, pull_request]
|
||||
permissions:
|
||||
contents: read
|
||||
jobs:
|
||||
build:
|
||||
runs-on: ubuntu-24.04
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4
|
||||
with:
|
||||
fetch-depth: 0
|
||||
- name: Set up JDK 17
|
||||
uses: actions/setup-java@3a4f6e1af504cf6a31855fa899c6aa5355ba6c12 # v4
|
||||
with:
|
||||
java-version: '17'
|
||||
distribution: 'zulu'
|
||||
- name: Setup Gradle
|
||||
uses: gradle/actions/setup-gradle@06832c7b30a0129d7fb559bcc6e43d26f6374244 # v4.3.1
|
||||
- name: Build Embeddable Jar
|
||||
run: ./gradlew --no-daemon --console=plain :fineract-progressive-loan-embeddable-schedule-generator:shadowJar
|
||||
- name: Pick up the JAR filename
|
||||
run: |
|
||||
EMBEDDABLE_JAR_FILE=(`ls fineract-progressive-loan-embeddable-schedule-generator/build/libs/*-all.jar | head -n 1`)
|
||||
echo "EMBEDDABLE_JAR_FILE=$EMBEDDABLE_JAR_FILE" >> $GITHUB_ENV
|
||||
- name: Run unit tests
|
||||
run: ./gradlew --no-daemon --console=plain :fineract-progressive-loan-embeddable-schedule-generator:test
|
||||
- name: Build Sample Application
|
||||
run: |
|
||||
mkdir sample-app
|
||||
javac -cp $EMBEDDABLE_JAR_FILE -d sample-app fineract-progressive-loan-embeddable-schedule-generator/misc/Main.java
|
||||
env:
|
||||
EMBEDDABLE_JAR_FILE: ${{ env.EMBEDDABLE_JAR_FILE }}
|
||||
- name: Run Schedule Generator Sample Application
|
||||
run: |
|
||||
java -cp $EMBEDDABLE_JAR_FILE:sample-app Main
|
||||
java -cp $EMBEDDABLE_JAR_FILE:sample-app Main 25
|
||||
env:
|
||||
EMBEDDABLE_JAR_FILE: ${{ env.EMBEDDABLE_JAR_FILE }}
|
||||
- name: Archive test results
|
||||
if: always()
|
||||
uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4
|
||||
with:
|
||||
name: test-results
|
||||
path: |
|
||||
build/reports/
|
||||
fineract-progressive-loan-embeddable-schedule-generator/build/reports/
|
||||
@@ -1,92 +1,150 @@
|
||||
name: Fineract Build & Test - MariaDB
|
||||
name: Fineract Cargo & Unit- & Integration tests - MariaDB
|
||||
|
||||
on: [push, pull_request]
|
||||
|
||||
permissions:
|
||||
contents: read
|
||||
|
||||
jobs:
|
||||
build:
|
||||
test:
|
||||
runs-on: ubuntu-24.04
|
||||
timeout-minutes: 60
|
||||
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
task: [test-core-1, test-core-2, test-core-3, test-core-4, test-core-5]
|
||||
|
||||
services:
|
||||
mariad:
|
||||
image: mariadb:11.5.2
|
||||
ports:
|
||||
- 3306:3306
|
||||
env:
|
||||
MARIADB_ROOT_PASSWORD: mysql
|
||||
options: --health-cmd="healthcheck.sh --su-mysql --connect --innodb_initialized" --health-interval=5s --health-timeout=2s --health-retries=3
|
||||
mock-oauth2-server:
|
||||
image: ghcr.io/navikt/mock-oauth2-server:2.1.10
|
||||
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" ] } } ] } ] }'
|
||||
mariadb:
|
||||
image: mariadb:11.5.2
|
||||
ports:
|
||||
- 3306:3306
|
||||
env:
|
||||
MARIADB_ROOT_PASSWORD: mysql
|
||||
options: --health-cmd="healthcheck.sh --su-mysql --connect --innodb_initialized" --health-interval=5s --health-timeout=2s --health-retries=3
|
||||
|
||||
mock-oauth2-server:
|
||||
image: ghcr.io/navikt/mock-oauth2-server:2.1.10
|
||||
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
|
||||
DEVELOCITY_ACCESS_KEY: ${{ secrets.DEVELOCITY_ACCESS_KEY }}
|
||||
TZ: Asia/Kolkata
|
||||
DEVELOCITY_ACCESS_KEY: ${{ secrets.DEVELOCITY_ACCESS_KEY }}
|
||||
AWS_ENDPOINT_URL: http://localhost:4566
|
||||
AWS_ACCESS_KEY_ID: localstack
|
||||
AWS_SECRET_ACCESS_KEY: localstack
|
||||
AWS_REGION: us-east-1
|
||||
FINERACT_REPORT_EXPORT_S3_ENABLED: true
|
||||
FINERACT_REPORT_EXPORT_S3_BUCKET_NAME: fineract-reports
|
||||
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4
|
||||
uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v4
|
||||
with:
|
||||
fetch-depth: 0
|
||||
- name: Set up JDK 17
|
||||
uses: actions/setup-java@3a4f6e1af504cf6a31855fa899c6aa5355ba6c12 # v4
|
||||
fetch-tags: true
|
||||
|
||||
- name: Set up JDK 21
|
||||
uses: actions/setup-java@dded0888837ed1f317902acf8a20df0ad188d165 # v4
|
||||
with:
|
||||
java-version: '17'
|
||||
java-version: '21'
|
||||
distribution: 'zulu'
|
||||
|
||||
- name: Cache Gradle dependencies
|
||||
uses: actions/cache@0057852bfaa89a56745cba8c7296529d2fc39830 # v4
|
||||
with:
|
||||
path: |
|
||||
~/.gradle/caches
|
||||
~/.gradle/wrapper
|
||||
key: gradle-${{ runner.os }}-${{ hashFiles('**/*.gradle*', '**/gradle-wrapper.properties') }}
|
||||
|
||||
- name: Setup Gradle and Validate Wrapper
|
||||
uses: gradle/actions/setup-gradle@06832c7b30a0129d7fb559bcc6e43d26f6374244 # v4.3.1
|
||||
uses: gradle/actions/setup-gradle@ac638b010cf58a27ee6c972d7336334ccaf61c96 # v4.4.1
|
||||
with:
|
||||
validate-wrappers: true
|
||||
|
||||
- name: Verify MariaDB connection
|
||||
run: |
|
||||
while ! mysqladmin ping -h"127.0.0.1" -P3306 ; do
|
||||
sleep 1
|
||||
done
|
||||
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
|
||||
./gradlew --no-daemon -q createDB -PdbName=fineract_tenants
|
||||
./gradlew --no-daemon -q createDB -PdbName=fineract_default
|
||||
|
||||
- name: Start LocalStack
|
||||
env:
|
||||
AWS_ENDPOINT_URL: http://localhost:4566
|
||||
AWS_ACCESS_KEY_ID: localstack
|
||||
AWS_SECRET_ACCESS_KEY: localstack
|
||||
AWS_REGION: us-east-1
|
||||
run: |
|
||||
docker run -d --name localstack -p 4566:4566 -p 4510-4559:4510-4559 localstack/localstack:2.1
|
||||
sleep 10
|
||||
docker exec localstack awslocal s3api create-bucket --bucket fineract-reports
|
||||
echo "LocalStack initialization complete"
|
||||
- name: Build & Test
|
||||
env:
|
||||
AWS_ENDPOINT_URL: http://localhost:4566
|
||||
AWS_ACCESS_KEY_ID: localstack
|
||||
AWS_SECRET_ACCESS_KEY: localstack
|
||||
AWS_REGION: us-east-1
|
||||
FINERACT_REPORT_EXPORT_S3_ENABLED: true
|
||||
FINERACT_REPORT_EXPORT_S3_BUCKET_NAME: fineract-reports
|
||||
|
||||
- name: Generate test class list (only for test-core-X)
|
||||
if: startsWith(matrix.task, 'test-core-')
|
||||
run: |
|
||||
./gradlew --no-daemon --console=plain build -x cucumber -x test -x doc
|
||||
./gradlew --no-daemon --console=plain cucumber -x :fineract-e2e-tests-runner:cucumber
|
||||
./gradlew --no-daemon --console=plain test -x :twofactor-tests:test -x :oauth2-test:test -x :fineract-e2e-tests-runner:test
|
||||
./gradlew --no-daemon --console=plain :twofactor-tests:test
|
||||
./gradlew --no-daemon --console=plain :oauth2-tests:test
|
||||
chmod +x scripts/split-tests.sh
|
||||
SHARD_INDEX=$(echo "${{ matrix.task }}" | awk -F'-' '{print $3}')
|
||||
./scripts/split-tests.sh 5 $SHARD_INDEX
|
||||
cat "shard-tests_${SHARD_INDEX}.txt"
|
||||
|
||||
- name: Run Gradle Task
|
||||
run: |
|
||||
set -e # Fail the script if any command fails
|
||||
SHARD_INDEX=$(echo "${{ matrix.task }}" | awk -F'-' '{print $3}')
|
||||
FAILED=0
|
||||
|
||||
case "${{ matrix.task }}" in
|
||||
test-core-*)
|
||||
echo "Grouping test classes by module..."
|
||||
declare -A module_tests
|
||||
|
||||
while IFS=, read -r module class; do
|
||||
module_tests["$module"]+="$class "
|
||||
done < "shard-tests_${SHARD_INDEX}.txt"
|
||||
|
||||
for module in "${!module_tests[@]}"; do
|
||||
echo "::group::Running tests in $module"
|
||||
for class in ${module_tests[$module]}; do
|
||||
echo " - $class"
|
||||
done
|
||||
|
||||
# Build test args
|
||||
test_args=$(for class in ${module_tests[$module]}; do echo --tests "$class"; done | xargs)
|
||||
|
||||
# Run test task for this module
|
||||
if ! ./gradlew "$module:test" $test_args -x checkstyleJmh -x checkstyleMain -x checkstyleTest -x spotlessCheck -x spotlessApply -x spotbugsMain -x spotbugsTest -x javadoc -x javadocJar -x modernizer; then
|
||||
echo "::error::Tests failed in module $module"
|
||||
FAILED=1
|
||||
fi
|
||||
echo "::endgroup::"
|
||||
done
|
||||
;;
|
||||
esac
|
||||
|
||||
# Exit with failure status if any test failed
|
||||
if [ "$FAILED" -eq 1 ]; then
|
||||
echo "::error::Some tests failed in this job"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
- name: Archive test results
|
||||
if: always()
|
||||
uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4
|
||||
with:
|
||||
name: test-results
|
||||
path: |
|
||||
build/reports/
|
||||
integration-tests/build/reports/
|
||||
twofactor-tests/build/reports/
|
||||
oauth2-tests/build/reports/
|
||||
name: test-results-${{ matrix.task }}
|
||||
path: '**/build/reports/'
|
||||
retention-days: 5
|
||||
|
||||
- name: Archive server logs
|
||||
if: always()
|
||||
uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4
|
||||
with:
|
||||
name: server-logs
|
||||
path: |
|
||||
integration-tests/build/cargo/
|
||||
twofactor-tests/build/cargo/
|
||||
oauth2-tests/build/cargo/
|
||||
name: server-logs-${{ matrix.task }}
|
||||
path: '**/build/cargo/'
|
||||
retention-days: 5
|
||||
|
||||
@@ -1,92 +1,150 @@
|
||||
name: Fineract Build & Test - MySQL
|
||||
name: Fineract Cargo & Unit- & Integration tests - MySQL
|
||||
|
||||
on: [push, pull_request]
|
||||
|
||||
permissions:
|
||||
contents: read
|
||||
|
||||
jobs:
|
||||
build:
|
||||
test:
|
||||
runs-on: ubuntu-24.04
|
||||
timeout-minutes: 60
|
||||
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
task: [test-core-1, test-core-2, test-core-3, test-core-4, test-core-5]
|
||||
|
||||
services:
|
||||
mariad:
|
||||
image: mysql:9.1
|
||||
ports:
|
||||
- 3306:3306
|
||||
env:
|
||||
MYSQL_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:2.1.10
|
||||
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" ] } } ] } ] }'
|
||||
mysql:
|
||||
image: mysql:9.1
|
||||
ports:
|
||||
- 3306:3306
|
||||
env:
|
||||
MYSQL_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:2.1.10
|
||||
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
|
||||
DEVELOCITY_ACCESS_KEY: ${{ secrets.DEVELOCITY_ACCESS_KEY }}
|
||||
TZ: Asia/Kolkata
|
||||
DEVELOCITY_ACCESS_KEY: ${{ secrets.DEVELOCITY_ACCESS_KEY }}
|
||||
AWS_ENDPOINT_URL: http://localhost:4566
|
||||
AWS_ACCESS_KEY_ID: localstack
|
||||
AWS_SECRET_ACCESS_KEY: localstack
|
||||
AWS_REGION: us-east-1
|
||||
FINERACT_REPORT_EXPORT_S3_ENABLED: true
|
||||
FINERACT_REPORT_EXPORT_S3_BUCKET_NAME: fineract-reports
|
||||
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4
|
||||
uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v4
|
||||
with:
|
||||
fetch-depth: 0
|
||||
- name: Set up JDK 17
|
||||
uses: actions/setup-java@3a4f6e1af504cf6a31855fa899c6aa5355ba6c12 # v4
|
||||
fetch-tags: true
|
||||
|
||||
- name: Set up JDK 21
|
||||
uses: actions/setup-java@dded0888837ed1f317902acf8a20df0ad188d165 # v4
|
||||
with:
|
||||
java-version: '17'
|
||||
java-version: '21'
|
||||
distribution: 'zulu'
|
||||
|
||||
- name: Cache Gradle dependencies
|
||||
uses: actions/cache@0057852bfaa89a56745cba8c7296529d2fc39830 # v4
|
||||
with:
|
||||
path: |
|
||||
~/.gradle/caches
|
||||
~/.gradle/wrapper
|
||||
key: gradle-${{ runner.os }}-${{ hashFiles('**/*.gradle*', '**/gradle-wrapper.properties') }}
|
||||
|
||||
- name: Setup Gradle and Validate Wrapper
|
||||
uses: gradle/actions/setup-gradle@06832c7b30a0129d7fb559bcc6e43d26f6374244 # v4.3.1
|
||||
uses: gradle/actions/setup-gradle@ac638b010cf58a27ee6c972d7336334ccaf61c96 # v4.4.1
|
||||
with:
|
||||
validate-wrappers: true
|
||||
- name: Verify MariaDB connection
|
||||
|
||||
- name: Verify MySQL connection
|
||||
run: |
|
||||
while ! mysqladmin ping -h"127.0.0.1" -P3306 ; do
|
||||
sleep 1
|
||||
done
|
||||
while ! mysqladmin ping -h"127.0.0.1" -P3306 ; do
|
||||
sleep 1
|
||||
done
|
||||
|
||||
- name: Initialise databases
|
||||
run: |
|
||||
./gradlew --no-daemon -q createMySQLDB -PdbName=fineract_tenants
|
||||
./gradlew --no-daemon -q createMySQLDB -PdbName=fineract_default
|
||||
./gradlew --no-daemon -q createMySQLDB -PdbName=fineract_tenants
|
||||
./gradlew --no-daemon -q createMySQLDB -PdbName=fineract_default
|
||||
|
||||
- name: Start LocalStack
|
||||
env:
|
||||
AWS_ENDPOINT_URL: http://localhost:4566
|
||||
AWS_ACCESS_KEY_ID: localstack
|
||||
AWS_SECRET_ACCESS_KEY: localstack
|
||||
AWS_REGION: us-east-1
|
||||
run: |
|
||||
docker run -d --name localstack -p 4566:4566 -p 4510-4559:4510-4559 localstack/localstack:2.1
|
||||
sleep 10
|
||||
docker exec localstack awslocal s3api create-bucket --bucket fineract-reports
|
||||
echo "LocalStack initialization complete"
|
||||
- name: Build & Test
|
||||
env:
|
||||
AWS_ENDPOINT_URL: http://localhost:4566
|
||||
AWS_ACCESS_KEY_ID: localstack
|
||||
AWS_SECRET_ACCESS_KEY: localstack
|
||||
AWS_REGION: us-east-1
|
||||
FINERACT_REPORT_EXPORT_S3_ENABLED: true
|
||||
FINERACT_REPORT_EXPORT_S3_BUCKET_NAME: fineract-reports
|
||||
|
||||
- name: Generate test class list (only for test-core-X)
|
||||
if: startsWith(matrix.task, 'test-core-')
|
||||
run: |
|
||||
./gradlew --no-daemon --console=plain build -x cucumber -x test -x doc
|
||||
./gradlew --no-daemon --console=plain cucumber -x :fineract-e2e-tests-runner:cucumber
|
||||
./gradlew --no-daemon --console=plain test -x :twofactor-tests:test -x :oauth2-test:test :fineract-e2e-tests-runner:test -PdbType=mysql
|
||||
./gradlew --no-daemon --console=plain :twofactor-tests:test -PdbType=mysql
|
||||
./gradlew --no-daemon --console=plain :oauth2-tests:test -PdbType=mysql
|
||||
chmod +x scripts/split-tests.sh
|
||||
SHARD_INDEX=$(echo "${{ matrix.task }}" | awk -F'-' '{print $3}')
|
||||
./scripts/split-tests.sh 5 $SHARD_INDEX
|
||||
cat "shard-tests_${SHARD_INDEX}.txt"
|
||||
|
||||
- name: Run Gradle Task
|
||||
run: |
|
||||
set -e # Fail the script if any command fails
|
||||
SHARD_INDEX=$(echo "${{ matrix.task }}" | awk -F'-' '{print $3}')
|
||||
FAILED=0
|
||||
|
||||
case "${{ matrix.task }}" in
|
||||
test-core-*)
|
||||
echo "Grouping test classes by module..."
|
||||
declare -A module_tests
|
||||
|
||||
while IFS=, read -r module class; do
|
||||
module_tests["$module"]+="$class "
|
||||
done < "shard-tests_${SHARD_INDEX}.txt"
|
||||
|
||||
for module in "${!module_tests[@]}"; do
|
||||
echo "::group::Running tests in $module"
|
||||
for class in ${module_tests[$module]}; do
|
||||
echo " - $class"
|
||||
done
|
||||
|
||||
# Build test args
|
||||
test_args=$(for class in ${module_tests[$module]}; do echo --tests "$class"; done | xargs)
|
||||
|
||||
# Run test task for this module
|
||||
if ! ./gradlew "$module:test" $test_args -PdbType=mysql -x checkstyleJmh -x checkstyleMain -x checkstyleTest -x spotlessCheck -x spotlessApply -x spotbugsMain -x spotbugsTest -x javadoc -x javadocJar -x modernizer; then
|
||||
echo "::error::Tests failed in module $module"
|
||||
FAILED=1
|
||||
fi
|
||||
echo "::endgroup::"
|
||||
done
|
||||
;;
|
||||
esac
|
||||
|
||||
# Exit with failure status if any test failed
|
||||
if [ "$FAILED" -eq 1 ]; then
|
||||
echo "::error::Some tests failed in this job"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
- name: Archive test results
|
||||
if: always()
|
||||
uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4
|
||||
with:
|
||||
name: test-results
|
||||
path: |
|
||||
build/reports/
|
||||
integration-tests/build/reports/
|
||||
twofactor-tests/build/reports/
|
||||
oauth2-tests/build/reports/
|
||||
name: test-results-${{ matrix.task }}
|
||||
path: '**/build/reports/'
|
||||
retention-days: 5
|
||||
|
||||
- name: Archive server logs
|
||||
if: always()
|
||||
uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4
|
||||
with:
|
||||
name: server-logs
|
||||
path: |
|
||||
integration-tests/build/cargo/
|
||||
twofactor-tests/build/cargo/
|
||||
oauth2-tests/build/cargo/
|
||||
name: server-logs-${{ matrix.task }}
|
||||
path: '**/build/cargo/'
|
||||
retention-days: 5
|
||||
|
||||
@@ -1,93 +1,151 @@
|
||||
name: Fineract Build & Test - PostgreSQL
|
||||
name: Fineract Cargo & Unit- & Integration tests - PostgreSQL
|
||||
|
||||
on: [push, pull_request]
|
||||
|
||||
permissions:
|
||||
contents: read
|
||||
|
||||
jobs:
|
||||
build:
|
||||
test:
|
||||
runs-on: ubuntu-24.04
|
||||
timeout-minutes: 60
|
||||
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
task: [test-core-1, test-core-2, test-core-3, test-core-4, test-core-5]
|
||||
|
||||
services:
|
||||
postgresql:
|
||||
image: postgres:17.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:2.1.10
|
||||
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" ] } } ] } ] }'
|
||||
postgresql:
|
||||
image: postgres:17.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:2.1.10
|
||||
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
|
||||
DEVELOCITY_ACCESS_KEY: ${{ secrets.DEVELOCITY_ACCESS_KEY }}
|
||||
TZ: Asia/Kolkata
|
||||
DEVELOCITY_ACCESS_KEY: ${{ secrets.DEVELOCITY_ACCESS_KEY }}
|
||||
AWS_ENDPOINT_URL: http://localhost:4566
|
||||
AWS_ACCESS_KEY_ID: localstack
|
||||
AWS_SECRET_ACCESS_KEY: localstack
|
||||
AWS_REGION: us-east-1
|
||||
FINERACT_REPORT_EXPORT_S3_ENABLED: true
|
||||
FINERACT_REPORT_EXPORT_S3_BUCKET_NAME: fineract-reports
|
||||
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4
|
||||
uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v4
|
||||
with:
|
||||
fetch-depth: 0
|
||||
- name: Set up JDK 17
|
||||
uses: actions/setup-java@3a4f6e1af504cf6a31855fa899c6aa5355ba6c12 # v4
|
||||
fetch-tags: true
|
||||
|
||||
- name: Set up JDK 21
|
||||
uses: actions/setup-java@dded0888837ed1f317902acf8a20df0ad188d165 # v4
|
||||
with:
|
||||
java-version: '17'
|
||||
java-version: '21'
|
||||
distribution: 'zulu'
|
||||
|
||||
- name: Cache Gradle dependencies
|
||||
uses: actions/cache@0057852bfaa89a56745cba8c7296529d2fc39830 # v4
|
||||
with:
|
||||
path: |
|
||||
~/.gradle/caches
|
||||
~/.gradle/wrapper
|
||||
key: gradle-${{ runner.os }}-${{ hashFiles('**/*.gradle*', '**/gradle-wrapper.properties') }}
|
||||
|
||||
- name: Setup Gradle and Validate Wrapper
|
||||
uses: gradle/actions/setup-gradle@06832c7b30a0129d7fb559bcc6e43d26f6374244 # v4.3.1
|
||||
uses: gradle/actions/setup-gradle@ac638b010cf58a27ee6c972d7336334ccaf61c96 # v4.4.1
|
||||
with:
|
||||
validate-wrappers: true
|
||||
|
||||
- name: Verify PostgreSQL connection
|
||||
run: |
|
||||
while ! pg_isready -d postgres -U root -h 127.0.0.1 -p 5432 ; do
|
||||
sleep 1
|
||||
done
|
||||
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
|
||||
./gradlew --no-daemon -q createPGDB -PdbName=fineract_tenants
|
||||
./gradlew --no-daemon -q createPGDB -PdbName=fineract_default
|
||||
|
||||
- name: Start LocalStack
|
||||
env:
|
||||
AWS_ENDPOINT_URL: http://localhost:4566
|
||||
AWS_ACCESS_KEY_ID: localstack
|
||||
AWS_SECRET_ACCESS_KEY: localstack
|
||||
AWS_REGION: us-east-1
|
||||
run: |
|
||||
docker run -d --name localstack -p 4566:4566 -p 4510-4559:4510-4559 localstack/localstack:2.1
|
||||
sleep 10
|
||||
docker exec localstack awslocal s3api create-bucket --bucket fineract-reports
|
||||
echo "LocalStack initialization complete"
|
||||
- name: Build & Test
|
||||
env:
|
||||
AWS_ENDPOINT_URL: http://localhost:4566
|
||||
AWS_ACCESS_KEY_ID: localstack
|
||||
AWS_SECRET_ACCESS_KEY: localstack
|
||||
AWS_REGION: us-east-1
|
||||
FINERACT_REPORT_EXPORT_S3_ENABLED: true
|
||||
FINERACT_REPORT_EXPORT_S3_BUCKET_NAME: fineract-reports
|
||||
|
||||
- name: Generate test class list (only for test-core-X)
|
||||
if: startsWith(matrix.task, 'test-core-')
|
||||
run: |
|
||||
./gradlew --no-daemon --console=plain build -x cucumber -x test -x doc
|
||||
./gradlew --no-daemon --console=plain cucumber -x :fineract-e2e-tests-runner:cucumber
|
||||
./gradlew --no-daemon --console=plain test -x :twofactor-tests:test -x :oauth2-test:test :fineract-e2e-tests-runner:test -PdbType=postgresql
|
||||
./gradlew --no-daemon --console=plain :twofactor-tests:test -PdbType=postgresql
|
||||
./gradlew --no-daemon --console=plain :oauth2-tests:test -PdbType=postgresql
|
||||
chmod +x scripts/split-tests.sh
|
||||
SHARD_INDEX=$(echo "${{ matrix.task }}" | awk -F'-' '{print $3}')
|
||||
./scripts/split-tests.sh 5 $SHARD_INDEX
|
||||
cat "shard-tests_${SHARD_INDEX}.txt"
|
||||
|
||||
- name: Run Gradle Task
|
||||
run: |
|
||||
set -e # Fail the script if any command fails
|
||||
SHARD_INDEX=$(echo "${{ matrix.task }}" | awk -F'-' '{print $3}')
|
||||
FAILED=0
|
||||
|
||||
case "${{ matrix.task }}" in
|
||||
test-core-*)
|
||||
echo "Grouping test classes by module..."
|
||||
declare -A module_tests
|
||||
|
||||
while IFS=, read -r module class; do
|
||||
module_tests["$module"]+="$class "
|
||||
done < "shard-tests_${SHARD_INDEX}.txt"
|
||||
|
||||
for module in "${!module_tests[@]}"; do
|
||||
echo "::group::Running tests in $module"
|
||||
for class in ${module_tests[$module]}; do
|
||||
echo " - $class"
|
||||
done
|
||||
|
||||
# Build test args
|
||||
test_args=$(for class in ${module_tests[$module]}; do echo --tests "$class"; done | xargs)
|
||||
|
||||
# Run test task for this module
|
||||
if ! ./gradlew "$module:test" $test_args -PdbType=postgresql -x checkstyleJmh -x checkstyleMain -x checkstyleTest -x spotlessCheck -x spotlessApply -x spotbugsMain -x spotbugsTest -x javadoc -x javadocJar -x modernizer; then
|
||||
echo "::error::Tests failed in module $module"
|
||||
FAILED=1
|
||||
fi
|
||||
echo "::endgroup::"
|
||||
done
|
||||
;;
|
||||
esac
|
||||
|
||||
# Exit with failure status if any test failed
|
||||
if [ "$FAILED" -eq 1 ]; then
|
||||
echo "::error::Some tests failed in this job"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
- name: Archive test results
|
||||
if: always()
|
||||
uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4
|
||||
with:
|
||||
name: test-results
|
||||
path: |
|
||||
build/reports/
|
||||
integration-tests/build/reports/
|
||||
twofactor-tests/build/reports/
|
||||
oauth2-tests/build/reports/
|
||||
name: test-results-${{ matrix.task }}
|
||||
path: '**/build/reports/'
|
||||
retention-days: 5
|
||||
|
||||
- name: Archive server logs
|
||||
if: always()
|
||||
uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4
|
||||
with:
|
||||
name: server-logs
|
||||
path: |
|
||||
integration-tests/build/cargo/
|
||||
twofactor-tests/build/cargo/
|
||||
oauth2-tests/build/cargo/
|
||||
name: server-logs-${{ matrix.task }}
|
||||
path: '**/build/cargo/'
|
||||
retention-days: 5
|
||||
|
||||
@@ -1,41 +0,0 @@
|
||||
name: Fineract Tests
|
||||
on: [push, pull_request]
|
||||
permissions:
|
||||
contents: read
|
||||
jobs:
|
||||
build:
|
||||
runs-on: ubuntu-24.04
|
||||
env:
|
||||
DEVELOCITY_ACCESS_KEY: ${{ secrets.DEVELOCITY_ACCESS_KEY }}
|
||||
IMAGE_NAME: fineract
|
||||
steps:
|
||||
- uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4
|
||||
with:
|
||||
fetch-depth: 0
|
||||
- name: Set up JDK 17
|
||||
uses: actions/setup-java@3a4f6e1af504cf6a31855fa899c6aa5355ba6c12 # v4
|
||||
with:
|
||||
java-version: '17'
|
||||
distribution: 'zulu'
|
||||
- name: Setup Gradle
|
||||
uses: gradle/actions/setup-gradle@06832c7b30a0129d7fb559bcc6e43d26f6374244 # v4.3.1
|
||||
- name: Build the image
|
||||
run: ./gradlew --no-daemon --console=plain :fineract-provider:jibDockerBuild -Djib.to.image=$IMAGE_NAME -x test -x cucumber
|
||||
- name: Start the Fineract stack
|
||||
run: docker compose -f docker-compose-postgresql-test-activemq.yml up -d
|
||||
- name: Check the stack
|
||||
run: docker ps
|
||||
- name: Check health Manager
|
||||
run: curl -f -k --retry 60 --retry-all-errors --connect-timeout 30 --retry-delay 30 https://localhost:8443/fineract-provider/actuator/health
|
||||
- name: Execute tests
|
||||
env:
|
||||
BASE_URL: https://localhost:8443
|
||||
TEST_USERNAME: mifos
|
||||
TEST_PASSWORD: password
|
||||
TEST_STRONG_PASSWORD: A1b2c3d4e5f$
|
||||
TEST_TENANT_ID: default
|
||||
INITIALIZATION_ENABLED: true
|
||||
EVENT_VERIFICATION_ENABLED: true
|
||||
ACTIVEMQ_BROKER_URL: tcp://localhost:61616
|
||||
ACTIVEMQ_TOPIC_NAME: events
|
||||
run: ./gradlew --no-daemon --console=plain :fineract-e2e-tests-runner:cucumber --tags 'not @Skip' allureReport
|
||||
@@ -10,27 +10,23 @@ permissions:
|
||||
jobs:
|
||||
build:
|
||||
runs-on: ubuntu-24.04
|
||||
timeout-minutes: 60
|
||||
env:
|
||||
DEVELOCITY_ACCESS_KEY: ${{ secrets.DEVELOCITY_ACCESS_KEY }}
|
||||
steps:
|
||||
- name: Checkout Source Code
|
||||
uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4
|
||||
uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v4
|
||||
with:
|
||||
fetch-depth: 0
|
||||
|
||||
- name: Set up JDK 17
|
||||
uses: actions/setup-java@3a4f6e1af504cf6a31855fa899c6aa5355ba6c12 # v4
|
||||
- name: Set up JDK 21
|
||||
uses: actions/setup-java@dded0888837ed1f317902acf8a20df0ad188d165 # v4
|
||||
with:
|
||||
java-version: '17'
|
||||
java-version: '21'
|
||||
distribution: 'zulu'
|
||||
|
||||
- name: Setup Gradle
|
||||
uses: gradle/actions/setup-gradle@06832c7b30a0129d7fb559bcc6e43d26f6374244 # v4.3.1
|
||||
|
||||
- name: Extract branch name
|
||||
shell: bash
|
||||
run: echo "branch=${GITHUB_HEAD_REF:-${GITHUB_REF#refs/heads/}}" >> $GITHUB_OUTPUT
|
||||
id: extract_branch
|
||||
uses: gradle/actions/setup-gradle@ac638b010cf58a27ee6c972d7336334ccaf61c96 # v4.4.1
|
||||
|
||||
- name: Get Git Hashes
|
||||
run: |
|
||||
@@ -40,8 +36,8 @@ jobs:
|
||||
|
||||
- name: Build the Apache Fineract image
|
||||
run: |
|
||||
TAGS=${{ steps.extract_branch.outputs.branch }}
|
||||
if [ "${{ steps.extract_branch.outputs.branch }}" == "develop" ]; then
|
||||
TAGS=${{ github.ref_name }}
|
||||
if [ "${{ github.ref_name }}" == "develop" ]; then
|
||||
TAGS="$TAGS,${{ steps.git_hashes.outputs.short_hash }},${{ steps.git_hashes.outputs.long_hash }}"
|
||||
fi
|
||||
./gradlew --no-daemon --console=plain :fineract-provider:jib -x test -x cucumber \
|
||||
|
||||
@@ -0,0 +1,105 @@
|
||||
name: Fineract Cargo & Unit- & Integration tests - Sequential Execution - PostgreSQL
|
||||
|
||||
on:
|
||||
workflow_dispatch:
|
||||
push:
|
||||
branches:
|
||||
- develop
|
||||
permissions:
|
||||
contents: read
|
||||
jobs:
|
||||
build:
|
||||
runs-on: ubuntu-24.04
|
||||
timeout-minutes: 180
|
||||
|
||||
services:
|
||||
postgresql:
|
||||
image: postgres:17.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:2.1.10
|
||||
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
|
||||
DEVELOCITY_ACCESS_KEY: ${{ secrets.DEVELOCITY_ACCESS_KEY }}
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v4
|
||||
with:
|
||||
fetch-depth: 0
|
||||
fetch-tags: true
|
||||
|
||||
- name: Set up JDK 21
|
||||
uses: actions/setup-java@dded0888837ed1f317902acf8a20df0ad188d165 # v4
|
||||
with:
|
||||
java-version: '21'
|
||||
distribution: 'zulu'
|
||||
- name: Setup Gradle and Validate Wrapper
|
||||
uses: gradle/actions/setup-gradle@ac638b010cf58a27ee6c972d7336334ccaf61c96 # v4.4.1
|
||||
with:
|
||||
validate-wrappers: true
|
||||
- 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: Start LocalStack
|
||||
env:
|
||||
AWS_ENDPOINT_URL: http://localhost:4566
|
||||
AWS_ACCESS_KEY_ID: localstack
|
||||
AWS_SECRET_ACCESS_KEY: localstack
|
||||
AWS_REGION: us-east-1
|
||||
run: |
|
||||
docker run -d --name localstack -p 4566:4566 -p 4510-4559:4510-4559 localstack/localstack:2.1
|
||||
sleep 10
|
||||
docker exec localstack awslocal s3api create-bucket --bucket fineract-reports
|
||||
echo "LocalStack initialization complete"
|
||||
- name: Build & Test
|
||||
env:
|
||||
AWS_ENDPOINT_URL: http://localhost:4566
|
||||
AWS_ACCESS_KEY_ID: localstack
|
||||
AWS_SECRET_ACCESS_KEY: localstack
|
||||
AWS_REGION: us-east-1
|
||||
FINERACT_REPORT_EXPORT_S3_ENABLED: true
|
||||
FINERACT_REPORT_EXPORT_S3_BUCKET_NAME: fineract-reports
|
||||
run: |
|
||||
./gradlew --no-daemon --console=plain build -x cucumber -x test -x doc
|
||||
./gradlew --no-daemon --console=plain cucumber -x :fineract-e2e-tests-runner:cucumber
|
||||
./gradlew --no-daemon --console=plain test -x :twofactor-tests:test -x :oauth2-test:test -x :fineract-e2e-tests-runner:test -PdbType=postgresql
|
||||
./gradlew --no-daemon --console=plain :twofactor-tests:test -PdbType=postgresql
|
||||
./gradlew --no-daemon --console=plain :oauth2-tests:test -PdbType=postgresql
|
||||
- name: Archive test results
|
||||
if: always()
|
||||
uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4
|
||||
with:
|
||||
name: test-results
|
||||
retention-days: 5
|
||||
path: |
|
||||
build/reports/
|
||||
integration-tests/build/reports/
|
||||
twofactor-tests/build/reports/
|
||||
oauth2-tests/build/reports/
|
||||
- name: Archive server logs
|
||||
if: always()
|
||||
uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4
|
||||
with:
|
||||
name: server-logs
|
||||
retention-days: 5
|
||||
path: |
|
||||
integration-tests/build/cargo/
|
||||
twofactor-tests/build/cargo/
|
||||
oauth2-tests/build/cargo/
|
||||
@@ -1,37 +0,0 @@
|
||||
name: Fineract ActiveMQ Smoke
|
||||
on: [push, pull_request]
|
||||
permissions:
|
||||
contents: read
|
||||
jobs:
|
||||
build:
|
||||
runs-on: ubuntu-24.04
|
||||
env:
|
||||
DEVELOCITY_ACCESS_KEY: ${{ secrets.DEVELOCITY_ACCESS_KEY }}
|
||||
IMAGE_NAME: fineract
|
||||
steps:
|
||||
- uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4
|
||||
with:
|
||||
fetch-depth: 0
|
||||
- name: Set up JDK 17
|
||||
uses: actions/setup-java@3a4f6e1af504cf6a31855fa899c6aa5355ba6c12 # v4
|
||||
with:
|
||||
java-version: '17'
|
||||
distribution: 'zulu'
|
||||
- name: Setup Gradle
|
||||
uses: gradle/actions/setup-gradle@06832c7b30a0129d7fb559bcc6e43d26f6374244 # v4.3.1
|
||||
- name: Build the image
|
||||
run: ./gradlew --no-daemon --console=plain :fineract-provider:jibDockerBuild -Djib.to.image=$IMAGE_NAME -x test -x cucumber
|
||||
- name: Start the ActiveMQ Stack
|
||||
run: docker compose -f docker-compose-postgresql-activemq.yml up --scale fineract-worker=1 -d
|
||||
- name: Check the stack
|
||||
run: docker ps
|
||||
- name: Check health Manager
|
||||
run: curl -f -k --retry 60 --retry-all-errors --connect-timeout 30 --retry-delay 30 https://localhost:8443/fineract-provider/actuator/health
|
||||
- name: Check health Worker1
|
||||
run: curl -f -k --retry 60 --retry-all-errors --connect-timeout 30 --retry-delay 30 https://localhost:8444/fineract-provider/actuator/health
|
||||
- name: Check info Manager
|
||||
run: (( $(curl -f -k --retry 5 --retry-all-errors --connect-timeout 30 --retry-delay 30 https://localhost:8443/fineract-provider/actuator/info | wc --chars) > 100 ))
|
||||
- name: Check info Worker1
|
||||
run: (( $(curl -f -k --retry 5 --retry-all-errors --connect-timeout 30 --retry-delay 30 https://localhost:8444/fineract-provider/actuator/info | wc --chars) > 100 ))
|
||||
- name: Run Smoke Test with Remote COB
|
||||
run: ./gradlew --no-daemon --console=plain :integration-tests:cleanTest :integration-tests:test --tests "org.apache.fineract.integrationtests.investor.externalassetowner.InitiateExternalAssetOwnerTransferTest.saleActiveLoanToExternalAssetOwnerAndBuybackADayLater" -PcargoDisabled
|
||||
@@ -1,37 +1,62 @@
|
||||
name: Fineract Kafka Smoke
|
||||
name: Fineract Messaging Smoke Tests
|
||||
|
||||
on: [push, pull_request]
|
||||
|
||||
permissions:
|
||||
contents: read
|
||||
|
||||
jobs:
|
||||
build:
|
||||
smoke-test:
|
||||
name: Smoke Test with ${{ matrix.messaging }}
|
||||
runs-on: ubuntu-24.04
|
||||
timeout-minutes: 60
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
include:
|
||||
- messaging: ActiveMQ
|
||||
compose_file: docker-compose-postgresql-activemq.yml
|
||||
- messaging: Kafka
|
||||
compose_file: docker-compose-postgresql-kafka.yml
|
||||
|
||||
env:
|
||||
DEVELOCITY_ACCESS_KEY: ${{ secrets.DEVELOCITY_ACCESS_KEY }}
|
||||
IMAGE_NAME: fineract
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4
|
||||
- uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v4
|
||||
with:
|
||||
fetch-depth: 0
|
||||
- name: Set up JDK 17
|
||||
uses: actions/setup-java@3a4f6e1af504cf6a31855fa899c6aa5355ba6c12 # v4
|
||||
|
||||
- name: Set up JDK 21
|
||||
uses: actions/setup-java@dded0888837ed1f317902acf8a20df0ad188d165 # v4
|
||||
with:
|
||||
java-version: '17'
|
||||
java-version: '21'
|
||||
distribution: 'zulu'
|
||||
|
||||
- name: Setup Gradle
|
||||
uses: gradle/actions/setup-gradle@06832c7b30a0129d7fb559bcc6e43d26f6374244 # v4.3.1
|
||||
uses: gradle/actions/setup-gradle@ac638b010cf58a27ee6c972d7336334ccaf61c96 # v4.4.1
|
||||
|
||||
- name: Build the image
|
||||
run: ./gradlew --no-daemon --console=plain :fineract-provider:jibDockerBuild -Djib.to.image=$IMAGE_NAME -x test -x cucumber
|
||||
- name: Start the Kafka Stack
|
||||
run: docker compose -f docker-compose-postgresql-kafka.yml up --scale fineract-worker=1 -d
|
||||
|
||||
- name: Start the ${{ matrix.messaging }} Stack
|
||||
run: docker compose -f ${{ matrix.compose_file }} up --scale fineract-worker=1 -d
|
||||
|
||||
- name: Check the stack
|
||||
run: docker ps
|
||||
|
||||
- name: Check health Manager
|
||||
run: curl -f -k --retry 60 --retry-all-errors --connect-timeout 30 --retry-delay 30 https://localhost:8443/fineract-provider/actuator/health
|
||||
|
||||
- name: Check health Worker1
|
||||
run: curl -f -k --retry 60 --retry-all-errors --connect-timeout 30 --retry-delay 30 https://localhost:8444/fineract-provider/actuator/health
|
||||
|
||||
- name: Check info Manager
|
||||
run: (( $(curl -f -k --retry 5 --retry-all-errors --connect-timeout 30 --retry-delay 30 https://localhost:8443/fineract-provider/actuator/info | wc --chars) > 100 ))
|
||||
|
||||
- name: Check info Worker1
|
||||
run: (( $(curl -f -k --retry 5 --retry-all-errors --connect-timeout 30 --retry-delay 30 https://localhost:8444/fineract-provider/actuator/info | wc --chars) > 100 ))
|
||||
|
||||
- name: Run Smoke Test with Remote COB
|
||||
run: ./gradlew --no-daemon --console=plain :integration-tests:cleanTest :integration-tests:test --tests "org.apache.fineract.integrationtests.investor.externalassetowner.InitiateExternalAssetOwnerTransferTest.saleActiveLoanToExternalAssetOwnerAndBuybackADayLater" -PcargoDisabled
|
||||
@@ -8,6 +8,7 @@ permissions:
|
||||
jobs:
|
||||
build:
|
||||
runs-on: ubuntu-24.04
|
||||
timeout-minutes: 60
|
||||
env:
|
||||
TZ: Asia/Kolkata
|
||||
SONAR_ORGANIZATION: ${{ secrets.SONAR_ORGANIZATION }}
|
||||
@@ -19,16 +20,16 @@ jobs:
|
||||
JAVA_BINARIES: .
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4
|
||||
uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v4
|
||||
with:
|
||||
fetch-depth: 0
|
||||
- name: Set up JDK 17
|
||||
uses: actions/setup-java@3a4f6e1af504cf6a31855fa899c6aa5355ba6c12 # v4
|
||||
- name: Set up JDK 21
|
||||
uses: actions/setup-java@dded0888837ed1f317902acf8a20df0ad188d165 # v4
|
||||
with:
|
||||
java-version: '17'
|
||||
java-version: '21'
|
||||
distribution: 'zulu'
|
||||
- name: Setup Gradle and Validate Wrapper
|
||||
uses: gradle/actions/setup-gradle@06832c7b30a0129d7fb559bcc6e43d26f6374244 # v4.3.1
|
||||
uses: gradle/actions/setup-gradle@ac638b010cf58a27ee6c972d7336334ccaf61c96 # v4.4.1
|
||||
with:
|
||||
validate-wrappers: true
|
||||
- name: Build
|
||||
|
||||
@@ -13,8 +13,9 @@ jobs:
|
||||
issues: write # for actions/stale to close stale issues
|
||||
pull-requests: write # for actions/stale to close stale PRs
|
||||
runs-on: ubuntu-latest
|
||||
timeout-minutes: 60
|
||||
steps:
|
||||
- uses: actions/stale@5bef64f19d7facfb25b37b414482c7164d639639 # v9
|
||||
- uses: actions/stale@5f858e3efba33a5ca4407a664cc011ad407f2008 # v9
|
||||
with:
|
||||
repo-token: ${{ secrets.GITHUB_TOKEN }}
|
||||
# stale-issue-message: 'Stale issue message'
|
||||
|
||||
+3
-1
@@ -32,4 +32,6 @@ fineract-provider/src/main/generated/
|
||||
gradleExp/
|
||||
|
||||
.run/
|
||||
.java-version
|
||||
.java-version
|
||||
|
||||
.windsurf/
|
||||
-43
@@ -1,43 +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.
|
||||
#
|
||||
|
||||
# https://www.gitpod.io
|
||||
# https://www.gitpod.io/docs/41_Config_Gitpod_File/
|
||||
# https://github.com/gitpod-io/workspace-images/tree/master/mysql
|
||||
|
||||
image: gitpod/workspace-mysql:2022-08-04-13-40-17
|
||||
ports:
|
||||
- port: 3306
|
||||
onOpen: ignore
|
||||
- port: 8005
|
||||
onOpen: ignore
|
||||
- port: 8009
|
||||
onOpen: ignore
|
||||
- port: 8080
|
||||
- port: 8081
|
||||
onOpen: ignore
|
||||
- port: 8443
|
||||
tasks:
|
||||
- command: |
|
||||
# NB MySQL on GitPod.io is currently quite slow.
|
||||
# Using authentication_string= instead of password= due to mysql major version difference
|
||||
mysql -e "USE mysql;\nUPDATE user SET authentication_string=PASSWORD('mysql') WHERE user='root';\nFLUSH PRIVILEGES;\n"
|
||||
./gradlew createDB -PdbName=fineract_tenants
|
||||
./gradlew createDB -PdbName=fineract_default
|
||||
./gradlew build -x test
|
||||
init: sdk default java 17.0.4.fx-zulu
|
||||
+1
-1
@@ -1,5 +1,5 @@
|
||||
Apache Fineract
|
||||
Copyright 2008-2021 The Apache Software Foundation
|
||||
Copyright 2008-2025 The Apache Software Foundation
|
||||
|
||||
This product includes software developed by The Apache Software
|
||||
Foundation (http://www.apache.org/).
|
||||
|
||||
+1
-1
@@ -1,5 +1,5 @@
|
||||
Apache Fineract
|
||||
Copyright 2008-2021 The Apache Software Foundation
|
||||
Copyright 2008-2025 The Apache Software Foundation
|
||||
|
||||
This product includes software developed by The Apache Software
|
||||
Foundation (http://www.apache.org/).
|
||||
|
||||
@@ -12,11 +12,6 @@ Fineract is a mature platform with open APIs that provides a reliable, robust, a
|
||||
|
||||
[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.
|
||||
|
||||
[](https://gitpod.io/#https://github.com/apache/fineract)
|
||||
to start contributing to this project in the online web-based IDE GitPod.io right away!
|
||||
(You may initially have to press F1 to Find Command and run "Java: Start Language Server".)
|
||||
It's of course also possible to contribute with a "traditional" local development environment (see below).
|
||||
|
||||
COMMUNITY
|
||||
=========
|
||||
|
||||
@@ -25,7 +20,7 @@ If you are interested in contributing to this project, but perhaps don't quite k
|
||||
|
||||
REQUIREMENTS
|
||||
============
|
||||
* `Java >= 17` (Azul Zulu JVM is tested by our CI on GitHub Actions)
|
||||
* `Java >= 21` (Azul Zulu JVM is tested by our CI on GitHub Actions)
|
||||
* MariaDB `11.5.2`
|
||||
|
||||
You can run the required version of the database server in a container, instead of having to install it, like this:
|
||||
@@ -38,7 +33,7 @@ and stop and destroy it like this:
|
||||
|
||||
<br>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.<br>
|
||||
|
||||
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.)
|
||||
Tomcat v10 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 10 is required.)
|
||||
|
||||
<br>IMPORTANT: If you use MySQL or MariaDB
|
||||
============
|
||||
@@ -72,8 +67,25 @@ __RECOMMENDATION__: you need to shift all dates in your database by the timezone
|
||||
Run the following commands:
|
||||
1. `./gradlew createDB -PdbName=fineract_tenants`
|
||||
1. `./gradlew createDB -PdbName=fineract_default`
|
||||
1. `./gradlew bootRun`
|
||||
1. `./gradlew devRun`
|
||||
|
||||
Fineract is now running, and will be listening for API requests on port 8443 by default.
|
||||
|
||||
Confirm Fineract is ready with, for example:
|
||||
|
||||
```bash
|
||||
curl --insecure https://localhost:8443/fineract-provider/actuator/health`
|
||||
```
|
||||
|
||||
To test authenticated endpoints, include credentials in your request:
|
||||
|
||||
```bash
|
||||
curl --location \
|
||||
https://localhost:8443/fineract-provider/api/v1/clients \
|
||||
--header 'Content-Type: application/json' \
|
||||
--header 'Fineract-Platform-TenantId: default' \
|
||||
--header 'Authorization: Basic bWlmb3M6cGFzc3dvcmQ='
|
||||
```
|
||||
|
||||
<br>INSTRUCTIONS: How to build the JAR file
|
||||
============
|
||||
@@ -91,53 +103,16 @@ The tenants database connection details are configured [via environment variable
|
||||
|
||||
<br>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.
|
||||
If you believe you have found a security vulnerability, [let us know privately](https://fineract.apache.org/#contribute).
|
||||
|
||||
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
|
||||
```
|
||||
|
||||
<br>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 (2FA)
|
||||
------------
|
||||
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
|
||||
```
|
||||
For details about security during development and deployment, see <https://fineract.apache.org/docs/current/#_security>.
|
||||
|
||||
|
||||
<br>INSTRUCTIONS: How to build a WAR file
|
||||
============
|
||||
1. Clone the repository or download and extract the archive file to your local 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.
|
||||
3. Deploy this WAR to your Tomcat v10 Servlet Container.
|
||||
|
||||
We recommend using the JAR instead of the WAR file deployment, because it's much easier.
|
||||
|
||||
@@ -170,9 +145,31 @@ Right now we depend on GitHub to know if "the build" is passing (it's actually m
|
||||
The authoritative source of truth for what commands/services/tests to run, how, and when are the files in `.github/workflows/`.
|
||||
Output from runs based on those configuration files appears at <https://github.com/apache/fineract/actions>.
|
||||
|
||||
Note these builds are run in [short-lived virtual machines](https://docs.github.com/en/actions/using-github-hosted-runners/using-github-hosted-runners), so locally reproducing the same may require additional effort, such as these extra clean-up procedures:
|
||||
Incorrect default Java-related executables may cause test failures.
|
||||
To fix this on Debian and Ubuntu systems, run the following:
|
||||
|
||||
```bash
|
||||
export JAVA_HOME=/usr/lib/jvm/zulu21
|
||||
sudo update-alternatives --set java $JAVA_HOME/bin/java
|
||||
sudo update-alternatives --set javac $JAVA_HOME/bin/javac
|
||||
sudo update-alternatives --set javadoc $JAVA_HOME/bin/javadoc
|
||||
```
|
||||
|
||||
This would correct, for example, a [class file verson error](https://en.wikipedia.org/wiki/Java_class_file#General_layout).
|
||||
You might see something like this if a Java 11 executable (class file format version 56) was the system default, but the integration tests were using Java 21 (class file format version 65):
|
||||
|
||||
```
|
||||
UnsupportedClassVersionError: com.example.package/ClassName has been compiled by a more recent version of the Java Runtime (class file version 65.0), this version of the Java Runtime only recognizes class file versions up to 55.0
|
||||
```
|
||||
|
||||
The GitHub builds are run in [short-lived virtual machines](https://docs.github.com/en/actions/using-github-hosted-runners/using-github-hosted-runners), so locally reproducing the same may require additional effort, such as these extra clean-up procedures:
|
||||
|
||||
```bash
|
||||
# Might fix `error: cannot find symbol` or other intermittent failures.
|
||||
# `doc` here is a placeholder for any task(s) you are trying to run.
|
||||
# 💚 This is generally very safe to run between builds.
|
||||
./gradlew --refresh-dependencies doc
|
||||
|
||||
# Destroy anything untracked by git.
|
||||
# ⚠️ This may delete something important, e.g. a finely-tuned IDE configuration.
|
||||
git clean --force -dx
|
||||
@@ -186,6 +183,23 @@ rm -rf ~/.gradle ~/.m2 /tmp/cargo*
|
||||
ps auxwww | grep [c]argo | awk '{ print $2 }' | xargs -r kill
|
||||
```
|
||||
|
||||
Integration test runs such as `./gradlew --no-daemon --console=plain test -x :twofactor-tests:test -x :oauth2-test:test :fineract-e2e-tests-runner:test -PdbType=postgresql` in `.github/workflows/build-postgresql.yml` often take an hour or longer to complete.
|
||||
If you notice the `:integration-tests:test` task taking significantly less time, say, one minute, gradle may be skipping it.
|
||||
Look for something like this in the test output:
|
||||
|
||||
```
|
||||
> Task :integration-tests:test UP-TO-DATE 👀
|
||||
Custom actions are attached to task ':integration-tests:test'.
|
||||
Build cache key for task ':integration-tests:test' is 6aeeec3f58bf9703d4c100fbaa657f5c
|
||||
Skipping task ':integration-tests:test' as it is up-to-date.
|
||||
Resolve mutations for :integration-tests:cargoStopLocal (Thread[Execution worker Thread 11,5,main]) started.
|
||||
:integration-tests:cargoStopLocal (Thread[Execution worker Thread 11,5,main]) started.
|
||||
```
|
||||
|
||||
(This is with the `--info` gradle argument with eyeballs added for emphasis)
|
||||
The `--rerun-tasks` gradle argument may help, or you can try destroying `~/.gradle` and other clean-up procedures as indicated above then re-running tests.
|
||||
This is useful for repeated test runs (say, for timing) when gradle would otherwise assume a task is "up-to-date" and not re-run it.
|
||||
|
||||
Testing within IDEs
|
||||
-----------------
|
||||
|
||||
@@ -274,6 +288,8 @@ Additionally, IDEs such as IntelliJ are useful for editing the AsciiDoc source f
|
||||
|
||||
HTML rendered from the AsciiDoc source files is also available online at <https://fineract.apache.org/docs/current/>.
|
||||
|
||||
A release version is derived from source control. The version will include `-SNAPSHOT` unless the current branch looks like a release or release maintenance branch. See `gitVersioning` settings in `build.gradle` for details.
|
||||
|
||||
Connection pool configuration
|
||||
=============================
|
||||
|
||||
@@ -284,10 +300,7 @@ NOTE: we'll keep backwards compatibility until one of the next releases to ensur
|
||||
<br>SSL CONFIGURATION
|
||||
=================
|
||||
|
||||
Read also [the HTTPS related doc](fineract-doc/src/docs/en/chapters/deployment/https.adoc).
|
||||
|
||||
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.
|
||||
See [the HTTPS related doc](https://fineract.apache.org/docs/current/#_https).
|
||||
|
||||
|
||||
<br>TOMCAT CONFIGURATION
|
||||
|
||||
@@ -0,0 +1,30 @@
|
||||
# Static Weaving Configuration
|
||||
|
||||
This document explains the static weaving setup for JPA entities in the Fineract project.
|
||||
|
||||
## Overview
|
||||
|
||||
Static weaving is a process that enhances JPA entities at build time to improve runtime performance. This is done using the `org.eclipse.persistence.tools.weaving.jpa.StaticWeave` which processes the compiled classes and applies the necessary bytecode transformations.
|
||||
|
||||
## Configuration
|
||||
|
||||
The static weaving is configured in `static-weaving.gradle` and applied to all Java projects that contain JPA entities.
|
||||
|
||||
## How It Works
|
||||
|
||||
1. **Compilation**: Java source files are compiled to the standard classes directory (`build/classes/java/main`).
|
||||
2. **Weaving**: Weaving happens as last step of **compileJava** task, which outputs them to the standard classes directory (`build/classes/java/main`).
|
||||
|
||||
## Adding Static Weaving to a Module
|
||||
|
||||
1. Add JPA entities to `src/main/java`
|
||||
2. Ensure there's a `persistence.xml` file in `src/main/resources/jpa/static-weaving/module/[module-name]/`
|
||||
3. The build will automatically detect and apply static weaving
|
||||
|
||||
## Troubleshooting
|
||||
|
||||
If you encounter issues with static weaving:
|
||||
|
||||
1. Check that the `persistence.xml` file exists in the correct location
|
||||
2. Verify that the output directories are being created correctly
|
||||
3. Check the build logs for any weaving-related errors
|
||||
+42
-42
@@ -22,12 +22,13 @@ buildscript {
|
||||
jacocoVersion = '0.8.12'
|
||||
retrofitVersion = '2.9.0'
|
||||
okhttpVersion = '4.9.3'
|
||||
oltuVersion = '1.0.1'
|
||||
fineractCustomProjects = []
|
||||
fineractJavaProjects = subprojects.findAll{
|
||||
[
|
||||
'fineract-api',
|
||||
'fineract-core',
|
||||
'fineract-cob',
|
||||
'fineract-validation',
|
||||
'fineract-command',
|
||||
'fineract-accounting',
|
||||
'fineract-provider',
|
||||
'fineract-branch',
|
||||
@@ -53,9 +54,11 @@ buildscript {
|
||||
fineractPublishProjects = subprojects.findAll{
|
||||
[
|
||||
'fineract-avro-schemas',
|
||||
'fineract-api',
|
||||
'fineract-client',
|
||||
'fineract-core',
|
||||
'fineract-cob',
|
||||
'fineract-validation',
|
||||
'fineract-command',
|
||||
'fineract-accounting',
|
||||
'fineract-provider',
|
||||
'fineract-investor',
|
||||
@@ -79,10 +82,10 @@ buildscript {
|
||||
|
||||
dependencies {
|
||||
classpath 'com.bmuschko:gradle-cargo-plugin:2.9.0'
|
||||
classpath 'org.eclipse.persistence:eclipselink:4.0.2'
|
||||
classpath 'org.eclipse.persistence:eclipselink:4.0.6'
|
||||
classpath 'jakarta.ws.rs:jakarta.ws.rs-api:3.1.0'
|
||||
classpath 'com.google.cloud.tools:jib-layer-filter-extension-gradle:0.3.0'
|
||||
classpath 'org.apache.commons:commons-lang3:3.17.0'
|
||||
classpath 'org.apache.commons:commons-lang3:3.18.0'
|
||||
classpath 'io.swagger.core.v3:swagger-jaxrs2-jakarta:2.2.22'
|
||||
classpath 'jakarta.servlet:jakarta.servlet-api:6.1.0'
|
||||
}
|
||||
@@ -97,21 +100,21 @@ plugins {
|
||||
id 'com.github.hierynomus.license' version '0.16.1' apply false
|
||||
id 'com.github.jk1.dependency-license-report' version '2.9' apply false
|
||||
id 'org.zeroturnaround.gradle.jrebel' version '1.2.0' apply false
|
||||
id 'org.springframework.boot' version '3.4.4' apply false
|
||||
id 'org.springframework.boot' version '3.5.5' apply false
|
||||
id 'net.ltgt.errorprone' version '4.1.0' apply false
|
||||
id 'io.swagger.core.v3.swagger-gradle-plugin' version '2.2.23' apply false
|
||||
id 'com.gorylenko.gradle-git-properties' version '2.4.2' 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 'com.google.cloud.tools.jib' version '3.4.4' apply false
|
||||
id 'org.asciidoctor.jvm.convert' version '4.0.5' apply false
|
||||
id 'org.asciidoctor.jvm.pdf' version '4.0.5' apply false
|
||||
id 'com.google.cloud.tools.jib' version '3.4.5' apply false
|
||||
id 'org.sonarqube' version '6.0.1.5171'
|
||||
id 'com.github.andygoossens.modernizer' version '1.10.0' apply false
|
||||
// TODO: upgrade to 6.0.4
|
||||
id 'com.github.spotbugs' version '6.0.26' apply false
|
||||
id 'se.thinkcode.cucumber-runner' version '0.0.11' apply false
|
||||
id "com.github.davidmc24.gradle.plugin.avro-base" version "1.9.1" apply false
|
||||
id 'org.openapi.generator' version '7.8.0' apply false
|
||||
id 'com.gradleup.shadow' version '8.3.5' apply false
|
||||
id 'me.champeau.jmh' version '0.7.1' apply false
|
||||
}
|
||||
|
||||
apply from: "${rootDir}/buildSrc/src/main/groovy/org.apache.fineract.release.gradle"
|
||||
@@ -134,14 +137,22 @@ gitVersioning.apply {
|
||||
branch("maintenance\\/\\d+\\.\\d+") {
|
||||
version = '${describe.tag.version.major}.${describe.tag.version.minor}.${describe.tag.version.patch}'
|
||||
}
|
||||
tag("(\\d+\\.\\d+\\.\\d+)") {
|
||||
version = '${describe.tag.version.major}.${describe.tag.version.minor}.${describe.tag.version.patch}'
|
||||
}
|
||||
}
|
||||
rev {
|
||||
version = '${describe.tag.version.major}.${describe.tag.version.minor.next}.${describe.tag.version.patch}-SNAPSHOT'
|
||||
version = '${describe.tag.version.major}.${describe.tag.version.minor.next}.0-SNAPSHOT'
|
||||
}
|
||||
}
|
||||
|
||||
ext['groovy.version'] = '4.0.17'
|
||||
ext['swaggerFile'] = "$rootDir/fineract-provider/build/classes/java/main/static/fineract.json".toString()
|
||||
ext['swaggerFile'] = "$rootDir/fineract-provider/build/resources/main/static/fineract.json".toString()
|
||||
|
||||
// Apply static weaving configuration to all subprojects
|
||||
subprojects { subproject ->
|
||||
apply from: rootProject.file('static-weaving.gradle')
|
||||
}
|
||||
|
||||
allprojects {
|
||||
group = 'org.apache.fineract'
|
||||
@@ -151,6 +162,10 @@ allprojects {
|
||||
}
|
||||
|
||||
configurations {
|
||||
implementation {
|
||||
exclude group: 'commons-logging', module: 'commons-logging'
|
||||
}
|
||||
|
||||
api {
|
||||
canBeResolved = true
|
||||
}
|
||||
@@ -327,7 +342,8 @@ allprojects {
|
||||
"**/generated/**/*MapperImpl.java",
|
||||
'**/META-INF/fineract-test.config',
|
||||
// Apache-specific GitHub metadata settings file
|
||||
'/.asf.yaml'
|
||||
'/.asf.yaml',
|
||||
'**/*.sh'
|
||||
]
|
||||
}
|
||||
}
|
||||
@@ -355,16 +371,13 @@ configure(project.fineractJavaProjects) {
|
||||
apply plugin: 'idea'
|
||||
|
||||
java {
|
||||
sourceCompatibility = JavaVersion.VERSION_17
|
||||
targetCompatibility = JavaVersion.VERSION_17
|
||||
toolchain {
|
||||
languageVersion = JavaLanguageVersion.of(21)
|
||||
}
|
||||
withSourcesJar()
|
||||
withJavadocJar()
|
||||
}
|
||||
|
||||
tasks.withType(ProcessResources) {
|
||||
destinationDir = layout.buildDirectory.dir('classes/java/main').get().asFile
|
||||
}
|
||||
|
||||
// Add performance optimizations
|
||||
configurations.all {
|
||||
resolutionStrategy {
|
||||
@@ -372,7 +385,7 @@ configure(project.fineractJavaProjects) {
|
||||
cacheDynamicVersionsFor 0, 'seconds'
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
tasks.withType(JavaCompile).configureEach {
|
||||
options.incremental = true
|
||||
options.fork = true
|
||||
@@ -402,15 +415,6 @@ configure(project.fineractJavaProjects) {
|
||||
|
||||
group = 'org.apache.fineract'
|
||||
|
||||
/* define the valid syntax level for source files */
|
||||
// sourceCompatibility = JavaVersion.VERSION_17
|
||||
// /* define binary compatibility version */
|
||||
// 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.classesDirectory
|
||||
sourceSets.test.output.resourcesDir = sourceSets.test.java.classesDirectory
|
||||
|
||||
configurations.named('spotbugs').configure {
|
||||
resolutionStrategy.eachDependency {
|
||||
if (it.requested.group == 'org.ow2.asm') {
|
||||
@@ -523,7 +527,7 @@ configure(project.fineractJavaProjects) {
|
||||
// Configuration for the Checkstyle plugin
|
||||
// https://docs.gradle.org/current/userguide/checkstyle_plugin.html
|
||||
dependencies {
|
||||
checkstyle 'com.puppycrawl.tools:checkstyle:10.20.1'
|
||||
checkstyle 'com.puppycrawl.tools:checkstyle:11.0.0'
|
||||
checkstyle 'com.github.sevntu-checkstyle:sevntu-checks:1.44.1'
|
||||
}
|
||||
|
||||
@@ -673,9 +677,10 @@ configure(project.fineractJavaProjects) {
|
||||
'org.junit.jupiter:junit-jupiter-api',
|
||||
'org.junit.jupiter:junit-jupiter-engine',
|
||||
'org.junit.jupiter:junit-jupiter-params',
|
||||
'org.junit.platform:junit-platform-runner', // required to be able to run tests directly under Eclipse, see FINERACT-943 & FINERACT-1021
|
||||
'org.bouncycastle:bcpkix-jdk15to18',
|
||||
'org.bouncycastle:bcprov-jdk15to18',
|
||||
'org.junit.platform:junit-platform-suite', // required to be able to run tests directly under Eclipse, see FINERACT-943 & FINERACT-1021
|
||||
'org.bouncycastle:bcpkix-jdk18on',
|
||||
'org.bouncycastle:bcprov-jdk18on',
|
||||
'org.bouncycastle:bcutil-jdk18on',
|
||||
'org.awaitility:awaitility',
|
||||
)
|
||||
|
||||
@@ -741,12 +746,6 @@ configure(project.fineractJavaProjects) {
|
||||
tasks.withType(Javadoc) {
|
||||
options.addStringOption('Xdoclint:none', '-quiet')
|
||||
options.encoding = 'UTF-8'
|
||||
// Disable strict checking to prevent build failures on invalid javadoc
|
||||
options.addBooleanOption('html5', true)
|
||||
// Add this if you're using Java 17 records or other modern features
|
||||
if (JavaVersion.current().isCompatibleWith(JavaVersion.VERSION_17)) {
|
||||
options.addBooleanOption('html5', true)
|
||||
}
|
||||
// Ignore any errors during javadoc generation
|
||||
failOnError = false
|
||||
}
|
||||
@@ -787,9 +786,10 @@ configure(project.fineractCustomProjects) {
|
||||
'org.mockito:mockito-junit-jupiter',
|
||||
'org.junit.jupiter:junit-jupiter-api',
|
||||
'org.junit.jupiter:junit-jupiter-engine',
|
||||
'org.junit.platform:junit-platform-runner', // required to be able to run tests directly under Eclipse, see FINERACT-943 & FINERACT-1021
|
||||
'org.bouncycastle:bcpkix-jdk15to18',
|
||||
'org.bouncycastle:bcprov-jdk15to18',
|
||||
'org.junit.platform:junit-platform-suite', // required to be able to run tests directly under Eclipse, see FINERACT-943 & FINERACT-1021
|
||||
'org.bouncycastle:bcpkix-jdk18on',
|
||||
'org.bouncycastle:bcprov-jdk18on',
|
||||
'org.bouncycastle:bcutil-jdk18on',
|
||||
'org.awaitility:awaitility',
|
||||
'io.github.classgraph:classgraph',
|
||||
'io.cucumber:cucumber-core',
|
||||
|
||||
@@ -20,7 +20,7 @@
|
||||
import static org.slf4j.LoggerFactory.*
|
||||
|
||||
plugins {
|
||||
id 'io.spring.dependency-management' version '1.1.6'
|
||||
id 'io.spring.dependency-management' version '1.1.7'
|
||||
id 'groovy'
|
||||
id 'java-gradle-plugin'
|
||||
id 'groovy-gradle-plugin'
|
||||
@@ -45,10 +45,14 @@ dependencies {
|
||||
implementation 'com.sun.activation:jakarta.activation'
|
||||
implementation 'com.sun.mail:jakarta.mail'
|
||||
implementation 'org.freemarker:freemarker'
|
||||
implementation 'org.tmatesoft.svnkit:svnkit'
|
||||
implementation 'org.bouncycastle:bcprov-jdk15on'
|
||||
implementation 'org.bouncycastle:bcpg-jdk15on'
|
||||
implementation ('com.tmatesoft.svnkit:svnkit') {
|
||||
exclude group: 'net.i2p.crypto', module: 'eddsa'
|
||||
}
|
||||
implementation 'org.bouncycastle:bcprov-jdk18on'
|
||||
implementation 'org.bouncycastle:bcutil-jdk18on'
|
||||
implementation 'org.bouncycastle:bcpg-jdk18on'
|
||||
implementation 'org.eclipse.jgit:org.eclipse.jgit'
|
||||
implementation 'org.eclipse.jgit:org.eclipse.jgit.gpg.bc'
|
||||
implementation 'org.eclipse.jgit:org.eclipse.jgit.ssh.apache'
|
||||
implementation 'com.vdurmont:semver4j'
|
||||
implementation 'org.beryx:text-io'
|
||||
|
||||
@@ -25,18 +25,18 @@ dependencyManagement {
|
||||
mavenBom 'com.squareup.okhttp3:okhttp-bom:4.12.0'
|
||||
mavenBom 'org.slf4j:slf4j-bom:2.0.17'
|
||||
mavenBom 'io.micrometer:micrometer-bom:1.13.6'
|
||||
mavenBom 'org.springframework:spring-framework-bom:6.2.5'
|
||||
mavenBom 'org.springframework.boot:spring-boot-dependencies:3.4.4'
|
||||
mavenBom 'org.springframework.boot:spring-boot-dependencies:3.5.5'
|
||||
mavenBom 'io.awspring.cloud:spring-cloud-aws-dependencies:3.2.1'
|
||||
mavenBom 'io.opentelemetry:opentelemetry-bom:1.44.1'
|
||||
mavenBom 'org.jetbrains.kotlin:kotlin-bom:2.0.21'
|
||||
mavenBom 'org.junit:junit-bom:5.11.3'
|
||||
mavenBom 'com.fasterxml.jackson:jackson-bom:2.18.3'
|
||||
mavenBom 'io.cucumber:cucumber-bom:7.20.1'
|
||||
mavenBom 'io.netty:netty-bom:4.1.119.Final'
|
||||
mavenBom 'org.mockito:mockito-bom:5.14.2'
|
||||
mavenBom 'software.amazon.awssdk:bom:2.29.9'
|
||||
mavenBom 'io.github.resilience4j:resilience4j-bom:2.2.0'
|
||||
mavenBom 'org.testcontainers:testcontainers-bom:1.20.4'
|
||||
mavenBom 'org.glassfish.jersey:jersey-bom:3.1.10'
|
||||
}
|
||||
|
||||
dependencies {
|
||||
@@ -50,12 +50,12 @@ dependencyManagement {
|
||||
dependency 'ch.qos.logback.contrib:logback-jackson:0.1.5'
|
||||
dependency 'org.codehaus.janino:janino:3.1.12'
|
||||
|
||||
|
||||
dependency 'org.eclipse.persistence:org.eclipse.persistence.jpa:4.0.2'
|
||||
dependency 'com.google.guava:guava:32.0.0-jre'
|
||||
dependency 'com.google.guava:guava:33.1.0-jre'
|
||||
dependency 'com.google.code.gson:gson:2.11.0'
|
||||
dependency 'com.google.googlejavaformat:google-java-format:1.24.0'
|
||||
dependency 'org.apache.commons:commons-collections4:4.4'
|
||||
dependency 'org.apache.commons:commons-compress:1.26.0'
|
||||
dependency ('software.amazon.msk:aws-msk-iam-auth:2.2.0') {
|
||||
exclude 'commons-logging:commons-logging:'
|
||||
}
|
||||
@@ -63,7 +63,7 @@ dependencyManagement {
|
||||
exclude 'com.sun.mail:javax.mail'
|
||||
exclude 'javax.activation:activation'
|
||||
}
|
||||
dependency 'commons-io:commons-io:2.17.0'
|
||||
dependency 'commons-io:commons-io:2.18.0'
|
||||
dependency 'com.github.librepdf:openpdf:2.0.3'
|
||||
dependency ('org.mnode.ical4j:ical4j:3.2.19') {
|
||||
exclude 'com.sun.mail:javax.mail'
|
||||
@@ -74,8 +74,13 @@ dependencyManagement {
|
||||
dependency 'org.ehcache:ehcache:3.10.8'
|
||||
dependency 'com.github.spullara.mustache.java:compiler:0.9.14'
|
||||
dependency 'com.jayway.jsonpath:json-path:2.9.0'
|
||||
dependency 'org.apache.tika:tika-core:2.9.3'
|
||||
dependency ('org.apache.tika:tika-parser-microsoft-module:2.9.3') {
|
||||
dependency ('org.apache.tika:tika-core:2.9.3') {
|
||||
exclude 'commons-logging:commons-logging'
|
||||
}
|
||||
dependency ('org.apache.tika:tika-core:2.9.3') {
|
||||
exclude 'commons-logging:commons-logging'
|
||||
}
|
||||
dependency ('org.apache.tika:tika-parser-miscoffice-module:2.9.3') {
|
||||
exclude 'org.bouncycastle:bcprov-jdk15on'
|
||||
exclude 'org.bouncycastle:bcmail-jdk15on'
|
||||
exclude 'org.bouncycastle:bcprov-jdk18on'
|
||||
@@ -92,7 +97,7 @@ dependencyManagement {
|
||||
exclude 'org.apache.commons:commons-compress'
|
||||
exclude 'xml-apis:xml-apis'
|
||||
}
|
||||
dependency ('org.apache.tika:tika-parser-miscoffice-module:2.9.3') {
|
||||
dependency ('org.apache.tika:tika-parser-microsoft-module:2.9.3') {
|
||||
exclude 'org.bouncycastle:bcprov-jdk15on'
|
||||
exclude 'org.bouncycastle:bcmail-jdk15on'
|
||||
exclude 'org.bouncycastle:bcprov-jdk18on'
|
||||
@@ -115,14 +120,11 @@ dependencyManagement {
|
||||
dependency 'jakarta.management.j2ee:jakarta.management.j2ee-api:1.1.4'
|
||||
dependency 'jakarta.jms:jakarta.jms-api:3.1.0'
|
||||
dependency 'jakarta.ws.rs:jakarta.ws.rs-api:3.1.0'
|
||||
dependency 'org.glassfish.jersey.media:jersey-media-multipart:3.1.10'
|
||||
dependency 'org.glassfish.jaxb:jaxb-runtime:2.3.6' // Swagger needs exactly this version
|
||||
dependency 'org.apache.bval:org.apache.bval.bundle:3.0.2'
|
||||
dependency 'joda-time:joda-time:2.13.1'
|
||||
|
||||
dependency 'io.github.classgraph:classgraph:4.8.179'
|
||||
dependency 'org.awaitility:awaitility:4.2.2'
|
||||
// TODO: upgrade to 4.8.3
|
||||
dependency 'com.github.spotbugs:spotbugs-annotations:4.8.6'
|
||||
dependency 'javax.cache:cache-api:1.1.1'
|
||||
dependency 'org.mock-server:mockserver-junit-jupiter:5.15.0'
|
||||
@@ -145,23 +147,21 @@ dependencyManagement {
|
||||
dependency "com.squareup.retrofit2:converter-gson:2.11.0"
|
||||
dependency "com.squareup.retrofit2:converter-protobuf:2.11.0"
|
||||
dependency 'io.reactivex.rxjava2:rxjava:2.2.21'
|
||||
dependency "org.apache.oltu.oauth2:org.apache.oltu.oauth2.common:1.0.1"
|
||||
dependency "org.apache.oltu.oauth2:org.apache.oltu.oauth2.client:1.0.1"
|
||||
dependency "org.apache.oltu.oauth2:org.apache.oltu.oauth2.httpclient4:1.0.1"
|
||||
dependency "io.gsonfire:gson-fire:1.9.0"
|
||||
dependency "com.google.code.findbugs:jsr305:3.0.2"
|
||||
dependency "commons-codec:commons-codec:1.17.1"
|
||||
dependency "org.projectlombok:lombok:1.18.36"
|
||||
|
||||
dependency 'org.bouncycastle:bcpkix-jdk15to18:1.79'
|
||||
dependency 'org.bouncycastle:bcprov-jdk15to18:1.79'
|
||||
dependency 'org.bouncycastle:bcprov-jdk15on:1.70'
|
||||
dependency 'org.bouncycastle:bcpg-jdk15on:1.70'
|
||||
dependency 'org.bouncycastle:bcpkix-jdk18on:1.80'
|
||||
dependency 'org.bouncycastle:bcprov-jdk18on:1.80'
|
||||
dependency 'org.bouncycastle:bcutil-jdk18on:1.80'
|
||||
dependency 'org.bouncycastle:bcpg-jdk18on:1.80'
|
||||
|
||||
dependency 'org.eclipse.jgit:org.eclipse.jgit:6.10.0.202406032230-r'
|
||||
dependency 'org.eclipse.jgit:org.eclipse.jgit.ssh.apache:7.0.0.202409031743-r'
|
||||
dependency 'org.eclipse.jgit:org.eclipse.jgit:7.2.0.202503040940-r'
|
||||
dependency 'org.eclipse.jgit:org.eclipse.jgit.gpg.bc:7.2.0.202503040940-r'
|
||||
dependency 'org.eclipse.jgit:org.eclipse.jgit.ssh.apache:7.2.0.202503040940-r'
|
||||
|
||||
dependency 'org.tmatesoft.svnkit:svnkit:1.10.11'
|
||||
dependency ('com.tmatesoft.svnkit:svnkit:1.10.12')
|
||||
dependency 'com.vdurmont:semver4j:3.1.0'
|
||||
dependency 'org.beryx:text-io:3.4.1'
|
||||
|
||||
@@ -192,6 +192,8 @@ dependencyManagement {
|
||||
dependency ('jakarta.xml.bind:jakarta.xml.bind-api:4.0.2') {
|
||||
exclude 'jakarta.activation:jakarta.activation-api'
|
||||
}
|
||||
dependency 'jakarta.validation:jakarta.validation-api:3.1.1'
|
||||
dependency 'org.hibernate.validator:hibernate-validator:9.0.1.Final'
|
||||
|
||||
dependency ('org.liquibase:liquibase-core:4.31.1') {
|
||||
exclude 'javax.xml.bind:jaxb-api'
|
||||
@@ -205,10 +207,10 @@ dependencyManagement {
|
||||
exclude 'pull-parser:pull-parser'
|
||||
}
|
||||
|
||||
dependency 'org.owasp.esapi:esapi:2.6.0.0'
|
||||
dependency 'org.owasp.esapi:esapi:2.7.0.0'
|
||||
dependency 'org.awaitility:awaitility:4.2.2'
|
||||
|
||||
dependencySet(group: 'org.apache.poi', version: '5.3.0') {
|
||||
dependencySet(group: 'org.apache.poi', version: '5.4.1') {
|
||||
entry 'poi'
|
||||
entry 'poi-ooxml'
|
||||
entry 'poi-ooxml-schemas'
|
||||
@@ -231,21 +233,49 @@ dependencyManagement {
|
||||
exclude 'org.slf4j:jcl-over-slf4j'
|
||||
exclude 'org.slf4j:slf4j-api'
|
||||
}
|
||||
dependency 'org.postgresql:postgresql:42.7.8'
|
||||
|
||||
//v42.7.5: performance issue: https://github.com/pgjdbc/pgjdbc/issues/3511#issuecomment-2637277977
|
||||
dependency 'org.postgresql:postgresql:42.7.4'
|
||||
dependency 'com.mysql:mysql-connector-j:9.2.0'
|
||||
|
||||
dependency 'org.assertj:assertj-core:3.26.3'
|
||||
|
||||
dependency 'org.apache.commons:commons-math3:3.6.1'
|
||||
dependency 'commons-beanutils:commons-beanutils:1.11.0'
|
||||
|
||||
dependency 'org.mockito:mockito-inline:5.2.0'
|
||||
|
||||
dependency 'com.github.tomakehurst:wiremock-standalone:3.0.1'
|
||||
dependency 'org.wiremock:wiremock-standalone:3.13.0'
|
||||
dependency 'org.apache.sshd:sshd-common:2.15.0'
|
||||
dependency 'org.apache.sshd:sshd-core:2.15.0'
|
||||
|
||||
dependency 'io.cucumber:cucumber-java:7.20.1'
|
||||
dependency 'io.cucumber:cucumber-java8:7.20.1'
|
||||
dependency 'io.cucumber:cucumber-junit-platform-engine:7.20.1'
|
||||
dependency 'io.cucumber:cucumber-spring:7.20.1'
|
||||
|
||||
dependency 'org.reflections:reflections:0.10.2'
|
||||
|
||||
dependency 'org.openjdk.jmh:jmh-core:1.37'
|
||||
dependency 'org.openjdk.jmh:jmh-generator-annprocess:1.37'
|
||||
|
||||
dependency 'org.springframework.restdocs:spring-restdocs-asciidoctor:3.0.3'
|
||||
dependency 'org.springframework.restdocs:spring-restdocs-mockmvc:3.0.3'
|
||||
dependency 'org.springframework.restdocs:spring-restdocs-webtestclient:3.0.3'
|
||||
dependency 'org.springframework.restdocs:spring-restdocs-restassured:3.0.3'
|
||||
|
||||
dependency 'com.lmax:disruptor:3.4.4'
|
||||
|
||||
dependency 'com.ibm.icu:icu4j:76.1'
|
||||
dependency 'org.yakworks:spring-icu4j:0.4.2'
|
||||
dependency 'org.apache.commons:commons-lang3:3.18.0'
|
||||
dependency 'com.nimbusds:nimbus-jose-jwt:10.0.2'
|
||||
// Force Spring Framework version: CVE-2025-41249
|
||||
dependency 'org.springframework:spring-core:6.2.11'
|
||||
// Force Spring Framework version: CVE-2025-41248
|
||||
dependency 'org.springframework.security:spring-security-core:6.5.4'
|
||||
// Force netty-codec version: CVE-2025-58057
|
||||
dependency 'io.netty:netty-codec:4.1.125.Final'
|
||||
// Force netty-codec version: CVE-2025-58056
|
||||
dependency 'io.netty:netty-codec-http:4.1.125.Final'
|
||||
}
|
||||
}
|
||||
|
||||
@@ -176,8 +176,8 @@ fineract {
|
||||
description: 'Sign the distribution artifacts',
|
||||
gpg: [
|
||||
files: [
|
||||
"${rootDir}/fineract-war/build/distributions/apache-fineract-${project.version}-src.tar.gz",
|
||||
"${rootDir}/fineract-war/build/distributions/apache-fineract-${project.version}-binary.tar.gz"
|
||||
"${rootDir}/fineract-war/build/distributions/apache-fineract-src-${project.version}.tar.gz",
|
||||
"${rootDir}/fineract-war/build/distributions/apache-fineract-bin-${project.version}.tar.gz"
|
||||
]
|
||||
]
|
||||
],
|
||||
|
||||
@@ -194,7 +194,7 @@ class FineractPlugin implements Plugin<Project> {
|
||||
|
||||
String version = project.properties?['fineract.release.version']
|
||||
String issue = project.properties?['fineract.release.issue']
|
||||
String date = project.properties?['fineract.release.date']
|
||||
String date = project.properties?['fineract.releaseBranch.date']
|
||||
|
||||
if(!version || !issue || !date) {
|
||||
TextIO textIO = TextIoFactory.getTextIO()
|
||||
@@ -225,7 +225,7 @@ class FineractPlugin implements Plugin<Project> {
|
||||
|
||||
this.context?.project?['fineract.release.version'] = version
|
||||
this.context?.project?['fineract.release.issue'] = issue
|
||||
this.context?.project?['fineract.release.date'] = date
|
||||
this.context?.project?['fineract.releaseBranch.date'] = date
|
||||
|
||||
if(step.email) {
|
||||
emailService.send( processEmailParams(step.email, this.context) )
|
||||
|
||||
@@ -19,14 +19,15 @@
|
||||
package org.apache.fineract.gradle.service
|
||||
|
||||
import org.apache.fineract.gradle.FineractPluginExtension
|
||||
import org.eclipse.jgit.annotations.NonNull
|
||||
import org.eclipse.jgit.annotations.Nullable
|
||||
import org.eclipse.jgit.api.Git
|
||||
import org.eclipse.jgit.api.errors.CanceledException
|
||||
import org.eclipse.jgit.lib.CommitBuilder
|
||||
import org.eclipse.jgit.lib.GpgSigner
|
||||
import org.eclipse.jgit.api.errors.UnsupportedSigningFormatException
|
||||
import org.eclipse.jgit.gpg.bc.internal.BouncyCastleGpgSigner
|
||||
import org.eclipse.jgit.lib.GpgConfig
|
||||
import org.eclipse.jgit.lib.GpgSignature
|
||||
import org.eclipse.jgit.lib.PersonIdent
|
||||
import org.eclipse.jgit.lib.Repository
|
||||
import org.eclipse.jgit.lib.Signers
|
||||
import org.eclipse.jgit.lib.StoredConfig
|
||||
import org.eclipse.jgit.storage.file.FileRepositoryBuilder
|
||||
import org.eclipse.jgit.transport.CredentialsProvider
|
||||
@@ -41,14 +42,15 @@ class GitService {
|
||||
private boolean dryRun
|
||||
|
||||
GitService(FineractPluginExtension.FineractPluginConfigGit config, FineractPluginExtension.FineractPluginConfigGpg gpgConfig) {
|
||||
GpgSigner.setDefault(new GpgSigner() {
|
||||
Signers.set(GpgConfig.GpgFormat.OPENPGP, new BouncyCastleGpgSigner() {
|
||||
|
||||
@Override
|
||||
void sign(@NonNull CommitBuilder commit, @Nullable String gpgSigningKey, @NonNull PersonIdent committer, CredentialsProvider credentialsProvider) throws CanceledException {
|
||||
GpgSignature sign(Repository repository, GpgConfig internalConfig, byte[] data, PersonIdent committer, String signingKey, CredentialsProvider credentialsProvider) throws CanceledException, IOException, UnsupportedSigningFormatException {
|
||||
log.warn("------------------------ KEY: ${gpgSigningKey} IDENT: ${committer}")
|
||||
}
|
||||
|
||||
@Override
|
||||
boolean canLocateSigningKey(@Nullable String gpgSigningKey, @NonNull PersonIdent committer, CredentialsProvider credentialsProvider) throws CanceledException {
|
||||
boolean canLocateSigningKey(Repository repository, GpgConfig internalConfig, PersonIdent committer, String signingKey, CredentialsProvider credentialsProvider) throws CanceledException {
|
||||
log.warn("------------------------ KEY: ${gpgSigningKey} IDENT: ${committer}")
|
||||
return false
|
||||
}
|
||||
|
||||
@@ -20,11 +20,9 @@
|
||||
-->
|
||||
Hello everyone,
|
||||
|
||||
... based on our "How to Release Apache Fineract" process documented at https://cwiki.apache.org/confluence/x/DRwIB:
|
||||
... based on our release process (https://fineract.apache.org/docs/current/#_releases), I will create a release/${project['fineract.release.version']} branch off develop in our git repository at https://github.com/apache/fineract on ${project['fineract.releaseBranch.date']}.
|
||||
|
||||
I will create a ${project['fineract.release.version']} branch off develop in our git repository at https://github.com/apache/fineract on ${project['fineract.release.date']}.
|
||||
|
||||
The release tracking umbrella issue for tracking all activity in JIRA is FINERACT-${project['fineract.release.issue']!'0000'} (https://issues.apache.org/jira/browse/FINERACT-${project['fineract.release.issue']!'0000'}) for this Fineract ${project['fineract.release.version']}.
|
||||
The release tracking umbrella issue for tracking all activity in JIRA is FINERACT-${project['fineract.release.issue']!'0000'} (https://issues.apache.org/jira/browse/FINERACT-${project['fineract.release.issue']!'0000'}).
|
||||
|
||||
If you have any work in progress that you would like to see included in this release, please add "blocking" links to the release JIRA issue.
|
||||
|
||||
|
||||
@@ -20,13 +20,13 @@
|
||||
-->
|
||||
Hello everyone,
|
||||
|
||||
... as previously announced, I've just created the release branch for our upcoming ${project['fineract.release.version']} release.
|
||||
... as previously announced, I've created the branch for our upcoming ${project['fineract.release.version']} release. The branch name is release/${project['fineract.release.version']}.
|
||||
|
||||
You can continue working and merging PRs to the develop branch for future releases, as always.
|
||||
You can continue working and merging PRs into the develop branch for future releases, as always.
|
||||
|
||||
The DRAFT release notes are on https://cwiki.apache.org/confluence/display/FINERACT/${project['fineract.release.version']}+-+Apache+Fineract. Does anyone see anything missing?
|
||||
I started the DRAFT release notes at https://cwiki.apache.org/confluence/display/FINERACT/${project['fineract.release.version']}+-+Apache+Fineract . Please help me by filling in "Summary of changes". Does anyone see anything else missing?
|
||||
|
||||
Does anyone have any last minutes changes they would like to see cherry-picked to branch ${project['fineract.release.version']}, or are we good go and actually cut the release based on this branch as it is?
|
||||
Does anyone have any last minute changes for the release branch, or are we good to go and actually cut the release based on this branch as it is?
|
||||
|
||||
I'll initiate the final stage of actually creating the release on ${project['fineract.release.date']} if nobody objects.
|
||||
|
||||
|
||||
@@ -30,7 +30,7 @@ Tagged as ${project['fineract.release.version']}
|
||||
|
||||
Committer PGP keys, including the release signing key: https://dist.apache.org/repos/dist/dev/fineract/KEYS
|
||||
|
||||
Note that this release contains source and binary artifacts.
|
||||
Note that this release candidate contains source and binary artifacts.
|
||||
|
||||
This vote will be open for 72 hours:
|
||||
|
||||
@@ -38,11 +38,11 @@ This vote will be open for 72 hours:
|
||||
[ ] +0 no opinion
|
||||
[ ] -1 disapprove (and reason why)
|
||||
|
||||
Please indicate if you are a binding vote (member of the PMC).
|
||||
Please indicate if you are a binding vote (member of the PMC). Note: PMC members are required to download, compile, and test the artifacts before submitting their +1 vote.
|
||||
|
||||
Please also indicate with "Tested: YES/NO/PARTIAL" if you have locally built and/or tested these artifacts and/or a clone of the code checked out to the release commit, following the form:
|
||||
|
||||
Tested: YES ... Verified integrity and signatures of release artifacts locally, built from source, ran jar/war: Did everything mentioned in the current release candidate verification guidance ( https://lists.apache.org/thread/hym94pdy3nk9gjspkz4qonv2v15n5dpo ). If you did more than that, please specify.
|
||||
Tested: YES ... Verified integrity and signatures of release artifacts locally, built from source, ran jar/war: Did everything mentioned in the current release candidate verification guidance ( https://fineract.apache.org/docs/rc/#_artifact_verification ). If you did more than that, please specify.
|
||||
|
||||
Tested: NO ... No testing performed on release candidate, e.g. relying on testing performed by other contributors and/or output of GitHub Actions, while exercising my right to vote.
|
||||
|
||||
|
||||
@@ -26,13 +26,9 @@ As discussed in https://issues.apache.org/jira/browse/FINERACT-1154, now that ev
|
||||
and make sure that everything on the release tag is merged to develop and that e.g. git describe works:
|
||||
|
||||
>> git checkout develop
|
||||
>> git branch -D ${project['fineract.release.version']}
|
||||
>> git push origin :${project['fineract.release.version']}
|
||||
>> git checkout develop
|
||||
>> git checkout -b merge-${project['fineract.release.version']}
|
||||
>> git merge -s recursive -Xignore-all-space ${project['fineract.release.version']}
|
||||
>> git commit
|
||||
>> git push <USER>
|
||||
>> hub pull-request
|
||||
>> git merge release/${project['fineract.release.version']}
|
||||
>> git push origin develop
|
||||
>> git branch -D release/${project['fineract.release.version']}
|
||||
>> git push origin :release/${project['fineract.release.version']}
|
||||
|
||||
[INSTRUCTIONS:END]
|
||||
|
||||
@@ -26,7 +26,7 @@ Following are the typical things we need to verify before voting on a release ca
|
||||
|
||||
Make sure release artifacts are hosted at https://dist.apache.org/repos/dist/dev/fineract
|
||||
|
||||
* Release candidates should be in format apache-fineract-${project['fineract.release.version']}-binary.tar.gz
|
||||
* Release candidates should be in format apache-fineract-bin-${project['fineract.release.version']}.tar.gz
|
||||
* Verify signatures and hashes. You may have to import the public key of the release manager to verify the signatures. (gpg --import KEYS or gpg --recv-key <key id>)
|
||||
* Git tag matches the released bits (diff -rf)
|
||||
* Can compile docs and code successfully from source
|
||||
|
||||
@@ -0,0 +1,48 @@
|
||||
{
|
||||
"approve": {
|
||||
"binding": [
|
||||
{
|
||||
"name": "Bharath Gowda",
|
||||
"email": "bgowda@mifos.org"
|
||||
},
|
||||
{
|
||||
"name": "Petri Tuomola",
|
||||
"email": "petri@tuomola.org"
|
||||
},
|
||||
{
|
||||
"name": "Victor Manuel Romero Rodriguez",
|
||||
"email": "victor.romero@fintecheando.mx"
|
||||
},
|
||||
{
|
||||
"name": "Aleksandar Vidakovic",
|
||||
"email": "cheetah@monkeysintown.com"
|
||||
},
|
||||
{
|
||||
"name": "Ádám Sághy",
|
||||
"email": "adamsaghy@gmail.com"
|
||||
}
|
||||
],
|
||||
"nonBinding": [
|
||||
{
|
||||
"name": "Kigred",
|
||||
"email": "kigred.developer@gmail.com"
|
||||
},
|
||||
{
|
||||
"name": "Adam Monsen",
|
||||
"email": "amonsen@mifos.org"
|
||||
}
|
||||
]
|
||||
},
|
||||
"disapprove": {
|
||||
"binding": [
|
||||
],
|
||||
"nonBinding": [
|
||||
]
|
||||
},
|
||||
"noOpinion": {
|
||||
"binding": [
|
||||
],
|
||||
"nonBinding": [
|
||||
]
|
||||
}
|
||||
}
|
||||
@@ -100,6 +100,14 @@
|
||||
<property name="forbiddenImportsRegexp" value="com.google.common.base.Charsets" />
|
||||
<property name="forbiddenImportsExcludesRegexp" value="" />
|
||||
<message key="forbid.certain.imports" value="Use ''java.nio.charset.StandardCharsets'' instead of ''{0}''" />
|
||||
</module>
|
||||
<!-- Forbid JetBrains annotations in Java sources; prefer Jakarta or Spring annotations -->
|
||||
<module name="com.github.sevntu.checkstyle.checks.coding.ForbidCertainImportsCheck">
|
||||
<property name="packageNameRegexp" value=".*" />
|
||||
<property name="forbiddenImportsRegexp" value="org.jetbrains.annotations(\..*)?" />
|
||||
<property name="forbiddenImportsExcludesRegexp" value="" />
|
||||
<message key="forbid.certain.imports"
|
||||
value="Use 'jakarta.validation.constraints.NotNull' (API/DTO) or 'org.springframework.lang.NonNull' (services) instead of JetBrains annotations: ''{0}''" />
|
||||
</module>
|
||||
<module name="OneStatementPerLine"/>
|
||||
<module name="EmptyStatement"/>
|
||||
|
||||
@@ -29,4 +29,8 @@
|
||||
<suppress files="[/\\]build[/\\]generated[/\\]" checks=".*"/>
|
||||
<!-- TODO: fix integration test formatting -->
|
||||
<suppress files="[/\\]integration-tests[/\\]src[/\\]test[/\\]main[/\\]" checks=".*"/>
|
||||
<!-- TODO: fix generic type name constraints -->
|
||||
<suppress files="[/\\]fineract-command[/\\]src[/\\]main[/\\]java[/\\]" checks="MethodTypeParameterName"/>
|
||||
<suppress files="[/\\]fineract-command[/\\]src[/\\]main[/\\]java[/\\]" checks="ClassTypeParameterName"/>
|
||||
<suppress files="[/\\]fineract-command[/\\]src[/\\]main[/\\]java[/\\]" checks="HideUtilityClassConstructor"/>
|
||||
</suppressions>
|
||||
|
||||
@@ -19,6 +19,7 @@
|
||||
|
||||
dependencies {
|
||||
implementation(project(':fineract-core'))
|
||||
implementation(project(':fineract-cob'))
|
||||
implementation(project(':fineract-loan'))
|
||||
implementation(project(':fineract-provider'))
|
||||
implementation('org.springframework.boot:spring-boot-starter-data-jpa')
|
||||
|
||||
@@ -20,7 +20,7 @@ package com.acme.fineract.loan.job;
|
||||
|
||||
public enum AcmeJobName {
|
||||
|
||||
ACME_NOOP_JOB("Acme Noop Job");
|
||||
ACME_NOOP_JOB("Acme Noop Job"); //
|
||||
|
||||
private final String name;
|
||||
|
||||
|
||||
+5
-2
@@ -20,6 +20,8 @@ package com.acme.fineract.loan.processor;
|
||||
|
||||
import org.apache.fineract.infrastructure.core.service.ExternalIdFactory;
|
||||
import org.apache.fineract.portfolio.loanaccount.domain.transactionprocessor.impl.FineractStyleLoanRepaymentScheduleTransactionProcessor;
|
||||
import org.apache.fineract.portfolio.loanaccount.serialization.LoanChargeValidator;
|
||||
import org.apache.fineract.portfolio.loanaccount.service.LoanBalanceService;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
@Component
|
||||
@@ -29,8 +31,9 @@ public class AcmeLoanRepaymentScheduleTransactionProcessor extends FineractStyle
|
||||
|
||||
public static final String STRATEGY_NAME = "ACME Corp.: standard loan transaction processing strategy";
|
||||
|
||||
public AcmeLoanRepaymentScheduleTransactionProcessor(ExternalIdFactory externalIdFactory) {
|
||||
super(externalIdFactory);
|
||||
public AcmeLoanRepaymentScheduleTransactionProcessor(final ExternalIdFactory externalIdFactory,
|
||||
final LoanChargeValidator loanChargeValidator, final LoanBalanceService loanBalanceService) {
|
||||
super(externalIdFactory, loanChargeValidator, loanBalanceService);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -19,6 +19,7 @@
|
||||
|
||||
dependencies {
|
||||
implementation(project(':fineract-core'))
|
||||
implementation(project(':fineract-cob'))
|
||||
implementation(project(':fineract-loan'))
|
||||
implementation(project(':fineract-provider'))
|
||||
implementation(project(':custom:acme:loan:cob'))
|
||||
|
||||
+2
-1
@@ -18,6 +18,7 @@
|
||||
*/
|
||||
package com.acme.fineract.portfolio.note.service;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.apache.fineract.portfolio.note.data.NoteData;
|
||||
@@ -43,6 +44,6 @@ public class AcmeNoteReadPlatformService implements NoteReadPlatformService, Ini
|
||||
|
||||
@Override
|
||||
public List<NoteData> retrieveNotesByResource(Long resourceId, Integer noteTypeId) {
|
||||
return null;
|
||||
return Collections.emptyList();
|
||||
}
|
||||
}
|
||||
|
||||
+5
@@ -42,6 +42,11 @@ public class AcmeNoteWritePlatformService implements NoteWritePlatformService, I
|
||||
throw new UnsupportedOperationException("createNote() is not yet implemented.");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void createLoanTransactionNote(Long loanTransactionId, String note) {
|
||||
throw new UnsupportedOperationException("createLoanTransactionNote() is not yet implemented.");
|
||||
}
|
||||
|
||||
@Override
|
||||
public CommandProcessingResult updateNote(JsonCommand command) {
|
||||
throw new UnsupportedOperationException("updateNote() is not yet implemented.");
|
||||
|
||||
+1
-1
@@ -42,7 +42,7 @@ public class AcmeNoteServiceStepDefinitions implements En {
|
||||
});
|
||||
|
||||
When("/^The user retrieves the service of interface class (.*)$/", (String interfaceClassName) -> {
|
||||
contextRunner.run((ctx) -> {
|
||||
contextRunner.run(ctx -> {
|
||||
this.interfaceClass = Class.forName(interfaceClassName.trim());
|
||||
|
||||
assertThat(this.interfaceClass.isInterface()).isTrue();
|
||||
|
||||
@@ -24,7 +24,7 @@ apply from: "${rootDir}/buildSrc/src/main/groovy/org.apache.fineract.dependencie
|
||||
|
||||
jib {
|
||||
from {
|
||||
image = 'azul/zulu-openjdk-alpine:17'
|
||||
image = 'azul/zulu-openjdk-alpine:21'
|
||||
platforms {
|
||||
platform {
|
||||
architecture = System.getProperty("os.arch").equals("aarch64")?"arm64":"amd64"
|
||||
@@ -76,7 +76,7 @@ jib {
|
||||
}
|
||||
// NOTE: other custom dependencies
|
||||
implementation 'org.mariadb.jdbc:mariadb-java-client'
|
||||
implementation 'mysql:mysql-connector-java:8.0.33'
|
||||
implementation 'com.mysql:mysql-connector-j'
|
||||
implementation 'org.postgresql:postgresql'
|
||||
annotationProcessor('org.springframework.boot:spring-boot-autoconfigure-processor')
|
||||
annotationProcessor('org.springframework.boot:spring-boot-configuration-processor')
|
||||
|
||||
@@ -20,7 +20,7 @@
|
||||
version: "3.7"
|
||||
services:
|
||||
kafka:
|
||||
image: "bitnami/kafka:3.8.1-debian-12-r1"
|
||||
image: "bitnamilegacy/kafka:4.0.0-debian-12-r10"
|
||||
ports:
|
||||
- "9092:9092"
|
||||
env_file:
|
||||
|
||||
@@ -21,23 +21,8 @@ description = 'Fineract Accounting'
|
||||
apply plugin: 'java'
|
||||
apply plugin: 'eclipse'
|
||||
|
||||
compileJava.doLast {
|
||||
def mainSS = sourceSets.main
|
||||
def source = mainSS.java.classesDirectory.get()
|
||||
copy {
|
||||
from file("src/main/resources/jpa/accounting/persistence.xml")
|
||||
into "${source}/META-INF/"
|
||||
}
|
||||
javaexec {
|
||||
description = 'Performs EclipseLink static weaving of entity classes'
|
||||
def target = source
|
||||
mainClass = 'org.eclipse.persistence.tools.weaving.jpa.StaticWeave'
|
||||
args '-persistenceinfo', source, source, target
|
||||
classpath sourceSets.main.runtimeClasspath
|
||||
}
|
||||
delete {
|
||||
delete "${source}/META-INF/persistence.xml"
|
||||
}
|
||||
compileJava {
|
||||
dependsOn ':fineract-avro-schemas:buildJavaSdk'
|
||||
}
|
||||
|
||||
configurations {
|
||||
@@ -85,10 +70,6 @@ eclipse {
|
||||
}
|
||||
}
|
||||
|
||||
/* http://stackoverflow.com/questions/19653311/jpa-repository-works-in-idea-and-production-but-not-in-gradle */
|
||||
sourceSets.main.output.resourcesDir = sourceSets.main.java.classesDirectory
|
||||
sourceSets.test.output.resourcesDir = sourceSets.test.java.classesDirectory
|
||||
|
||||
if (!(project.hasProperty('env') && project.getProperty('env') == 'dev')) {
|
||||
sourceSets {
|
||||
test {
|
||||
|
||||
+1
-1
@@ -40,7 +40,7 @@ final class AccrualAccountingApiResourceSwagger {
|
||||
public String locale;
|
||||
@Schema(example = "dd MMMM yyyy")
|
||||
public String dateFormat;
|
||||
@Schema(example = "04 June 2014", description = "which specifies periodic accruals should happen till the given Date", required = true)
|
||||
@Schema(example = "04 June 2014", description = "which specifies periodic accruals should happen till the given Date")
|
||||
public String tillDate;
|
||||
}
|
||||
|
||||
|
||||
+6
-1
@@ -26,7 +26,12 @@ import java.util.Set;
|
||||
***/
|
||||
public enum GLClosureJsonInputParams {
|
||||
|
||||
ID("id"), OFFICE_ID("officeId"), CLOSING_DATE("closingDate"), COMMENTS("comments"), LOCALE("locale"), DATE_FORMAT("dateFormat");
|
||||
ID("id"), //
|
||||
OFFICE_ID("officeId"), //
|
||||
CLOSING_DATE("closingDate"), //
|
||||
COMMENTS("comments"), //
|
||||
LOCALE("locale"), //
|
||||
DATE_FORMAT("dateFormat"); //
|
||||
|
||||
private final String value;
|
||||
|
||||
|
||||
+1
-1
@@ -126,7 +126,7 @@ public class GLClosuresApiResource {
|
||||
@Consumes({ MediaType.APPLICATION_JSON })
|
||||
@Produces({ MediaType.APPLICATION_JSON })
|
||||
@Operation(summary = "Update an Accounting closure", description = "Once an accounting closure is created, only the comments associated with it may be edited")
|
||||
@RequestBody(content = @Content(schema = @Schema(implementation = GLClosuresApiResourceSwagger.PutGlClosuresRequest.class, required = true)))
|
||||
@RequestBody(content = @Content(schema = @Schema(implementation = GLClosuresApiResourceSwagger.PutGlClosuresRequest.class)))
|
||||
@ApiResponses({
|
||||
@ApiResponse(responseCode = "200", description = "OK", content = @Content(schema = @Schema(implementation = GLClosuresApiResourceSwagger.PutGlClosuresResponse.class))) })
|
||||
public CommandProcessingResult updateGLClosure(@PathParam("glClosureId") @Parameter(description = "glClosureId") final Long glClosureId,
|
||||
|
||||
+2
-1
@@ -29,7 +29,8 @@ public class GLClosureInvalidException extends AbstractPlatformDomainRuleExcepti
|
||||
/*** enum of reasons for invalid Accounting Closure **/
|
||||
public enum GlClosureInvalidReason {
|
||||
|
||||
FUTURE_DATE, ACCOUNTING_CLOSED;
|
||||
FUTURE_DATE, //
|
||||
ACCOUNTING_CLOSED; //
|
||||
|
||||
public String errorMessage() {
|
||||
if (name().equalsIgnoreCase("FUTURE_DATE")) {
|
||||
|
||||
+3
-4
@@ -72,10 +72,9 @@ public class GLClosureWritePlatformServiceJpaRepositoryImpl implements GLClosure
|
||||
}
|
||||
// shouldn't be before an existing accounting closure
|
||||
final GLClosure latestGLClosure = this.glClosureRepository.getLatestGLClosureByBranch(officeId);
|
||||
if (latestGLClosure != null) {
|
||||
if (DateUtils.isAfter(latestGLClosure.getClosingDate(), closureDate)) {
|
||||
throw new GLClosureInvalidException(GlClosureInvalidReason.ACCOUNTING_CLOSED, latestGLClosure.getClosingDate());
|
||||
}
|
||||
if (latestGLClosure != null && DateUtils.isAfter(latestGLClosure.getClosingDate(), closureDate)) {
|
||||
throw new GLClosureInvalidException(GlClosureInvalidReason.ACCOUNTING_CLOSED, latestGLClosure.getClosingDate());
|
||||
|
||||
}
|
||||
final GLClosure glClosure = GLClosure.fromJson(office, command);
|
||||
|
||||
|
||||
+3
-3
@@ -79,7 +79,7 @@ public class FinancialActivityAccountsApiResource {
|
||||
@Consumes({ MediaType.APPLICATION_JSON })
|
||||
@Produces({ MediaType.APPLICATION_JSON })
|
||||
public FinancialActivityAccountData retrieveTemplate() {
|
||||
context.authenticatedUser().validateHasReadPermission(FinancialActivityAccountsConstants.resourceNameForPermission);
|
||||
context.authenticatedUser().validateHasReadPermission(FinancialActivityAccountsConstants.RESOURCE_NAME_FOR_PERMISSION);
|
||||
return financialActivityAccountReadPlatformService.getFinancialActivityAccountTemplate();
|
||||
}
|
||||
|
||||
@@ -91,7 +91,7 @@ public class FinancialActivityAccountsApiResource {
|
||||
financialactivityaccounts""")
|
||||
@ApiResponse(responseCode = "200", description = "OK", content = @Content(array = @ArraySchema(schema = @Schema(implementation = FinancialActivityAccountsApiResourceSwagger.GetFinancialActivityAccountsResponse.class))))
|
||||
public List<FinancialActivityAccountData> retrieveAll() {
|
||||
context.authenticatedUser().validateHasReadPermission(FinancialActivityAccountsConstants.resourceNameForPermission);
|
||||
context.authenticatedUser().validateHasReadPermission(FinancialActivityAccountsConstants.RESOURCE_NAME_FOR_PERMISSION);
|
||||
return financialActivityAccountReadPlatformService.retrieveAll();
|
||||
}
|
||||
|
||||
@@ -105,7 +105,7 @@ public class FinancialActivityAccountsApiResource {
|
||||
@ApiResponse(responseCode = "200", description = "OK", content = @Content(schema = @Schema(implementation = FinancialActivityAccountsApiResourceSwagger.GetFinancialActivityAccountsResponse.class)))
|
||||
public FinancialActivityAccountData retreive(@PathParam("mappingId") @Parameter(description = "mappingId") final Long mappingId,
|
||||
@Context final UriInfo uriInfo) {
|
||||
context.authenticatedUser().validateHasReadPermission(FinancialActivityAccountsConstants.resourceNameForPermission);
|
||||
context.authenticatedUser().validateHasReadPermission(FinancialActivityAccountsConstants.RESOURCE_NAME_FOR_PERMISSION);
|
||||
|
||||
final ApiRequestJsonSerializationSettings settings = apiRequestParameterHelper.process(uriInfo.getQueryParameters());
|
||||
FinancialActivityAccountData financialActivityAccountData = financialActivityAccountReadPlatformService.retrieve(mappingId);
|
||||
|
||||
+8
-8
@@ -28,12 +28,12 @@ public final class FinancialActivityAccountsConstants {
|
||||
|
||||
}
|
||||
|
||||
private static final String idParamName = "id";
|
||||
private static final String factivityDataParamName = "financialActivityData";
|
||||
private static final String glAccountDataParamName = "glAccountData";
|
||||
private static final String glAccountOptionsParamName = "glAccountOptions";
|
||||
private static final String financialActivityOptionsParamName = "financialActivityOptions";
|
||||
public static final String resourceNameForPermission = "FINANCIALACTIVITYACCOUNT";
|
||||
static final Set<String> RESPONSE_DATA_PARAMETERS = new HashSet<>(Arrays.asList(idParamName, factivityDataParamName,
|
||||
glAccountDataParamName, glAccountOptionsParamName, financialActivityOptionsParamName));
|
||||
private static final String ID_PARAM_NAME = "id";
|
||||
private static final String FINANCIAL_ACTIVITY_DATA_PARAM_NAME = "financialActivityData";
|
||||
private static final String GL_ACCOUNT_DATA_PARAM_NAME = "glAccountData";
|
||||
private static final String GL_ACCOUNT_OPTIONS_PARAM_NAME = "glAccountOptions";
|
||||
private static final String FINANCIAL_ACTIVITY_OPTIONS_PARAM_NAME = "financialActivityOptions";
|
||||
public static final String RESOURCE_NAME_FOR_PERMISSION = "FINANCIALACTIVITYACCOUNT";
|
||||
static final Set<String> RESPONSE_DATA_PARAMETERS = new HashSet<>(Arrays.asList(ID_PARAM_NAME, FINANCIAL_ACTIVITY_DATA_PARAM_NAME,
|
||||
GL_ACCOUNT_DATA_PARAM_NAME, GL_ACCOUNT_OPTIONS_PARAM_NAME, FINANCIAL_ACTIVITY_OPTIONS_PARAM_NAME));
|
||||
}
|
||||
|
||||
+2
-1
@@ -26,7 +26,8 @@ import java.util.Set;
|
||||
***/
|
||||
public enum FinancialActivityAccountsJsonInputParams {
|
||||
|
||||
FINANCIAL_ACTIVITY_ID("financialActivityId"), GL_ACCOUNT_ID("glAccountId");
|
||||
FINANCIAL_ACTIVITY_ID("financialActivityId"), //
|
||||
GL_ACCOUNT_ID("glAccountId"); //
|
||||
|
||||
private final String value;
|
||||
|
||||
|
||||
+3
-3
@@ -25,14 +25,14 @@ import org.apache.fineract.infrastructure.core.exception.AbstractPlatformDomainR
|
||||
*/
|
||||
public class DuplicateFinancialActivityAccountFoundException extends AbstractPlatformDomainRuleException {
|
||||
|
||||
private static final String errorCode = "error.msg.financialActivityAccount.exists";
|
||||
private static final String ERROR_CODE = "error.msg.financialActivityAccount.exists";
|
||||
|
||||
public DuplicateFinancialActivityAccountFoundException(final Integer financialActivityType) {
|
||||
super(errorCode, "Mapping for activity already exists " + financialActivityType, financialActivityType);
|
||||
super(ERROR_CODE, "Mapping for activity already exists " + financialActivityType, financialActivityType);
|
||||
}
|
||||
|
||||
public static String getErrorcode() {
|
||||
return errorCode;
|
||||
return ERROR_CODE;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
+3
-3
@@ -27,10 +27,10 @@ import org.apache.fineract.infrastructure.core.exception.AbstractPlatformDomainR
|
||||
*/
|
||||
public class FinancialActivityAccountInvalidException extends AbstractPlatformDomainRuleException {
|
||||
|
||||
private static final String errorCode = "error.msg.financialActivityAccount.invalid";
|
||||
private static final String ERROR_CODE = "error.msg.financialActivityAccount.invalid";
|
||||
|
||||
public FinancialActivityAccountInvalidException(final FinancialActivity financialActivity, final GLAccount glAccount) {
|
||||
super(errorCode,
|
||||
super(ERROR_CODE,
|
||||
"Financial Activity '" + financialActivity.getCode() + "' with Id :" + financialActivity.getValue()
|
||||
+ "' can only be associated with a Ledger Account of Type " + financialActivity.getMappedGLAccountType().getCode()
|
||||
+ " the provided Ledger Account '" + glAccount.getName() + "(" + glAccount.getGlCode()
|
||||
@@ -40,6 +40,6 @@ public class FinancialActivityAccountInvalidException extends AbstractPlatformDo
|
||||
}
|
||||
|
||||
public static String getErrorcode() {
|
||||
return errorCode;
|
||||
return ERROR_CODE;
|
||||
}
|
||||
}
|
||||
|
||||
+1
-1
@@ -213,7 +213,7 @@ public class GLAccountsApiResource {
|
||||
@Consumes({ MediaType.APPLICATION_JSON })
|
||||
@Produces({ MediaType.APPLICATION_JSON })
|
||||
@Operation(tags = { "General Ledger Account" }, summary = "Delete a GL Account", description = "Deletes a GL Account")
|
||||
@ApiResponse(responseCode = "200", description = "OK", content = @Content(schema = @Schema(implementation = GLAccountsApiResourceSwagger.DeleteGLAccountsRequest.class)))
|
||||
@ApiResponse(responseCode = "200", description = "OK", content = @Content(schema = @Schema(implementation = GLAccountsApiResourceSwagger.DeleteGLAccountsResponse.class)))
|
||||
public CommandProcessingResult deleteGLAccount(
|
||||
@PathParam("glAccountId") @Parameter(description = "glAccountId") final Long glAccountId) {
|
||||
final CommandWrapper commandRequest = new CommandWrapperBuilder().deleteGLAccount(glAccountId).build();
|
||||
|
||||
+6
-6
@@ -203,23 +203,23 @@ final class GLAccountsApiResourceSwagger {
|
||||
public PutGLAccountsResponsechangesSwagger changes;
|
||||
}
|
||||
|
||||
@Schema(description = "DeleteGLAccountsRequest")
|
||||
public static final class DeleteGLAccountsRequest {
|
||||
@Schema(description = "DeleteGLAccountsResponse")
|
||||
public static final class DeleteGLAccountsResponse {
|
||||
|
||||
private DeleteGLAccountsRequest() {
|
||||
private DeleteGLAccountsResponse() {
|
||||
|
||||
}
|
||||
|
||||
private static final class DeleteGLAccountsRequestchangesSwagger {
|
||||
private static final class DeleteGLAccountsResponseChangesSwagger {
|
||||
|
||||
private DeleteGLAccountsRequestchangesSwagger() {}
|
||||
private DeleteGLAccountsResponseChangesSwagger() {}
|
||||
|
||||
}
|
||||
|
||||
@Schema(example = "1")
|
||||
public Long resourceId;
|
||||
|
||||
private DeleteGLAccountsRequestchangesSwagger changes;
|
||||
private DeleteGLAccountsResponseChangesSwagger changes;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
+7
-1
@@ -28,13 +28,17 @@ public class GLAccountInvalidDeleteException extends AbstractPlatformDomainRuleE
|
||||
/*** Enum of reasons for invalid delete **/
|
||||
public enum GlAccountInvalidDeleteReason {
|
||||
|
||||
TRANSACTIONS_LOGGED, HAS_CHILDREN;
|
||||
TRANSACTIONS_LOGGED, //
|
||||
HAS_CHILDREN, //
|
||||
PRODUCT_MAPPING; //
|
||||
|
||||
public String errorMessage() {
|
||||
if (name().equalsIgnoreCase("TRANSACTIONS_LOGGED")) {
|
||||
return "This GL Account cannot be deleted as it has transactions logged against it";
|
||||
} else if (name().equalsIgnoreCase("HAS_CHILDREN")) {
|
||||
return "Cannot delete this Header GL Account without first deleting or reassigning its children";
|
||||
} else if (name().equalsIgnoreCase("PRODUCT_MAPPING")) {
|
||||
return "Cannot delete this GL Account as it is mapped to a Product";
|
||||
}
|
||||
return name();
|
||||
}
|
||||
@@ -44,6 +48,8 @@ public class GLAccountInvalidDeleteException extends AbstractPlatformDomainRuleE
|
||||
return "error.msg.glaccount.glcode.invalid.delete.transactions.logged";
|
||||
} else if (name().equalsIgnoreCase("HAS_CHILDREN")) {
|
||||
return "error.msg.glaccount.glcode.invalid.delete.has.children";
|
||||
} else if (name().equalsIgnoreCase("PRODUCT_MAPPING")) {
|
||||
return "error.msg.glaccount.glcode.invalid.delete.product.mapping";
|
||||
}
|
||||
return name();
|
||||
}
|
||||
|
||||
+5
-5
@@ -28,20 +28,20 @@ public class GLAccountInvalidUpdateException extends AbstractPlatformDomainRuleE
|
||||
/*** Enum of reasons for invalid delete **/
|
||||
public enum GlAccountInvalidUpdateReason {
|
||||
|
||||
TRANSANCTIONS_LOGGED;
|
||||
TRANSANCTIONS_LOGGED; //
|
||||
|
||||
public String errorMessage() {
|
||||
if (name().toString().equalsIgnoreCase("TRANSANCTIONS_LOGGED")) {
|
||||
if (name().equalsIgnoreCase("TRANSANCTIONS_LOGGED")) {
|
||||
return "This Usage of this (detail) GL Account as it already has transactions logged against it";
|
||||
}
|
||||
return name().toString();
|
||||
return name();
|
||||
}
|
||||
|
||||
public String errorCode() {
|
||||
if (name().toString().equalsIgnoreCase("TRANSANCTIONS_LOGGED")) {
|
||||
if (name().equalsIgnoreCase("TRANSANCTIONS_LOGGED")) {
|
||||
return "error.msg.glaccount.glcode.invalid.update.transactions.logged";
|
||||
}
|
||||
return name().toString();
|
||||
return name();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+16
-9
@@ -37,6 +37,7 @@ import org.apache.fineract.accounting.glaccount.exception.GLAccountNotFoundExcep
|
||||
import org.apache.fineract.accounting.glaccount.exception.InvalidParentGLAccountHeadException;
|
||||
import org.apache.fineract.accounting.glaccount.serialization.GLAccountCommandFromApiJsonDeserializer;
|
||||
import org.apache.fineract.accounting.journalentry.domain.JournalEntryRepository;
|
||||
import org.apache.fineract.accounting.producttoaccountmapping.domain.ProductToGLAccountMappingRepository;
|
||||
import org.apache.fineract.infrastructure.codes.domain.CodeValue;
|
||||
import org.apache.fineract.infrastructure.codes.domain.CodeValueRepositoryWrapper;
|
||||
import org.apache.fineract.infrastructure.core.api.JsonCommand;
|
||||
@@ -58,9 +59,11 @@ import org.springframework.transaction.annotation.Transactional;
|
||||
public class GLAccountWritePlatformServiceJpaRepositoryImpl implements GLAccountWritePlatformService {
|
||||
|
||||
private static final Logger LOG = LoggerFactory.getLogger(GLAccountWritePlatformServiceJpaRepositoryImpl.class);
|
||||
private static final String GL_ACCOUNT = "glAccount";
|
||||
|
||||
private final GLAccountRepository glAccountRepository;
|
||||
private final JournalEntryRepository glJournalEntryRepository;
|
||||
private final ProductToGLAccountMappingRepository productToGLAccountMappingRepository;
|
||||
private final GLAccountCommandFromApiJsonDeserializer fromApiJsonDeserializer;
|
||||
private final CodeValueRepositoryWrapper codeValueRepositoryWrapper;
|
||||
private final JdbcTemplate jdbcTemplate;
|
||||
@@ -144,13 +147,11 @@ public class GLAccountWritePlatformServiceJpaRepositoryImpl implements GLAccount
|
||||
/**
|
||||
* a detail account cannot be changed to a header account if transactions are already logged against it
|
||||
**/
|
||||
if (changesOnly.containsKey(GLAccountJsonInputParams.USAGE.getValue())) {
|
||||
if (glAccount.isHeaderAccount()) {
|
||||
final boolean journalEntriesForAccountExist = this.glJournalEntryRepository
|
||||
.exists((root, query, criteriaBuilder) -> criteriaBuilder.equal(root.get("glAccountId"), glAccountId));
|
||||
if (journalEntriesForAccountExist) {
|
||||
throw new GLAccountInvalidUpdateException(GlAccountInvalidUpdateReason.TRANSANCTIONS_LOGGED, glAccountId);
|
||||
}
|
||||
if (changesOnly.containsKey(GLAccountJsonInputParams.USAGE.getValue()) && glAccount.isHeaderAccount()) {
|
||||
final boolean journalEntriesForAccountExist = this.glJournalEntryRepository
|
||||
.exists((root, query, criteriaBuilder) -> criteriaBuilder.equal(root.get(GL_ACCOUNT).get("id"), glAccountId));
|
||||
if (journalEntriesForAccountExist) {
|
||||
throw new GLAccountInvalidUpdateException(GlAccountInvalidUpdateReason.TRANSANCTIONS_LOGGED, glAccountId);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -186,16 +187,22 @@ public class GLAccountWritePlatformServiceJpaRepositoryImpl implements GLAccount
|
||||
.orElseThrow(() -> new GLAccountNotFoundException(glAccountId));
|
||||
|
||||
// validate this isn't a header account that has children
|
||||
if (glAccount.isHeaderAccount() && glAccount.getChildren().size() > 0) {
|
||||
if (glAccount.isHeaderAccount() && !glAccount.getChildren().isEmpty()) {
|
||||
throw new GLAccountInvalidDeleteException(GlAccountInvalidDeleteReason.HAS_CHILDREN, glAccountId);
|
||||
}
|
||||
|
||||
// does this account have transactions logged against it
|
||||
final boolean journalEntriesForAccountExist = this.glJournalEntryRepository
|
||||
.exists((root, query, criteriaBuilder) -> criteriaBuilder.equal(root.get("glAccountId"), glAccountId));
|
||||
.exists((root, query, criteriaBuilder) -> criteriaBuilder.equal(root.get(GL_ACCOUNT).get("id"), glAccountId));
|
||||
if (journalEntriesForAccountExist) {
|
||||
throw new GLAccountInvalidDeleteException(GlAccountInvalidDeleteReason.TRANSACTIONS_LOGGED, glAccountId);
|
||||
}
|
||||
// does this account mapped to product
|
||||
final boolean accountMappingForAccountExists = this.productToGLAccountMappingRepository
|
||||
.exists((root, query, criteriaBuilder) -> criteriaBuilder.equal(root.get(GL_ACCOUNT).get("id"), glAccountId));
|
||||
if (accountMappingForAccountExists) {
|
||||
throw new GLAccountInvalidDeleteException(GlAccountInvalidDeleteReason.PRODUCT_MAPPING, glAccountId);
|
||||
}
|
||||
this.glAccountRepository.delete(glAccount);
|
||||
|
||||
return new CommandProcessingResultBuilder().withEntityId(glAccountId).build();
|
||||
|
||||
+1
@@ -71,6 +71,7 @@ public interface JournalEntryMapper {
|
||||
@Mapping(target = "debits", ignore = true)
|
||||
@Mapping(target = "transactionDetails", ignore = true)
|
||||
@Mapping(target = "savingTransactionId", ignore = true)
|
||||
@Mapping(target = "externalAssetOwner", ignore = true)
|
||||
JournalEntryData map(JournalEntry journalEntry);
|
||||
|
||||
@Named("entityType")
|
||||
|
||||
+20
-6
@@ -26,11 +26,25 @@ import java.util.Set;
|
||||
***/
|
||||
public enum JournalEntryJsonInputParams {
|
||||
|
||||
OFFICE_ID("officeId"), TRANSACTION_DATE("transactionDate"), COMMENTS("comments"), CREDITS("credits"), DEBITS("debits"), LOCALE(
|
||||
"locale"), DATE_FORMAT("dateFormat"), REFERENCE_NUMBER("referenceNumber"), USE_ACCOUNTING_RULE(
|
||||
"useAccountingRule"), ACCOUNTING_RULE("accountingRule"), AMOUNT("amount"), CURRENCY_CODE(
|
||||
"currencyCode"), PAYMENT_TYPE_ID("paymentTypeId"), ACCOUNT_NUMBER("accountNumber"), CHECK_NUMBER(
|
||||
"checkNumber"), ROUTING_CODE("routingCode"), RECEIPT_NUMBER("receiptNumber"), BANK_NUMBER("bankNumber");
|
||||
OFFICE_ID("officeId"), //
|
||||
TRANSACTION_DATE("transactionDate"), //
|
||||
COMMENTS("comments"), //
|
||||
CREDITS("credits"), //
|
||||
DEBITS("debits"), //
|
||||
LOCALE("locale"), //
|
||||
DATE_FORMAT("dateFormat"), //
|
||||
REFERENCE_NUMBER("referenceNumber"), //
|
||||
USE_ACCOUNTING_RULE("useAccountingRule"), //
|
||||
ACCOUNTING_RULE("accountingRule"), //
|
||||
AMOUNT("amount"), //
|
||||
CURRENCY_CODE("currencyCode"), //
|
||||
PAYMENT_TYPE_ID("paymentTypeId"), //
|
||||
ACCOUNT_NUMBER("accountNumber"), //
|
||||
CHECK_NUMBER("checkNumber"), //
|
||||
ROUTING_CODE("routingCode"), //
|
||||
RECEIPT_NUMBER("receiptNumber"), //
|
||||
BANK_NUMBER("bankNumber"), //
|
||||
EXTERNAL_ASSET_OWNER("externalAssetOwner"); //
|
||||
|
||||
private final String value;
|
||||
|
||||
@@ -52,7 +66,7 @@ public enum JournalEntryJsonInputParams {
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return name().replaceAll("_", " ");
|
||||
return name().replace("_", " ");
|
||||
}
|
||||
|
||||
public String getValue() {
|
||||
|
||||
+6
@@ -52,6 +52,9 @@ public class JournalEntryCommand {
|
||||
|
||||
private final SingleDebitOrCreditEntryCommand[] credits;
|
||||
private final SingleDebitOrCreditEntryCommand[] debits;
|
||||
private final String locale;
|
||||
private final String dateFormat;
|
||||
private final String externalAssetOwner;
|
||||
|
||||
public void validateForCreate() {
|
||||
|
||||
@@ -73,6 +76,9 @@ public class JournalEntryCommand {
|
||||
|
||||
baseDataValidator.reset().parameter("paymentTypeId").value(this.paymentTypeId).ignoreIfNull().longGreaterThanZero();
|
||||
|
||||
baseDataValidator.reset().parameter(JournalEntryJsonInputParams.EXTERNAL_ASSET_OWNER.getValue()).value(this.externalAssetOwner)
|
||||
.ignoreIfNull().notExceedingLengthOf(100);
|
||||
|
||||
// validation for credit array elements
|
||||
if (this.credits != null) {
|
||||
if (this.credits.length == 0) {
|
||||
|
||||
+5
-3
@@ -94,6 +94,7 @@ public class JournalEntryData {
|
||||
private String routingCode;
|
||||
private String receiptNumber;
|
||||
private String bankNumber;
|
||||
private String externalAssetOwner;
|
||||
private transient Long savingTransactionId;
|
||||
|
||||
public JournalEntryData() {}
|
||||
@@ -191,7 +192,7 @@ public class JournalEntryData {
|
||||
final EnumOptionData entityType, final Long entityId, final Long createdByUserId, final LocalDate submittedOnDate,
|
||||
final String createdByUserName, final String comments, final Boolean reversed, final String referenceNumber,
|
||||
final BigDecimal officeRunningBalance, final BigDecimal organizationRunningBalance, final Boolean runningBalanceComputed,
|
||||
final TransactionDetailData transactionDetailData, final CurrencyData currency) {
|
||||
final TransactionDetailData transactionDetailData, final CurrencyData currency, final String externalAssetOwner) {
|
||||
this.id = id;
|
||||
this.officeId = officeId;
|
||||
this.officeName = officeName;
|
||||
@@ -218,6 +219,7 @@ public class JournalEntryData {
|
||||
this.runningBalanceComputed = runningBalanceComputed;
|
||||
this.transactionDetails = transactionDetailData;
|
||||
this.currency = currency;
|
||||
this.externalAssetOwner = externalAssetOwner;
|
||||
}
|
||||
|
||||
public static JournalEntryData importInstance(Long officeId, LocalDate transactionDate, String currencyCode, Long paymentTypeId,
|
||||
@@ -259,10 +261,11 @@ public class JournalEntryData {
|
||||
final Boolean runningBalanceComputed = null;
|
||||
final TransactionDetailData transactionDetailData = null;
|
||||
final CurrencyData currency = null;
|
||||
final String externalAssetOwner = null;
|
||||
return new JournalEntryData(id, officeId, officeName, glAccountName, glAccountId, glAccountCode, glAccountClassification,
|
||||
transactionDate, entryType, amount, transactionId, manualEntry, entityType, entityId, createdByUserId, submittedOnDate,
|
||||
createdByUserName, comments, reversed, referenceNumber, officeRunningBalance, organizationRunningBalance,
|
||||
runningBalanceComputed, transactionDetailData, currency);
|
||||
runningBalanceComputed, transactionDetailData, currency, externalAssetOwner);
|
||||
}
|
||||
|
||||
public Integer getRowIndex() {
|
||||
@@ -274,7 +277,6 @@ public class JournalEntryData {
|
||||
}
|
||||
|
||||
public void addDebits(CreditDebit debit) {
|
||||
|
||||
this.debits.add(debit);
|
||||
}
|
||||
|
||||
|
||||
+1
-1
@@ -38,7 +38,7 @@ public interface JournalEntryRepository extends JpaRepository<JournalEntry, Long
|
||||
@Query("select journalEntry from JournalEntry journalEntry where journalEntry.entityId= :entityId and journalEntry.entityType = :entityType")
|
||||
List<JournalEntry> findProvisioningJournalEntriesByEntityId(@Param("entityId") Long entityId, @Param("entityType") Integer entityType);
|
||||
|
||||
@Query("select journalEntry from JournalEntry journalEntry where journalEntry.transactionId= :transactionId and journalEntry.reversed=false and journalEntry.entityType = :entityType")
|
||||
@Query("select journalEntry from JournalEntry journalEntry where journalEntry.transactionId= :transactionId and journalEntry.reversed=false and journalEntry.entityType = :entityType order by journalEntry.transactionDate asc, journalEntry.createdDate asc, journalEntry.id asc")
|
||||
List<JournalEntry> findJournalEntries(@Param("transactionId") String transactionId, @Param("entityType") Integer entityType);
|
||||
|
||||
}
|
||||
|
||||
+9
-1
@@ -29,7 +29,15 @@ public class JournalEntryInvalidException extends AbstractPlatformDomainRuleExce
|
||||
/*** enum of reasons for invalid Journal Entry **/
|
||||
public enum GlJournalEntryInvalidReason {
|
||||
|
||||
FUTURE_DATE, ACCOUNTING_CLOSED, NO_DEBITS_OR_CREDITS, DEBIT_CREDIT_SUM_MISMATCH_WITH_AMOUNT, DEBIT_CREDIT_SUM_MISMATCH, DEBIT_CREDIT_ACCOUNT_OR_AMOUNT_EMPTY, GL_ACCOUNT_DISABLED, GL_ACCOUNT_MANUAL_ENTRIES_NOT_PERMITTED, INVALID_DEBIT_OR_CREDIT_ACCOUNTS;
|
||||
FUTURE_DATE, //
|
||||
ACCOUNTING_CLOSED, //
|
||||
NO_DEBITS_OR_CREDITS, //
|
||||
DEBIT_CREDIT_SUM_MISMATCH_WITH_AMOUNT, //
|
||||
DEBIT_CREDIT_SUM_MISMATCH, //
|
||||
DEBIT_CREDIT_ACCOUNT_OR_AMOUNT_EMPTY, //
|
||||
GL_ACCOUNT_DISABLED, //
|
||||
GL_ACCOUNT_MANUAL_ENTRIES_NOT_PERMITTED, //
|
||||
INVALID_DEBIT_OR_CREDIT_ACCOUNTS; //
|
||||
|
||||
public String errorMessage() {
|
||||
if (name().equalsIgnoreCase("FUTURE_DATE")) {
|
||||
|
||||
+6
-2
@@ -73,7 +73,7 @@ public final class JournalEntryCommandFromApiJsonDeserializer extends AbstractFr
|
||||
element);
|
||||
final JsonObject topLevelJsonElement = element.getAsJsonObject();
|
||||
final Locale locale = this.fromApiJsonHelper.extractLocaleParameter(topLevelJsonElement);
|
||||
|
||||
final String localeStr = locale.getLanguage() + "_" + locale.getCountry() + '_' + locale.getVariant();
|
||||
final BigDecimal amount = this.fromApiJsonHelper.extractBigDecimalNamed(JournalEntryJsonInputParams.AMOUNT.getValue(), element,
|
||||
locale);
|
||||
final Long paymentTypeId = this.fromApiJsonHelper.extractLongNamed(JournalEntryJsonInputParams.PAYMENT_TYPE_ID.getValue(), element);
|
||||
@@ -84,6 +84,8 @@ public final class JournalEntryCommandFromApiJsonDeserializer extends AbstractFr
|
||||
element);
|
||||
final String bankNumber = this.fromApiJsonHelper.extractStringNamed(JournalEntryJsonInputParams.BANK_NUMBER.getValue(), element);
|
||||
final String routingCode = this.fromApiJsonHelper.extractStringNamed(JournalEntryJsonInputParams.ROUTING_CODE.getValue(), element);
|
||||
final String externalAssetOwner = this.fromApiJsonHelper
|
||||
.extractStringNamed(JournalEntryJsonInputParams.EXTERNAL_ASSET_OWNER.getValue(), element);
|
||||
|
||||
SingleDebitOrCreditEntryCommand[] credits = null;
|
||||
SingleDebitOrCreditEntryCommand[] debits = null;
|
||||
@@ -97,8 +99,10 @@ public final class JournalEntryCommandFromApiJsonDeserializer extends AbstractFr
|
||||
debits = populateCreditsOrDebitsArray(topLevelJsonElement, locale, JournalEntryJsonInputParams.DEBITS.getValue());
|
||||
}
|
||||
}
|
||||
String dateFormat = this.fromApiJsonHelper.extractStringNamed(JournalEntryJsonInputParams.DATE_FORMAT.getValue(), element);
|
||||
return new JournalEntryCommand(officeId, currencyCode, transactionDate, comments, referenceNumber, accountingRuleId, amount,
|
||||
paymentTypeId, accountNumber, checkNumber, receiptNumber, bankNumber, routingCode, credits, debits);
|
||||
paymentTypeId, accountNumber, checkNumber, receiptNumber, bankNumber, routingCode, credits, debits, localeStr, dateFormat,
|
||||
externalAssetOwner);
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
+16
-2
@@ -68,10 +68,24 @@ public class ProductToGLAccountMapping extends AbstractPersistableCustom<Long> {
|
||||
@JoinColumn(name = "charge_off_reason_id", nullable = true)
|
||||
private CodeValue chargeOffReason;
|
||||
|
||||
@ManyToOne
|
||||
@JoinColumn(name = "write_off_reason_id", nullable = true)
|
||||
private CodeValue writeOffReason;
|
||||
|
||||
@ManyToOne
|
||||
@JoinColumn(name = "capitalized_income_classification_id", nullable = true)
|
||||
private CodeValue capitalizedIncomeClassification;
|
||||
|
||||
@ManyToOne
|
||||
@JoinColumn(name = "buydown_fee_classification_id", nullable = true)
|
||||
private CodeValue buydownFeeClassification;
|
||||
|
||||
public static ProductToGLAccountMapping createNew(final GLAccount glAccount, final Long productId, final int productType,
|
||||
final int financialAccountType, final CodeValue chargeOffReason) {
|
||||
final int financialAccountType, final CodeValue chargeOffReason, final CodeValue capitalizedIncomeClassification,
|
||||
final CodeValue buydownFeeClassification) {
|
||||
|
||||
return new ProductToGLAccountMapping().setGlAccount(glAccount).setProductId(productId).setProductType(productType)
|
||||
.setFinancialAccountType(financialAccountType).setChargeOffReason(chargeOffReason);
|
||||
.setFinancialAccountType(financialAccountType).setChargeOffReason(chargeOffReason)
|
||||
.setCapitalizedIncomeClassification(capitalizedIncomeClassification).setBuydownFeeClassification(buydownFeeClassification);
|
||||
}
|
||||
}
|
||||
|
||||
+26
-2
@@ -35,7 +35,7 @@ public interface ProductToGLAccountMappingRepository
|
||||
@Param("productType") int productType, @Param("financialAccountType") int financialAccountType,
|
||||
@Param("chargeId") Long ChargeId);
|
||||
|
||||
@Query("select mapping from ProductToGLAccountMapping mapping where mapping.productId =:productId and mapping.productType =:productType and mapping.financialAccountType=:financialAccountType and mapping.paymentType is NULL and mapping.charge is NULL and mapping.chargeOffReason is NULL")
|
||||
@Query("select mapping from ProductToGLAccountMapping mapping where mapping.productId =:productId and mapping.productType =:productType and mapping.financialAccountType=:financialAccountType and mapping.paymentType is NULL and mapping.charge is NULL and mapping.chargeOffReason is NULL and mapping.writeOffReason is NULL and mapping.capitalizedIncomeClassification is NULL and mapping.buydownFeeClassification is NULL")
|
||||
ProductToGLAccountMapping findCoreProductToFinAccountMapping(@Param("productId") Long productId, @Param("productType") int productType,
|
||||
@Param("financialAccountType") int financialAccountType);
|
||||
|
||||
@@ -66,11 +66,18 @@ public interface ProductToGLAccountMappingRepository
|
||||
List<ProductToGLAccountMapping> findAllChargeOffReasonsMappings(@Param("productId") Long productId,
|
||||
@Param("productType") int productType);
|
||||
|
||||
List<ProductToGLAccountMapping> findAllProductToGLAccountMappingsByProductIdAndProductTypeAndFinancialAccountType(Long productId,
|
||||
int productType, int financialAccountType);
|
||||
|
||||
@Query("select mapping from ProductToGLAccountMapping mapping where mapping.productId =:productId and mapping.productType =:productType and mapping.writeOffReason is not NULL")
|
||||
List<ProductToGLAccountMapping> findAllWriteOffReasonsMappings(@Param("productId") Long productId,
|
||||
@Param("productType") int productType);
|
||||
|
||||
@Query("select mapping from ProductToGLAccountMapping mapping where mapping.chargeOffReason.id =:chargeOffReasonId AND mapping.productId =:productId AND mapping.productType =:productType")
|
||||
ProductToGLAccountMapping findChargeOffReasonMapping(@Param("productId") Long productId, @Param("productType") Integer productType,
|
||||
@Param("chargeOffReasonId") Long chargeOffReasonId);
|
||||
|
||||
@Query("select mapping from ProductToGLAccountMapping mapping where mapping.productId =:productId AND mapping.productType =:productType AND mapping.charge IS NULL AND mapping.paymentType IS NULL AND mapping.chargeOffReason IS NULL")
|
||||
@Query("select mapping from ProductToGLAccountMapping mapping where mapping.productId =:productId AND mapping.productType =:productType AND mapping.charge IS NULL AND mapping.paymentType IS NULL AND mapping.chargeOffReason IS NULL AND mapping.writeOffReason IS NULL AND mapping.capitalizedIncomeClassification is NULL AND mapping.buydownFeeClassification is NULL")
|
||||
List<ProductToGLAccountMapping> findAllRegularMappings(@Param("productId") Long productId, @Param("productType") Integer productType);
|
||||
|
||||
@Query("select mapping from ProductToGLAccountMapping mapping where mapping.productId =:productId and mapping.productType =:productType and mapping.paymentType is not NULL")
|
||||
@@ -82,4 +89,21 @@ public interface ProductToGLAccountMappingRepository
|
||||
|
||||
@Query("select mapping from ProductToGLAccountMapping mapping where mapping.productId =:productId AND mapping.productType =:productType AND mapping.charge.penalty = FALSE")
|
||||
List<ProductToGLAccountMapping> findAllFeeMappings(@Param("productId") Long productId, @Param("productType") Integer productType);
|
||||
|
||||
@Query("select mapping from ProductToGLAccountMapping mapping where mapping.productId =:productId and mapping.productType =:productType and mapping.capitalizedIncomeClassification is not NULL")
|
||||
List<ProductToGLAccountMapping> findAllCapitalizedIncomeClassificationsMappings(@Param("productId") Long productId,
|
||||
@Param("productType") int productType);
|
||||
|
||||
@Query("select mapping from ProductToGLAccountMapping mapping where mapping.productId =:productId and mapping.productType =:productType and mapping.buydownFeeClassification is not NULL")
|
||||
List<ProductToGLAccountMapping> findAllBuyDownFeeClassificationsMappings(@Param("productId") Long productId,
|
||||
@Param("productType") int productType);
|
||||
|
||||
@Query("select mapping from ProductToGLAccountMapping mapping where mapping.buydownFeeClassification.id = :classificationId AND mapping.productId = :productId AND mapping.productType = :productType")
|
||||
ProductToGLAccountMapping findBuydownFeeClassificationMapping(@Param("productId") Long productId,
|
||||
@Param("productType") Integer productType, @Param("classificationId") Long classificationId);
|
||||
|
||||
@Query("select mapping from ProductToGLAccountMapping mapping where mapping.capitalizedIncomeClassification.id = :classificationId AND mapping.productId = :productId AND mapping.productType = :productType")
|
||||
ProductToGLAccountMapping findCapitalizedIncomeClassificationMapping(@Param("productId") Long productId,
|
||||
@Param("productType") Integer productType, @Param("classificationId") Long classificationId);
|
||||
|
||||
}
|
||||
|
||||
+1
-1
@@ -29,7 +29,7 @@ public class ProductToGLAccountMappingInvalidException extends AbstractPlatformD
|
||||
final String actualAccountCategory, final String expectedAccountCategory) {
|
||||
super("error.msg." + paramName + ".invalid.account.type",
|
||||
"Passed in GLAccount " + paramName + " with Id " + accountId + "maps to the account " + accountName + " of type "
|
||||
+ actualAccountCategory + ", the expected account type was one among" + expectedAccountCategory,
|
||||
+ actualAccountCategory + ", the expected account type was one among " + expectedAccountCategory,
|
||||
paramName, accountId, accountName, actualAccountCategory, expectedAccountCategory);
|
||||
}
|
||||
}
|
||||
|
||||
+295
-69
@@ -29,6 +29,7 @@ import java.util.Map;
|
||||
import java.util.Objects;
|
||||
import java.util.Optional;
|
||||
import java.util.Set;
|
||||
import java.util.function.Predicate;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import org.apache.fineract.accounting.common.AccountingConstants.CashAccountsForLoan;
|
||||
import org.apache.fineract.accounting.common.AccountingConstants.LoanProductAccountingParams;
|
||||
@@ -90,7 +91,7 @@ public class ProductToGLAccountMappingHelper {
|
||||
final ProductToGLAccountMapping accountMapping = this.accountMappingRepository.findCoreProductToFinAccountMapping(productId,
|
||||
portfolioProductType.getValue(), accountTypeId);
|
||||
if (accountMapping == null) {
|
||||
ArrayList<String> optionalProductToGLAccountMappingEntries = new ArrayList<String>();
|
||||
ArrayList<String> optionalProductToGLAccountMappingEntries = new ArrayList<>();
|
||||
optionalProductToGLAccountMappingEntries.add(LoanProductAccountingParams.GOODWILL_CREDIT.getValue());
|
||||
optionalProductToGLAccountMappingEntries.add(LoanProductAccountingParams.INCOME_FROM_CHARGE_OFF_INTEREST.getValue());
|
||||
optionalProductToGLAccountMappingEntries.add(LoanProductAccountingParams.INCOME_FROM_CHARGE_OFF_FEES.getValue());
|
||||
@@ -100,6 +101,11 @@ public class ProductToGLAccountMappingHelper {
|
||||
optionalProductToGLAccountMappingEntries.add("incomeFromGoodwillCreditInterestAccountId");
|
||||
optionalProductToGLAccountMappingEntries.add("incomeFromGoodwillCreditFeesAccountId");
|
||||
optionalProductToGLAccountMappingEntries.add("incomeFromGoodwillCreditPenaltyAccountId");
|
||||
optionalProductToGLAccountMappingEntries.add("interestReceivableAccountId");
|
||||
optionalProductToGLAccountMappingEntries.add(LoanProductAccountingParams.DEFERRED_INCOME_LIABILITY.getValue());
|
||||
optionalProductToGLAccountMappingEntries.add(LoanProductAccountingParams.INCOME_FROM_CAPITALIZATION.getValue());
|
||||
optionalProductToGLAccountMappingEntries.add(LoanProductAccountingParams.BUY_DOWN_EXPENSE.getValue());
|
||||
optionalProductToGLAccountMappingEntries.add(LoanProductAccountingParams.INCOME_FROM_BUY_DOWN.getValue());
|
||||
|
||||
if (optionalProductToGLAccountMappingEntries.contains(paramName)) {
|
||||
saveProductToAccountMapping(element, paramName, productId, accountTypeId, expectedAccountType, portfolioProductType);
|
||||
@@ -201,23 +207,49 @@ public class ProductToGLAccountMappingHelper {
|
||||
}
|
||||
}
|
||||
|
||||
public void saveChargeOffReasonToGLAccountMappings(final JsonCommand command, final JsonElement element, final Long productId,
|
||||
final Map<String, Object> changes, final PortfolioProductType portfolioProductType) {
|
||||
public void saveReasonToGLAccountMappings(final JsonCommand command, final JsonElement element, final Long productId,
|
||||
final Map<String, Object> changes, final PortfolioProductType portfolioProductType,
|
||||
final LoanProductAccountingParams arrayNameParam, final LoanProductAccountingParams reasonCodeValueIdParam,
|
||||
final CashAccountsForLoan cashAccountsForLoan) {
|
||||
|
||||
final String arrayName = LoanProductAccountingParams.CHARGE_OFF_REASON_TO_EXPENSE_ACCOUNT_MAPPINGS.getValue();
|
||||
final JsonArray chargeOffReasonToExpenseAccountMappingArray = this.fromApiJsonHelper.extractJsonArrayNamed(arrayName, element);
|
||||
final String arrayName = arrayNameParam.getValue();
|
||||
final JsonArray reasonToExpenseAccountMappingArray = this.fromApiJsonHelper.extractJsonArrayNamed(arrayName, element);
|
||||
|
||||
if (chargeOffReasonToExpenseAccountMappingArray != null) {
|
||||
if (reasonToExpenseAccountMappingArray != null) {
|
||||
if (changes != null) {
|
||||
changes.put(arrayName, command.jsonFragment(arrayName));
|
||||
}
|
||||
|
||||
for (int i = 0; i < chargeOffReasonToExpenseAccountMappingArray.size(); i++) {
|
||||
final JsonObject jsonObject = chargeOffReasonToExpenseAccountMappingArray.get(i).getAsJsonObject();
|
||||
final Long reasonId = jsonObject.get(LoanProductAccountingParams.CHARGE_OFF_REASON_CODE_VALUE_ID.getValue()).getAsLong();
|
||||
for (int i = 0; i < reasonToExpenseAccountMappingArray.size(); i++) {
|
||||
final JsonObject jsonObject = reasonToExpenseAccountMappingArray.get(i).getAsJsonObject();
|
||||
final Long reasonId = jsonObject.get(reasonCodeValueIdParam.getValue()).getAsLong();
|
||||
final Long expenseAccountId = jsonObject.get(LoanProductAccountingParams.EXPENSE_GL_ACCOUNT_ID.getValue()).getAsLong();
|
||||
|
||||
saveChargeOffReasonToExpenseMapping(productId, reasonId, expenseAccountId, portfolioProductType);
|
||||
saveReasonToExpenseMapping(productId, reasonId, expenseAccountId, portfolioProductType, cashAccountsForLoan);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void saveClassificationToGLAccountMappings(final JsonCommand command, final JsonElement element, final Long productId,
|
||||
final Map<String, Object> changes, final PortfolioProductType portfolioProductType,
|
||||
final LoanProductAccountingParams classificationParameter) {
|
||||
|
||||
final String arrayName = classificationParameter.getValue();
|
||||
final JsonArray classificationToIncomeAccountMappingArray = this.fromApiJsonHelper.extractJsonArrayNamed(arrayName, element);
|
||||
|
||||
if (classificationToIncomeAccountMappingArray != null) {
|
||||
if (changes != null) {
|
||||
changes.put(arrayName, command.jsonFragment(arrayName));
|
||||
}
|
||||
|
||||
for (int i = 0; i < classificationToIncomeAccountMappingArray.size(); i++) {
|
||||
final JsonObject jsonObject = classificationToIncomeAccountMappingArray.get(i).getAsJsonObject();
|
||||
final Long classificationId = jsonObject.get(LoanProductAccountingParams.CLASSIFICATION_CODE_VALUE_ID.getValue())
|
||||
.getAsLong();
|
||||
final Long incomeAccountId = jsonObject.get(LoanProductAccountingParams.INCOME_ACCOUNT_ID.getValue()).getAsLong();
|
||||
|
||||
saveClassificationToIncomeMapping(productId, classificationId, incomeAccountId, portfolioProductType,
|
||||
classificationParameter);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -268,7 +300,7 @@ public class ProductToGLAccountMappingHelper {
|
||||
|
||||
// If input map is empty, delete all existing mappings
|
||||
if (inputChargeToIncomeAccountMap.size() == 0) {
|
||||
this.accountMappingRepository.deleteAllInBatch(existingChargeToIncomeAccountMappings);
|
||||
this.accountMappingRepository.deleteAll(existingChargeToIncomeAccountMappings);
|
||||
} /**
|
||||
* Else, <br/>
|
||||
* update existing mappings OR <br/>
|
||||
@@ -348,7 +380,7 @@ public class ProductToGLAccountMappingHelper {
|
||||
|
||||
// If input map is empty, delete all existing mappings
|
||||
if (inputPaymentChannelFundSourceMap.isEmpty()) {
|
||||
this.accountMappingRepository.deleteAllInBatch(existingPaymentChannelToFundSourceMappings);
|
||||
this.accountMappingRepository.deleteAll(existingPaymentChannelToFundSourceMappings);
|
||||
} /**
|
||||
* Else, <br/>
|
||||
* update existing mappings OR <br/>
|
||||
@@ -384,60 +416,143 @@ public class ProductToGLAccountMappingHelper {
|
||||
}
|
||||
}
|
||||
|
||||
public void updateChargeOffReasonToGLAccountMappings(final JsonCommand command, final JsonElement element, final Long productId,
|
||||
final Map<String, Object> changes, final PortfolioProductType portfolioProductType) {
|
||||
private Long getReasonIdByCashAccountForLoan(final ProductToGLAccountMapping productToGLAccountMapping,
|
||||
final CashAccountsForLoan cashAccountsForLoan) {
|
||||
return switch (cashAccountsForLoan) {
|
||||
case LOSSES_WRITTEN_OFF -> productToGLAccountMapping != null && productToGLAccountMapping.getWriteOffReason() != null
|
||||
? productToGLAccountMapping.getWriteOffReason().getId()
|
||||
: null;
|
||||
case CHARGE_OFF_EXPENSE -> productToGLAccountMapping != null && productToGLAccountMapping.getChargeOffReason() != null
|
||||
? productToGLAccountMapping.getChargeOffReason().getId()
|
||||
: null;
|
||||
default -> throw new IllegalStateException("Unexpected value: " + cashAccountsForLoan);
|
||||
};
|
||||
}
|
||||
|
||||
final List<ProductToGLAccountMapping> existingChargeOffReasonToGLAccountMappings = this.accountMappingRepository
|
||||
.findAllChargeOffReasonsMappings(productId, portfolioProductType.getValue());
|
||||
final JsonArray chargeOffReasonToGLAccountMappingArray = this.fromApiJsonHelper
|
||||
.extractJsonArrayNamed(LoanProductAccountingParams.CHARGE_OFF_REASON_TO_EXPENSE_ACCOUNT_MAPPINGS.getValue(), element);
|
||||
public void updateReasonToGLAccountMappings(final JsonCommand command, final JsonElement element, final Long productId,
|
||||
final Map<String, Object> changes, final PortfolioProductType portfolioProductType,
|
||||
final List<ProductToGLAccountMapping> existingReasonToGLAccountMappings,
|
||||
final LoanProductAccountingParams reasonToExpenseAccountMappingsParam, final LoanProductAccountingParams reasonCodeValueIdParam,
|
||||
final CashAccountsForLoan cashAccountsForLoan) {
|
||||
|
||||
final Map<Long, Long> inputChargeOffReasonToGLAccountMap = new HashMap<>();
|
||||
final JsonArray reasonToGLAccountMappingArray = this.fromApiJsonHelper
|
||||
.extractJsonArrayNamed(reasonToExpenseAccountMappingsParam.getValue(), element);
|
||||
|
||||
final Set<Long> existingChargeOffReasons = new HashSet<>();
|
||||
if (chargeOffReasonToGLAccountMappingArray != null) {
|
||||
final Map<Long, Long> inputReasonToGLAccountMap = new HashMap<>();
|
||||
|
||||
final Set<Long> existingReasons = new HashSet<>();
|
||||
if (reasonToGLAccountMappingArray != null) {
|
||||
if (changes != null) {
|
||||
changes.put(LoanProductAccountingParams.CHARGE_OFF_REASON_TO_EXPENSE_ACCOUNT_MAPPINGS.getValue(),
|
||||
command.jsonFragment(LoanProductAccountingParams.CHARGE_OFF_REASON_TO_EXPENSE_ACCOUNT_MAPPINGS.getValue()));
|
||||
changes.put(reasonToExpenseAccountMappingsParam.getValue(),
|
||||
command.jsonFragment(reasonToExpenseAccountMappingsParam.getValue()));
|
||||
}
|
||||
|
||||
for (int i = 0; i < chargeOffReasonToGLAccountMappingArray.size(); i++) {
|
||||
final JsonObject jsonObject = chargeOffReasonToGLAccountMappingArray.get(i).getAsJsonObject();
|
||||
for (int i = 0; i < reasonToGLAccountMappingArray.size(); i++) {
|
||||
final JsonObject jsonObject = reasonToGLAccountMappingArray.get(i).getAsJsonObject();
|
||||
final Long expenseGlAccountId = jsonObject.get(LoanProductAccountingParams.EXPENSE_GL_ACCOUNT_ID.getValue()).getAsLong();
|
||||
final Long chargeOffReasonCodeValueId = jsonObject
|
||||
.get(LoanProductAccountingParams.CHARGE_OFF_REASON_CODE_VALUE_ID.getValue()).getAsLong();
|
||||
inputChargeOffReasonToGLAccountMap.put(chargeOffReasonCodeValueId, expenseGlAccountId);
|
||||
final Long reasonCodeValueId = jsonObject.get(reasonCodeValueIdParam.getValue()).getAsLong();
|
||||
inputReasonToGLAccountMap.put(reasonCodeValueId, expenseGlAccountId);
|
||||
}
|
||||
|
||||
// If input map is empty, delete all existing mappings
|
||||
if (inputChargeOffReasonToGLAccountMap.isEmpty()) {
|
||||
this.accountMappingRepository.deleteAllInBatch(existingChargeOffReasonToGLAccountMappings);
|
||||
if (inputReasonToGLAccountMap.isEmpty()) {
|
||||
this.accountMappingRepository.deleteAll(existingReasonToGLAccountMappings);
|
||||
|
||||
} else {
|
||||
for (final ProductToGLAccountMapping existingChargeOffReasonToGLAccountMapping : existingChargeOffReasonToGLAccountMappings) {
|
||||
final Long currentChargeOffReasonId = existingChargeOffReasonToGLAccountMapping.getChargeOffReason().getId();
|
||||
if (currentChargeOffReasonId != null) {
|
||||
existingChargeOffReasons.add(currentChargeOffReasonId);
|
||||
for (final ProductToGLAccountMapping existingReasonToGLAccountMapping : existingReasonToGLAccountMappings) {
|
||||
final Long currentReasonId = getReasonIdByCashAccountForLoan(existingReasonToGLAccountMapping, cashAccountsForLoan);
|
||||
if (currentReasonId != null) {
|
||||
existingReasons.add(currentReasonId);
|
||||
// update existing mappings (if required)
|
||||
if (inputChargeOffReasonToGLAccountMap.containsKey(currentChargeOffReasonId)) {
|
||||
final Long newGLAccountId = inputChargeOffReasonToGLAccountMap.get(currentChargeOffReasonId);
|
||||
if (!newGLAccountId.equals(existingChargeOffReasonToGLAccountMapping.getGlAccount().getId())) {
|
||||
if (inputReasonToGLAccountMap.containsKey(currentReasonId)) {
|
||||
final Long newGLAccountId = inputReasonToGLAccountMap.get(currentReasonId);
|
||||
if (!newGLAccountId.equals(existingReasonToGLAccountMapping.getGlAccount().getId())) {
|
||||
final Optional<GLAccount> glAccount = accountRepository.findById(newGLAccountId);
|
||||
if (glAccount.isPresent()) {
|
||||
existingChargeOffReasonToGLAccountMapping.setGlAccount(glAccount.get());
|
||||
this.accountMappingRepository.saveAndFlush(existingChargeOffReasonToGLAccountMapping);
|
||||
existingReasonToGLAccountMapping.setGlAccount(glAccount.get());
|
||||
this.accountMappingRepository.saveAndFlush(existingReasonToGLAccountMapping);
|
||||
}
|
||||
}
|
||||
} // deleted payment type
|
||||
else {
|
||||
this.accountMappingRepository.delete(existingChargeOffReasonToGLAccountMapping);
|
||||
this.accountMappingRepository.delete(existingReasonToGLAccountMapping);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// only the newly added
|
||||
for (Map.Entry<Long, Long> entry : inputChargeOffReasonToGLAccountMap.entrySet().stream()
|
||||
.filter(e -> !existingChargeOffReasons.contains(e.getKey())).toList()) {
|
||||
saveChargeOffReasonToExpenseMapping(productId, entry.getKey(), entry.getValue(), portfolioProductType);
|
||||
for (Map.Entry<Long, Long> entry : inputReasonToGLAccountMap.entrySet().stream()
|
||||
.filter(e -> !existingReasons.contains(e.getKey())).toList()) {
|
||||
saveReasonToExpenseMapping(productId, entry.getKey(), entry.getValue(), portfolioProductType, cashAccountsForLoan);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void updateClassificationToGLAccountMappings(final JsonCommand command, final JsonElement element, final Long productId,
|
||||
final Map<String, Object> changes, final PortfolioProductType portfolioProductType,
|
||||
final LoanProductAccountingParams classificationParameter) {
|
||||
|
||||
final List<ProductToGLAccountMapping> existingClassificationToGLAccountMappings = classificationParameter
|
||||
.equals(LoanProductAccountingParams.CAPITALIZED_INCOME_CLASSIFICATION_TO_INCOME_ACCOUNT_MAPPINGS)
|
||||
? this.accountMappingRepository.findAllCapitalizedIncomeClassificationsMappings(productId,
|
||||
portfolioProductType.getValue())
|
||||
: this.accountMappingRepository.findAllBuyDownFeeClassificationsMappings(productId,
|
||||
portfolioProductType.getValue());
|
||||
|
||||
final JsonArray classificationToGLAccountMappingArray = this.fromApiJsonHelper
|
||||
.extractJsonArrayNamed(classificationParameter.getValue(), element);
|
||||
|
||||
final Map<Long, Long> inputClassificationToGLAccountMap = new HashMap<>();
|
||||
|
||||
final Set<Long> existingClassifications = new HashSet<>();
|
||||
if (classificationToGLAccountMappingArray != null) {
|
||||
if (changes != null) {
|
||||
changes.put(classificationParameter.getValue(), command.jsonFragment(classificationParameter.getValue()));
|
||||
}
|
||||
|
||||
for (int i = 0; i < classificationToGLAccountMappingArray.size(); i++) {
|
||||
final JsonObject jsonObject = classificationToGLAccountMappingArray.get(i).getAsJsonObject();
|
||||
final Long incomeGlAccountId = jsonObject.get(LoanProductAccountingParams.INCOME_ACCOUNT_ID.getValue()).getAsLong();
|
||||
final Long classificationCodeValueId = jsonObject.get(LoanProductAccountingParams.CLASSIFICATION_CODE_VALUE_ID.getValue())
|
||||
.getAsLong();
|
||||
inputClassificationToGLAccountMap.put(classificationCodeValueId, incomeGlAccountId);
|
||||
}
|
||||
|
||||
// If input map is empty, delete all existing mappings
|
||||
if (inputClassificationToGLAccountMap.isEmpty()) {
|
||||
this.accountMappingRepository.deleteAll(existingClassificationToGLAccountMappings);
|
||||
} else {
|
||||
for (final ProductToGLAccountMapping existingClassificationToGLAccountMapping : existingClassificationToGLAccountMappings) {
|
||||
final Long currentClassificationId = classificationParameter
|
||||
.equals(LoanProductAccountingParams.CAPITALIZED_INCOME_CLASSIFICATION_TO_INCOME_ACCOUNT_MAPPINGS)
|
||||
? existingClassificationToGLAccountMapping.getCapitalizedIncomeClassification().getId()
|
||||
: existingClassificationToGLAccountMapping.getBuydownFeeClassification().getId();
|
||||
|
||||
if (currentClassificationId != null) {
|
||||
existingClassifications.add(currentClassificationId);
|
||||
// update existing mappings (if required)
|
||||
if (inputClassificationToGLAccountMap.containsKey(currentClassificationId)) {
|
||||
final Long newGLAccountId = inputClassificationToGLAccountMap.get(currentClassificationId);
|
||||
if (!newGLAccountId.equals(existingClassificationToGLAccountMapping.getGlAccount().getId())) {
|
||||
final Optional<GLAccount> glAccount = accountRepository.findById(newGLAccountId);
|
||||
if (glAccount.isPresent()) {
|
||||
existingClassificationToGLAccountMapping.setGlAccount(glAccount.get());
|
||||
this.accountMappingRepository.saveAndFlush(existingClassificationToGLAccountMapping);
|
||||
}
|
||||
}
|
||||
} // deleted previous record
|
||||
else {
|
||||
this.accountMappingRepository.delete(existingClassificationToGLAccountMapping);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// only the newly added
|
||||
for (Map.Entry<Long, Long> entry : inputClassificationToGLAccountMap.entrySet().stream()
|
||||
.filter(e -> !existingClassifications.contains(e.getKey())).toList()) {
|
||||
saveClassificationToIncomeMapping(productId, entry.getKey(), entry.getValue(), portfolioProductType,
|
||||
classificationParameter);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -489,21 +604,70 @@ public class ProductToGLAccountMappingHelper {
|
||||
this.accountMappingRepository.saveAndFlush(accountMapping);
|
||||
}
|
||||
|
||||
private void saveChargeOffReasonToExpenseMapping(final Long productId, final Long reasonId, final Long expenseAccountId,
|
||||
final PortfolioProductType portfolioProductType) {
|
||||
private Predicate<? super ProductToGLAccountMapping> matching(final CashAccountsForLoan typeDef, final Long reasonId) {
|
||||
return switch (typeDef) {
|
||||
case CHARGE_OFF_EXPENSE -> (mapping) -> (mapping.getChargeOffReason() != null && mapping.getChargeOffReason().getId() != null
|
||||
&& mapping.getChargeOffReason().getId().equals(reasonId));
|
||||
case LOSSES_WRITTEN_OFF -> (mapping) -> (mapping.getWriteOffReason() != null && mapping.getWriteOffReason().getId() != null
|
||||
&& mapping.getWriteOffReason().getId().equals(reasonId));
|
||||
default -> throw new IllegalStateException("Unexpected value: " + typeDef);
|
||||
};
|
||||
}
|
||||
|
||||
private void saveReasonToExpenseMapping(final Long productId, final Long reasonId, final Long expenseAccountId,
|
||||
final PortfolioProductType portfolioProductType, final CashAccountsForLoan cashAccountsForLoan) {
|
||||
|
||||
final Optional<GLAccount> glAccount = accountRepository.findById(expenseAccountId);
|
||||
|
||||
final boolean reasonMappingExists = this.accountMappingRepository
|
||||
.findAllChargeOffReasonsMappings(productId, portfolioProductType.getValue()).stream()
|
||||
.anyMatch(mapping -> mapping.getChargeOffReason().getId().equals(reasonId));
|
||||
|
||||
final Optional<CodeValue> codeValueOptional = codeValueRepository.findById(reasonId);
|
||||
|
||||
if (glAccount.isPresent() && !reasonMappingExists && codeValueOptional.isPresent()) {
|
||||
final boolean reasonMappingExists = this.accountMappingRepository
|
||||
.findAllProductToGLAccountMappingsByProductIdAndProductTypeAndFinancialAccountType(productId,
|
||||
portfolioProductType.getValue(), cashAccountsForLoan.getValue())
|
||||
.stream().anyMatch(matching(cashAccountsForLoan, reasonId));
|
||||
|
||||
if (!reasonMappingExists && glAccount.isPresent() && codeValueOptional.isPresent()) {
|
||||
final ProductToGLAccountMapping accountMapping = new ProductToGLAccountMapping().setGlAccount(glAccount.get())
|
||||
.setProductId(productId).setProductType(portfolioProductType.getValue())
|
||||
.setFinancialAccountType(CashAccountsForLoan.CHARGE_OFF_EXPENSE.getValue()).setChargeOffReason(codeValueOptional.get());
|
||||
.setFinancialAccountType(cashAccountsForLoan.getValue());
|
||||
|
||||
switch (cashAccountsForLoan) {
|
||||
case CHARGE_OFF_EXPENSE -> accountMapping.setChargeOffReason(codeValueOptional.get());
|
||||
case LOSSES_WRITTEN_OFF -> accountMapping.setWriteOffReason(codeValueOptional.get());
|
||||
default -> throw new IllegalStateException("Unexpected value: " + cashAccountsForLoan);
|
||||
}
|
||||
|
||||
this.accountMappingRepository.saveAndFlush(accountMapping);
|
||||
}
|
||||
}
|
||||
|
||||
private void saveClassificationToIncomeMapping(final Long productId, final Long classificationId, final Long incomeAccountId,
|
||||
final PortfolioProductType portfolioProductType, final LoanProductAccountingParams classificationParameter) {
|
||||
|
||||
final Optional<GLAccount> glAccount = accountRepository.findById(incomeAccountId);
|
||||
|
||||
boolean classificationMappingExists = false;
|
||||
if (classificationParameter.equals(LoanProductAccountingParams.CAPITALIZED_INCOME_CLASSIFICATION_TO_INCOME_ACCOUNT_MAPPINGS)) {
|
||||
classificationMappingExists = this.accountMappingRepository
|
||||
.findAllCapitalizedIncomeClassificationsMappings(productId, portfolioProductType.getValue()).stream()
|
||||
.anyMatch(mapping -> mapping.getCapitalizedIncomeClassification().getId().equals(classificationId));
|
||||
} else {
|
||||
classificationMappingExists = this.accountMappingRepository
|
||||
.findAllBuyDownFeeClassificationsMappings(productId, portfolioProductType.getValue()).stream()
|
||||
.anyMatch(mapping -> mapping.getBuydownFeeClassification().getId().equals(classificationId));
|
||||
}
|
||||
|
||||
final Optional<CodeValue> codeValueOptional = codeValueRepository.findById(classificationId);
|
||||
|
||||
if (glAccount.isPresent() && !classificationMappingExists && codeValueOptional.isPresent()) {
|
||||
final ProductToGLAccountMapping accountMapping = new ProductToGLAccountMapping().setGlAccount(glAccount.get())
|
||||
.setProductId(productId).setProductType(portfolioProductType.getValue())
|
||||
.setFinancialAccountType(CashAccountsForLoan.CLASSIFICATION_INCOME.getValue());
|
||||
|
||||
if (classificationParameter.equals(LoanProductAccountingParams.CAPITALIZED_INCOME_CLASSIFICATION_TO_INCOME_ACCOUNT_MAPPINGS)) {
|
||||
accountMapping.setCapitalizedIncomeClassification(codeValueOptional.get());
|
||||
} else {
|
||||
accountMapping.setBuydownFeeClassification(codeValueOptional.get());
|
||||
}
|
||||
|
||||
this.accountMappingRepository.saveAndFlush(accountMapping);
|
||||
}
|
||||
@@ -555,30 +719,42 @@ public class ProductToGLAccountMappingHelper {
|
||||
return glAccount;
|
||||
}
|
||||
|
||||
public void deleteProductToGLAccountMapping(final Long loanProductId, final PortfolioProductType portfolioProductType) {
|
||||
final List<ProductToGLAccountMapping> productToGLAccountMappings = this.accountMappingRepository
|
||||
.findByProductIdAndProductType(loanProductId, portfolioProductType.getValue());
|
||||
if (productToGLAccountMappings != null && productToGLAccountMappings.size() > 0) {
|
||||
this.accountMappingRepository.deleteAllInBatch(productToGLAccountMappings);
|
||||
public void deleteProductToGLAccountMapping(final Long loanProductId, final PortfolioProductType portfolioProductType,
|
||||
final int accountTypeId) {
|
||||
final ProductToGLAccountMapping accountMapping = this.accountMappingRepository.findCoreProductToFinAccountMapping(loanProductId,
|
||||
portfolioProductType.getValue(), accountTypeId);
|
||||
if (accountMapping != null && accountMapping.getGlAccount() != null) {
|
||||
this.accountMappingRepository.delete(accountMapping);
|
||||
}
|
||||
}
|
||||
|
||||
public void validateChargeOffMappingsInDatabase(final List<JsonObject> mappings) {
|
||||
final List<ApiParameterError> validationErrors = new ArrayList<>();
|
||||
public void deleteProductToGLAccountMapping(final Long loanProductId, final PortfolioProductType portfolioProductType) {
|
||||
final List<ProductToGLAccountMapping> productToGLAccountMappings = this.accountMappingRepository
|
||||
.findByProductIdAndProductType(loanProductId, portfolioProductType.getValue());
|
||||
if (productToGLAccountMappings != null && !productToGLAccountMappings.isEmpty()) {
|
||||
this.accountMappingRepository.deleteAll(productToGLAccountMappings);
|
||||
}
|
||||
}
|
||||
|
||||
public void validateWriteOffMappingsInDatabase(final List<ApiParameterError> validationErrors, final List<JsonObject> mappings) {
|
||||
for (JsonObject jsonObject : mappings) {
|
||||
final Long writeOffReasonCodeValueId = this.fromApiJsonHelper
|
||||
.extractLongNamed(LoanProductAccountingParams.WRITE_OFF_REASON_CODE_VALUE_ID.getValue(), jsonObject);
|
||||
|
||||
// Validation: writeOffReasonCodeValueId must exist in the database
|
||||
CodeValue codeValue = this.codeValueRepository.findByCodeNameAndId("WriteOffReasons", writeOffReasonCodeValueId);
|
||||
if (codeValue == null) {
|
||||
validationErrors.add(ApiParameterError.parameterError("validation.msg.writeoffreason.invalid",
|
||||
"Write-off reason with ID " + writeOffReasonCodeValueId + " does not exist",
|
||||
LoanProductAccountingParams.WRITE_OFF_REASON_TO_EXPENSE_ACCOUNT_MAPPINGS.getValue()));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void validateGLAccountInDatabase(final List<ApiParameterError> validationErrors, final List<JsonObject> mappings) {
|
||||
for (JsonObject jsonObject : mappings) {
|
||||
final Long expenseGlAccountId = this.fromApiJsonHelper
|
||||
.extractLongNamed(LoanProductAccountingParams.EXPENSE_GL_ACCOUNT_ID.getValue(), jsonObject);
|
||||
final Long chargeOffReasonCodeValueId = this.fromApiJsonHelper
|
||||
.extractLongNamed(LoanProductAccountingParams.CHARGE_OFF_REASON_CODE_VALUE_ID.getValue(), jsonObject);
|
||||
|
||||
// Validation: chargeOffReasonCodeValueId must exist in the database
|
||||
CodeValue codeValue = this.codeValueRepository.findByCodeNameAndId("ChargeOffReasons", chargeOffReasonCodeValueId);
|
||||
if (codeValue == null) {
|
||||
validationErrors.add(ApiParameterError.parameterError("validation.msg.chargeoffreason.invalid",
|
||||
"Charge-off reason with ID " + chargeOffReasonCodeValueId + " does not exist",
|
||||
LoanProductAccountingParams.CHARGE_OFF_REASON_TO_EXPENSE_ACCOUNT_MAPPINGS.getValue()));
|
||||
}
|
||||
|
||||
// Validation: expenseGLAccountId must exist as a valid Expense GL account
|
||||
final Optional<GLAccount> glAccount = accountRepository.findById(expenseGlAccountId);
|
||||
@@ -590,10 +766,60 @@ public class ProductToGLAccountMappingHelper {
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void validateChargeOffMappingsInDatabase(final List<ApiParameterError> validationErrors, final List<JsonObject> mappings) {
|
||||
|
||||
for (JsonObject jsonObject : mappings) {
|
||||
final Long chargeOffReasonCodeValueId = this.fromApiJsonHelper
|
||||
.extractLongNamed(LoanProductAccountingParams.CHARGE_OFF_REASON_CODE_VALUE_ID.getValue(), jsonObject);
|
||||
|
||||
// Validation: chargeOffReasonCodeValueId must exist in the database
|
||||
CodeValue codeValue = this.codeValueRepository.findByCodeNameAndId("ChargeOffReasons", chargeOffReasonCodeValueId);
|
||||
if (codeValue == null) {
|
||||
validationErrors.add(ApiParameterError.parameterError("validation.msg.chargeoffreason.invalid",
|
||||
"Charge-off reason with ID " + chargeOffReasonCodeValueId + " does not exist",
|
||||
LoanProductAccountingParams.CHARGE_OFF_REASON_TO_EXPENSE_ACCOUNT_MAPPINGS.getValue()));
|
||||
}
|
||||
}
|
||||
|
||||
// Throw all collected validation errors, if any
|
||||
if (!validationErrors.isEmpty()) {
|
||||
throw new PlatformApiDataValidationException(validationErrors);
|
||||
}
|
||||
}
|
||||
|
||||
public void validateClassificationMappingsInDatabase(final List<JsonObject> mappings, final String dataCodeName) {
|
||||
final List<ApiParameterError> validationErrors = new ArrayList<>();
|
||||
|
||||
for (JsonObject jsonObject : mappings) {
|
||||
final Long incomeGlAccountId = this.fromApiJsonHelper.extractLongNamed(LoanProductAccountingParams.INCOME_ACCOUNT_ID.getValue(),
|
||||
jsonObject);
|
||||
final Long classificationCodeValueId = this.fromApiJsonHelper
|
||||
.extractLongNamed(LoanProductAccountingParams.CLASSIFICATION_CODE_VALUE_ID.getValue(), jsonObject);
|
||||
|
||||
// Validation: classificationCodeValueId must exist in the database
|
||||
final CodeValue codeValue = this.codeValueRepository.findByCodeNameAndId(dataCodeName, classificationCodeValueId);
|
||||
if (codeValue == null) {
|
||||
validationErrors.add(ApiParameterError.parameterError("validation.msg.classification.invalid",
|
||||
"Classification with ID " + classificationCodeValueId + " does not exist", dataCodeName));
|
||||
}
|
||||
|
||||
// Validation: expenseGLAccountId must exist as a valid Expense GL account
|
||||
final Optional<GLAccount> glAccount = accountRepository.findById(incomeGlAccountId);
|
||||
|
||||
if (glAccount.isEmpty() || !GLAccountType.fromInt(glAccount.get().getType()).isIncomeType()) {
|
||||
validationErrors.add(ApiParameterError.parameterError("validation.msg.glaccount.not.found",
|
||||
"GL Account with ID " + incomeGlAccountId + " does not exist or is not an Income GL account",
|
||||
LoanProductAccountingParams.INCOME_ACCOUNT_ID.getValue()));
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
// Throw all collected validation errors, if any
|
||||
if (!validationErrors.isEmpty()) {
|
||||
throw new PlatformApiDataValidationException(validationErrors);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
+8
@@ -20,9 +20,12 @@ package org.apache.fineract.accounting.producttoaccountmapping.service;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import org.apache.fineract.accounting.common.AccountingConstants.LoanProductAccountingParams;
|
||||
import org.apache.fineract.accounting.producttoaccountmapping.data.ChargeOffReasonToGLAccountMapper;
|
||||
import org.apache.fineract.accounting.producttoaccountmapping.data.ChargeToGLAccountMapper;
|
||||
import org.apache.fineract.accounting.producttoaccountmapping.data.ClassificationToGLAccountData;
|
||||
import org.apache.fineract.accounting.producttoaccountmapping.data.PaymentTypeToGLAccountMapper;
|
||||
import org.apache.fineract.accounting.producttoaccountmapping.data.WriteOffReasonsToExpenseAccountMapper;
|
||||
|
||||
public interface ProductToGLAccountMappingReadPlatformService {
|
||||
|
||||
@@ -49,4 +52,9 @@ public interface ProductToGLAccountMappingReadPlatformService {
|
||||
List<ChargeToGLAccountMapper> fetchFeeToIncomeAccountMappingsForShareProduct(Long productId);
|
||||
|
||||
List<ChargeOffReasonToGLAccountMapper> fetchChargeOffReasonMappingsForLoanProduct(Long loanProductId);
|
||||
|
||||
List<WriteOffReasonsToExpenseAccountMapper> fetchWriteOffReasonMappingsForLoanProduct(Long loanProductId);
|
||||
|
||||
List<ClassificationToGLAccountData> fetchClassificationMappingsForLoanProduct(Long loanProductId,
|
||||
LoanProductAccountingParams classificationParameter);
|
||||
}
|
||||
|
||||
+72
-11
@@ -30,6 +30,7 @@ import org.apache.fineract.accounting.common.AccountingConstants.CashAccountsFor
|
||||
import org.apache.fineract.accounting.common.AccountingConstants.CashAccountsForSavings;
|
||||
import org.apache.fineract.accounting.common.AccountingConstants.CashAccountsForShares;
|
||||
import org.apache.fineract.accounting.common.AccountingConstants.LoanProductAccountingDataParams;
|
||||
import org.apache.fineract.accounting.common.AccountingConstants.LoanProductAccountingParams;
|
||||
import org.apache.fineract.accounting.common.AccountingConstants.SavingProductAccountingDataParams;
|
||||
import org.apache.fineract.accounting.common.AccountingConstants.SharesProductAccountingParams;
|
||||
import org.apache.fineract.accounting.common.AccountingRuleType;
|
||||
@@ -37,14 +38,16 @@ import org.apache.fineract.accounting.common.AccountingValidations;
|
||||
import org.apache.fineract.accounting.glaccount.data.GLAccountData;
|
||||
import org.apache.fineract.accounting.producttoaccountmapping.data.ChargeOffReasonToGLAccountMapper;
|
||||
import org.apache.fineract.accounting.producttoaccountmapping.data.ChargeToGLAccountMapper;
|
||||
import org.apache.fineract.accounting.producttoaccountmapping.data.ClassificationToGLAccountData;
|
||||
import org.apache.fineract.accounting.producttoaccountmapping.data.PaymentTypeToGLAccountMapper;
|
||||
import org.apache.fineract.accounting.producttoaccountmapping.data.WriteOffReasonsToExpenseAccountMapper;
|
||||
import org.apache.fineract.accounting.producttoaccountmapping.domain.ProductToGLAccountMapping;
|
||||
import org.apache.fineract.accounting.producttoaccountmapping.domain.ProductToGLAccountMappingRepository;
|
||||
import org.apache.fineract.infrastructure.codes.data.CodeValueData;
|
||||
import org.apache.fineract.infrastructure.codes.mapper.CodeValueMapper;
|
||||
import org.apache.fineract.portfolio.PortfolioProductType;
|
||||
import org.apache.fineract.portfolio.charge.data.ChargeData;
|
||||
import org.apache.fineract.portfolio.paymenttype.data.PaymentTypeData;
|
||||
import org.springframework.jdbc.core.JdbcTemplate;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
@Slf4j
|
||||
@@ -52,9 +55,8 @@ import org.springframework.stereotype.Service;
|
||||
@RequiredArgsConstructor
|
||||
public class ProductToGLAccountMappingReadPlatformServiceImpl implements ProductToGLAccountMappingReadPlatformService {
|
||||
|
||||
private final JdbcTemplate jdbcTemplate;
|
||||
|
||||
private final ProductToGLAccountMappingRepository productToGLAccountMappingRepository;
|
||||
private final CodeValueMapper codeValueMapper;
|
||||
|
||||
@Override
|
||||
public Map<String, Object> fetchAccountMappingDetailsForLoanProduct(final Long loanProductId, final Integer accountingType) {
|
||||
@@ -167,6 +169,14 @@ public class ProductToGLAccountMappingReadPlatformServiceImpl implements Product
|
||||
} else if (glAccountForLoan.equals(AccrualAccountsForLoan.INCOME_FROM_GOODWILL_CREDIT_PENALTY)) {
|
||||
accountMappingDetails.put(LoanProductAccountingDataParams.INCOME_FROM_GOODWILL_CREDIT_PENALTY.getValue(),
|
||||
gLAccountData);
|
||||
} else if (glAccountForLoan.equals(AccrualAccountsForLoan.DEFERRED_INCOME_LIABILITY)) {
|
||||
accountMappingDetails.put(LoanProductAccountingDataParams.DEFERRED_INCOME_LIABILITY.getValue(), gLAccountData);
|
||||
} else if (glAccountForLoan.equals(AccrualAccountsForLoan.INCOME_FROM_CAPITALIZATION)) {
|
||||
accountMappingDetails.put(LoanProductAccountingDataParams.INCOME_FROM_CAPITALIZATION.getValue(), gLAccountData);
|
||||
} else if (glAccountForLoan.equals(AccrualAccountsForLoan.BUY_DOWN_EXPENSE)) {
|
||||
accountMappingDetails.put(LoanProductAccountingDataParams.BUY_DOWN_EXPENSE.getValue(), gLAccountData);
|
||||
} else if (glAccountForLoan.equals(AccrualAccountsForLoan.INCOME_FROM_BUY_DOWN)) {
|
||||
accountMappingDetails.put(LoanProductAccountingDataParams.INCOME_FROM_BUY_DOWN.getValue(), gLAccountData);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -275,14 +285,7 @@ public class ProductToGLAccountMappingReadPlatformServiceImpl implements Product
|
||||
final String glAccountName = mapping.getGlAccount().getName();
|
||||
final String glCode = mapping.getGlAccount().getGlCode();
|
||||
final GLAccountData chargeOffExpenseAccount = new GLAccountData().setId(glAccountId).setName(glAccountName).setGlCode(glCode);
|
||||
final Long chargeOffReasonId = mapping.getChargeOffReason().getId();
|
||||
final String codeValue = mapping.getChargeOffReason().getLabel();
|
||||
final String codeDescription = mapping.getChargeOffReason().getDescription();
|
||||
final Integer orderPosition = mapping.getChargeOffReason().getPosition();
|
||||
final boolean isActive = mapping.getChargeOffReason().isActive();
|
||||
final boolean isMandatory = mapping.getChargeOffReason().isMandatory();
|
||||
final CodeValueData chargeOffReasonsCodeValue = CodeValueData.builder().id(chargeOffReasonId).name(codeValue)
|
||||
.description(codeDescription).position(orderPosition).active(isActive).mandatory(isMandatory).build();
|
||||
final CodeValueData chargeOffReasonsCodeValue = codeValueMapper.map(mapping.getChargeOffReason());
|
||||
|
||||
final ChargeOffReasonToGLAccountMapper chargeOffReasonToGLAccountMapper = new ChargeOffReasonToGLAccountMapper()
|
||||
.setChargeOffReasonCodeValue(chargeOffReasonsCodeValue).setExpenseAccount(chargeOffExpenseAccount);
|
||||
@@ -291,6 +294,51 @@ public class ProductToGLAccountMappingReadPlatformServiceImpl implements Product
|
||||
return chargeOffReasonToGLAccountMappers;
|
||||
}
|
||||
|
||||
private List<WriteOffReasonsToExpenseAccountMapper> fetchWriteOffReasonMappings(final PortfolioProductType portfolioProductType,
|
||||
final Long loanProductId) {
|
||||
final List<ProductToGLAccountMapping> mappings = productToGLAccountMappingRepository.findAllWriteOffReasonsMappings(loanProductId,
|
||||
portfolioProductType.getValue());
|
||||
List<WriteOffReasonsToExpenseAccountMapper> writeOffReasonsToExpenseAccountMappers = mappings.isEmpty() ? null : new ArrayList<>();
|
||||
for (final ProductToGLAccountMapping mapping : mappings) {
|
||||
final String glCode = String.valueOf(mapping.getGlAccount().getId());
|
||||
final String writeOffReasonId = String.valueOf(mapping.getWriteOffReason().getId());
|
||||
|
||||
final WriteOffReasonsToExpenseAccountMapper writeOffReasonToGLAccountMapper = new WriteOffReasonsToExpenseAccountMapper()
|
||||
.setWriteOffReasonCodeValueId(writeOffReasonId).setExpenseAccountId(glCode);
|
||||
writeOffReasonsToExpenseAccountMappers.add(writeOffReasonToGLAccountMapper);
|
||||
}
|
||||
return writeOffReasonsToExpenseAccountMappers;
|
||||
}
|
||||
|
||||
private List<ClassificationToGLAccountData> fetchClassificationMappings(final PortfolioProductType portfolioProductType,
|
||||
final Long loanProductId, LoanProductAccountingParams classificationParameter) {
|
||||
final List<ProductToGLAccountMapping> mappings = classificationParameter
|
||||
.equals(LoanProductAccountingParams.CAPITALIZED_INCOME_CLASSIFICATION_TO_INCOME_ACCOUNT_MAPPINGS)
|
||||
? productToGLAccountMappingRepository.findAllCapitalizedIncomeClassificationsMappings(loanProductId,
|
||||
portfolioProductType.getValue())
|
||||
: productToGLAccountMappingRepository.findAllBuyDownFeeClassificationsMappings(loanProductId,
|
||||
portfolioProductType.getValue());
|
||||
|
||||
productToGLAccountMappingRepository.findAllChargeOffReasonsMappings(loanProductId, portfolioProductType.getValue());
|
||||
List<ClassificationToGLAccountData> classificationToGLAccountMappers = mappings.isEmpty() ? null : new ArrayList<>();
|
||||
for (final ProductToGLAccountMapping mapping : mappings) {
|
||||
final Long glAccountId = mapping.getGlAccount().getId();
|
||||
final String glAccountName = mapping.getGlAccount().getName();
|
||||
final String glCode = mapping.getGlAccount().getGlCode();
|
||||
final GLAccountData glAccountData = new GLAccountData().setId(glAccountId).setName(glAccountName).setGlCode(glCode);
|
||||
|
||||
final CodeValueData classificationCodeValue = classificationParameter
|
||||
.equals(LoanProductAccountingParams.CAPITALIZED_INCOME_CLASSIFICATION_TO_INCOME_ACCOUNT_MAPPINGS)
|
||||
? codeValueMapper.map(mapping.getCapitalizedIncomeClassification())
|
||||
: codeValueMapper.map(mapping.getBuydownFeeClassification());
|
||||
|
||||
final ClassificationToGLAccountData classificationToGLAccountMapper = new ClassificationToGLAccountData()
|
||||
.setClassificationCodeValue(classificationCodeValue).setIncomeAccount(glAccountData);
|
||||
classificationToGLAccountMappers.add(classificationToGLAccountMapper);
|
||||
}
|
||||
return classificationToGLAccountMappers;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Map<String, Object> fetchAccountMappingDetailsForShareProduct(Long productId, Integer accountingType) {
|
||||
|
||||
@@ -336,6 +384,17 @@ public class ProductToGLAccountMappingReadPlatformServiceImpl implements Product
|
||||
return fetchChargeOffReasonMappings(PortfolioProductType.LOAN, loanProductId);
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<WriteOffReasonsToExpenseAccountMapper> fetchWriteOffReasonMappingsForLoanProduct(Long loanProductId) {
|
||||
return fetchWriteOffReasonMappings(PortfolioProductType.LOAN, loanProductId);
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<ClassificationToGLAccountData> fetchClassificationMappingsForLoanProduct(Long loanProductId,
|
||||
LoanProductAccountingParams classificationParameter) {
|
||||
return fetchClassificationMappings(PortfolioProductType.LOAN, loanProductId, classificationParameter);
|
||||
}
|
||||
|
||||
private Map<String, Object> setAccrualPeriodicSavingsProductToGLAccountMaps(final List<ProductToGLAccountMapping> mappings) {
|
||||
final Map<String, Object> accountMappingDetails = new LinkedHashMap<>(8);
|
||||
|
||||
@@ -350,6 +409,8 @@ public class ProductToGLAccountMappingReadPlatformServiceImpl implements Product
|
||||
// Assets
|
||||
if (glAccountForSavings.equals(AccrualAccountsForSavings.SAVINGS_REFERENCE)) {
|
||||
accountMappingDetails.put(SavingProductAccountingDataParams.SAVINGS_REFERENCE.getValue(), glAccountData);
|
||||
} else if (glAccountForSavings.equals(AccrualAccountsForSavings.INTEREST_RECEIVABLE)) {
|
||||
accountMappingDetails.put(SavingProductAccountingDataParams.INTEREST_RECEIVABLE.getValue(), glAccountData);
|
||||
} else if (glAccountForSavings.equals(AccrualAccountsForSavings.OVERDRAFT_PORTFOLIO_CONTROL)) {
|
||||
accountMappingDetails.put(SavingProductAccountingDataParams.OVERDRAFT_PORTFOLIO_CONTROL.getValue(), glAccountData);
|
||||
} else if (glAccountForSavings.equals(AccrualAccountsForSavings.FEES_RECEIVABLE)) {
|
||||
|
||||
+2
-1
@@ -30,7 +30,8 @@ public interface ProductToGLAccountMappingWritePlatformService {
|
||||
void createSavingProductToGLAccountMapping(Long savingProductId, JsonCommand command, DepositAccountType accountType);
|
||||
|
||||
Map<String, Object> updateLoanProductToGLAccountMapping(Long loanProductId, JsonCommand command, boolean accountingRuleChanged,
|
||||
AccountingRuleType accountingRuleTypeId);
|
||||
AccountingRuleType accountingRuleTypeId, boolean enableIncomeCapitalization, boolean enableBuyDownFee,
|
||||
boolean merchantBuyDownFee);
|
||||
|
||||
Map<String, Object> updateSavingsProductToGLAccountMapping(Long savingsProductId, JsonCommand command, boolean accountingRuleChanged,
|
||||
int accountingRuleTypeId, DepositAccountType accountType);
|
||||
|
||||
+4
@@ -263,6 +263,10 @@ public class SavingsProductToGLAccountMappingHelper extends ProductToGLAccountMa
|
||||
savingsProductId, AccrualAccountsForSavings.FEES_RECEIVABLE.getValue(),
|
||||
AccrualAccountsForSavings.FEES_RECEIVABLE.toString(), changes);
|
||||
|
||||
mergeSavingsToAssetAccountMappingChanges(element, SavingProductAccountingParams.INTEREST_RECEIVABLE.getValue(),
|
||||
savingsProductId, AccrualAccountsForSavings.INTEREST_RECEIVABLE.getValue(),
|
||||
AccrualAccountsForSavings.INTEREST_RECEIVABLE.toString(), changes);
|
||||
|
||||
mergeSavingsToAssetAccountMappingChanges(element, SavingProductAccountingParams.PENALTIES_RECEIVABLE.getValue(),
|
||||
savingsProductId, AccrualAccountsForSavings.PENALTIES_RECEIVABLE.getValue(),
|
||||
AccrualAccountsForSavings.PENALTIES_RECEIVABLE.toString(), changes);
|
||||
|
||||
+1
-1
@@ -262,7 +262,7 @@ public class ProvisioningEntriesReadPlatformServiceImpl implements ProvisioningE
|
||||
LoanProductProvisioningEntryRowMapper mapper = new LoanProductProvisioningEntryRowMapper();
|
||||
final String sql = "select " + mapper.getSchema() + " where entry.criteria_id = ?";
|
||||
Collection<LoanProductProvisioningEntryData> entries = this.jdbcTemplate.query(sql, mapper, criteriaId); // NOSONAR
|
||||
if (entries != null && entries.size() > 0) {
|
||||
if (entries != null && !entries.isEmpty()) {
|
||||
Long entryId = ((LoanProductProvisioningEntryData) entries.toArray()[0]).getHistoryId();
|
||||
ProvisioningEntryDataMapper mapper1 = new ProvisioningEntryDataMapper();
|
||||
final String sql1 = "select " + mapper1.getSchema() + " where entry.id = ?";
|
||||
|
||||
+12
-5
@@ -26,10 +26,17 @@ import java.util.Set;
|
||||
***/
|
||||
public enum AccountingRuleJsonInputParams {
|
||||
|
||||
ID("id"), OFFICE_ID("officeId"), ACCOUNT_TO_DEBIT("accountToDebit"), ACCOUNT_TO_CREDIT("accountToCredit"), NAME("name"), DESCRIPTION(
|
||||
"description"), SYSTEM_DEFINED("systemDefined"), DEBIT_ACCOUNT_TAGS("debitTags"), CREDIT_ACCOUNT_TAGS(
|
||||
"creditTags"), ALLOW_MULTIPLE_CREDIT_ENTRIES(
|
||||
"allowMultipleCreditEntries"), ALLOW_MULTIPLE_DEBIT_ENTRIES("allowMultipleDebitEntries");
|
||||
ID("id"), //
|
||||
OFFICE_ID("officeId"), //
|
||||
ACCOUNT_TO_DEBIT("accountToDebit"), //
|
||||
ACCOUNT_TO_CREDIT("accountToCredit"), //
|
||||
NAME("name"), //
|
||||
DESCRIPTION("description"), //
|
||||
SYSTEM_DEFINED("systemDefined"), //
|
||||
DEBIT_ACCOUNT_TAGS("debitTags"), //
|
||||
CREDIT_ACCOUNT_TAGS("creditTags"), //
|
||||
ALLOW_MULTIPLE_CREDIT_ENTRIES("allowMultipleCreditEntries"), //
|
||||
ALLOW_MULTIPLE_DEBIT_ENTRIES("allowMultipleDebitEntries"); //
|
||||
|
||||
private final String value;
|
||||
|
||||
@@ -51,7 +58,7 @@ public enum AccountingRuleJsonInputParams {
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return name().toString().replace("_", " ");
|
||||
return name().replace("_", " ");
|
||||
}
|
||||
|
||||
public String getValue() {
|
||||
|
||||
+2
-2
@@ -52,9 +52,9 @@ public class AccountingRuleData {
|
||||
|
||||
// template
|
||||
@SuppressWarnings("unused")
|
||||
private List<OfficeData> allowedOffices = new ArrayList<OfficeData>();
|
||||
private List<OfficeData> allowedOffices = new ArrayList<>();
|
||||
@SuppressWarnings("unused")
|
||||
private List<GLAccountData> allowedAccounts = new ArrayList<GLAccountData>();
|
||||
private List<GLAccountData> allowedAccounts = new ArrayList<>();
|
||||
@SuppressWarnings("unused")
|
||||
private Collection<CodeValueData> allowedCreditTagOptions;
|
||||
@SuppressWarnings("unused")
|
||||
|
||||
+3
-4
@@ -138,10 +138,9 @@ public class AccountingRule extends AbstractPersistableCustom<Long> {
|
||||
if (this.accountToCredit == null) {
|
||||
this.allowMultipleCreditEntries = newValue;
|
||||
}
|
||||
} else if (paramName.equals(AccountingRuleJsonInputParams.ALLOW_MULTIPLE_DEBIT_ENTRIES.getValue())) {
|
||||
if (this.accountToDebit == null) {
|
||||
this.allowMultipleDebitEntries = newValue;
|
||||
}
|
||||
} else if (paramName.equals(AccountingRuleJsonInputParams.ALLOW_MULTIPLE_DEBIT_ENTRIES.getValue())
|
||||
&& this.accountToDebit == null) {
|
||||
this.allowMultipleDebitEntries = newValue;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+8
-7
@@ -29,24 +29,25 @@ public class AccountingRuleInvalidException extends AbstractPlatformDomainRuleEx
|
||||
/*** enum of reasons for invalid Accounting Closure **/
|
||||
public enum GlClosureInvalidReason {
|
||||
|
||||
FUTURE_DATE, ACCOUNTING_CLOSED;
|
||||
FUTURE_DATE, //
|
||||
ACCOUNTING_CLOSED; //
|
||||
|
||||
public String errorMessage() {
|
||||
if (name().toString().equalsIgnoreCase("FUTURE_DATE")) {
|
||||
if (name().equalsIgnoreCase("FUTURE_DATE")) {
|
||||
return "Accounting closures cannot be made for a future date";
|
||||
} else if (name().toString().equalsIgnoreCase("ACCOUNTING_CLOSED")) {
|
||||
} else if (name().equalsIgnoreCase("ACCOUNTING_CLOSED")) {
|
||||
return "Accounting Closure for this branch has already been defined for a greater date";
|
||||
}
|
||||
return name().toString();
|
||||
return name();
|
||||
}
|
||||
|
||||
public String errorCode() {
|
||||
if (name().toString().equalsIgnoreCase("FUTURE_DATE")) {
|
||||
if (name().equalsIgnoreCase("FUTURE_DATE")) {
|
||||
return "error.msg.glclosure.invalid.future.date";
|
||||
} else if (name().toString().equalsIgnoreCase("ACCOUNTING_CLOSED")) {
|
||||
} else if (name().equalsIgnoreCase("ACCOUNTING_CLOSED")) {
|
||||
return "error.msg.glclosure.invalid.accounting.closed";
|
||||
}
|
||||
return name().toString();
|
||||
return name();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+2
-2
@@ -111,8 +111,8 @@ public class AccountingRuleWritePlatformServiceJpaRepositoryImpl implements Acco
|
||||
// get the GL Accounts or tags to Debit and Credit
|
||||
final String[] debitTags = command.arrayValueOfParameterNamed(AccountingRuleJsonInputParams.DEBIT_ACCOUNT_TAGS.getValue());
|
||||
final String[] creditTags = command.arrayValueOfParameterNamed(AccountingRuleJsonInputParams.CREDIT_ACCOUNT_TAGS.getValue());
|
||||
final Set<String> incomingDebitTags = debitTags == null ? new HashSet<String>() : new HashSet<>(Arrays.asList(debitTags));
|
||||
final Set<String> incomingCreditTags = creditTags == null ? new HashSet<String>() : new HashSet<>(Arrays.asList(creditTags));
|
||||
final Set<String> incomingDebitTags = debitTags == null ? new HashSet<>() : new HashSet<>(Arrays.asList(debitTags));
|
||||
final Set<String> incomingCreditTags = creditTags == null ? new HashSet<>() : new HashSet<>(Arrays.asList(creditTags));
|
||||
final Long accountToDebitId = command.longValueOfParameterNamed(AccountingRuleJsonInputParams.ACCOUNT_TO_DEBIT.getValue());
|
||||
final Long accountToCreditId = command.longValueOfParameterNamed(AccountingRuleJsonInputParams.ACCOUNT_TO_CREDIT.getValue());
|
||||
|
||||
|
||||
+1
-1
@@ -25,7 +25,7 @@ public abstract class JournalEntryBusinessEvent extends AbstractBusinessEvent<Jo
|
||||
|
||||
private static final String CATEGORY = "Accounting";
|
||||
|
||||
public JournalEntryBusinessEvent(JournalEntry value) {
|
||||
protected JournalEntryBusinessEvent(JournalEntry value) {
|
||||
super(value);
|
||||
}
|
||||
|
||||
|
||||
@@ -1,51 +0,0 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!--
|
||||
|
||||
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.
|
||||
|
||||
-->
|
||||
|
||||
|
||||
<persistence version="2.0"
|
||||
xmlns="http://java.sun.com/xml/ns/persistence" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://java.sun.com/xml/ns/persistence http://java.sun.com/xml/ns/persistence/persistence_2_0.xsd">
|
||||
|
||||
<!-- This file is only used for static weaving, nothing more. -->
|
||||
<!-- You can find the runtime configuration in the JPAConfig class -->
|
||||
<persistence-unit name="jpa-pu" transaction-type="RESOURCE_LOCAL">
|
||||
<provider>org.eclipse.persistence.jpa.PersistenceProvider</provider>
|
||||
<!-- Fineract core module -->
|
||||
<class>org.apache.fineract.accounting.glaccount.domain.GLAccount</class>
|
||||
<class>org.apache.fineract.infrastructure.codes.domain.Code</class>
|
||||
<class>org.apache.fineract.infrastructure.codes.domain.CodeValue</class>
|
||||
<class>org.apache.fineract.infrastructure.core.domain.AbstractPersistableCustom</class>
|
||||
<class>org.apache.fineract.organisation.office.domain.Office</class>
|
||||
<class>org.apache.fineract.portfolio.paymenttype.domain.PaymentType</class>
|
||||
<class>org.apache.fineract.portfolio.paymentdetail.domain.PaymentDetail</class>
|
||||
<class>org.apache.fineract.portfolio.tax.domain.TaxComponent</class>
|
||||
<class>org.apache.fineract.portfolio.tax.domain.TaxComponentHistory</class>
|
||||
<class>org.apache.fineract.portfolio.tax.domain.TaxGroup</class>
|
||||
<class>org.apache.fineract.portfolio.tax.domain.TaxGroupMappings</class>
|
||||
<!-- Fineract Charge module -->
|
||||
<class>org.apache.fineract.portfolio.charge.domain.Charge</class>
|
||||
<exclude-unlisted-classes>false</exclude-unlisted-classes>
|
||||
<properties>
|
||||
<property name="eclipselink.weaving" value="static" />
|
||||
</properties>
|
||||
</persistence-unit>
|
||||
</persistence>
|
||||
+52
-39
@@ -22,56 +22,69 @@
|
||||
|
||||
|
||||
<persistence version="2.0"
|
||||
xmlns="http://java.sun.com/xml/ns/persistence" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://java.sun.com/xml/ns/persistence http://java.sun.com/xml/ns/persistence/persistence_2_0.xsd">
|
||||
xmlns="http://java.sun.com/xml/ns/persistence"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://java.sun.com/xml/ns/persistence http://java.sun.com/xml/ns/persistence/persistence_2_0.xsd">
|
||||
|
||||
<!-- This file is only used for static weaving, nothing more. -->
|
||||
<!-- You can find the runtime configuration in the JPAConfig class -->
|
||||
<persistence-unit name="jpa-pu" transaction-type="RESOURCE_LOCAL">
|
||||
<provider>org.eclipse.persistence.jpa.PersistenceProvider</provider>
|
||||
<!-- Fineract core module -->
|
||||
<class>org.apache.fineract.accounting.glaccount.domain.GLAccount</class>
|
||||
<class>org.apache.fineract.accounting.journalentry.domain.JournalEntry</class>
|
||||
<class>org.apache.fineract.infrastructure.core.domain.AbstractPersistableCustom</class>
|
||||
<class>org.apache.fineract.infrastructure.core.domain.AbstractAuditableWithUTCDateTimeCustom</class>
|
||||
<class>org.apache.fineract.infrastructure.codes.domain.Code</class>
|
||||
<class>org.apache.fineract.infrastructure.codes.domain.CodeValue</class>
|
||||
<class>org.apache.fineract.infrastructure.documentmanagement.domain.Image</class>
|
||||
<class>org.apache.fineract.organisation.staff.domain.Staff</class>
|
||||
<class>org.apache.fineract.organisation.office.domain.Office</class>
|
||||
<class>org.apache.fineract.organisation.monetary.domain.OrganisationCurrency</class>
|
||||
<class>org.apache.fineract.organisation.monetary.domain.ApplicationCurrency</class>
|
||||
<class>org.apache.fineract.organisation.holiday.domain.Holiday</class>
|
||||
<class>org.apache.fineract.organisation.workingdays.domain.WorkingDays</class>
|
||||
<class>org.apache.fineract.portfolio.group.domain.Group</class>
|
||||
<class>org.apache.fineract.portfolio.group.domain.GroupLevel</class>
|
||||
<class>org.apache.fineract.portfolio.group.domain.StaffAssignmentHistory</class>
|
||||
<class>org.apache.fineract.portfolio.group.domain.GroupRole</class>
|
||||
<class>org.apache.fineract.portfolio.client.domain.Client</class>
|
||||
<class>org.apache.fineract.portfolio.client.domain.ClientIdentifier</class>
|
||||
<class>org.apache.fineract.portfolio.rate.domain.Rate</class>
|
||||
<class>org.apache.fineract.portfolio.fund.domain.Fund</class>
|
||||
<class>org.apache.fineract.portfolio.delinquency.domain.DelinquencyBucket</class>
|
||||
<class>org.apache.fineract.portfolio.delinquency.domain.DelinquencyRange</class>
|
||||
<class>org.apache.fineract.portfolio.paymenttype.domain.PaymentType</class>
|
||||
<class>org.apache.fineract.portfolio.paymentdetail.domain.PaymentDetail</class>
|
||||
<class>org.apache.fineract.portfolio.floatingrates.domain.FloatingRate</class>
|
||||
<class>org.apache.fineract.portfolio.floatingrates.domain.FloatingRatePeriod</class>
|
||||
<class>org.apache.fineract.portfolio.calendar.domain.Calendar</class>
|
||||
<class>org.apache.fineract.portfolio.calendar.domain.CalendarHistory</class>
|
||||
<class>org.apache.fineract.portfolio.calendar.domain.CalendarInstance</class>
|
||||
<class>org.apache.fineract.useradministration.domain.AppUser</class>
|
||||
|
||||
<!-- Core Module Entities -->
|
||||
<class>org.apache.fineract.useradministration.domain.Role</class>
|
||||
<class>org.apache.fineract.portfolio.fund.domain.Fund</class>
|
||||
<class>org.apache.fineract.infrastructure.documentmanagement.domain.Image</class>
|
||||
<class>org.apache.fineract.organisation.workingdays.domain.WorkingDays</class>
|
||||
<class>org.apache.fineract.useradministration.domain.Permission</class>
|
||||
<class>org.apache.fineract.useradministration.domain.AppUserClientMapping</class>
|
||||
<!-- Fineract Charge module -->
|
||||
<class>org.apache.fineract.commands.domain.CommandSource</class>
|
||||
<class>org.apache.fineract.useradministration.domain.AppUser</class>
|
||||
<class>org.apache.fineract.accounting.glaccount.domain.GLAccount</class>
|
||||
<class>org.apache.fineract.organisation.monetary.domain.OrganisationCurrency</class>
|
||||
<class>org.apache.fineract.organisation.staff.domain.Staff</class>
|
||||
<class>org.apache.fineract.portfolio.rate.domain.Rate</class>
|
||||
<class>org.apache.fineract.organisation.monetary.domain.ApplicationCurrency</class>
|
||||
<class>org.apache.fineract.portfolio.calendar.domain.CalendarInstance</class>
|
||||
<class>org.apache.fineract.portfolio.paymentdetail.domain.PaymentDetail</class>
|
||||
<class>org.apache.fineract.portfolio.calendar.domain.Calendar</class>
|
||||
<class>org.apache.fineract.portfolio.calendar.domain.CalendarHistory</class>
|
||||
<class>org.apache.fineract.portfolio.client.domain.ClientIdentifier</class>
|
||||
<class>org.apache.fineract.portfolio.delinquency.domain.DelinquencyBucket</class>
|
||||
<class>org.apache.fineract.portfolio.delinquency.domain.DelinquencyRange</class>
|
||||
<class>org.apache.fineract.portfolio.group.domain.StaffAssignmentHistory</class>
|
||||
<class>org.apache.fineract.portfolio.group.domain.Group</class>
|
||||
<class>org.apache.fineract.portfolio.client.domain.Client</class>
|
||||
<class>org.apache.fineract.infrastructure.event.external.repository.domain.ExternalEventConfiguration</class>
|
||||
<class>org.apache.fineract.portfolio.group.domain.GroupRole</class>
|
||||
<class>org.apache.fineract.portfolio.paymenttype.domain.PaymentType</class>
|
||||
<class>org.apache.fineract.portfolio.group.domain.GroupLevel</class>
|
||||
<class>org.apache.fineract.infrastructure.event.external.repository.domain.ExternalEvent</class>
|
||||
<class>org.apache.fineract.organisation.office.domain.Office</class>
|
||||
<class>org.apache.fineract.organisation.holiday.domain.Holiday</class>
|
||||
<class>org.apache.fineract.infrastructure.cache.domain.PlatformCache</class>
|
||||
<class>org.apache.fineract.infrastructure.codes.domain.Code</class>
|
||||
<class>org.apache.fineract.infrastructure.businessdate.domain.BusinessDate</class>
|
||||
<class>org.apache.fineract.infrastructure.codes.domain.CodeValue</class>
|
||||
|
||||
<!-- Accounting Module Entities -->
|
||||
<class>org.apache.fineract.accounting.closure.domain.GLClosure</class>
|
||||
<class>org.apache.fineract.accounting.financialactivityaccount.domain.FinancialActivityAccount</class>
|
||||
<class>org.apache.fineract.accounting.glaccount.domain.TrialBalance</class>
|
||||
<class>org.apache.fineract.accounting.producttoaccountmapping.domain.ProductToGLAccountMapping</class>
|
||||
<class>org.apache.fineract.accounting.rule.domain.AccountingRule</class>
|
||||
<class>org.apache.fineract.accounting.rule.domain.AccountingTagRule</class>
|
||||
<class>org.apache.fineract.accounting.journalentry.domain.JournalEntry</class>
|
||||
|
||||
<!-- Charge Module Entities -->
|
||||
<class>org.apache.fineract.portfolio.charge.domain.Charge</class>
|
||||
<!-- Fineract Tax module -->
|
||||
<class>org.apache.fineract.portfolio.tax.domain.TaxGroup</class>
|
||||
<class>org.apache.fineract.portfolio.tax.domain.TaxGroupMappings</class>
|
||||
|
||||
<!-- Tax Module Entities -->
|
||||
<class>org.apache.fineract.portfolio.tax.domain.TaxComponent</class>
|
||||
<class>org.apache.fineract.portfolio.tax.domain.TaxComponentHistory</class>
|
||||
<class>org.apache.fineract.portfolio.loanaccount.domain.LoanStatusConverter</class>
|
||||
<class>org.apache.fineract.portfolio.tax.domain.TaxGroup</class>
|
||||
<class>org.apache.fineract.portfolio.tax.domain.TaxGroupMappings</class>
|
||||
|
||||
<exclude-unlisted-classes>false</exclude-unlisted-classes>
|
||||
<properties>
|
||||
<property name="eclipselink.weaving" value="static" />
|
||||
@@ -0,0 +1,80 @@
|
||||
{
|
||||
"name": "DocumentDataV1",
|
||||
"namespace": "org.apache.fineract.avro.document.v1",
|
||||
"doc": "Metadata emitted by DocumentCreatedBusinessEvent when a file is stored in Fineract.",
|
||||
"type": "record",
|
||||
"fields": [
|
||||
{
|
||||
"default": null,
|
||||
"name": "id",
|
||||
"type": [
|
||||
"null",
|
||||
"long"
|
||||
]
|
||||
},
|
||||
{
|
||||
"default": null,
|
||||
"name": "parentEntityType",
|
||||
"type": [
|
||||
"null",
|
||||
"string"
|
||||
]
|
||||
},
|
||||
{
|
||||
"default": null,
|
||||
"name": "parentEntityId",
|
||||
"type": [
|
||||
"null",
|
||||
"long"
|
||||
]
|
||||
},
|
||||
{
|
||||
"default": null,
|
||||
"name": "name",
|
||||
"type": [
|
||||
"null",
|
||||
"string"
|
||||
]
|
||||
},
|
||||
{
|
||||
"default": null,
|
||||
"name": "fileName",
|
||||
"type": [
|
||||
"null",
|
||||
"string"
|
||||
]
|
||||
},
|
||||
{
|
||||
"default": null,
|
||||
"name": "size",
|
||||
"type": [
|
||||
"null",
|
||||
"long"
|
||||
]
|
||||
},
|
||||
{
|
||||
"default": null,
|
||||
"name": "type",
|
||||
"type": [
|
||||
"null",
|
||||
"string"
|
||||
]
|
||||
},
|
||||
{
|
||||
"default": null,
|
||||
"name": "description",
|
||||
"type": [
|
||||
"null",
|
||||
"string"
|
||||
]
|
||||
},
|
||||
{
|
||||
"default": null,
|
||||
"name": "storageType",
|
||||
"type": [
|
||||
"null",
|
||||
"int"
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -11,6 +11,14 @@
|
||||
"bigdecimal"
|
||||
]
|
||||
},
|
||||
{
|
||||
"default": null,
|
||||
"name": "availableDisbursementAmountWithOverApplied",
|
||||
"type": [
|
||||
"null",
|
||||
"bigdecimal"
|
||||
]
|
||||
},
|
||||
{
|
||||
"default": null,
|
||||
"name": "pastDueDays",
|
||||
@@ -27,6 +35,14 @@
|
||||
"string"
|
||||
]
|
||||
},
|
||||
{
|
||||
"default": null,
|
||||
"name": "nextPaymentAmount",
|
||||
"type": [
|
||||
"null",
|
||||
"bigdecimal"
|
||||
]
|
||||
},
|
||||
{
|
||||
"default": null,
|
||||
"name": "delinquentDays",
|
||||
|
||||
@@ -61,6 +61,17 @@
|
||||
"items": "org.apache.fineract.avro.loan.v1.LoanInstallmentDelinquencyBucketDataV1"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"default": null,
|
||||
"name": "customData",
|
||||
"type": [
|
||||
"null",
|
||||
{
|
||||
"values": "bytes",
|
||||
"type": "map"
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
|
||||
@@ -55,6 +55,14 @@
|
||||
"string"
|
||||
]
|
||||
},
|
||||
{
|
||||
"default": null,
|
||||
"name": "previousOwnerExternalId",
|
||||
"type": [
|
||||
"null",
|
||||
"string"
|
||||
]
|
||||
},
|
||||
{
|
||||
"default": null,
|
||||
"name": "currency",
|
||||
@@ -161,6 +169,17 @@
|
||||
"null",
|
||||
"string"
|
||||
]
|
||||
},
|
||||
{
|
||||
"default": null,
|
||||
"name": "customData",
|
||||
"type": [
|
||||
"null",
|
||||
{
|
||||
"values": "bytes",
|
||||
"type": "map"
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
|
||||
@@ -657,6 +657,17 @@
|
||||
"null",
|
||||
"boolean"
|
||||
]
|
||||
},
|
||||
{
|
||||
"default": null,
|
||||
"name": "customData",
|
||||
"type": [
|
||||
"null",
|
||||
{
|
||||
"values": "bytes",
|
||||
"type": "map"
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
|
||||
@@ -38,6 +38,17 @@
|
||||
"null",
|
||||
"org.apache.fineract.avro.loan.v1.RepaymentPastDueDataV1"
|
||||
]
|
||||
},
|
||||
{
|
||||
"default": null,
|
||||
"name": "customData",
|
||||
"type": [
|
||||
"null",
|
||||
{
|
||||
"values": "bytes",
|
||||
"type": "map"
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
|
||||
@@ -458,6 +458,30 @@
|
||||
"null",
|
||||
"bigdecimal"
|
||||
]
|
||||
},
|
||||
{
|
||||
"default": null,
|
||||
"name": "totalPrincipal",
|
||||
"type": [
|
||||
"null",
|
||||
"bigdecimal"
|
||||
]
|
||||
},
|
||||
{
|
||||
"default": null,
|
||||
"name": "totalCapitalizedIncome",
|
||||
"type": [
|
||||
"null",
|
||||
"bigdecimal"
|
||||
]
|
||||
},
|
||||
{
|
||||
"default": null,
|
||||
"name": "totalCapitalizedIncomeAdjustment",
|
||||
"type": [
|
||||
"null",
|
||||
"bigdecimal"
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
|
||||
@@ -18,6 +18,17 @@
|
||||
"null",
|
||||
"org.apache.fineract.avro.loan.v1.LoanTransactionDataV1"
|
||||
]
|
||||
},
|
||||
{
|
||||
"default": null,
|
||||
"name": "customData",
|
||||
"type": [
|
||||
"null",
|
||||
{
|
||||
"values": "bytes",
|
||||
"type": "map"
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
|
||||
@@ -263,6 +263,14 @@
|
||||
"null",
|
||||
"boolean"
|
||||
]
|
||||
},
|
||||
{
|
||||
"default": null,
|
||||
"name": "classification",
|
||||
"type": [
|
||||
"null",
|
||||
"org.apache.fineract.avro.generic.v1.CodeValueDataV1"
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
|
||||
@@ -21,31 +21,10 @@ description = 'Fineract Branch'
|
||||
apply plugin: 'java'
|
||||
apply plugin: 'eclipse'
|
||||
|
||||
compileJava.doLast {
|
||||
def mainSS = sourceSets.main
|
||||
def source = mainSS.java.classesDirectory.get()
|
||||
copy {
|
||||
from file("src/main/resources/jpa/branch/persistence.xml")
|
||||
into "${source}/META-INF/"
|
||||
}
|
||||
javaexec {
|
||||
description = 'Performs EclipseLink static weaving of entity classes'
|
||||
def target = source
|
||||
main 'org.eclipse.persistence.tools.weaving.jpa.StaticWeave'
|
||||
args '-persistenceinfo', source, source, target
|
||||
classpath sourceSets.main.runtimeClasspath
|
||||
}
|
||||
delete {
|
||||
delete "${source}/META-INF/persistence.xml"
|
||||
}
|
||||
compileJava {
|
||||
dependsOn ':fineract-avro-schemas:buildJavaSdk'
|
||||
}
|
||||
|
||||
// Configuration for Swagger documentation generation task
|
||||
// https://github.com/swagger-api/swagger-core/tree/master/modules/swagger-gradle-plugin
|
||||
import org.apache.tools.ant.filters.ReplaceTokens
|
||||
|
||||
|
||||
|
||||
configurations {
|
||||
providedRuntime // needed for Spring Boot executable WAR
|
||||
providedCompile
|
||||
@@ -91,10 +70,6 @@ eclipse {
|
||||
}
|
||||
}
|
||||
|
||||
/* http://stackoverflow.com/questions/19653311/jpa-repository-works-in-idea-and-production-but-not-in-gradle */
|
||||
sourceSets.main.output.resourcesDir = sourceSets.main.java.classesDirectory
|
||||
sourceSets.test.output.resourcesDir = sourceSets.test.java.classesDirectory
|
||||
|
||||
if (!(project.hasProperty('env') && project.getProperty('env') == 'dev')) {
|
||||
sourceSets {
|
||||
test {
|
||||
|
||||
+5
-2
@@ -28,8 +28,11 @@ import lombok.Getter;
|
||||
@AllArgsConstructor
|
||||
public enum TellerStatus {
|
||||
|
||||
INVALID(0, "tellerStatusType.invalid"), PENDING(100, "tellerStatusType.pending"), ACTIVE(300, "tellerStatusType.active"), INACTIVE(400,
|
||||
"tellerStatusType.inactive"), CLOSED(600, "tellerStatusType.closed");
|
||||
INVALID(0, "tellerStatusType.invalid"), //
|
||||
PENDING(100, "tellerStatusType.pending"), //
|
||||
ACTIVE(300, "tellerStatusType.active"), //
|
||||
INACTIVE(400, "tellerStatusType.inactive"), //
|
||||
CLOSED(600, "tellerStatusType.closed"); //
|
||||
|
||||
private final Integer value;
|
||||
private final String code;
|
||||
|
||||
+100
@@ -0,0 +1,100 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!--
|
||||
|
||||
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.
|
||||
|
||||
-->
|
||||
|
||||
|
||||
<persistence version="2.0"
|
||||
xmlns="http://java.sun.com/xml/ns/persistence"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://java.sun.com/xml/ns/persistence http://java.sun.com/xml/ns/persistence/persistence_2_0.xsd">
|
||||
|
||||
<!-- This file is only used for static weaving, nothing more. -->
|
||||
<!-- You can find the runtime configuration in the JPAConfig class -->
|
||||
<persistence-unit name="jpa-pu" transaction-type="RESOURCE_LOCAL">
|
||||
<provider>org.eclipse.persistence.jpa.PersistenceProvider</provider>
|
||||
|
||||
<!-- Core Module Entities -->
|
||||
<class>org.apache.fineract.useradministration.domain.Role</class>
|
||||
<class>org.apache.fineract.portfolio.fund.domain.Fund</class>
|
||||
<class>org.apache.fineract.infrastructure.documentmanagement.domain.Image</class>
|
||||
<class>org.apache.fineract.organisation.workingdays.domain.WorkingDays</class>
|
||||
<class>org.apache.fineract.useradministration.domain.Permission</class>
|
||||
<class>org.apache.fineract.useradministration.domain.AppUserClientMapping</class>
|
||||
<class>org.apache.fineract.commands.domain.CommandSource</class>
|
||||
<class>org.apache.fineract.useradministration.domain.AppUser</class>
|
||||
<class>org.apache.fineract.accounting.glaccount.domain.GLAccount</class>
|
||||
<class>org.apache.fineract.organisation.monetary.domain.OrganisationCurrency</class>
|
||||
<class>org.apache.fineract.organisation.staff.domain.Staff</class>
|
||||
<class>org.apache.fineract.portfolio.rate.domain.Rate</class>
|
||||
<class>org.apache.fineract.organisation.monetary.domain.ApplicationCurrency</class>
|
||||
<class>org.apache.fineract.portfolio.calendar.domain.CalendarInstance</class>
|
||||
<class>org.apache.fineract.portfolio.paymentdetail.domain.PaymentDetail</class>
|
||||
<class>org.apache.fineract.portfolio.calendar.domain.Calendar</class>
|
||||
<class>org.apache.fineract.portfolio.calendar.domain.CalendarHistory</class>
|
||||
<class>org.apache.fineract.portfolio.client.domain.ClientIdentifier</class>
|
||||
<class>org.apache.fineract.portfolio.delinquency.domain.DelinquencyBucket</class>
|
||||
<class>org.apache.fineract.portfolio.delinquency.domain.DelinquencyRange</class>
|
||||
<class>org.apache.fineract.portfolio.group.domain.StaffAssignmentHistory</class>
|
||||
<class>org.apache.fineract.portfolio.group.domain.Group</class>
|
||||
<class>org.apache.fineract.portfolio.client.domain.Client</class>
|
||||
<class>org.apache.fineract.infrastructure.event.external.repository.domain.ExternalEventConfiguration</class>
|
||||
<class>org.apache.fineract.portfolio.group.domain.GroupRole</class>
|
||||
<class>org.apache.fineract.portfolio.paymenttype.domain.PaymentType</class>
|
||||
<class>org.apache.fineract.portfolio.group.domain.GroupLevel</class>
|
||||
<class>org.apache.fineract.infrastructure.event.external.repository.domain.ExternalEvent</class>
|
||||
<class>org.apache.fineract.organisation.office.domain.Office</class>
|
||||
<class>org.apache.fineract.organisation.holiday.domain.Holiday</class>
|
||||
<class>org.apache.fineract.infrastructure.cache.domain.PlatformCache</class>
|
||||
<class>org.apache.fineract.infrastructure.codes.domain.Code</class>
|
||||
<class>org.apache.fineract.infrastructure.businessdate.domain.BusinessDate</class>
|
||||
<class>org.apache.fineract.infrastructure.codes.domain.CodeValue</class>
|
||||
|
||||
<!-- Accounting Module Entities -->
|
||||
<class>org.apache.fineract.accounting.closure.domain.GLClosure</class>
|
||||
<class>org.apache.fineract.accounting.financialactivityaccount.domain.FinancialActivityAccount</class>
|
||||
<class>org.apache.fineract.accounting.glaccount.domain.TrialBalance</class>
|
||||
<class>org.apache.fineract.accounting.producttoaccountmapping.domain.ProductToGLAccountMapping</class>
|
||||
<class>org.apache.fineract.accounting.rule.domain.AccountingRule</class>
|
||||
<class>org.apache.fineract.accounting.rule.domain.AccountingTagRule</class>
|
||||
<class>org.apache.fineract.accounting.journalentry.domain.JournalEntry</class>
|
||||
|
||||
<!-- Charge Module Entities -->
|
||||
<class>org.apache.fineract.portfolio.charge.domain.Charge</class>
|
||||
|
||||
<!-- Branch Module Entities -->
|
||||
<class>org.apache.fineract.organisation.teller.domain.CashierTransaction</class>
|
||||
<class>org.apache.fineract.organisation.teller.domain.Teller</class>
|
||||
<class>org.apache.fineract.organisation.teller.domain.Cashier</class>
|
||||
<class>org.apache.fineract.organisation.teller.domain.TellerTransaction</class>
|
||||
|
||||
<!-- Tax Module Entities -->
|
||||
<class>org.apache.fineract.portfolio.tax.domain.TaxComponent</class>
|
||||
<class>org.apache.fineract.portfolio.tax.domain.TaxComponentHistory</class>
|
||||
<class>org.apache.fineract.portfolio.tax.domain.TaxGroup</class>
|
||||
<class>org.apache.fineract.portfolio.tax.domain.TaxGroupMappings</class>
|
||||
|
||||
|
||||
<exclude-unlisted-classes>false</exclude-unlisted-classes>
|
||||
<properties>
|
||||
<property name="eclipselink.weaving" value="static" />
|
||||
</properties>
|
||||
</persistence-unit>
|
||||
</persistence>
|
||||
@@ -21,31 +21,10 @@ description = 'Fineract Charge'
|
||||
apply plugin: 'java'
|
||||
apply plugin: 'eclipse'
|
||||
|
||||
compileJava.doLast {
|
||||
def mainSS = sourceSets.main
|
||||
def source = mainSS.java.classesDirectory.get()
|
||||
copy {
|
||||
from file("src/main/resources/jpa/charge/persistence.xml")
|
||||
into "${source}/META-INF/"
|
||||
}
|
||||
javaexec {
|
||||
description = 'Performs EclipseLink static weaving of entity classes'
|
||||
def target = source
|
||||
main 'org.eclipse.persistence.tools.weaving.jpa.StaticWeave'
|
||||
args '-persistenceinfo', source, source, target
|
||||
classpath sourceSets.main.runtimeClasspath
|
||||
}
|
||||
delete {
|
||||
delete "${source}/META-INF/persistence.xml"
|
||||
}
|
||||
compileJava {
|
||||
dependsOn ':fineract-avro-schemas:buildJavaSdk'
|
||||
}
|
||||
|
||||
// Configuration for Swagger documentation generation task
|
||||
// https://github.com/swagger-api/swagger-core/tree/master/modules/swagger-gradle-plugin
|
||||
import org.apache.tools.ant.filters.ReplaceTokens
|
||||
|
||||
|
||||
|
||||
configurations {
|
||||
providedRuntime // needed for Spring Boot executable WAR
|
||||
providedCompile
|
||||
@@ -91,10 +70,6 @@ eclipse {
|
||||
}
|
||||
}
|
||||
|
||||
/* http://stackoverflow.com/questions/19653311/jpa-repository-works-in-idea-and-production-but-not-in-gradle */
|
||||
sourceSets.main.output.resourcesDir = sourceSets.main.java.classesDirectory
|
||||
sourceSets.test.output.resourcesDir = sourceSets.test.java.classesDirectory
|
||||
|
||||
if (!(project.hasProperty('env') && project.getProperty('env') == 'dev')) {
|
||||
sourceSets {
|
||||
test {
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user