[ 
https://issues.apache.org/jira/browse/FINERACT-2476?page=com.atlassian.jira.plugin.system.issuetabpanels:comment-tabpanel&focusedCommentId=18057282#comment-18057282
 ] 

abdelrahman commented on FINERACT-2476:
---------------------------------------

Hi [~rhopman],
I’m interested in starting to contribute.
May I work on this issue?

> Enable Group Savings Accounts as Guarantors with Guarantee Percentage 
> Requirements
> ----------------------------------------------------------------------------------
>
>                 Key: FINERACT-2476
>                 URL: https://issues.apache.org/jira/browse/FINERACT-2476
>             Project: Apache Fineract
>          Issue Type: Improvement
>          Components: Loan, Savings
>            Reporter: Ralph Hopman
>            Priority: Minor
>
> Group savings accounts cannot be used as guarantors when loan products have 
> non-zero guarantee percentage requirements (mandatoryGuarantee, 
> minimumGuaranteeFromGuarantor, minimumGuaranteeFromOwnFunds > 0), limiting 
> valid business scenarios for group lending.
> h2. Problem Statement
> Group savings accounts are currently blocked from serving as guarantors when 
> loan products enforce minimum guarantee percentages. This creates an 
> artificial limitation that prevents valid business scenarios, particularly in 
> group-based lending models where group savings serve as collective collateral.
> h2. Current Behavior
>  # *With zero guarantee requirements* 
> ({{{}withOnHoldFundDetails("0","0","0"){}}}):
>  ** Group accounts work as guarantors
>  ** Holds are placed correctly on loan approval
>  # *With non-zero guarantee requirements* (e.g., 
> {{{}withOnHoldFundDetails("20","10","10"){}}}):
>  ** Group accounts fail validation during loan approval
>  ** Error: Self-guarantee validation expects {{guarantor.entityId}} to match 
> {{loan.clientId}}
>  ** Group accounts have {{{}client_id = NULL{}}}, causing validation failure
> h2. Expected Behavior
> Group savings accounts should be usable as guarantors regardless of guarantee 
> percentage requirements, as long as:
>  * The guarantor account is active
>  * Sufficient funds are available
>  * The account is not in a restricted state
>  * Standard guarantor business rules are met (excluding self-guarantee check 
> for group accounts)
> h1. Technical Analysis
> h2. Root Cause
> {*}File{*}: {{GuarantorDomainServiceImpl.java}}
> {*}Method{*}: {{validateGuarantorBusinessRules(Loan loan)}}
> {code:java}
> if (loanProduct.isHoldGuaranteeFunds()) {
>     // Validation logic runs here
>     // Self-guarantee check assumes guarantor.entityId matches loan.clientId
>     // For group accounts: client_id = NULL → validation fails
> }
> {code}
> The validation logic was designed with individual client accounts in mind and 
> does not account for group-owned accounts as valid guarantors.
> h2. Database Schema Context
> {*}Table{*}: {{m_savings_account}}
>  * Individual client accounts: {{{}client_id = [client_id]{}}}, {{group_id = 
> NULL}}
>  * Group accounts: {{{}client_id = NULL{}}}, {{group_id = [group_id]}}
> The self-guarantee validation checks if the savings account's {{client_id}} 
> matches the loan borrower's {{{}client_id{}}}, which always fails for group 
> accounts.
> h2. Proposed Solution
> Modify {{validateGuarantorBusinessRules()}} to:
>  # Detect when a guarantor account is a group account ({{{}client_id = 
> NULL{}}}, {{{}group_id != NULL{}}})
>  # For group accounts, skip or adapt the self-guarantee validation
>  # Optionally check if the borrower is a member of the guarantor group
>  # Apply all other validation rules normally
> h2. Functional Requirements
>  * Group savings accounts can be added as guarantors for loans with non-zero 
> guarantee requirements
>  * Automatic holds are placed on group guarantor accounts equal to the 
> guarantee amount
>  * Holds are placed on loan approval (existing timing)
>  * Validation enforces guarantee percentage requirements correctly
>  * Individual client accounts continue to work exactly as before (no 
> regression)
>  * Self-guarantee validation still applies to individual client accounts
> h2. Business Rules
>  # Group account must be active
>  # Group account must have sufficient available balance
>  # Guarantee amount must meet minimum percentage requirements
>  # Standard guarantor validation rules apply (excluding problematic 
> self-guarantee check)
> h2. Technical Requirements
>  # No changes to database schema required
>  # Backward compatible with existing guarantor records
>  # API responses unchanged (maintaining contract)
>  # Existing tests continue to pass
> h1. Test Scenarios
> h2. Test Case 1: Group Account as Guarantor with 20% Minimum Guarantee
> {*}Setup{*}:
>  * Loan product with {{withOnHoldFundDetails("20", "10", "10")}}
>  * Loan amount: 10,000
>  * Group savings account with balance: 10,000
>  * Guarantee amount: 2,500 (25% of loan)
> {*}Steps{*}:
>  # Create loan with group guarantor
>  # Approve loan
> {*}Expected{*}:
>  * Loan approval succeeds
>  * Hold of 2,500 placed on group account
>  * {{onHoldFunds = 2,500}}
>  * {{availableBalance = 7,500}}
> h2. Test Case 2: Insufficient Guarantee Percentage
> {*}Setup{*}:
>  * Loan product with {{withOnHoldFundDetails("20", "10", "10")}} (20% 
> mandatory minimum)
>  * Loan amount: 10,000
>  * Group savings account with balance: 10,000
>  * Guarantee amount: 1,000 (10% of loan)
> {*}Expected{*}:
>  * Validation error: Guarantee amount below minimum requirement
> h2. Test Case 3: Mixed Guarantors
> {*}Setup{*}:
>  * Loan with multiple guarantors:
>  ** Guarantor 1: Individual client account (3,000)
>  ** Guarantor 2: Group account (2,000)
>  * Loan amount: 10,000 with 50% guarantee requirement
> {*}Expected{*}:
>  * Total guarantee: 5,000 (50%) meets requirement
>  * Holds placed on both accounts correctly
> h1. Code References
> h2. Files to Modify
>  # *{{GuarantorDomainServiceImpl.java}}* (primary changes)
>  ** Location: 
> {{fineract-core/src/main/java/org/apache/fineract/portfolio/loanaccount/guarantor/service/}}
>  ** Method: {{validateGuarantorBusinessRules(Loan loan)}}
>  ** Line: ~112 (where {{if (loanProduct.isHoldGuaranteeFunds())}} check 
> occurs)
>  # *Related Validation Logic*
>  ** Self-guarantee checking logic
>  ** Account ownership verification
>  ** Minimum percentage validation
> h2. Relevant Database Tables
>  * {{m_savings_account}} (guarantor source accounts)
>  * {{m_guarantor}} (guarantor relationships)
>  * {{m_loan}} (borrower information)
>  * {{m_portfolio_account_associations}} (account associations)
> h2. Test Files to Update
>  * {{GuarantorTest.java}} - Add group account scenarios
>  * {{GroupSavingsIntegrationTest.java}} - Expand guarantor tests with 
> non-zero percentages
> h1. Example Validation Logic Modification
> h2. Current Logic (Pseudocode)
> {code:java}
> if (loanProduct.isHoldGuaranteeFunds()) {
>     for (Guarantor guarantor : loan.getGuarantors()) {
>         // Validate account belongs to client
>         if (!isAccountBelongsToClient(guarantor.savingsAccount, 
> guarantor.entityId)) {
>             throw new ValidationError("Account must belong to guarantor");
>         }
>         
>         // Check self-guarantee
>         if (guarantor.entityId.equals(loan.clientId)) {
>             throw new ValidationError("Cannot self-guarantee");
>         }
>         
>         // Other validations...
>     }
> }
> {code}
> h2. Proposed Logic (Pseudocode)
> {code:java}
> if (loanProduct.isHoldGuaranteeFunds()) {
>     for (Guarantor guarantor : loan.getGuarantors()) {
>         SavingsAccount savingsAccount = guarantor.getSavingsAccount();
>         
>         // Determine account type
>         boolean isGroupAccount = (savingsAccount.getClientId() == null && 
>                                   savingsAccount.getGroupId() != null);
>         
>         if (isGroupAccount) {
>             // Group account validation path
>             validateGroupGuarantorAccount(savingsAccount, loan);
>         } else {
>             // Individual account validation path (existing logic)
>             if (!isAccountBelongsToClient(savingsAccount, 
> guarantor.entityId)) {
>                 throw new ValidationError("Account must belong to guarantor");
>             }
>             
>             // Check self-guarantee (only for individual accounts)
>             if (guarantor.entityId.equals(loan.clientId)) {
>                 throw new ValidationError("Cannot self-guarantee");
>             }
>         }
>         
>         // Common validations for both account types
>         validateAccountStatus(savingsAccount);
>         validateSufficientFunds(savingsAccount, guarantor.amount);
>         // Other validations...
>     }
> }
> {code}
> h1. Impact Assessment
> h2. Business Impact
>  * {*}High positive{*}: Enables valid group lending scenarios
>  * {*}Low risk{*}: Only affects guarantor validation logic
>  * {*}Backward compatible{*}: No impact on existing functionality
> h2. Technical Impact
>  * {*}Code changes{*}: Isolated to guarantor validation service
>  * {*}Database{*}: No schema changes required
>  * {*}API{*}: No breaking changes
>  * {*}Performance{*}: Negligible (adds conditional check in validation)
> h1. Additional Notes
> h2. Workaround (Current)
> Loan products can use {{.withOnHoldFundDetails("0","0","0")}} to enable group 
> guarantors, but this:
>  * Disables all guarantee percentage enforcement
>  * Cannot enforce business rules requiring minimum guarantees
>  * Proves the technical capability exists
> h2. User Impact
> Financial institutions using group-based lending models (common in 
> microfinance) currently cannot:
>  * Use group savings as collateral when guarantee percentages are required
>  * Enforce minimum guarantee amounts with group accounts
>  * Fully leverage group solidarity savings for loan security



--
This message was sent by Atlassian Jira
(v8.20.10#820010)

Reply via email to