Hello Fineract developers, I reproduced the following behavior in the actual ShareProductDividendAssembler on develop e4474a0f4a4c65a75e7758e47db1fd277e5fcfef (the source is identical in tag 1.15.0):
- 100 approved shares purchased on 2026-01-01; - product minimum active period: 90 days; - dividend window: 2026-07-01 through 2026-08-01; - a single active account, USD 100.00 to distribute. The purchase age is 212 days. The assembler first clips the purchase date to July 1 and then tests 31 days against the 90-day minimum. It returns null; the production caller maps this to eligible.shares.not.found. I interpret the documented minimum active period as eligibility age, in which case this account should qualify and receive 100.00. Please confirm whether the intended policy instead counts only days inside each payout window; that would exclude even longstanding holdings whenever the window is shorter than the configured minimum. I prepared a patch that checks age before clipping the share-day weighting date. A 12-case native suite covers threshold equality, recent purchases and equal in-window weights for accounts with different older purchase dates. The original source fails seven cases under the holding-age interpretation. Only database read interfaces are mocked; the assembler and monetary calculations are real. No HTTP/database payout reproduction is claimed. I found FINERACT-148/329 about dividend total rounding and FINERACT-608 about allocation; this report concerns the eligibility date instead. If the proposed interpretation is correct, could you create or identify a Jira issue for the correction? The proposed correction passes all 12 native cases. Spotless and Checkstyle main/test checks pass. Attachments: a detailed report with reproduction commands, a source-only patch, a patch including the native JUnit tests, and JSON test vectors. Regards, Khamit
dividend-test-vectors.json
Description: application/json
# Dividend eligibility clips the holding period to the payout window ShareProductDividendAssembler replaces a purchase date before the dividend window with the window start, then uses that clipped date for minimumActivePeriod. Thus a 31-day dividend window with a 90-day minimum rejects every purchase, even shares held for years. When no positive share-days remain, calculateDividends returns null, and the production caller raises eligible.shares.not.found. ## Reproduction and proposed interpretation Use an active account holding 100 approved shares purchased on 2026-01-01. Set the product's minimum active period to 90 days, the dividend window to 2026-07-01 through 2026-08-01, the currency to USD with two decimals, and the dividend pool to 100.00. Actual holding age at the window end is 212 days; the code tests 31 days instead. Under the holding-age interpretation, the sole eligible account should receive 100.00. The [Mifos user documentation](https://mifosforge.jira.com/wiki/spaces/docs/pages/129531946/Share%2Bproducts) describes a minimum active period to receive dividends. This report interprets that setting as eligibility age. If the intended policy is instead a minimum entirely within each payout window, please confirm that policy; it would make any shorter window ineligible regardless of the actual holding age. The proposed patch depends on the holding-age interpretation. ## Test design and application reachability ShareProductDividendMinimumActivePeriodTest invokes the real assembler and Money implementation with real product, account, transaction and payout objects. Only the two database read service interfaces are mocked. Tenant rounding is explicitly HALF_UP and restored after each test. Inputs exercise minimum periods 0, 30, 31, 32, 90, 212 and 213; purchase ages 89, 90 and 91 days at a 90-day threshold; two older accounts with equal in-window holdings; and a recent ineligible purchase alongside an older account. The equal-holdings case ensures a fix does not add pre-window days to dividend weights. ShareProductDataSerializer accepts a minimum active period in days without restricting it to the future dividend window. Its dividend validator requires dates in ascending order and a positive amount. ShareAccountReadPlatformServiceImpl retrieves approved purchases for active accounts without clipping their transaction dates. ShareProductWritePlatformServiceJpaRepositoryImpl.createShareProductDividend invokes the assembler and throws the no-eligible-shares exception for null. These paths were inspected; no HTTP or persisted payout execution is claimed. ## Proposed correction Compute eligibility age from the original purchase date, then clip only the date used for in-window share-day weighting. Keep the threshold's existing inclusive behavior and retain exclusion of recent purchases. ## Related reports checked FINERACT-148 and FINERACT-329 already report mismatches in rounded dividend totals. FINERACT-608 is a dividend distribution complaint; its example does not specify this clipped minimum-period case. This report does not claim a new rounding-total defect. No exact duplicate was identified in the recorded searches; intended policy still needs maintainer confirmation. ## Verified native results Tested baseline: e4474a0f4a4c65a75e7758e47db1fd277e5fcfef, with the same assembler source in tag 1.15.0 (byte comparison only for the release tag). The original implementation fails 7 of the 12 cases; the proposed correction passes all 12. Module Spotless and Checkstyle main/test checks pass. These tests confirm implementation behavior under the stated holding-age interpretation; the expected business policy still warrants maintainer confirmation. ## Running the attached reproducer Use JDK 25 and a separate checkout at the baseline commit. First apply dividend-eligibility-with-tests.patch. To reproduce the original failure while retaining the tests, reverse only dividend-eligibility.patch. Reapply that source-only patch to verify the correction. ```sh git apply dividend-eligibility-with-tests.patch git apply --reverse dividend-eligibility.patch ./gradlew --no-daemon --no-scan --max-workers=2 :fineract-provider:test --tests "*ShareProductDividendMinimumActivePeriodTest" git apply dividend-eligibility.patch ./gradlew --no-daemon --no-scan --max-workers=2 :fineract-provider:test --tests "*ShareProductDividendMinimumActivePeriodTest" ``` The first test run is expected to fail; the second should pass. Only run these patch commands in an isolated checkout.
