Compare commits

...
494 Commits
Author SHA1 Message Date
Adam Monsen 1005b56d0f update link to rc verification instructions
Fineract Build & Cucumber tests (without E2E tests) / verify (main, build-core) (push) Canceled after 0s
Fineract Build & Cucumber tests (without E2E tests) / verify (main, cucumber) (push) Canceled after 0s
Fineract Build & Cucumber tests (without E2E tests) / verify (progressive-loan, build-progressive-loan) (push) Canceled after 0s
Fineract Docker Builds / build (false, docker-compose-postgresql.yml, postgresql) (push) Canceled after 0s
Fineract Docker Builds / build (true, docker-compose.yml, mariadb) (push) Canceled after 0s
Fineract E2E Tests / E2E Tests (Shard 1 of 10) (push) Canceled after 0s
Fineract E2E Tests / E2E Tests (Shard 10 of 10) (push) Canceled after 0s
Fineract E2E Tests / E2E Tests (Shard 2 of 10) (push) Canceled after 0s
Fineract E2E Tests / E2E Tests (Shard 3 of 10) (push) Canceled after 0s
Fineract E2E Tests / E2E Tests (Shard 4 of 10) (push) Canceled after 0s
Fineract E2E Tests / E2E Tests (Shard 5 of 10) (push) Canceled after 0s
Fineract E2E Tests / E2E Tests (Shard 6 of 10) (push) Canceled after 0s
Fineract E2E Tests / E2E Tests (Shard 7 of 10) (push) Canceled after 0s
Fineract E2E Tests / E2E Tests (Shard 8 of 10) (push) Canceled after 0s
Fineract E2E Tests / E2E Tests (Shard 9 of 10) (push) Canceled after 0s
Fineract Documentation build / build (push) Canceled after 0s
Fineract Cargo & Unit- & Integration tests - MariaDB / test (test-core-1) (push) Canceled after 0s
Fineract Cargo & Unit- & Integration tests - MariaDB / test (test-core-2) (push) Canceled after 0s
Fineract Cargo & Unit- & Integration tests - MariaDB / test (test-core-3) (push) Canceled after 0s
Fineract Cargo & Unit- & Integration tests - MariaDB / test (test-core-4) (push) Canceled after 0s
Fineract Cargo & Unit- & Integration tests - MariaDB / test (test-core-5) (push) Canceled after 0s
Fineract Cargo & Unit- & Integration tests - MySQL / test (test-core-1) (push) Canceled after 0s
Fineract Cargo & Unit- & Integration tests - MySQL / test (test-core-2) (push) Canceled after 0s
Fineract Cargo & Unit- & Integration tests - MySQL / test (test-core-3) (push) Canceled after 0s
Fineract Cargo & Unit- & Integration tests - MySQL / test (test-core-4) (push) Canceled after 0s
Fineract Cargo & Unit- & Integration tests - MySQL / test (test-core-5) (push) Canceled after 0s
Fineract Cargo & Unit- & Integration tests - PostgreSQL / test (test-core-1) (push) Canceled after 0s
Fineract Cargo & Unit- & Integration tests - PostgreSQL / test (test-core-2) (push) Canceled after 0s
Fineract Cargo & Unit- & Integration tests - PostgreSQL / test (test-core-3) (push) Canceled after 0s
Fineract Cargo & Unit- & Integration tests - PostgreSQL / test (test-core-4) (push) Canceled after 0s
Fineract Cargo & Unit- & Integration tests - PostgreSQL / test (test-core-5) (push) Canceled after 0s
Fineract Messaging Smoke Tests / Smoke Test with ActiveMQ (push) Canceled after 0s
Fineract Messaging Smoke Tests / Smoke Test with Kafka (push) Canceled after 0s
2025-10-13 09:23:35 -07:00
Adam Monsen e8673d5ff3 fix typos in step 9 re: running the binary 2025-10-13 09:19:15 -07:00
Adam Monsen 5d478f5fbb improve step 9 artifact verification gpg tips 2025-10-13 09:14:22 -07:00
Adam Monsen 513fbe1833 fix tarball explosion in release step 9 🧯 2025-10-11 17:17:32 -07:00
Adam Monsen ee55b4ef75 cucumber.adoc: fix list continuations
Fixes:

```
> Task :fineract-doc:asciidoctorPdf
chapters/testing/cucumber.adoc: line 409: list item index: expected 1, got 3
chapters/testing/cucumber.adoc: line 411: list item index: expected 2, got 4
chapters/testing/cucumber.adoc: line 418: list item index: expected 1, got 5
```

See https://docs.asciidoctor.org/asciidoc/latest/lists/continuation/#list-continuation
2025-10-11 17:17:31 -07:00
Adam Monsen cce46de767 further improve release steps 6 and 9
Originally I thought I was causing issues by running `./gradlew clean` separate from `./gradlew srcDistTar binaryDistTar`. If I did (or so I thought), a `fineract-provider/build/classes/java/main/git.properties` file was _sometimes_ not generated (the `generateGitProperties` task failing, misbehaving, or not even running? was the file getting deleted? no idea).

Unsure of the cause, at least I understand that file is supposed to end up at `BOOT-INF/classes/git.properties` in `fineract-provider-VERSION.jar` in the binary release tarball. Its contents are displayed at the `/fineract-provider/actuator/info` endpoint. I think that's more or less how it works, but I did not spend enough time on this to be certain.

Now I think it wasn't at all related to how I was running our Gradle tasks, but rather some nasty behavior in gradle-git-properties:

* https://github.com/n0mer/gradle-git-properties/issues/233
* https://github.com/gradle/gradle/issues/34177

Yuck. 🤢
2025-10-11 17:17:03 -07:00
Adam Monsen 6052ae60b4 release step 6: fix sanity check example 2025-10-10 14:33:47 -07:00
Adam Monsen 6f09c9425d improve staging doc and commands in release step 8 2025-10-09 10:58:08 -07:00
Adam Monsen 45404bafba doc: remove errant config but keep :sectlinks:
See 89e9cfcd7d

