2424import org .apache .fineract .infrastructure .core .service .DateUtils ;
2525import org .apache .fineract .infrastructure .core .service .MathUtil ;
2626import org .apache .fineract .portfolio .loanaccount .domain .Loan ;
27+ import org .apache .fineract .portfolio .loanproduct .domain .LoanProduct ;
2728import org .apache .fineract .portfolio .loanaccount .exception .InvalidLoanStateTransitionException ;
2829import org .apache .fineract .portfolio .loanaccount .exception .LoanDisbursalException ;
2930import org .springframework .stereotype .Component ;
@@ -39,29 +40,59 @@ public void compareDisbursedToApprovedOrProposedPrincipal(final Loan loan, final
3940 final BigDecimal totalCapitalizedIncomeAdjustment = MathUtil .nullToZero (loan .getSummary ().getTotalCapitalizedIncomeAdjustment ());
4041 final BigDecimal netCapitalizedIncome = totalCapitalizedIncome .subtract (totalCapitalizedIncomeAdjustment );
4142
42- if (loan .loanProduct ().isAllowApprovedDisbursedAmountsOverApplied ()) {
43- // Validate total disbursed amount (after this transaction) against max allowed
44- validateOverMaximumAmount (loan , totalDisbursed , netCapitalizedIncome );
45- } else {
46- if ((totalDisbursed .compareTo (loan .getApprovedPrincipal ()) > 0 )
47- || (totalDisbursed .add (netCapitalizedIncome ).compareTo (loan .getApprovedPrincipal ()) > 0 )) {
48- final String errorMsg = "Loan can't be disbursed, disburse amount is exceeding approved principal." ;
49- throw new LoanDisbursalException (errorMsg , "disburse.amount.must.be.less.than.approved.principal" , totalDisbursed ,
50- loan .getApprovedPrincipal ());
43+ // Always use the same logic for over-applied config and fallback
44+ LoanProduct loanProduct = loan .getLoanProduct ();
45+ BigDecimal approvedPrincipal = loan .getApprovedPrincipal ();
46+ BigDecimal maxAllowed = approvedPrincipal ;
47+
48+ if (loanProduct .getOverAppliedCalculationType () != null && loanProduct .getOverAppliedNumber () != null ) {
49+ BigDecimal overAppliedNumber = BigDecimal .valueOf (loanProduct .getOverAppliedNumber ());
50+ if ("percentage" .equalsIgnoreCase (loanProduct .getOverAppliedCalculationType ())) {
51+ BigDecimal extra = approvedPrincipal .multiply (overAppliedNumber ).divide (BigDecimal .valueOf (100 ));
52+ maxAllowed = approvedPrincipal .add (extra );
53+ } else {
54+ // ABSOLUTE (flat)
55+ maxAllowed = approvedPrincipal .add (overAppliedNumber );
5156 }
5257 }
58+
59+ BigDecimal total = totalDisbursed .add (netCapitalizedIncome );
60+ if (maxAllowed == null ) {
61+ maxAllowed = approvedPrincipal ;
62+ }
63+ if (total .compareTo (maxAllowed ) > 0 ) {
64+ throw new LoanDisbursalException (
65+ "Disbursement exceeds allowed limit including over-applied threshold" ,
66+ "disburse.amount.must.be.less.than.or.equal.to.max.allowed" , total , maxAllowed );
67+ }
5368 }
5469
5570 public void validateOverMaximumAmount (final Loan loan , final BigDecimal totalDisbursed , final BigDecimal capitalizedIncome ) {
56- final BigDecimal maxDisbursedAmount = loanApplicationValidator .getOverAppliedMax (loan );
57- if (totalDisbursed .add (capitalizedIncome ).compareTo (maxDisbursedAmount ) > 0 ) {
71+ LoanProduct loanProduct = loan .getLoanProduct ();
72+ BigDecimal approvedPrincipal = loan .getApprovedPrincipal ();
73+ BigDecimal maxAllowed = approvedPrincipal ;
74+
75+ if (loanProduct .getOverAppliedCalculationType () != null && loanProduct .getOverAppliedNumber () != null ) {
76+ BigDecimal overAppliedNumber = BigDecimal .valueOf (loanProduct .getOverAppliedNumber ());
77+ if ("percentage" .equalsIgnoreCase (loanProduct .getOverAppliedCalculationType ())) {
78+ BigDecimal extra = approvedPrincipal .multiply (overAppliedNumber ).divide (BigDecimal .valueOf (100 ));
79+ maxAllowed = approvedPrincipal .add (extra );
80+ } else {
81+ // ABSOLUTE (flat)
82+ maxAllowed = approvedPrincipal .add (overAppliedNumber );
83+ }
84+ }
85+
86+ BigDecimal total = totalDisbursed .add (capitalizedIncome );
87+ if (maxAllowed == null ) {
88+ maxAllowed = approvedPrincipal ;
89+ }
90+ if (total .compareTo (maxAllowed ) > 0 ) {
5891 final String errorMessage = String .format (
59- "Loan disbursal amount can't be greater than maximum applied loan amount calculation. "
60- + "Total disbursed amount: %s Maximum disbursal amount: %s" ,
61- totalDisbursed .stripTrailingZeros ().toPlainString (), maxDisbursedAmount .stripTrailingZeros ().toPlainString ());
92+ "Disbursement exceeds allowed limit including over-applied threshold. Total disbursed amount: %s Maximum allowed: %s" ,
93+ total .stripTrailingZeros ().toPlainString (), maxAllowed .stripTrailingZeros ().toPlainString ());
6294 throw new InvalidLoanStateTransitionException ("disbursal" ,
63- "amount.can't.be.greater.than.maximum.applied.loan.amount.calculation" , errorMessage , totalDisbursed ,
64- maxDisbursedAmount );
95+ "amount.can't.be.greater.than.maximum.applied.loan.amount.calculation" , errorMessage , total , maxAllowed );
6596 }
6697 }
6798
0 commit comments