I think this was a typo. It's presumably changing the highlighter midstream and causing section numbering to start at the "Fineract Development Environment" chapter. But I really like `:sectlinks:` and I want to keep that! It's handy for sharing deep / sorta permanent links to specific sections (just click on any heading and copy the URL).
2025-10-09 10:29:07 -07:00
Adam Monsen 80c84af3a4 clean during artifact build release step 6
I think the `clean` task is important here, Felix and I were seeing
issues with jar filenames with incorrect version numbers. His work on
FINERACT-2341 may have fixed whatever was causing it, but let's
also/still do the `clean` before building release artifacts / candidates
just to be safe.
2025-10-09 10:29:00 -07:00
Adam Saghy 7791939860 FINERACT-2326: Do not remove external id if transaction got not replayed 2025-10-08 21:38:32 +02:00
Adam Saghy 6066c0d97f FINERACT-2326: Fix Trial Balance Summary with asset owner report 2025-10-08 17:05:57 +02:00
Arnold GalovicsandArnold Gálovics a950e4e36a FINERACT-2326: Loan point in time API now properly handles future dates 2025-10-08 10:31:21 +02:00
Adam Monsen 288319b874 improve release branch email template
* fix typos
* simplify
* adapt to how I use this today, including explicit branch name
2025-10-07 11:17:42 -07:00
Adam Monsen c1d005d00e improve release process kickoff email template
this is shorter & sweeter
2025-10-07 10:12:24 -07:00
Adam Saghy 4838843b5c FINERACT-2326: Upgrade dependencies 2025-10-07 16:11:55 +02:00
Adam Saghy 3a59a72891 FINERACT-2326: Fix Trial Balance Summary with asset owner report 2025-10-07 16:11:49 +02:00
Víctor RomeroandAdam Saghy 0a0e3eb504 FINERACT-2326: Upgrade dependencies
FINERACT-2326: Upgrade dependencies - Postgresql
2025-10-07 13:58:44 +02:00
dependabot[bot]andArnold Gálovics 43b61ab715 Bump actions/stale from 10.0.0 to 10.1.0
Bumps [actions/stale](https://github.com/actions/stale) from 10.0.0 to 10.1.0.
- [Release notes](https://github.com/actions/stale/releases)
- [Changelog](https://github.com/actions/stale/blob/main/CHANGELOG.md)
- [Commits](https://github.com/actions/stale/compare/3a9db7e6a41a89f618792c92c0e97cc736e1b13f...5f858e3efba33a5ca4407a664cc011ad407f2008)

---
updated-dependencies:
- dependency-name: actions/stale
  dependency-version: 10.1.0
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2025-10-06 20:40:23 +02:00
kengneruphineandArnold Gálovics 8e3de2b72a FINERACT-2359: Wrong Days in Year configuration used for calculating interest 2025-10-06 20:00:27 +02:00
Adam SaghyandArnold Gálovics e0e4415727 FINERACT-2387: Fix zero amount reversed transaction creation issue 2025-10-06 19:59:19 +02:00
mariiaKraievskaandAdam Saghy 09bacb8827 FINERACT-2348: Accounting mismatch in case amortization and amortization adjustment occurs at the same time 2025-10-06 11:25:34 +02:00
Adam Saghy ceb9f0f783 FINERACT-2386: Update read query to support other products 2025-10-06 11:24:30 +02:00
Adam Saghy 334da61ed8 FINERACT-2348: Add missing indexes 2025-10-06 11:23:33 +02:00
Adam Saghy 89e9cfcd7d FINERACT-2386: Journal entry aggregation capabilities 2025-10-03 11:07:12 +02:00
Adam SaghyandArnold Gálovics 297fa8e707 FINERACT-2326: Close opened savings account after integration test execution 2025-10-02 20:57:25 +02:00
JohnAlvaandAdam Saghy 963f8550b8 FINERACT-2378: Failing integration test: org.apache.fineract.integrationtests.SchedulerJobsTestResults#testInterestTransferForSavings 2025-10-01 15:32:13 +02:00
sayhaedandAdam Saghy d782e65fc2 FINERACT-2376: Unable to re-invest maturity amount or principal for fixed deposit at closing 2025-10-01 15:31:25 +02:00
Attila BudaiandAdam Saghy cb7ead208f FINERACT-1724: Document integration and e2e testing in fineract 2025-10-01 12:14:57 +02:00
MarianaDmytrivBinariksandAdam Saghy 5a56ea50f3 FINERACT-2384: e2e tests for re-age trn before maturity date 2025-10-01 12:12:43 +02:00
Soma SörösandAdam Saghy d50906bef2 FINERACT-2384: Incorrect reage transaction date and repayment schedule 2025-10-01 12:12:43 +02:00
Soma SörösandAdam Saghy d6323be7dd FINERACT-2358: Allow to configure advanced accounting rules based on write-off reason 2025-10-01 10:29:03 +02:00
Peter KovacsandAdam Saghy 641f755193 FINERACT-2374: Advance Accounting rule for classification type - E2E tests 2025-09-30 12:27:45 +02:00
Jose Alberto HernandezandAdam Saghy cb70555485 FINERACT-2374: Advance Accounting rule for classification type 2025-09-30 12:27:45 +02:00
Adam Saghy 6d3e5fa150 FINERACT-2326: Update Kafka docker image for testing 2025-09-30 11:12:26 +02:00
Víctor RomeroandGitHub 1082067a6e Revert "FINERACT-2378: Failing integration test: org.apache.fineract.integrat…" (#5064)
This reverts commit 3b58f6af22.
2025-09-29 17:51:27 -06:00
Juan Pablo Alvarez HernandezandGitHub 3b58f6af22 FINERACT-2378: Failing integration test: org.apache.fineract.integrationtests.SchedulerJobsTestResults#testInterestTransferForSavings (#5059) 2025-09-29 17:50:40 -06:00
dependabot[bot]andArnold Gálovics c694b4a106 Bump actions/cache from 4.2.4 to 4.3.0
Bumps [actions/cache](https://github.com/actions/cache) from 4.2.4 to 4.3.0.
- [Release notes](https://github.com/actions/cache/releases)
- [Changelog](https://github.com/actions/cache/blob/main/RELEASES.md)
- [Commits](https://github.com/actions/cache/compare/0400d5f644dc74513175e3cd8d07132dd4860809...0057852bfaa89a56745cba8c7296529d2fc39830)

---
updated-dependencies:
- dependency-name: actions/cache
  dependency-version: 4.3.0
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2025-09-29 08:31:21 +02:00
Adam SaghyandArnold Gálovics 8197e3c951 FINERACT-2326: Trigger manual sequential integration test run 2025-09-27 15:16:05 +02:00
MarianaDmytrivBinariksandAdam Saghy 9ab766387d FINERACT-2381: e2e tests for fixes with accruals calculation after reprocessing loan 2025-09-26 18:22:40 +02:00
Adam Saghy ef80634b4e FINERACT-2381: Fix Accrual Activity calculation 2025-09-26 18:22:40 +02:00
Ruphine KengneandGitHub e063081a82 FINERACT-2326: add test Fineract API requests to README 2025-09-25 08:48:18 -07:00
marta-jankovicsandGitHub f30aa368fd Merge pull request #5055 from adamsaghy/FINERACT-2326/e2e-tests-core-jar
Fineract 2326: e2e tests core jar
2025-09-25 13:29:10 +02:00
Adam Saghy 9c9ae2f6ce FINERACT-2326: Build jar for fineract-e2e-tests-core module 2025-09-25 11:37:39 +02:00
dependabot[bot]andArnold Gálovics 9015a81c4b Bump actions/setup-node from 4.4.0 to 5.0.0
Bumps [actions/setup-node](https://github.com/actions/setup-node) from 4.4.0 to 5.0.0.
- [Release notes](https://github.com/actions/setup-node/releases)
- [Commits](https://github.com/actions/setup-node/compare/49933ea5288caeca8642d1e84afbd3f7d6820020...a0853c24544627f65ddf259abe73b1d18a591444)

---
updated-dependencies:
- dependency-name: actions/setup-node
  dependency-version: 5.0.0
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>
2025-09-25 08:19:43 +02:00
Adam Saghy 71af1cd35a FINERACT-2326: Run the integration tests sequentially on develop branch 2025-09-24 18:05:55 +02:00
MarianaDmytrivBinariksandAdam Saghy 38bdbc7943 FINERACT-2354: e2e tests for re-age trn with n+1 trns 2025-09-24 14:38:59 +02:00
Oleksii NovikovandAdam Saghy 5df6af6a23 FINERACT-2354: Merge re-aged installment with the next (N+1) installment if they overlap 2025-09-24 14:38:59 +02:00
Adam Saghy 054e4aee52 FINERACT-2326: Run the integration tests sequentially on develop branch 2025-09-23 15:30:03 +02:00
Adam SaghyandArnold Gálovics 84c90d6016 FINERACT-2326: Fix split-tests.sh script 2025-09-23 09:34:44 +02:00
Adam Saghy 7f07c0afce FINERACT-2326: Upgrade asciidoc dependencies 2025-09-18 20:55:01 +02:00
Adam Monsen d48eb161ea FINERACT-2377: upgrade Gradle to 8.14.3
9 didn't work
2025-09-18 11:23:12 -05:00
Adam SaghyandArnold Gálovics f52c94751e FINERACT-2326: Upgrade dependencies 2025-09-18 17:29:31 +02:00
Adam Saghy 0dd34ebaa6 Revert "FINERACT-2350: Fix DockerHub tags, use 'latest' for develop and version tags for release"
This reverts commit eaa9c858ed.
2025-09-18 09:35:05 +02:00
Adam Saghy 03b1b1bb12 Revert "FINERACT-2350: Fix Spotless formatting"
This reverts commit 2ea85ea37d.
2025-09-18 09:35:05 +02:00
tomasAscencioandGitHub a2c66e6c31 FINERACT-2353: openAPI definition does not expose required GET parameters (#5025) 2025-09-16 21:43:35 -06:00
Peter KovacsandAleksandar Vidakovic e1cfbb4d20 FINERACT-2326: Reprocessing loan internal api for testing purpose - E2E tests 2025-09-16 15:11:55 +02:00
Jose Alberto HernandezandAleksandar Vidakovic 000ebb4c1d FINERACT-2326: Reprocessing loan internal api for testing purpose 2025-09-16 15:11:55 +02:00
MarianaDmytrivBinariksandAleksandar Vidakovic 23080c5041 FINERACT-2354: e2e tests for N+1 installment with re-age trn 2025-09-16 10:54:00 +02:00
Oleksii NovikovandAleksandar Vidakovic 8bddd15113 FINERACT-2354: Handle N+1 installment together with re-aged installment correctly 2025-09-16 10:54:00 +02:00
Adam Saghy e02aaa9a1c FINERACT-2326: Upgrade dependencies 2025-09-15 16:43:53 -05:00
Rustam ZeinalovandAleksandar Vidakovic 3c3e2811ca FINERACT-2326: updated e2e test to verify loan status and outstanding balance 2025-09-15 17:40:25 +02:00
mariiaKraievskaandAleksandar Vidakovic c7f5743b12 FINERACT-2326: Repayment Reversal Failing After Full Repayment of Principal and Fee 2025-09-15 17:40:25 +02:00
Adam Saghy 627ccf603f FINERACT-2326: Upgrade dependencies 2025-09-12 10:32:13 -05:00
CsengeSótiandArnold Gálovics fa9c7b9364 FINERACT-1984: OAuth2.1 2025-09-12 14:58:37 +02:00
Arnold GalovicsandArnold Gálovics 0c0d8592bb FINERACT-2326: Fix for loading loan summaries for multiple loans 2025-09-10 21:21:32 +02:00
Akshat SoniandAdam Saghy 2ea85ea37d FINERACT-2350: Fix Spotless formatting 2025-09-10 19:44:19 +02:00
Akshat SoniandAdam Saghy eaa9c858ed FINERACT-2350: Fix DockerHub tags, use 'latest' for develop and version tags for release 2025-09-10 19:44:19 +02:00
mariiaKraievskaandAdam Saghy 8da0842f87 FINERACT-2348: Refactor Capitalized income / Buydown fee amortization allocation calculation 2025-09-10 12:30:38 +02:00
JohnAlvaandAdam Saghy 719cba74c2 FINERACT-2312: Post interest with adjustments for savings accounts 2025-09-10 10:16:29 +02:00
sayhaedandAdam Saghy 44e71bf171 FINERACT-2312: Reverse of Accruals to adjust late deposits 2025-09-10 10:14:15 +02:00
Adam Monsen 6aea428d87 clarify "builds" refers to GitHub 2025-09-09 08:40:44 -07:00
MarianaDmytrivBinariksandAdam Saghy 56d410d4f5 FINERACT-2308: e2e tests for multiple tranches at the same date 2025-09-09 15:32:13 +02:00
Attila BudaiandAdam Saghy 91c9c4e61f FINERACT-2308: fix duplicates for multiple tranches 2025-09-09 15:32:13 +02:00
MarianaDmytrivBinariksandAdam Saghy 467d82846d FINERACT-2354: e2e tests for re-age trn undo and again added at the same date 2025-09-09 12:12:22 +02:00
Oleksii NovikovandAdam Saghy 7ee1919ddb FINERACT-2354: Allow re-age today if the previous re-age was reversed 2025-09-09 12:12:22 +02:00
Arun KandAdam Saghy 5b1d72d15b FINERACT-821: Replace 500 by meaningful error when request requires configured S3 2025-09-08 23:12:54 +02:00
Felix van HoveandAdam Saghy 4838526a05 FINERACT-2341: Correct version calculation in gradle 2025-09-08 21:35:25 +02:00
dependabot[bot]andArnold Gálovics ddc476c407 Bump actions/stale from 9.1.0 to 10.0.0
Bumps [actions/stale](https://github.com/actions/stale) from 9.1.0 to 10.0.0.
- [Release notes](https://github.com/actions/stale/releases)
- [Changelog](https://github.com/actions/stale/blob/main/CHANGELOG.md)
- [Commits](https://github.com/actions/stale/compare/5bef64f19d7facfb25b37b414482c7164d639639...3a9db7e6a41a89f618792c92c0e97cc736e1b13f)

---
updated-dependencies:
- dependency-name: actions/stale
  dependency-version: 10.0.0
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>
2025-09-08 20:46:56 +02:00
mariiaKraievskaandAdam Saghy cd0ecfcda0 FINERACT-2348: Calculate and store Capitalized income / Buydown fee amortization allocation schedule 2025-09-08 14:00:06 +02:00
Arnold GalovicsandArnold Gálovics 9790f59e4a FINERACT-2326: Fix for NPE when account fund transfer happens 2025-09-06 12:20:31 +02:00
Adam Saghy 240a51eec1 FINERACT-2373: Fix backward compatibility issue of Loan COB 2025-09-05 18:36:19 +02:00
Adam SaghyandGitHub a81f4f8fe9 FINERACT-2326: CodeValue serialization enhancement (#5007) 2025-09-04 11:53:02 -06:00
budaidevandGitHub fdcb013e7a FINERACT-2326: documenting loan charge (#5009) 2025-09-04 11:48:58 -06:00
JohnAlvaandAdam Saghy fb8f2f7cb6 FINERACT-2312: Reverse of Accruals to adjust late deposits 2025-09-04 10:25:51 +02:00
Juan-Pablo-AlvarezandAdam Saghy a6fa1adc99 FINERACT-2312: Post interest with adjustments for savings accounts 2025-09-04 10:24:42 +02:00
MarianaDmytrivBinariksandAdam Saghy ef1e2e1095 FINERACT-2355: e2e tests for merchant issued refunds allocation with paid installments 2025-09-03 12:55:58 +02:00
Oleksii NovikovandAdam Saghy 33c74abeb7 FINERACT-2355: Fix charge off and loan charge for zero installments 2025-09-03 12:55:58 +02:00
Attila BudaiandAdam Saghy 7378aea0b2 FINERACT-2267: proper not null annotations. Remove jetbrains notnull, all services use non-null 2025-09-03 12:24:37 +02:00
Jose Alberto HernandezandAdam Saghy 65538495aa FINERACT-2347: Introduce classification field on loan transactions 2025-09-03 11:43:06 +02:00
Jose Alberto HernandezandArnold Gálovics 9ba17bf79a FINERACT-2326: Delinquent section in loan details using associations 2025-09-02 20:21:13 +02:00
Adam SaghyandArnold Gálovics 937bfe529c FINERACT-2326: Improve LoanTransactionData DTO structure 2025-09-02 20:20:33 +02:00
Rustam ZeinalovandAdam Saghy d06eb618d0 FINERACT-2356: added e2e tests for validation of accounting during write-off in case the loan was already charged-off 2025-09-01 13:43:43 +02:00
mariiaKraievskaandAdam Saghy b9564f806b FINERACT-2356: Fix incorrect accounting during write-off in case the loan was already charged-off 2025-09-01 13:43:43 +02:00
Attila BudaiandAdam Saghy 567e1c9800 FINERACT-2081: ESAPI.encoder().encodeForSQL is deprecated, so replaced the method with parameterized queries based solution with user input validation 2025-09-01 13:41:49 +02:00
MarianaDmytrivBinariksandAdam Saghy 917dd4d117 FINERACT-2326: added e2e auto tests for available over applied amount with disbursement amount calculation 2025-08-28 11:09:45 +02:00
mariiaKraievskaandAdam Saghy 2cba4430c7 FINERACT-2326: Add additional field which would return available disbursement amount with over applied amount 2025-08-28 11:09:45 +02:00
dependabot[bot]andArnold Gálovics 8bd9444689 Bump actions/checkout from 4.3.0 to 5.0.0
Bumps [actions/checkout](https://github.com/actions/checkout) from 4.3.0 to 5.0.0.
- [Release notes](https://github.com/actions/checkout/releases)
- [Changelog](https://github.com/actions/checkout/blob/main/CHANGELOG.md)
- [Commits](https://github.com/actions/checkout/compare/08eba0b27e820071cde6df949e0beb9ba4906955...08c6903cd8c0fde910a37f88322edcfb5dd907a8)

---
updated-dependencies:
- dependency-name: actions/checkout
  dependency-version: 5.0.0
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>
2025-08-27 18:34:41 +02:00
dependabot[bot]andArnold Gálovics fd18235d9e Bump actions/setup-java from 4.7.1 to 5.0.0
Bumps [actions/setup-java](https://github.com/actions/setup-java) from 4.7.1 to 5.0.0.
- [Release notes](https://github.com/actions/setup-java/releases)
- [Commits](https://github.com/actions/setup-java/compare/c5195efecf7bdfc987ee8bae7a71cb8b11521c00...dded0888837ed1f317902acf8a20df0ad188d165)

---
updated-dependencies:
- dependency-name: actions/setup-java
  dependency-version: 5.0.0
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>
2025-08-27 18:34:31 +02:00
Jose Alberto HernandezandAdam Saghy 7bf43970f2 FINERACT-2326: Swagger - Add capitalizedIncomeAdjustment as part Loan summary 2025-08-27 11:05:03 +02:00
Rustam ZeinalovandAdam Saghy f87f5207da FINERACT-2173: added e2e tests covering extended migration scenario with multidisbursal 2025-08-25 13:00:55 +02:00
Mend RenovateandArnold Gálovics a0dbbea7cf FINERACT-2181: Update actions/setup-java digest to c5195ef 2025-08-25 11:08:43 +02:00
Mend RenovateandArnold Gálovics 048b059f24 FINERACT-2181: Update actions/checkout digest to 08eba0b 2025-08-25 11:08:38 +02:00
Adam SaghyandArnold Gálovics 5d71ffd4ea FINERACT-2326: Use exact business date during savings account accrual tests 2025-08-25 09:28:12 +02:00
Arnold GalovicsandArnold Gálovics 9ef79f86a0 FINERACT-2326: Enhanced loan retrieval API to avoid some of the N+1 queries when loading summaries 2025-08-24 22:03:56 +02:00
Adam SaghyandArnold Gálovics 2a29b1ca0e FINERACT-2326: Deregister static mocks 2025-08-23 21:08:56 +02:00
Adam MonsenandArnold Gálovics 8f3ad9c092 FINERACT-2349: final 1.12.1 release doc updates
Tidy up docs post-1.12.1 release, alongside updates to https://cwiki.apache.org/confluence/display/FINERACT/
2025-08-21 18:16:53 +02:00
Arun KandArnold Gálovics fb911db8a9 FINERACT-2337 Fix docker publish for tags 2025-08-21 18:16:26 +02:00
dependabot[bot]andArnold Gálovics 9a138b2355 Bump actions/setup-java from 4.7.1 to 5.0.0
Bumps [actions/setup-java](https://github.com/actions/setup-java) from 4.7.1 to 5.0.0.
- [Release notes](https://github.com/actions/setup-java/releases)
- [Commits](https://github.com/actions/setup-java/compare/c5195efecf7bdfc987ee8bae7a71cb8b11521c00...dded0888837ed1f317902acf8a20df0ad188d165)

---
updated-dependencies:
- dependency-name: actions/setup-java
  dependency-version: 5.0.0
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>
2025-08-21 18:15:49 +02:00
MarianaDmytrivBinariksandAdam Saghy 5b638c682b FINERACT-1926: added e2e tests for asset owner event changes with previous owner 2025-08-21 13:50:34 +02:00
Oleksii NovikovandAdam Saghy 4786139882 FINERACT-1926: Add previous owner to ExternalAssetOwnerTransfer 2025-08-21 13:50:34 +02:00
adam.magyariandAdam Saghy f1c28792f3 FINERACT-2326: Backdated loan charge-off accrual fix 2025-08-21 12:26:07 +02:00
MarianaDmytrivBinariksandAdam Saghy 4f27d5a225 FINERACT-2317: added e2e tests for update available disb amount validation with zero value 2025-08-21 11:35:23 +02:00
Oleksii NovikovandAdam Saghy 641dbe26d7 FINERACT-2317: Fix updating the available disbursed amount to zero after loan approval 2025-08-21 11:35:23 +02:00
Attila BudaiandAdam Saghy 8fe9dbc614 FINERACT-2327: when Interest Refund was created manually, we should only return the newly created Interest Refund transaction identifiers in the result. 2025-08-21 11:10:51 +02:00
MarianaDmytrivBinariksandAdam Saghy 6c875fa6c6 FINERACT-2330: added e2e tests for buy down fee for non-merchant 2025-08-21 10:23:09 +02:00
Jose Alberto HernandezandAdam Saghy 141f17ecfc FINERACT-2330: Buy-Down fees adjustment Acct for non merchant product 2025-08-21 10:23:09 +02:00
Soma SörösandAdam Saghy 14589e2600 FINERACT-1981: Progressive Loan schedule handling - Reschedule installment (Extend repayment period) 2025-08-21 10:22:07 +02:00
Rustam ZeinalovandAdam Saghy 47b55b5ee6 added e2e tests for validation of progressive Loan schedule handling - Reschedule installment (Extend repayment period) 2025-08-21 10:22:07 +02:00
Christopher Sayhaed Giron VegaandGitHub b349cf6831 FINERACT-2312: Accruals added for savings accounts (#4885) 2025-08-20 15:00:09 -06:00
04GomezandGitHub c936c19b85 FINERACT-2312: Adjustment to savings account products by adding a new accounting account interest receivables account. (#4876) 2025-08-20 09:54:18 -06:00
Peter KovacsandAdam Saghy 1e926669d3 FINERACT-1981: Reschedule loan with interest rate change from zero breaks repayment schedule and loan status to OVERPAID - E2E tests 2025-08-19 14:45:19 +02:00
Soma SörösandAdam Saghy 7285a958fe FINERACT-1981: Reschedule loan with interest rate change from zero breaks repayment schedule and loan status to OVERPAID 2025-08-19 14:45:19 +02:00
Oleksii NovikovandAdam Saghy b9a75cf9cc FINERACT-2279: Add contract termination documentation 2025-08-19 13:20:51 +02:00
mariiaKraievskaandAdam Saghy ace59352fa FINERACT-2233: Rework journal entry handling logic in Loan module 2025-08-19 13:19:40 +02:00
Adam Saghy 942ad0183c FINERACT-2326: Rework business date validation and dto handling 2025-08-19 13:18:40 +02:00
Adam Saghy f41d986b2a FINERACT-2326: Introduce FineractProgressiveLoanBeanConfiguration to allow conditionally register beans in fineract-progressive-loan module 2025-08-19 11:44:23 +02:00
Jose Alberto HernandezandAdam Saghy ea7a2589ca FINERACT-2232: DeferredIncomeApi as CapitalizedIncomeApi 2025-08-19 11:42:58 +02:00
Adam Saghy 77f7d9aab8 FINERACT-2326: Use Hibernate Validator 2025-08-18 19:07:34 +02:00
mariiaKraievskaandAdam Saghy 3fb9b94e47 FINERACT-2326: Fix UserLoanPermissionTest 2025-08-18 14:14:55 +02:00
Mend RenovateandArnold Gálovics 7214f55d58 FINERACT-2181: Update dependency com.puppycrawl.tools:checkstyle to v11 2025-08-18 08:28:26 +02:00
Mend RenovateandArnold Gálovics 0b66b4837f FINERACT-2181: Update dependency node to v22 2025-08-18 08:28:05 +02:00
Soma SörösandArnold Gálovics 18d6a7cf69 FINERACT-2326: Missing user permission for Capitalized Income and Buydown fee 2025-08-15 22:56:43 +02:00
Jose Alberto HernandezandArnold Gálovics 6bbc4bd3f3 FINERACT-2330: Buy-Down fees Accounting for non merchant product 2025-08-15 22:54:36 +02:00
Jose Alberto HernandezandArnold Gálovics 125c8b4db2 FINERACT-2326: Extract out external dependencies from Client and Group entity 2025-08-15 22:53:14 +02:00
dependabot[bot]andArnold Gálovics 37f31ecb14 Bump actions/checkout from 4.2.2 to 5.0.0
Bumps [actions/checkout](https://github.com/actions/checkout) from 4.2.2 to 5.0.0.
- [Release notes](https://github.com/actions/checkout/releases)
- [Changelog](https://github.com/actions/checkout/blob/main/CHANGELOG.md)
- [Commits](https://github.com/actions/checkout/compare/11bd71901bbe5b1630ceea73d27597364c9af683...08c6903cd8c0fde910a37f88322edcfb5dd907a8)

---
updated-dependencies:
- dependency-name: actions/checkout
  dependency-version: 5.0.0
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>
2025-08-15 22:49:30 +02:00
Adam Saghy 0f53f7766a FINERACT-2326: Fix swagger generation 2025-08-15 14:55:21 +02:00
Adam SaghyandArnold Gálovics db5d8dd76f FINERACT-2326: Fix swagger generation 2025-08-15 13:41:55 +02:00
Adam Saghy bd89952e5c FINERACT-2326: Improve command query param regexp to allow hyphens 2025-08-15 13:03:39 +02:00
MarianaDmytrivBinariksandAdam Saghy 1e1787399a FINERACT-2343: added e2e tests for business date and currency validation 2025-08-14 15:35:26 +02:00
Oleksii NovikovandAdam Saghy 56f0b83d40 FINERACT-2343: Fix update currency api validation 2025-08-14 15:35:26 +02:00
Adam SaghyandArnold Gálovics 8e5113ddcd FINERACT-2326: Fix swagger generation 2025-08-14 09:54:16 +02:00
Oleksii NovikovandAdam Saghy ebb6b6c500 FINERACT-2324: Remove getLoanTransactions from accounting 2025-08-13 14:39:01 +02:00
Soma SörösandAdam Saghy 87c0a02402 FINERACT-2326: [DOC] Interest rate change documentation 2025-08-13 14:37:48 +02:00
Attila BudaiandAdam Saghy 2babdd3c64 FINERACT-2323: support the multiple legs for journal entries 2025-08-13 14:36:39 +02:00
Jose Alberto HernandezandAdam Saghy 33fae09afb FINERACT-2326: Charges with Tax group Id ignored 2025-08-13 13:58:21 +02:00
Jose Alberto HernandezandAdam Saghy c55cfe9d08 FINERACT-2326: Tax component and group issue serialization 2025-08-13 13:57:09 +02:00
adam.magyariandAdam Saghy 6b7df527de FINERACT-2338: Allow backdated interest change on progressive loans
- charge-off handling
- write-off handling
- closed loans
- external owner changes
2025-08-13 13:52:30 +02:00
Adam Saghy c2519c77c7 FINERACT-2326: Improve null-safety 2025-08-13 11:02:22 +02:00
adam.magyariandAdam Saghy 53d9790c8c FINERACT-2338: Allow backdated interest change on progressive loans - documentation 2025-08-11 15:09:56 +02:00
Attila BudaiandAdam Saghy 56c71f7fee FINERACT-2326: The journal entries should be ordered in explicit order 2025-08-11 15:06:47 +02:00
Adam MonsenandGitHub b9c2589247 FINERACT-2340: remove nonexistant project "fineract-api" (#4924) 2025-08-08 11:01:08 -06:00
b0ca0a24cc FINERACT-2314: IP tracking (#4825)
Co-authored-by: Juan Pablo Alvarez Hernandez <work_jpa@hotmailcom>
2025-08-08 10:58:19 -06:00
dependabot[bot]andArnold Gálovics 39050aa01f Bump actions/cache from 4.2.3 to 4.2.4
Bumps [actions/cache](https://github.com/actions/cache) from 4.2.3 to 4.2.4.
- [Release notes](https://github.com/actions/cache/releases)
- [Changelog](https://github.com/actions/cache/blob/main/RELEASES.md)
- [Commits](https://github.com/actions/cache/compare/5a3ec84eff668545956fd18022155c47e93e2684...0400d5f644dc74513175e3cd8d07132dd4860809)

---
updated-dependencies:
- dependency-name: actions/cache
  dependency-version: 4.2.4
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2025-08-08 17:02:30 +02:00
mark.vituskaandAdam Saghy 93ef69abb1 FINERACT-2317: Add documentation for approved amount modification endpoints 2025-08-08 09:57:31 +02:00
Adam Monsen 67272d1aea FINERACT-2336: improve asciidoc post-1.12.1 release
* update release notice years in NOTICE_RELEASE and NOTICE_SOURCE
* step 5
  * simplify mention of tests: "Ensure all tests pass for this commit both in CI and locally"
  * recommend GPG signing annotated release tag
* step 8: improve svn commands
  * This way is simpler and more efficient, especially with a bunch of release candidate dirs in the staging area.
* step 10: mention need to test rc before +1 vote -- See:
  * https://www.apache.org/legal/release-policy.html#release-approval
  * https://www.apache.org/legal/release-policy.html#approving-a-release
* step 12: only PMC members can upload releases
* step 13: simplify & explain "finalize branch" instructions
  * Document what worked for me for 1.12.1.
  * I didn't need to create the extra `merge-$VERSION` branch and do the recursive merge.
* document how asciidoctor upgrade is blocked
  * see "official docs - deps stuck" thread on fineract dev mailing list
  * https://lists.apache.org/thread/7mmsj13spb11vgz0z38fhwgzwtq03brr
  * can't upgrade to 4.x because of one of these:
    * https://github.com/asciidoctor/asciidoctorj-pdf/issues/25
    * https://github.com/jruby/jruby/issues/5573
    * https://github.com/asciidoctor/asciidoctorj-pdf/issues/16
* improve asciidoc config - opt for simplicity where the complexity adds nothing
  * compat-mode is off by default, no need for it here
  * default optimization should be fine
  * media should have been screen | print | prepress, just leave it as default instead
  * page size? I really don't think this is going to be printed much, just go with default
  * PDF version 1.8 is invalid, just use the default unless we someday have a good reason to pin this
  * reduce copyright years sources of truth
  * see also: https://docs.asciidoctor.org/pdf-converter/latest/asciidoc-attributes/
* remove unnecessary asciidoctorj 3.0.0 version string -- no need to pin this
* remove prompt character from Bash shell examples
  * it isn't properly syntax-highlighted and it looks confusing with line numbers (which we might want to add)
  * it isn't necessary
  * the prompt character ("%" in this case) is not typically included in shell code examples because it makes it harder to copy and paste shell code examples
  * $ is likely more common than % (at least on Debian/Ubuntu), but either way I'd say exclude it
* fix source code syntax labels - use "bash" only when it is actually Bash shell code
* persistence.adoc
  * fix broken enumerated list
    * resolves these warnings seen with, e.g.: `gradle --info doc`
    * `Jul 27, 2025 8:26:48 PM uri:classloader:/gems/asciidoctor-2.0.10/lib/asciidoctor/parser.rb parse_list_item`
    * `WARNING: chapters/architecture/persistence.adoc: line 104: list item index: expected 1, got 2`
    * `Jul 27, 2025 8:26:48 PM uri:classloader:/gems/asciidoctor-2.0.10/lib/asciidoctor/parser.rb parse_list`
    * `WARNING: chapters/architecture/persistence.adoc: line 110: list item index: expected 1, got 3`
  * fix wrapping (we use hardbreaks)
  * fix typo: `s/plane text/plain text/`
* switch to rouge syntax highlighter - it handles more source languages
* fix broken long shell code lines
* fix .avro file syntax highlighting (it's JSON)
* configuration-gpg.adoc
  * fix accidental block continuation
    * One little plus sign was making `= Email` appear verbatim in rendered output because it was interpreted as a list continuation.
    * See https://docs.asciidoctor.org/asciidoc/latest/lists/continuation/#list-continuation
  * recommend more secure keys
  * add a line continuation for an enumerated list
* architecture-overview.puml: remove this unused (likely a "Hello World") diagram
* release-schedule.puml: fix pluralization of days
  * purely aesthetic: doesn't affect chart rendering
* fix src/bin/binary tarball name typos
  * missed a few in e090da2a01
* fix release branch name
  * must match `release/{revnumber}`, per gitVersioning stanza in top level build.gradle
* harden.adoc: fix broken link to CISA
* fineract-doc/build.gradle
  * ensure HTML task has diagrams and images availble
2025-08-07 07:02:10 -07:00
Oleksii NovikovandAdam Saghy ebda7cee4b FINERACT-2311: Add buydown fees documentation 2025-08-07 14:52:47 +02:00
Pinchez25andAdam Saghy 52d3f32381 FINERACT-2218: Fix Type Mismatch in Survey Validation Query 2025-08-07 10:21:55 +02:00
Adam Monsen 0601bfca77 FINERACT-2339: squelch static weaving log messages
This quality of life patch reduces static weaving log message priority,
reducing the default gradle build output by about 60 lines.

example gradle run with these messages:

    > Configure project :custom
    ℹ Skipping static weaving configuration for non-Java project: custom

    > Configure project :fineract-accounting
    Configuring EclipseLink static weaving for fineract-accounting

    > Configure project :fineract-branch
    Configuring EclipseLink static weaving for fineract-branch
    ...
2025-08-06 09:33:03 -07:00
Oleksii NovikovandAdam Saghy 68474e250d FINERACT-2232: Add capitalize income documentation 2025-08-06 14:27:28 +02:00
Peter KovacsandAdam Saghy 9ed26cb236 FINERACT-2311: Buy Down fees - External business events - E2E tests 2025-08-06 13:53:04 +02:00
adam.magyariandAdam Saghy 6a198de0cc FINERACT-2311: Buy Down fees - External business events
- buy down fee reversal fix
- added more listeners for buy down fee amortization on closed loans
2025-08-06 13:53:04 +02:00
Soma SörösandAdam Saghy aa68f251d3 FINERACT-2311: Buy Down fees - External business events 2025-08-06 13:53:04 +02:00
MarianaDmytrivBinariksandAdam Saghy 9c37ef437d FINERACT-2322: added e2e test with next payment data check 2025-08-06 13:52:43 +02:00
Soma SörösandAdam Saghy 28043ce438 FINERACT-2322: Extend loan collection data with next due payment amount field 2025-08-06 13:52:43 +02:00
MarianaDmytrivBinariksandAdam Saghy 514a684281 FINERACT-2317: added e2e test for update available disbursement amount 2025-08-06 12:46:28 +02:00
mark.vituskaandAdam Saghy 1c82507707 FINERACT-2317: Add new endpoints to indirectly modify loan approved amount 2025-08-06 12:46:28 +02:00
Rustam ZeinalovandAdam Saghy 2cc0cda1a6 FINERACT-2317: added e2e test to verify inclusion of capitalized income and buy down fee in available disbursement calculation 2025-08-06 09:19:23 +02:00
Oleksii NovikovandAdam Saghy 25b440b842 FINERACT-2317: Include capitalized income and buy down fee in available disbursement calculation 2025-08-06 09:19:23 +02:00
Peter KovacsandAdam Saghy 9f53440543 FINERACT-1968: Progressive Loan schedule handling - interest handling (DECLINING BALANCE interest, Same as repayment period, Equal installments) - E2E tests 2025-08-05 13:49:41 +02:00
Soma SörösandAdam Saghy dfab66132b FINERACT-1968: Progressive Loan schedule handling - interest handling (DECLINING BALANCE interest, Same as repayment period, Equal installments) 2025-08-05 13:49:41 +02:00
MarianaDmytrivBinariksandAdam Saghy 8d829b1063 FINERACT-2338: added e2e test for backdated interest rate change 2025-08-05 13:48:39 +02:00
adam.magyariandAdam Saghy d82ffddecc FINERACT-2338: Allow backdated interest rate change on progressive loans 2025-08-05 13:48:39 +02:00
mariiaKraievskaandAdam Saghy 0daf42ec33 FINERACT-2124: Fix final income accrual calculation with multiple fee charges 2025-08-05 13:46:22 +02:00
Rustam ZeinalovandAdam Saghy 68f20c29e9 FINERACT-2326: added e2e tests for validation of ability to reschedule non-interest-bearing progressive loans to have interest 2025-08-04 14:03:00 +02:00
mark.vituskaandAdam Saghy 3428e33035 FINERACT-2326: Add the ability to reschedule non-interest-bearing progressive loans to have interest 2025-08-04 14:03:00 +02:00
MarianaDmytrivBinariksandArnold Gálovics 6a67e58a3a FINERACT-2232: added checkes for fetching deferred income data via external-id 2025-08-03 14:36:05 +02:00
Oleksii NovikovandArnold Gálovics 9740f95745 FINERACT-2232: Add fetching of Capitalized Income details by external id 2025-08-03 14:36:05 +02:00
MarianaDmytrivBinariksandAdam Saghy 7b7118dfba FINERACT-2308: added e2e tests for approved over applied amount for loan that expects tranches 2025-08-01 15:44:43 +02:00
mariiaKraievskaandAdam Saghy 68bfd7a3f8 FINERACT-2308: Allow approval / disbursal above loan applied amount for multidisbursal progressive loan that does expect tranches 2025-08-01 15:44:43 +02:00
Rustam ZeinalovandAdam Saghy cb4c66302a FINERACT-1968: added e2e test cases for progressive Loan schedule handling - interest handling (FLAT interest, Daily, Equal installments) 2025-08-01 15:31:49 +02:00
Soma SörösandAdam Saghy bbe3ead849 FINERACT-1968: Progressive Loan schedule handling - interest handling (FLAT interest, Daily, Equal installments) 2025-08-01 15:31:49 +02:00
Jose Alberto HernandezandAdam Saghy bd8b4fedf4 FINERACT-2326: Set precision of 6 for the audit fields of the datatables (mysql) 2025-08-01 11:14:03 +02:00
Attila BudaiandAdam Saghy 0762a012e5 FINERACT-2181: Fix the interest calculation for non active loan 2025-07-31 19:59:15 +02:00
MarianaDmytrivBinariksandAdam Saghy 3e2684c0d6 FINERACT-2311: added e2e tests for buy down fees fetch amortization details 2025-07-31 10:01:32 +02:00
Oleksii NovikovandAdam Saghy ca3f63badf FINERACT-2311: Add GET API for buy down fees related information 2025-07-31 10:01:32 +02:00
Jose Alberto HernandezandAdam Saghy 54f055d9c7 FINERACT-2326: Capitalized Income transaction template considering over applied amount when enabled 2025-07-31 09:59:50 +02:00
Rustam ZeinalovandAdam Saghy 59c98b7329 FINERACT-2311: added e2e tests for validation of buy down fees reversal of existing transaction 2025-07-30 18:43:55 +02:00
Jose Alberto HernandezandAdam Saghy e46a98065e FINERACT-2311: Buy Down fees - Reversal of existing transaction 2025-07-30 18:43:55 +02:00
Adam Saghy 0581c09273 FINERACT-2326: Set timeout for github actions 2025-07-30 16:38:08 +02:00
mark.vituskaandAdam Saghy 0728ffc2ad FINERACT-2326: add installment amount in multiples of handling to flat interest emi calculation 2025-07-30 13:17:05 +02:00
Pinchez25andArnold Gálovics 00d613175c FINERACT-2315: Fix SMS Status Reports Error 2025-07-29 22:25:37 +02:00
Jose Alberto HernandezandArnold Gálovics 7452ea2552 FINERACT-1932: Fineract modularization - fineract-cob 2025-07-29 21:46:39 +02:00
Adam Monsen e090da2a01 FINERACT-2335: don't rename release tarballs
Release tarballs are currently renamed (without changing the contents): apache-fineract-src-1.12.1.tar.gz becomes apache-fineract-1.12.1-src.tar.gz . The former matches the exploded directory name, the latter does not. The difference is subtle but meaningful... I strongly prefer the former because it's less surprising / more common, and easier to work with from scripts.

There's no functional difference, this should only impact aesthetics.

I did also shorten `binary` to `bin` so release artifact name lengths match.
2025-07-28 11:04:23 -07:00
Adam Saghy ab8bb930ec FINERACT-2333: Batch API - Support date format: from array to string 2025-07-28 19:06:48 +02:00
Adam Saghy 52be53778d FINERACT-2326: Locale Validator shall accept all valid language codes 2025-07-28 18:25:37 +02:00
Adam Saghy 271ac859bc FINERACT-2118: Make region as optional and remove hardcoded default value 2025-07-28 18:11:08 +02:00
adam.magyariandAdam Saghy 0698c4ada5 FINERACT-2311: Buy down fee adjustment - portion fix 2025-07-28 16:06:00 +02:00
Adam Saghy d80643a0f2 FINERACT-2326: EclipseLink sometimes fails if JPQL cache is not warm up but concurrent queries are executed 2025-07-28 16:04:36 +02:00
mark.vituskaandAdam Saghy 68b35024f6 FINERACT-2326: Fix payment allocation when current period is closed 2025-07-28 14:23:54 +02:00
Jose Alberto HernandezandAdam Saghy 70373eafef FINERACT-2311: Buy Down Fees template API changes 2025-07-28 14:09:58 +02:00
Naphlin AkenaandAdam Saghy dadc36b6b4 FINERACT-2118: Use S3 service accounts
Allow usage of S3 service accounts and support any S3 compatible storage
endpoints
2025-07-28 11:42:29 +02:00
Adam Monsen a8d23ee747 Merge branch 'release/1.12.1' into develop
* release/1.12.1:
  save 1.12.1 vote result
2025-07-27 15:45:27 -07:00
Adam Monsen 97aa931a59 save 1.12.1 vote result 2025-07-27 15:39:29 -07:00
mariiaKraievskaandAleksandar Vidakovic 45749d3edd FINERACT-2311: Buy Down fees Adjustment - Reversal of existing transaction 2025-07-25 12:57:51 +02:00
Rustam ZeinalovandAleksandar Vidakovic 0b5391169f FINERACT-2327: added e2e testing for validatoin of feature allow to create Interest Refund transaction manually 2025-07-23 11:32:30 +02:00
mariiaKraievskaandAleksandar Vidakovic c2e19bb68f FINERACT-2327: Allow to create Interest Refund transaction manually 2025-07-23 11:32:30 +02:00
Adam Saghy 59409550a7 FINERACT-2181: Money helper exception handling 2025-07-21 18:03:33 +02:00
Attila BudaiandAdam Saghy 27bf6d05d5 FINERACT-2181: Moneyhelper multitenant configuration fix, rework it to be a utility class 2025-07-21 18:03:33 +02:00
Rustam ZeinalovandAdam Saghy ecbefb04c4 FINERACT-2317: Added e2e tests covering support for modifying loan approved amounts with validation and history tracking 2025-07-21 17:13:51 +02:00
mark.vituskaandAdam Saghy 6d65f07924 FINERACT-2317: Add support for modifying loan approved amounts with validation and history tracking 2025-07-21 17:13:51 +02:00
Adam Saghy c84ba089f0 Revert "FINERACT-2181: Fix overdue balance updates in advanced payment schedu…"
This reverts commit 46e1bd0492.
2025-07-21 13:29:17 +02:00
Adam Saghy 81d6d2e54e FINERACT-2181: Batch Api - Add Interest pause API support 2025-07-21 12:26:03 +02:00
mark.vituskaandAdam Saghy 46e1bd0492 FINERACT-2181: Fix overdue balance updates in advanced payment schedule processing 2025-07-21 11:47:25 +02:00
adam.magyariandAdam Saghy de7f27f733 FINERACT-2181: Fix github actions not failing test runs on failed tests
- added validation for cumulative multidisburse loan applications for interest method
- test fixes
2025-07-19 21:22:10 +02:00
Jose Alberto HernandezandArnold Gálovics 84f7c9218f FINERACT-2232: Capitalized Income - Fetch amortization details 2025-07-18 22:08:01 +02:00
a7med3del1973andArnold Gálovics c0859f4fda FINERACT-2182: Group creation fails due to NullPointerException when random-account-number=enabled 2025-07-18 17:51:10 +02:00
Mend RenovateandArnold Gálovics a30a34bea8 FINERACT-2181: Update dependency org.hibernate.validator:hibernate-validator to v9 2025-07-18 17:24:30 +02:00
Rustam ZeinalovandAdam Saghy 0729eab430 FINERACT-2325: added e2e tests covering edge cases for disable automatic Interest Refund calculation feature 2025-07-17 16:31:48 +02:00
mariiaKraievskaandAdam Saghy aad7756bf5 FINERACT-2325: Disable automatic Interest Refund calculation 2025-07-17 16:31:48 +02:00
Jose Alberto HernandezandAdam Saghy e2f481f351 FINERACT-2181: Capitalized Income and Buy Down Fees accounting values are still displayed on loan product after feature disabled 2025-07-16 12:06:52 +02:00
Adam Saghy 9e15e459f0 FINERACT-2181: Remove suboptimal indexes 2025-07-15 10:53:26 +02:00
MarianaDmytrivBinariksandAdam Saghy 42ff9743dd FINERACT-2311: added e2e auto test scenarios for add buy down fee final amortization with pay off and charge-off 2025-07-15 10:46:55 +02:00
adam.magyariandAdam Saghy 880580f736 FINERACT-2311: Buy down fee - final amortization
- early repayment
- write off
- charge-off
2025-07-15 10:46:55 +02:00
Adam Saghy 35c51278f9 FINERACT-2181: Change execution order in 1029_add_installment_amount_in_multiples_of_to_loan.xml 2025-07-15 10:07:11 +02:00
Adam SaghyandArnold Gálovics bc4b3555f6 FINERACT-2181: Batch API - Fix read-only connection handling 2025-07-11 21:55:02 +02:00
Mend RenovateandArnold Gálovics 0752106742 FINERACT-2181: Pin dependencies 2025-07-11 10:06:14 +02:00
soticsengeandGitHub 93bfc6fb66 FINERACT-2321: Adding arrears days to loan/at-date api 2025-07-10 16:24:32 +02:00
Rustam ZeinalovandAdam Saghy 5a0115e6ec FINERACT-2319: added e2e test for verifying backdated repayment allocation respects payment order for future dated penalties 2025-07-10 15:03:43 +02:00
Adam Saghy 711aa7910e FINERACT-2181: Batch API - Add interest pause API 2025-07-10 14:02:47 +02:00
Oleksii NovikovandAdam Saghy fc93db16b5 FINERACT-2319: Add penalty-first payment allocation strategy for progressive loans with backdated repayment charge handling 2025-07-10 13:38:56 +02:00
mariiaKraievskaandAdam Saghy 68b2fcb7e1 FINERACT-1968: Added e2e test for validation of progressive Loan schedule handling - (FLAT interest, Same as repayment period, Equal installments) 2025-07-09 14:39:18 +02:00
Soma SörösandAdam Saghy 40f8b59ab4 FINERACT-1968: Progressive Loan schedule handling - interest handling (FLAT interest, Same as repayment period, Equal installments) 2025-07-09 14:39:18 +02:00
Rustam ZeinalovandAdam Saghy 3f359bb368 FINERACT-1981: added e2e test for validation of progressive Loan schedule handling 2025-07-08 23:22:50 +02:00
mariiaKraievskaandAdam Saghy d165a3feda FINERACT-1981: Progressive Loan schedule handling - Installment charges 2025-07-08 23:22:50 +02:00
MarianaDmytrivBinariksandAdam Saghy f76a65ed99 FINERACT-2311: added e2e auto test scenarios for add buy down fee adjustment trn 2025-07-08 22:47:53 +02:00
Jose Alberto HernandezandAdam Saghy 53108227ae FINERACT-2311: Add Buy Down Fees transaction support 2025-07-08 13:50:24 +02:00
adam.magyariandAdam Saghy b8d6dfa794 FINERACT-2311: Buy down fee - daily amortization 2025-07-08 12:38:02 +02:00
Jose Alberto HernandezandAdam Saghy 8a5300ef23 FINERACT-2311: Buy Down fee adjustment - Template API 2025-07-08 12:20:01 +02:00
Adam Saghy 095e0818e4 Revert "FINERACT-2304: Fix auditing of failed batch request while enclosing t…"
This reverts commit 96eb744592.
2025-07-08 09:17:33 +02:00
Oleksii NovikovandArnold Gálovics 96eb744592 FINERACT-2304: Fix auditing of failed batch request while enclosing transaction got enabled 2025-07-08 09:01:46 +02:00
a7med3del1973andArnold Gálovics c09f620324 FINEREACT-2181: Removed unnecessary explicit toString() calls 2025-07-08 08:58:55 +02:00
mark.vituskaandAdam Saghy df995bc932 FINERACT-2181: Fix for certain interest recalculation settings making prepay api and payment allocation inconsistent 2025-07-07 17:04:17 +02:00
MarianaDmytrivBinariksandAdam Saghy 01f850aecc FINERACT-2311: added e2e auto test scenarios for add buy down fees to loan 2025-07-07 17:03:47 +02:00
Attila BudaiandAdam Saghy b2bce4a45d FINERACT-2311: Add buydown fees adjustments 2025-07-07 15:29:27 +02:00
MarianaDmytrivBinariksandAdam Saghy c8b88c3664 FINERACT-2311: added e2e auto test scenarios for manual journal entries with asset externalization owner 2025-07-07 13:59:33 +02:00
Jose Alberto HernandezandAdam Saghy 0c1ca2baba FINERACT-2198: Extend Manual Journal entry to support Asset Externalization 2025-07-07 13:59:33 +02:00
mark.vituskaandAdam Saghy 4feee70a7a FINERACT-2311: Add buy down fee balance entity and db table, create balance on transaction 2025-07-04 14:23:28 +02:00
Rustam ZeinalovandAdam Saghy 71e763115e FINERACT-2181: add e2e test for validation of reschedule loan with interest rate change from / to zero 2025-07-04 14:11:49 +02:00
Jose Alberto HernandezandAdam Saghy bf040561ab FINERACT-2181: Not allow Reschedule loan with interest rate change from / to zero 2025-07-04 14:11:49 +02:00
Abhinav CillankiandAdam Saghy a591f26546 FINERACT-2318: add LoanApplicationModifiedBusinessEvent & LoanWithdrawnByApplicantBusinessEvent 2025-07-04 12:41:57 +02:00
Adam SaghyandArnold Gálovics 70eb2add0d FINERACT-2181: Use matrix jobs via Github Actions to improve performance 2025-07-02 10:01:37 +02:00
Adam SaghyandArnold Gálovics dc2101bc21 FINERACT-2181: Drop resource manipulation 2025-07-02 09:59:27 +02:00
Jose Alberto HernandezandAdam Saghy 570f44ac93 FINERACT-2181: Swagger enhancement for PostSavingsProductsRequest 2025-07-01 20:17:03 +02:00
MarianaDmytrivBinariksandAdam Saghy 072017c601 FINERACT-2181: added e2e auto test scenarios for loan accrual activity posing events 2025-07-01 20:16:50 +02:00
mariiaKraievskaandAdam Saghy f853898818 FINERACT-2181: New Loan Accrual Activity transactions publish LoanAdjustTransaction event during loan reopen 2025-07-01 20:16:50 +02:00
Rustam ZeinalovandAdam Saghy 1d24a8c244 FINERACT-2181: added e2e test validatin accrual entries added after after reseting Loan undo disbursement and running COB 2025-07-01 20:16:15 +02:00
Jose Alberto HernandezandAdam Saghy a8cb6806b0 FINERACT-2181: Reset Last Closed Business date after Loan undo disbursement 2025-07-01 20:16:15 +02:00
budaidevandAdam Saghy 98b7328508 FINERACT-2311: Add buydown fees to loan 2025-07-01 20:14:43 +02:00
Oleksii NovikovandAdam Saghy cb6a15c3d2 FINERACT-2234: Replace in-memory transaction loops with repository queries 2025-07-01 20:14:28 +02:00
Adam Saghy dd4ca4d3e2 FINERACT-2181: Remove processResource hack 2025-07-01 12:30:19 +02:00
viktorpavlenkoandAleksandar Vidakovic 4c3da5b06a FINERACT-2247: New command processing - Currency Management (org.apache.fineract.organisation.monetary) 2025-06-28 10:38:32 +02:00
viktorpavlenkoandAleksandar Vidakovic 0629bb2d48 FINERACT-2241: New command processing - Cache Management (org.apache.fineract.infrastructure.cache) 2025-06-27 12:49:37 +02:00
viktorpavlenkoandAleksandar Vidakovic ba06234f26 FINERACT-2242: New command processing - External Event Configuration (org.apache.fineract.infrastructure.event.external) 2025-06-26 15:37:53 +02:00
budaidevandAdam Saghy 86024b83cc FINERACT-2304: Making sure that in the publishHookErrorEvent or publishHookEvent does not throw any exception 2025-06-26 15:07:06 +02:00
MarianaDmytrivBinariksandAdam Saghy f09055199a FINERACT-2311: cover accounting config for buy down fees auto tests 2025-06-26 10:02:49 +02:00
adam.magyariandAdam Saghy d88f6a2f22 FINERACT-2311: Loan product - Buy down fees accounting configuration 2025-06-26 10:02:49 +02:00
viktorpavlenkoandAleksandar Vidakovic bb46397daa FINERACT-2238: New command processing - Business Date Management (org.apache.fineract.infrastructure.businessdate) 2025-06-26 00:49:05 +02:00
a7med3del1973andAdam Saghy d5958f36c7 FINERACT-2213: Client transfer from one branch to another leaves loans attached to the client in transfer.in.progress status instead of active 2025-06-24 15:20:08 +02:00
MarianaDmytrivBinariksandAdam Saghy 28fbaa920d FINERACT-2311: add tests for buy down fees on product level 2025-06-24 15:06:54 +02:00
Rustam ZeinalovandAdam Saghy dc3ead4f80 FINERACT-2311: Added e2e tests for validation of backend part of buy down fees 2025-06-24 15:06:54 +02:00
adam.magyariandAdam Saghy 1b1d6be956 FINERACT-2311: Loan product - Buy down fees configuration 2025-06-24 15:06:54 +02:00
Adam Saghy 29d1ed3cd4 FINERACT-2181: JIB docker build requires resources files to be merged with classes 2025-06-24 10:09:46 +02:00
mark.vituskaandAdam Saghy 9c872760e5 FINERACT-2181: add e2e test to cover capitalized income amortization adjustment case 2025-06-23 13:13:40 +02:00
Adam Saghy db28259b1a FINERACT-2181: Gradle task rework - Optimized weaving across all modules 2025-06-22 22:41:34 +02:00
MarianaDmytrivBinariksandAdam Saghy ee5290c92e FINERACT-2181: add tests for capitalized income validation with enabled over appiled amount setting 2025-06-22 22:35:36 +02:00
mariiaKraievskaandAdam Saghy e4ab6110ff FINERACT-2181: Fix validation for add capitalized income to loan transaction 2025-06-22 22:35:36 +02:00
Arnold GalovicsandArnold Gálovics a76c189a04 Revert "FINERACT-2181: Some tweaks in the gradle build to ensure correct task processing"
This reverts commit 6cb60f48
2025-06-20 21:53:28 +02:00
Arnold GalovicsandArnold Gálovics 1ebfad230c Revert "FINERACT-2181: Some tweaks in the gradle build to ensure correct task processing"
This reverts commit 11cecb0d45.
2025-06-20 21:53:28 +02:00
Arnold GalovicsandArnold Gálovics d46ab4e73e Revert "FINERACT-2181: Make 'staticWeaveJPA' gradle task cacheable"
This reverts commit dd2c29fb91.
2025-06-20 21:53:28 +02:00
Arnold GalovicsandArnold Gálovics 4b7335b724 Revert "FINERACT-2181: Add missing converters to persistence.xml"
This reverts commit 62bb1e6509.
2025-06-20 21:53:28 +02:00
mark.vituskaandArnold Gálovics 3829c4404f FINERACT-2181: ensure loan transactions are saved and linked to loan object consistently across business steps 2025-06-19 21:45:29 +02:00
Adam SaghyandArnold Gálovics 62bb1e6509 FINERACT-2181: Add missing converters to persistence.xml 2025-06-19 21:44:52 +02:00
Adam SaghyandArnold Gálovics b7513849c8 FINERACT-2181: Fix randomly failing COB catch up test 2025-06-19 21:44:34 +02:00
Arnold GalovicsandArnold Gálovics a158c930bc FINERACT-2181: Prepayment flow test fixes 2025-06-19 11:10:36 +02:00
CsengeSótiandArnold Gálovics cb82af119b FINERACT-2181: fix prepayment functionality when prepayment happens in the first month of loan 2025-06-19 11:10:36 +02:00
Adam SaghyandArnold Gálovics dd2c29fb91 FINERACT-2181: Make 'staticWeaveJPA' gradle task cacheable 2025-06-19 07:12:59 +02:00
mark.vituskaandAdam Saghy 5a7d2d42f9 FINERACT-2181: add e2e test to cover additional future unrecognized interest use-case 2025-06-18 22:56:33 +02:00
tamasszabo-dpcandAdam Saghy 5aa4afb87c FINERACT-2181: Added test cases to cover MIR scenarios where last installment principal got updated to null 2025-06-18 19:43:06 +02:00
Soma SörösandAdam Saghy 74d079bc3d FINERACT-2181: Prevent Infinite Loop on MIR when last installment principal got updated to null 2025-06-18 19:43:06 +02:00
dependabot[bot]GitHubdependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
a21fe48c79 Bump gradle/actions from 4.4.0 to 4.4.1 (#4765)
Bumps [gradle/actions](https://github.com/gradle/actions) from 4.4.0 to 4.4.1.
- [Release notes](https://github.com/gradle/actions/releases)
- [Commits](https://github.com/gradle/actions/compare/8379f6a1328ee0e06e2bb424dadb7b159856a326...ac638b010cf58a27ee6c972d7336334ccaf61c96)

---
updated-dependencies:
- dependency-name: gradle/actions
  dependency-version: 4.4.1
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-06-18 08:29:29 -06:00
Rustam ZeinalovandAdam Saghy 0319be4416 FINERACT-2279: added e2e for validation contract termination undo 2025-06-18 16:19:33 +02:00
mariiaKraievskaandAdam Saghy ee29ce23ac FINERACT-2279: Contract Termination - Undo 2025-06-18 16:19:33 +02:00
Adam SaghyandArnold Gálovics 11cecb0d45 FINERACT-2181: Some tweaks in the gradle build to ensure correct task processing 2025-06-18 15:54:00 +02:00
MarianaDmytrivBinariksandAdam Saghy e840db50fc FINERACT-2308: added e2e tests for allow approval disbursal over applied amount calculation 2025-06-18 15:15:28 +02:00
Jose Alberto HernandezandAdam Saghy bb29932658 FINERACT-2308: Allow approval and disbursal above loan applied amount with non multibursal loan product 2025-06-18 15:15:28 +02:00
mariiaKraievskaandAdam Saghy 38a5686df8 FINERACT-2181: Update outstandingBalance when the LoanInterestRecalculationCOBBusinessStep of COB job is executed 2025-06-18 12:23:24 +02:00
Rustam ZeinalovandAdam Saghy 2644981424 FINERACT-2181: Added e2e test covering case with lifting charge-off flag and charge-off date in case the charge-off transaction got reversed 2025-06-18 12:21:58 +02:00
Abhinav CillankiandAdam Saghy 159eff0ad4 FINERACT-2309: Emit external events on document upload and delete 2025-06-18 12:20:36 +02:00
mariiaKraievskaandAdam Saghy 496e37e3d4 FINERACT-2181: Accruals on accounts where charge adjustments and refunds are done on the same day causing duplicate journal entries 2025-06-18 12:14:20 +02:00
mark.vituskaandAdam Saghy 5649aa3ded FINERACT-2281: fix unrecognized interest handling when first period is unpaid 2025-06-18 10:53:30 +02:00
Adam Monsen 4d56a4f230 add gradle --refresh-dependencies band-aid
I'd love some expert eyes on this section and feedback on whether these kinds of extra clean-up procedures are often, sometimes, or rarely useful.
2025-06-16 15:23:26 -07:00
Adam Monsen f28d252f17 FINERACT-2310: collate and improve security documentation
* fix various typos, spacing, formatting issues
* fix links to legacy docs in API docs
* update keycloak oauth dev instructions
* update default oauth URL for latest Keycloak
* use consistent quoting in oauth docs (single quotes)
* use asciidoc auto-enumerated lists whenever possible
* migrate security topics from readme into asciidoc: oauth, 2FA, HTTPS
* move :hardbreaks: setting to config file so all config settings are in one place. (I think it's fine that `license.adoc` will use hardbreaks -- that's how the plain text version is formatted so it should look more familiar)
* add intro to security chapter
* migrate in Securing Fineract wiki content from https://cwiki.apache.org/confluence/display/FINERACT/Securing+Fineract
* just say "oauth" (not "oauth2") to conform terminology throughout docs -- OAuth 2.0 is just the latest version
* cross-ref HTTPS section from Securing Fineract
* reposition hardening options as tips
* see also: https://lists.apache.org/thread/81qdxttffp6wn23c48zvk93hc13373qv
* simplify/clarify example oauth curl requests
  * Testing just now and I didn't need --location.
  * Also I imagine folks will need --insecure with the self-signed default cert in dev.
* don't change default oauth URL
  * no surprises for existing deployments
  * clarifies the keycloak v26 example
2025-06-16 15:12:55 -07:00
budaidevandAdam Saghy 2c77f6a277 FINERACT-2304: Avoid retrying after the command succeed 2025-06-14 14:08:35 +02:00
Peter KovacsandAdam Saghy e77f783609 FINERACT-2232: Capitalized income and Caplitalized income adjustment in case of loan is overpaid - E2E 2025-06-14 14:04:27 +02:00
Jose Alberto HernandezandAdam Saghy 3b5b96a5f4 FINERACT-2232: Capitalized income and Caplitalized income adjustment in case of loan is overpaid 2025-06-14 14:04:27 +02:00
Peter KovacsandAdam Saghy 009d7b71a9 FINERACT-2232: Capitalized income - Business events - E2E 2025-06-13 18:01:14 +02:00
adam.magyariandAdam Saghy 6cd634cb2f FINERACT-2232: Capitalized income - Business events 2025-06-13 18:01:14 +02:00
Jose Alberto HernandezandAdam Saghy de580c2cef FINERACT-2232: Add missing fields on the Capitalized Income and Adjustment transactions 2025-06-12 23:47:49 +02:00
MarianaDmytrivBinariksandAdam Saghy c490e167b8 FINERACT-2232: added e2e automation tests for capitalized income amortization calculation 2025-06-12 23:42:12 +02:00
adam.magyariandAdam Saghy 76b9cde83c FINERACT-2232: Capitalized income - Amortization rework 2025-06-12 23:42:12 +02:00
Soma SörösandArnold Gálovics e811491da7 FINERACT-2304: Handle Stuck CommandProcessing Retries 2025-06-12 10:12:24 +02:00
Adam Saghy 7c656ecae8 FINERACT-2181: Using JUnit 5 for E2E 2025-06-11 20:44:21 +02:00
Adam Saghy c37e2daa86 FINERACT-2181: Enhance job execution polling in E2E tests 2025-06-10 17:54:51 +02:00
Adam Saghy 3cef64f3cf FINERACT-2181: Add missing indexes (with check and concurrently) 2025-06-10 14:27:05 +02:00
Oleksii NovikovandAdam Saghy 4d7a3efc13 FINERACT-2234: Improve accrual activity posting business step performance 2025-06-10 13:16:36 +02:00
Rustam ZeinalovandAdam Saghy 3ce44f836d FINERACT-2232: added e2e test for validation of capitalized income balance handling during reverse replay situations 2025-06-10 10:06:48 +02:00
mark.vituskaandAdam Saghy ad8fe13064 FINERACT-2232: fix capitalized income balance handling during reverse replay situations 2025-06-10 10:06:48 +02:00
Jose Alberto HernandezandArnold Gálovics 76a03ecdbf FINERACT-2232: Capitalized income and Caplitalized income adjustment in case of loan is overpaid 2025-06-06 18:43:31 +02:00
Soma SörösandArnold Gálovics 8edf49e689 FINERACT-2304: Fix SynchronousCommandProcessingService retry error handling around execute command 2025-06-06 18:42:53 +02:00
Adam Saghy 19b2a77127 FINERACT-2181: Fix integration test / unify getLoanRepaymentScheduleDetail() 2025-06-06 15:08:40 +02:00
Soma SörösandAdam Saghy caf42f733c FINERACT-2304: Create Configuration assembler and move resilience4j props into fineract namespace implement proper retry for SynchronousCommandProcessingService and BatchApiServiceImpl 2025-06-06 14:03:11 +02:00
Rustam ZeinalovandAdam Saghy a687227f33 INERACT-2211: added e2e test for validation of bug fix 2025-06-06 10:55:17 +02:00
budaidevandAdam Saghy 56e89ba544 FINERACT-2211: Second disbursement error fix 2025-06-06 10:55:17 +02:00
Jose Alberto HernandezandAdam Saghy 39a8d5c63e FINERACT-2181: Installment amount in multiples of should be inherited from loan product to loan level 2025-06-06 10:54:29 +02:00
RamsesCamacho1171andGitHub 95a8231b18 FINERACT-2202: Bulk import fix (#4735)
LGMT
2025-06-05 18:34:04 -06:00
tamasszabo-dpcandAdam Saghy 23f6a2ec62 FINERACT-2181: Added revert replay checks for transactions check 2025-06-05 14:59:27 +02:00
Oleksii NovikovandAdam Saghy dc1d6610a3 FINERACT-2181: Add Merchant Issued Refund reverse replayed with penalty charge test 2025-06-05 14:59:27 +02:00
Rustam ZeinalovandAdam Saghy dc267a2a1a FINERACT-2553: added e2e test covering case with backdated repayment covers remaining balance after charge-off 2025-06-05 14:58:20 +02:00
mariiaKraievskaandAdam Saghy 71a4d08849 FINERACT-2553: Fix repayment schedule during accelerate maturity date charge off/contract termination when full backdated repayment occurs after it 2025-06-05 14:58:20 +02:00
mdmytrivandAdam Saghy 57ef4a2771 FINERACT-2307: added e2e tests for disbursement with Capitalized Income amount calculation while approved over applied setting enabled 2025-06-05 14:57:00 +02:00
Adam Saghy 6e5c6c4913 FINERACT-2181: No need for explicit serialization 2025-06-04 21:24:21 +02:00
mark.vituskaandAdam Saghy 83905d627d FINERACT-2181: fix name collision in swagger resources 2025-06-04 21:24:21 +02:00
Adam Saghy f383ee7c17 FINERACT-2181: Remove command param lower casing 2025-06-04 21:23:59 +02:00
Adam Saghy 9e39ecb279 FINERACT-2181: Add datatable field to Loan request swagger 2025-06-04 21:23:51 +02:00
Adam Saghy a8f2fcd903 FINERACT-2181: Update Transaction summary with asset owner report 2025-06-04 21:23:28 +02:00
a7med3del1973andAdam Saghy 9e12e3b1cd FINERACT-2181: Refactor code quality 2025-06-03 10:47:39 +02:00
mdmytrivandAdam Saghy a308a96bed FINERACT-2232: added e2e automation tests for capitalized income reversal 2025-06-03 10:46:56 +02:00
tamasszabo-dpcandAdam Saghy 50851e8b21 FINERACT-2232: Added capitalized income adjustment reversal scenarios 2025-06-03 10:46:56 +02:00
adam.magyariandAdam Saghy 1556b8608f FINERACT-2232: Capitalized income - transaction reversal 2025-06-03 10:46:56 +02:00
mdmytrivandArnold Gálovics 5f223e527e FINERACT-2181: added e2e automation tests for disbursement with Capitalized income amount calculation fix 2025-06-02 21:24:31 +02:00
tamasszabo-dpcandArnold Gálovics 19270b7651 FINERACT-2152: Added test case to check the repayment schedule when interest pause added on the 1st day 2025-06-02 21:24:15 +02:00
Oleksii NovikovandArnold Gálovics 42f5de937d FINERACT-2152: Fix interest pause on the 1st day of the 1st period 2025-06-02 21:24:15 +02:00
mdmytrivandAdam Saghy c44972043e FINERACT-2232: added e2e automation tests for capitalized income validation with future date and COB run 2025-06-02 13:22:02 +02:00
adam.magyariandAdam Saghy 5281c7b17d FINERACT-2232: Validations and cob step fix
- Add validation for capitalized income transaction not being in the future
- CapitalizedIncomeAmortizationBusinessStep add filter against too early amortization
2025-06-02 13:22:02 +02:00
Adam SaghyandArnold Gálovics 1aff3fc9b6 FINERACT-2181: Add null safety to Money class 2025-06-02 09:31:38 +02:00
Adam SaghyandArnold Gálovics 0296bf80cf FINERACT-2181: Do not create zero amount Accrual at disbursement 2025-06-02 08:26:51 +02:00
Jose Alberto HernandezandAdam Saghy 060cdb5685 FINERACT-2181: Loan disbursement amount exceed loan principal amount when we have Capitalized Income 2025-06-01 18:05:03 +02:00
mark.vituskaandAdam Saghy 0d8d6671a1 FINERACT-2304: Add versioning to LoanTransaction entity 2025-06-01 18:04:00 +02:00
Oleksii NovikovandAdam Saghy f6f8c6f4a5 FINERACT-2274: Rework Accrual service 2025-06-01 18:03:22 +02:00
fa405f09fd FINERACT-2202: Bulk import fix (#4709)
Co-authored-by: Edder Lugo <edder.sanjuan@fintecheando.mx>
2025-05-30 18:47:09 -06:00
Adam Saghy 5e884d5f45 FINERACT-2279: Contract Termination - Schedule Handing & Reverse-replay 2025-05-31 00:22:00 +02:00
Adam Monsen c5275cbd34 FINERACT-2306: release doc fixes
* docs: link directly to FINERACT-873 and shorten it for brevity / clarity
* fineract plugin:
  * print email, don't send (WIP, but I might keep this... I prefer manually sending emails for now.)
  * support different release date and release branch date

I originally modified EmailService (disabling the actual email sending by just commenting it out) but I reverted that change per discussion with Ádám Sághy. You won't see this in the squashed final commit so I'm mentioning it here for posterity.

Ádám wrote:

> Is there a reason to remove the email sending?

I replied:

> Great question. I did think about this for a bit. I should have been more transparent about my intent. Allow me to explain.
>
> For the 1.12.0 release process I used the groovy code to generate email templates, but I wanted to edit the emails before sending so I disabled this line, and intentionally left it so, figuring I'd be the one using and [hopefully minimally] maintaining it for now.
>
> The Fineract (release) plugin appears to be more or less unmaintained for about 2 1/2 years now (save the semiautomated dependency updates). Looking at the code and history, I assumed I was the only one that would be using it now and in the near future. It also struck me how most everything it does is primarily to work around antiquated Apache release process steps that are not necessarily what we want for Fineract. Personally I think the Fineract release plugin should be simply replaced by a better release process.
>
> I think I'll add a comment there, and of course I welcome your feedback.
>
> Anyway yeah, my intent here was simply to do the simplest, safest, and most useful change here so I could keep this release plugin limping along until we improve the release process itself. No disrespect to @vidakovic and @vorburger and whomever else poured love into this code over the years. Perhaps the options for releasing Apache code have improved since then?
>
> Today we can of course do better (e.g. just let GitHub help us release with far fewer clicks/steps).
>
> Also I am not proposing we change the release process today or even soon. Maybe in a quarter or two I'll propose changes, if/when there seems to be political will around that.

Ádám replied:

> hmm... i am not particularly mind if you are reworking the release process, but i think having a "send" step which was meant to sending a mail but now the actual sending got commented out is misleading, no?

I replied:

> Yep, you're right. I think I'll just back out this change because I agree with you it's bad to just leave the send() call commented out without any other changes.
2025-05-30 09:12:44 -07:00
Soma SörösandAdam Saghy 21425f50c4 FINERACT-2275: Review whether reprocessing accruals are in fact needed or not after recalculated interest on loan 2025-05-29 17:35:33 +02:00
tamasszabo-dpcandAdam Saghy b867de889b FINERACT-2232: Added capitalized income scenarios to cover reverse replay logic 2025-05-29 16:19:29 +02:00
Rustam ZeinalovandAdam Saghy 7051fe94aa FINERACT-2232: Added e2e test covering capitalized income adjustment 2025-05-29 16:19:29 +02:00
adam.magyariandAdam Saghy 82eafad8dd FINERACT-2232: Capitalized income adjustment 2025-05-29 16:19:29 +02:00
Jose Alberto HernandezandAdam Saghy 94cc68ba7c FINERACT-2181: Fix Consult Loan repayment schedule with disbursement harge using amount plus interest 2025-05-29 15:08:50 +02:00
Rustam ZeinalovandAdam Saghy 9d6243442c FINERACT-1981: Updated e2e tests covering the feature 2025-05-29 15:01:23 +02:00
budaidevandAdam Saghy 6e77b0702a FINERACT-1981: Loan schedule handling of tranche disbursement charges 2025-05-29 15:01:23 +02:00
mark.vituskaandAdam Saghy 96d6099cc1 FINERACT-2304 - fix entity manager usage only through persistence context annotation 2025-05-29 13:52:49 +02:00
a7med3del1973andAdam Saghy d71c0bd204 FINERACT-2267: Use the proper not-null annotation in Fineract code base 2025-05-27 20:21:19 +02:00
Peter KovacsandAdam Saghy 8d7d8ca7ef FINERACT-2232: add income capitalization principal handling and repayment schedule calculations on loans - E2E tests 2025-05-27 18:35:39 +02:00
mark.vituskaandAdam Saghy aac62a92bb FINERACT-2232: add income capitalization principal handling and repayment schedule calculations on loans 2025-05-27 18:35:39 +02:00
mark.vituskaandAdam Saghy c89ec910d8 FINERACT-2181: fix api double values in loan definitions 2025-05-27 10:02:25 +02:00
Peter KovacsandAdam Saghy a40c0d4703 FINERACT-2232: add income capitalization principal handling and repayment schedule calculations on loans - E2E tests 2025-05-27 10:02:25 +02:00
mark.vituskaandAdam Saghy e5329f6fe3 FINERACT-2232: add income capitalization principal handling and repayment schedule calculations on loans 2025-05-27 10:02:25 +02:00
mariiaKraievskaandAdam Saghy 07839951b9 FINERACT-2278: Rework raiseBusinessEventForAccrualTransactions to not use loan.getLoanTransactions() 2025-05-26 16:24:56 +02:00
mariiaKraievskaandAdam Saghy 8b86229a3e FINERACT-2277: Deprecate findExistingReversedTransactionIds and fetch only the ids from database instead 2025-05-26 14:41:32 +02:00
mariiaKraievskaandAdam Saghy 13e4c8b55d FINERACT-2276: Deprecate findExistingTransactionIds and fetch only the ids from database instead 2025-05-26 11:40:10 +02:00
mariiaKraievskaandAdam Saghy 88105c3cac FINERACT-2273: Make sure the setters of Loan repayment installment entity balances maintain the scaling of 6 and set null in case the value is zero 2025-05-26 11:27:26 +02:00
Adam Saghy 6cb60f48fc FINERACT-2181: Some tweaks in the gradle build to ensure correct task processing 2025-05-25 22:12:22 +02:00
Adam Saghy 25ef93a30b FINERACT-2181: Add missing index for transaction_id field of acc_gl_journal_entry table 2025-05-25 19:18:21 +02:00
Adam Saghy b0a9bcb3ec FINERACT-2181: Use disruptor only if it is configured 2025-05-25 19:18:13 +02:00
mdmytrivandArnold Gálovics 1aa8395458 FINERACT-2281: added e2e automation tests for cases with accrual calculation on maturity date scenarios 2025-05-24 12:13:45 +02:00
mdmytrivandAdam Saghy d963c340ee FINERACT-2281: added e2e automation tests for cases with no interest activities are recognized for reversal repayment scenarios 2025-05-24 01:18:46 +02:00
Jose Alberto HernandezandAdam Saghy 544607a05a FINERACT-2232: Capitalized Incomce Adjustment template 2025-05-24 01:17:55 +02:00
Peter KovacsandAdam Saghy f6e24d420a FINERACT-2181: unSkip fixed scenarios - @TestRailId:C2795, @TestRailId:C2798 2025-05-23 09:43:43 +02:00
Soma SörösandAdam Saghy 98055682d3 FINERACT-2281: Interest Activities Not Posting For Loan With Repayment Reversal 2025-05-23 09:42:09 +02:00
Adam Saghy ecac6d2153 FINERACT-2181: Format enums 2025-05-22 17:13:49 +02:00
Oleksii NovikovandAdam Saghy 47d5330802 FINERACT-2080: Extract calculations from loan entity 2025-05-22 13:58:44 +02:00
Adam Saghy 18a55874ba FINERACT-2286: Make configurable the outstanding interest strategy during asset owner transfer 2025-05-22 13:27:36 +02:00
mark.vituskaandArnold Gálovics a3a5aabb7f FINERACT-2181: fix accrual calculation date condition 2025-05-22 11:41:19 +02:00
Adam Saghy 9c01540990 FINERACT-2181: Check whether loan got closed after the test 2025-05-22 10:37:57 +02:00
danielales2541andAdam Saghy 24145ae308 FINERACT-2202: Bulk import fix 2025-05-22 10:37:36 +02:00
mariiaKraievskaandAdam Saghy 5cd604df43 FINERACT-2272: Move fetching chargeback transactions out of foreach of delinquency calculation 2025-05-22 10:22:35 +02:00
Adam Saghy 91da34a8c6 FINERACT-2262: Fix cache resolution 2025-05-21 21:13:31 +02:00
Adam Saghy f8d9958ea7 FINERACT-2181: Fix audit filtering 2025-05-21 21:12:02 +02:00
Adam Saghy 15c968bc1b FINERACT-2181: Fix fully paid check on EmiModel 2025-05-21 17:16:02 +02:00
mariiaKraievskaandArnold Gálovics 4861ad19fd FINERACT-2232: Capitalized income - amortization in case of Charge-off event 2025-05-19 21:56:48 +02:00
dependabot[bot]andArnold Gálovics 39062ad1a1 Bump gradle/actions from 4.3.1 to 4.4.0
Bumps [gradle/actions](https://github.com/gradle/actions) from 4.3.1 to 4.4.0.
- [Release notes](https://github.com/gradle/actions/releases)
- [Commits](https://github.com/gradle/actions/compare/06832c7b30a0129d7fb559bcc6e43d26f6374244...8379f6a1328ee0e06e2bb424dadb7b159856a326)

---
updated-dependencies:
- dependency-name: gradle/actions
  dependency-version: 4.4.0
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2025-05-19 19:40:00 +02:00
Adam Saghy 5f59091b70 FINERACT-2283: Self-service APIs are disabled by default 2025-05-16 23:18:02 +02:00
Adam Saghy c79de9bb7a FINERACT-2282: Support Client filtering by legal form 2025-05-16 19:36:48 +02:00
mariiaKraievskaandAdam Saghy ed42fb2410 FINERACT-2179: Advance Payment Allocation- Next-Last Option behaviour change 2025-05-16 15:51:16 +02:00
a7med3del1973andAdam Saghy 6d49d76e73 FINERACT-2181:improve code quality 2025-05-16 15:45:37 +02:00
Jose Alberto HernandezandAdam Saghy 62afd41182 FINERACT-2181: fix Charges using percentage calculation with min and max gap values 2025-05-16 15:44:37 +02:00
mdmytrivandAdam Saghy 793dcd8e8b FINERACT-2280: add e2e automation tests for scenarios with prevent interest pause for loan with interest rate zero 2025-05-16 14:25:06 +02:00
Soma SörösandAdam Saghy 9ab08ec428 FINERACT-2280: Interest pause breaks repayment schedule while loan is added with interest rate zero 2025-05-16 14:25:06 +02:00
Soma SörösandAdam Saghy cd03dc020e FINERACT-2220: Use stored ProgressiveLoanInterestScheduleModel for processLatestTransaction if applicable 2025-05-16 10:03:54 +02:00
mdmytrivandAdam Saghy 1fc2aae654 FINERACT-2181: add e2e automation tests while charge-off is added before charge and charge waive 2025-05-14 12:17:49 +02:00
mark.vituskaandAdam Saghy 8c34fe2122 FINERACT-2181: fix undo transaction on charges waiver not reversing changes on loan charge 2025-05-14 12:17:49 +02:00
Peter KovacsandAdam Saghy 34712d223a FINERACT-2232: Capitalized income - Daily amortization - E2E tests 2025-05-14 12:17:19 +02:00
adam.magyariandAdam Saghy ed4fba3ace FINERACT-2232: Capitalized income - Daily amortization 2025-05-14 12:17:19 +02:00
mariiaKraievskaandAdam Saghy e69378637d FINERACT-2232: Capitalized income - amortization in case of Preclose event 2025-05-13 15:09:37 +02:00
mdmytrivandAdam Saghy d1154c59ba FINERACT-2181: added e2e automation tests for expected tranches with disbursements fix 2025-05-13 09:39:42 +02:00
adam.magyariandAdam Saghy e7b6722e54 FINERACT-2181: Add missing swagger definition for addAndDeleteDisbursementDetail request 2025-05-13 09:39:42 +02:00
Adam Saghy 8488918b3b FINERACT-2181: Update dependencies 2025-05-12 10:37:28 +02:00
budaidevandAdam Saghy 788cd7aff7 FINERACT-2080: Extract complex loan actions out from Loan entity 2025-05-12 10:24:26 +02:00
Víctor RomeroandGitHub ec566b7166 FINERACT: 2181 Update build.gradle for publishing fineract-command 2025-05-10 10:48:28 -06:00
danielales2541andArnold Gálovics e70e00328a FINERACT-2202: Bulk import fix 2025-05-10 14:39:06 +02:00
Jose Alberto HernandezandArnold Gálovics 9026fb9546 FINERACT-2181: Fix Consult Loan repayment schedule with disbursement charge using interest 2025-05-10 14:35:29 +02:00
f2efad40a6 FINERACT-2202: Bulk import fix (#4650)
Co-authored-by: danielales2541 <danielalejandrolara573@gmail.com>
2025-05-09 12:07:27 -06:00
mariiaKraievskaandAdam Saghy fad9d3e4eb FINERACT-2210: Reverse the charge-off transaction if the amount balance becomes zero 2025-05-09 10:52:18 +02:00
Adam Saghy c39a79e9b1 FINERACT-2262: Fix cache resolution 2025-05-07 16:28:52 +02:00
Adam SaghyandArnold Gálovics 4a3455b1e2 FINERACT-2181: Add missing disallowInterestCalculationOnPastDue field to PutLoanProductsProductIdRequest swagger definition 2025-05-06 19:10:32 +02:00
adam.magyariandArnold Gálovics b93ad461b4 FINERACT-2181: Loan expect tranche fix 2025-05-06 11:05:42 +02:00
Adam Saghy c7c85cb038 FINERACT-2181: Add missing indexes 2025-05-05 15:57:31 +02:00
Víctor RomeroandGitHub 0465af7015 FINERACT-2181: Update EclipseLink
FINERACT-2181: Update EclipseLink
2025-05-03 17:28:40 -06:00
Adam Saghy aaf1351c4f FINERACT-2268: Fix GL account deletion logic 2025-04-30 14:04:12 +02:00
budaidevandAdam Saghy 354f1bdc93 FINERACT-2234: add interest recalc filter 2025-04-30 13:52:32 +02:00
Soma SörösandAdam Saghy 071592eceb FINERACT-2220: Use stored ProgressiveLoanInterestScheduleModel for Periodic Accrual Calculation 2025-04-30 13:29:29 +02:00
danielales2541andAdam Saghy 0563311251 FINERACT-2202: Bulk import fix 2025-04-30 10:43:37 +02:00
mdmytrivandAdam Saghy 642ea23e9e FINERACT-2232: e2e tests for capitalized income after disbursement 2025-04-30 10:23:55 +02:00
Adam Saghy 752dd4a10e FINERACT-2232: Capitalized income - Add Capitalized income to Loan 2025-04-30 10:23:55 +02:00
mariiaKraievskaandAdam Saghy e10542838e FINERACT-2232: Capitalized income - Add Capitalized income to Loan 2025-04-30 10:23:55 +02:00
Peter KovacsandAdam Saghy bb0bdb9670 FINERACT-2210: fix previously refunded interest calculation during interest refund - E2E test 2025-04-29 13:28:55 +02:00
mark.vituskaandAdam Saghy 931e920295 FINERACT-2210: fix previously refunded interest calculation during interest refund 2025-04-29 13:28:55 +02:00
Soma SörösandAdam Saghy 2d17fcd478 FINERACT-2220: Use stored ProgressiveLoanInterestScheduleModel for calculation 2025-04-29 13:12:51 +02:00
mdmytrivandAdam Saghy d7f321bc65 FINERACT-2264: added e2e tests for incorrect interest handling in case of early repayment in the middle of interest pause 2025-04-28 23:45:33 +02:00
Soma SörösandAdam Saghy 509cbd8b19 FINERACT-2264: Interest pause issue - Interest calculation start again in case of early repayment during interest period 2025-04-28 23:45:33 +02:00
Rustam ZeinalovandAdam Saghy bbf797fc34 FINERACT-2226: Added e2e tests for testing repayment reversal issue after charge off and MIR 2025-04-28 17:56:44 +02:00
mariiaKraievskaandAdam Saghy c8a641e474 FINERACT-2226: Fix repayment reversal issue after charge off and MIR 2025-04-28 17:56:44 +02:00
viktorpavlenkoandAdam Saghy db28fa1463 FINERACT-2169: Refactor account api controller; 2025-04-28 14:55:37 +02:00
adam.magyariandAdam Saghy 964017e666 FINERACT-2232: Capitalized income - amortization calc util 2025-04-28 14:53:40 +02:00
budaidevandAdam Saghy 6d3e19cf25 FINERACT-2234: add extra caches to frequent database queries during the interest recalculation 2025-04-28 14:51:11 +02:00
Peter KovacsandAdam Saghy efd17d5a3e FINERACT-2265: Progressive Loan - Interest Recalculation fails for - RecalculationRestFrequencyType SameAsRepaymentPeriod - E2E 2025-04-25 16:36:56 +02:00
Rustam ZeinalovandAdam Saghy c66dc9530d FINERACT-2173:updated existing and added new e2e tests covering basic migration scenario related to cob 2025-04-25 13:58:12 +02:00
adam.magyariandAdam Saghy d88f634197 FINERACT-2232: Capitalized income - income type config 2025-04-25 12:35:23 +02:00
adam.magyariandAdam Saghy 85fac1e1b0 FINERACT-2232: Capitalized income - accounting configuration 2025-04-25 12:35:23 +02:00
Adam MonsenandAdam Saghy 834e90dce0 FINERACT-2269: various small dev-focused improvements
remove unnecessary javadoc html5 option

html5 output is the default since at least Java 17

improve markdown formatting for PR template

fix casing, per GH recommendations

https://docs.github.com/en/communities/using-templates-to-encourage-useful-issues-and-pull-requests/creating-a-pull-request-template-for-your-repository recommends lowercase

document system default Java issues

reorder integration test hints importance-wise

make devRun the default

It's faster and more obviously useful for developers.

See https://lists.apache.org/thread/zxvtx9nqqbojvt0dd65tk8zd4xp6ot0t

mention gradle not re-running tests

remove Gitpod

per James, Ádám, and Victor, this is no longer used/supported

for setting up a local dev environment see the top-level README.md and https://fineract-academy.com
2025-04-24 14:31:54 +02:00
oleksandr.masliukandAdam Saghy 8eca8cbc8c FINERACT-2169: Refactor WorkingDaysApiResource - apply dto 2025-04-24 14:31:23 +02:00
viktorpavlenkoandAdam Saghy c069a6bf3c FINERACT-2169: Refactor staff api controller; 2025-04-24 14:02:27 +02:00
Oleksii NovikovandAdam Saghy e5a23406ca FINERACT-2080: Extract accountNumberRequiresAutoGeneration from loan entity 2025-04-24 11:55:36 +02:00
Jose Alberto HernandezandAdam Saghy 205b39ddf0 FINERACT-2232: Loan account capitalized income transaction template 2025-04-24 11:48:10 +02:00
mariiaKraievskaandAdam Saghy 13c99f98ab FINERACT-2210: Fix incorrect accounting of "buyback" for charged-off loan with fraud 2025-04-24 11:46:14 +02:00
viktorpavlenkoandAdam Saghy 30543fd72e FINERACT-2169: Refactor client address controller; 2025-04-24 11:45:13 +02:00
mark.vituskaandAdam Saghy 99f12d6091 FINERACT-2140: added hsts protocol support through system property 2025-04-23 12:22:45 +02:00
viktorpavlenkoandAdam Saghy a9fe523eae FINERACT-2169: Refactor collection sheet api; 2025-04-23 12:17:35 +02:00
viktorpavlenkoandAdam Saghy a72a919562 FINERACT-2169: Refactor group level api; 2025-04-23 12:15:02 +02:00
viktorpavlenkoandAdam Saghy 2ec05beea6 FINERACT-2169: Refactor interest rate chart slab api; 2025-04-23 11:24:47 +02:00
Oleksii NovikovandAdam Saghy 3687391148 FINERACT-2221: Add immediate charge accrual post maturity for progressive loans 2025-04-23 10:58:23 +02:00
viktorpavlenkoandAdam Saghy 241906e042 FINERACT-2169: Refactor client family member api; 2025-04-23 10:57:50 +02:00
oleksandr.masliukandAdam Saghy c0c7b45700 FINERACT-2169: Apply dto in ClientIdentifiersApiResource 2025-04-23 10:20:10 +02:00
Oleksii NovikovandAdam Saghy 64dddfca48 FINERACT-2080: Extract loanLifecycleStateMachine from Loan entity, refactor transition functionality 2025-04-23 10:12:53 +02:00
Marta JankovicsandAdam Saghy 79c006774e FINERACT-2185: User management improvement 2025-04-23 09:56:05 +02:00
Aleksandar VidakovicandAleksandar Vidakovic 8d83b5547c FINERACT-2169: New command processing infrastructure 2025-04-22 21:50:28 +02:00
CsengeSótiandArnold Gálovics fd45f43f36 FINERACT-2235: fix loan list assotiations flag for loans without summary 2025-04-22 21:22:04 +02:00
mdmytrivandArnold Gálovics e326ed4b8a FINERACT-2260: added e2e tests for incorrect interest handling in case of early repayment 2025-04-22 17:21:17 +02:00
adam.magyariandAdam Saghy 07e64da523 FINERACT-2232: Capitalized income config backend validation 2025-04-22 17:11:54 +02:00
mariiaKraievskaandAdam Saghy a11c567413 FINERACT-2210: Fix journal entries creation issue when amount is null 2025-04-22 17:10:54 +02:00
Soma SörösandAdam Saghy a1d51e1e34 FINERACT-2265: Progressive Loan - Interest Recalculation fails for - RecalculationRestFrequencyType SameAsRepaymentPeriod 2025-04-22 15:19:11 +02:00
Rustam ZeinalovandAdam Saghy 9660ca8f97 FINERACT-2173: added e2e tests covering basic migration scenario related to cob 2025-04-22 12:39:42 +02:00
adam.magyariandAdam Saghy 269c2b1f28 FINERACT-2232: Create LoanCapitalizedIncomeBalance entity and table 2025-04-22 12:34:01 +02:00
dependabot[bot]andAdam Saghy cbfd370844 Bump actions/setup-node from 4.3.0 to 4.4.0
Bumps [actions/setup-node](https://github.com/actions/setup-node) from 4.3.0 to 4.4.0.
- [Release notes](https://github.com/actions/setup-node/releases)
- [Commits](https://github.com/actions/setup-node/compare/cdca7365b2dadb8aad0a33bc7601856ffabcc48e...49933ea5288caeca8642d1e84afbd3f7d6820020)

---
updated-dependencies:
- dependency-name: actions/setup-node
  dependency-version: 4.4.0
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2025-04-22 12:24:21 +02:00
Jose Alberto HernandezandAdam Saghy 5578d8bce5 FINERACT-2180: Allow use any Java distribution 2025-04-22 11:29:40 +02:00
danielales2541andAdam Saghy d15243fb31 FINERACT-2202: Bulk import fix 2025-04-22 10:55:45 +02:00
CsengeSótiandArnold Gálovics 1b9cb5c6d5 FINERACT-2236: add clientId filter to loans request 2025-04-17 17:41:47 +02:00
a7med3del1973andAdam Saghy 98894d1f21 FINERACT-2181: Refactor constants to follow naming convention 2025-04-17 15:01:17 +02:00
Victor RomeroandAdam Saghy 9f4f1d4f17 FINERACT-2094: Update to Java 21
modernize locale instantiations (fixes an error found by the modernizer plugin) - use Locale.of() instead of new Locale()

use recommended gradle toolchain syntax to specify Java class file format version see https://docs.gradle.org/current/userguide/java_plugin.html#toolchain_and_compatibility

mark html5 for later fix (it's the default)

use dummy byte arrays to work around mockito exception

```
org.mockito.exceptions.base.MockitoException:
Mockito cannot mock this class: class java.nio.ByteBuffer.

If you're not sure why you're getting this error, please open an issue on GitHub.

Java               : 21
JVM vendor name    : Ubuntu
JVM vendor version : 21.0.6+7-Ubuntu-122.04.1
JVM name           : OpenJDK 64-Bit Server VM
JVM version        : 21.0.6+7-Ubuntu-122.04.1
JVM info           : mixed mode, sharing
OS name            : Linux
OS version         : 5.15.0-136-generic

You are seeing this disclaimer because Mockito is configured to create inlined mocks.
You can learn about inline mocks and their limitations under item #39 of the Mockito class javadoc.

Underlying exception : org.mockito.exceptions.base.MockitoException: Unsupported settings with this type 'java.nio.ByteBuffer'
	at app//org.apache.fineract.infrastructure.event.external.jobs.SendAsynchronousEventsTaskletTest.givenBatchSize2WhenEventSendFailsThenExecutionStops(SendAsynchronousEventsTaskletTest.java:170)
	at java.base@21.0.6/java.lang.reflect.Method.invoke(Method.java:580)
	at java.base@21.0.6/java.util.ArrayList.forEach(ArrayList.java:1596)
	at java.base@21.0.6/java.util.ArrayList.forEach(ArrayList.java:1596)
Caused by: org.mockito.exceptions.base.MockitoException: Unsupported settings with this type 'java.nio.ByteBuffer'
	at app//net.bytebuddy.TypeCache.findOrInsert(TypeCache.java:168)
	at app//net.bytebuddy.TypeCache$WithInlineExpunction.findOrInsert(TypeCache.java:399)
	at app//net.bytebuddy.TypeCache.findOrInsert(TypeCache.java:190)
	at app//net.bytebuddy.TypeCache$WithInlineExpunction.findOrInsert(TypeCache.java:410)
	... 4 more
```

see also: https://stackoverflow.com/questions/47046996/java-lang-unsupportedoperationexception-when-mocking-java-nio-bytebuffer-class

wrap byte arrays with ByteBuffer

fix:

```
/home/adamm/git/apache/fineract/fineract-provider/src/test/java/org/apache/fineract/infrastructure/event/external/jobs/SendAsynchronousEventsTaskletTest.java:148: error: incompatible types: byte[] cannot be converted to ByteBuffer
                "anidempotencyKey", "aSchema", "dummy".getBytes());
                                                               ^
/home/adamm/git/apache/fineract/fineract-provider/src/test/java/org/apache/fineract/infrastructure/event/external/jobs/SendAsynchronousEventsTaskletTest.java:170: error: incompatible types: byte[] cannot be converted to ByteBuffer
                "anidempotencyKey", "aSchema", "dummy".getBytes());
                                                               ^
/home/adamm/git/apache/fineract/fineract-provider/src/test/java/org/apache/fineract/infrastructure/event/external/jobs/SendAsynchronousEventsTaskletTest.java:189: error: incompatible types: byte[] cannot be converted to ByteBuffer
                "anidempotencyKey", "aSchema", "dummy".getBytes());
                                                               ^
/home/adamm/git/apache/fineract/fineract-provider/src/test/java/org/apache/fineract/infrastructure/event/external/jobs/SendAsynchronousEventsTaskletTest.java:210: error: incompatible types: byte[] cannot be converted to ByteBuffer
                "anidempotencyKey", "aSchema", "dummy".getBytes());
```

...and use StandardCharsets with getBytes
2025-04-17 15:01:00 +02:00
oleksandr.masliukandAdam Saghy 60bc3acaf1 FINERACT-2169: Apply dto into GuarantorsApiResource 2025-04-17 15:00:12 +02:00
CsengeSótiandArnold Gálovics 12617ea1df FINERACT-2235: add summary data to loans list api 2025-04-17 14:02:22 +02:00
Adam Saghy 6455311f6c FINERACT-2181: Use daily as recalculation rule in tests 2025-04-16 15:12:39 +02:00
Adam Saghy 1f76a8aeb2 FINERACT-2262: Improve cache handling and add customization option 2025-04-15 19:45:42 +02:00
adam.magyariandAdam Saghy cb8cbd2043 FINERACT-2232: Generalization of StringEnumOptionData enums 2025-04-15 19:45:25 +02:00
adam.magyariandAdam Saghy 7df7be2b16 FINERACT-2232: Progressive loan income capitalization config 2025-04-15 19:45:25 +02:00
Jose Alberto HernandezandAdam Saghy 6a65bc6592 FINERACT-2181: Add customData field to LoanAccountDelinquencyRangeBusinessEvent 2025-04-15 15:16:03 +02:00
Jose Alberto HernandezandAdam Saghy 2eca91eb98 FINERACT-2181: Add customData field to LoanRepaymentBusinessEvent 2025-04-15 15:15:45 +02:00
Jose Alberto HernandezandAdam Saghy 8ce76e1ad6 FINERACT-2181: Add customData field to LoanAdjustTransactionBusinessEvent 2025-04-15 15:15:21 +02:00
Jose Alberto HernandezandAdam Saghy 2143d35e29 FINERACT-2181: Add customData field to InvestorBusinessEvent 2025-04-15 15:14:45 +02:00
Rustam ZeinalovandAdam Saghy b9b5eb60d1 FINERACT-2181: test verifying no accrual activity created for approved loan 2025-04-15 10:54:38 +02:00
mariiaKraievskaandAdam Saghy 11912881af FINERACT-2234: Improve "Add periodic accrual entries" business step performance 2025-04-15 10:54:05 +02:00
Jose Alberto HernandezandAdam Saghy 4ebf768286 FINERACT-2181: Add customData field to LoanProductBusinessEvent 2025-04-14 23:08:13 +02:00
budaidevandAdam Saghy 035cfd087c FINERACT-2081: payment_types cache was missing which caused exception during the interest recalculation process with cache on 2025-04-14 20:33:21 +02:00
Abhinav CillankiandAdam Saghy bad50aaa4d FINERACT-2237: Fix GSIM account creation to generate single parent for multiple clients 2025-04-14 17:05:17 +02:00
mdmytrivandAdam Saghy 67cdb88f66 FINERACT-2181: added e2e tests interestRecognitionOnDisbursementDate flag 2025-04-14 16:21:12 +02:00
mariiaKraievskaandAdam Saghy 245b095195 FINERACT-2181: Fix the API to return interestRecognitionOnDisbursementDate in GetLoanProductsResponse 2025-04-14 16:21:12 +02:00
mark.vituskaandAdam Saghy f8d5bde921 FINERACT-2080: extracted json based workflows from Loan and other Loan related entities 2025-04-14 16:14:12 +02:00
Jose Alberto HernandezandAdam Saghy b4b2ef3701 FINERACT-2081: External service credential values masked 2025-04-14 16:05:21 +02:00
Mend RenovateandArnold Gálovics 07ea81e399 FINERACT-2181: Update bitnami/kafka Docker tag to v4 2025-04-12 09:46:12 +02:00
dependabot[bot]andArnold Gálovics e842ba6962 Bump actions/setup-java from 4.7.0 to 4.7.1
Bumps [actions/setup-java](https://github.com/actions/setup-java) from 4.7.0 to 4.7.1.
- [Release notes](https://github.com/actions/setup-java/releases)
- [Commits](https://github.com/actions/setup-java/compare/3a4f6e1af504cf6a31855fa899c6aa5355ba6c12...c5195efecf7bdfc987ee8bae7a71cb8b11521c00)

---
updated-dependencies:
- dependency-name: actions/setup-java
  dependency-version: 4.7.1
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2025-04-12 09:30:59 +02:00
Adam SaghyandArnold Gálovics 815421fd94 FINERACT-2181: No Accrual Activity for not active loans 2025-04-12 09:14:52 +02:00
Adam SaghyandArnold Gálovics d947183529 FINERACT-2260: Fix incorrect interest handling in case of early repayment 2025-04-12 09:12:08 +02:00
mariiaKraievskaandAdam Saghy 76a5ec89cc FINERACT-2181: Fix savings integration tests 2025-04-10 21:20:35 +02:00
danielales2541andAdam Saghy 055fd58ea1 FINERACT-2202: Bulk import fix 2025-04-10 15:20:51 +02:00
1662 changed files with 115798 additions and 20658 deletions
@@ -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.
+114
View File
@@ -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 ))
+55
View File
@@ -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 ))
+9 -8
View File
@@ -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
+183
View File
@@ -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/
+116 -58
View File
@@ -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
+117 -59
View File
@@ -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
+117 -59
View File
@@ -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
-41
View File
@@ -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
+8 -12
View File
@@ -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/
-37
View File
@@ -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
+6 -5
View File
@@ -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
+2 -1
View File
@@ -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
View File
@@ -32,4 +32,6 @@ fineract-provider/src/main/generated/
gradleExp/
.run/
.java-version
.java-version
.windsurf/
-43
View File
@@ -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
View File
@@ -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
View File
@@ -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/).
+66 -53
View File
@@ -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.
[![Code Now! (Gitpod)](https://gitpod.io/button/open-in-gitpod.svg)](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
+30
View File
@@ -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
View File
@@ -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',
+8 -4
View File
@@ -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": [
]
}
}
+8
View File
@@ -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"/>
+4
View File
@@ -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>
+1
View File
@@ -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;
@@ -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'))
@@ -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();
}
}
@@ -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.");
@@ -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();
+2 -2
View File
@@ -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')
+1 -1
View File
@@ -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:
+2 -21
View 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 {
@@ -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;
}
@@ -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;
@@ -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,
@@ -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")) {
@@ -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);
@@ -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);
@@ -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));
}
@@ -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;
@@ -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;
}
}
@@ -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;
}
}
@@ -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();
@@ -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;
}
}
@@ -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();
}
@@ -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();
}
}
@@ -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();
@@ -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")
@@ -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() {
@@ -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) {
@@ -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);
}
@@ -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);
}
@@ -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")) {
@@ -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);
}
/**
@@ -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);
}
}
@@ -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);
}
@@ -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);
}
}
@@ -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);
}
}
}
@@ -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);
}
@@ -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)) {
@@ -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);
@@ -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);
@@ -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 = ?";
@@ -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() {
@@ -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")
@@ -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;
}
}
}
@@ -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();
}
}
@@ -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());
@@ -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>
@@ -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"
]
}
]
}
+2 -27
View File
@@ -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 {
@@ -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;
@@ -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>
+2 -27
View File
@@ -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