FINERACT-2174: Allow for recognition of Interest on first day end of day - Introducing the flag
This commit is contained in:
committed by
Adam Saghy
parent
7d0474cc17
commit
3a5888ee4b
@@ -815,6 +815,14 @@
|
||||
"null",
|
||||
"boolean"
|
||||
]
|
||||
},
|
||||
{
|
||||
"default": null,
|
||||
"name": "interestRecognitionOnDisbursementDate",
|
||||
"type": [
|
||||
"null",
|
||||
"boolean"
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
|
||||
@@ -641,6 +641,14 @@
|
||||
"null",
|
||||
"org.apache.fineract.avro.loan.v1.DelinquencyBucketDataV1"
|
||||
]
|
||||
},
|
||||
{
|
||||
"default": null,
|
||||
"name": "interestRecognitionOnDisbursementDate",
|
||||
"type": [
|
||||
"null",
|
||||
"boolean"
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
|
||||
+2
@@ -177,6 +177,8 @@ public interface LoanApiConstants {
|
||||
// Data Validator names
|
||||
String LOAN_FRAUD_DATAVALIDATOR_PREFIX = "loans.fraud";
|
||||
|
||||
String INTEREST_RECOGNITION_ON_DISBURSEMENT_DATE = "interestRecognitionOnDisbursementDate";
|
||||
|
||||
// Loan Summary Transaction Types
|
||||
List<Integer> LOAN_SUMMARY_TRANSACTION_TYPES = List.of(LoanTransactionType.CHARGE_ADJUSTMENT.getValue(), //
|
||||
LoanTransactionType.CHARGEBACK.getValue(), //
|
||||
|
||||
+10
-5
@@ -229,6 +229,7 @@ public final class LoanApplicationTerms {
|
||||
private boolean enableAccrualActivityPosting;
|
||||
private List<LoanSupportedInterestRefundTypes> supportedInterestRefundTypes;
|
||||
private LoanChargeOffBehaviour chargeOffBehaviour;
|
||||
private boolean interestRecognitionOnDisbursementDate;
|
||||
|
||||
private LoanApplicationTerms(Builder builder) {
|
||||
this.currency = builder.currency;
|
||||
@@ -460,7 +461,7 @@ public final class LoanApplicationTerms {
|
||||
final LocalDate submittedOnDate, final LoanScheduleType loanScheduleType,
|
||||
final LoanScheduleProcessingType loanScheduleProcessingType, final Integer fixedLength,
|
||||
final boolean enableAccrualActivityPosting, final List<LoanSupportedInterestRefundTypes> supportedInterestRefundTypes,
|
||||
final LoanChargeOffBehaviour chargeOffBehaviour) {
|
||||
final LoanChargeOffBehaviour chargeOffBehaviour, final boolean interestRecognitionOnDisbursementDate) {
|
||||
|
||||
final LoanRescheduleStrategyMethod rescheduleStrategyMethod = null;
|
||||
final CalendarHistoryDataWrapper calendarHistoryDataWrapper = null;
|
||||
@@ -479,7 +480,8 @@ public final class LoanApplicationTerms {
|
||||
isInterestToBeRecoveredFirstWhenGreaterThanEMI, fixedPrincipalPercentagePerInstallment,
|
||||
isPrincipalCompoundingDisabledForOverdueLoans, enableDownPayment, disbursedAmountPercentageForDownPayment,
|
||||
isAutoRepaymentForDownPaymentEnabled, repaymentStartDateType, submittedOnDate, loanScheduleType, loanScheduleProcessingType,
|
||||
fixedLength, enableAccrualActivityPosting, supportedInterestRefundTypes, chargeOffBehaviour);
|
||||
fixedLength, enableAccrualActivityPosting, supportedInterestRefundTypes, chargeOffBehaviour,
|
||||
interestRecognitionOnDisbursementDate);
|
||||
|
||||
}
|
||||
|
||||
@@ -552,7 +554,8 @@ public final class LoanApplicationTerms {
|
||||
fixedPrincipalPercentagePerInstallment, isPrincipalCompoundingDisabledForOverdueLoans, isDownPaymentEnabled,
|
||||
disbursedAmountPercentageForDownPayment, isAutoRepaymentForDownPaymentEnabled, repaymentStartDateType, submittedOnDate,
|
||||
loanScheduleType, loanScheduleProcessingType, fixedLength, loanProductRelatedDetail.isEnableAccrualActivityPosting(),
|
||||
loanProductRelatedDetail.getSupportedInterestRefundTypes(), loanProductRelatedDetail.getChargeOffBehaviour());
|
||||
loanProductRelatedDetail.getSupportedInterestRefundTypes(), loanProductRelatedDetail.getChargeOffBehaviour(),
|
||||
loanProductRelatedDetail.isInterestRecognitionOnDisbursementDate());
|
||||
}
|
||||
|
||||
private LoanApplicationTerms(final CurrencyData currency, final Integer loanTermFrequency,
|
||||
@@ -582,7 +585,8 @@ public final class LoanApplicationTerms {
|
||||
final BigDecimal disbursedAmountPercentageForDownPayment, final boolean isAutoRepaymentForDownPaymentEnabled,
|
||||
final RepaymentStartDateType repaymentStartDateType, final LocalDate submittedOnDate, final LoanScheduleType loanScheduleType,
|
||||
final LoanScheduleProcessingType loanScheduleProcessingType, final Integer fixedLength, boolean enableAccrualActivityPosting,
|
||||
final List<LoanSupportedInterestRefundTypes> supportedInterestRefundTypes, final LoanChargeOffBehaviour chargeOffBehaviour) {
|
||||
final List<LoanSupportedInterestRefundTypes> supportedInterestRefundTypes, final LoanChargeOffBehaviour chargeOffBehaviour,
|
||||
final boolean interestRecognitionOnDisbursementDate) {
|
||||
|
||||
this.currency = currency;
|
||||
this.loanTermFrequency = loanTermFrequency;
|
||||
@@ -682,6 +686,7 @@ public final class LoanApplicationTerms {
|
||||
this.fixedLength = fixedLength;
|
||||
this.supportedInterestRefundTypes = supportedInterestRefundTypes;
|
||||
this.chargeOffBehaviour = chargeOffBehaviour;
|
||||
this.interestRecognitionOnDisbursementDate = interestRecognitionOnDisbursementDate;
|
||||
}
|
||||
|
||||
public Money adjustPrincipalIfLastRepaymentPeriod(final Money principalForPeriod, final Money totalCumulativePrincipalToDate,
|
||||
@@ -1543,7 +1548,7 @@ public final class LoanApplicationTerms {
|
||||
this.interestRecalculationEnabled, this.isEqualAmortization, this.isDownPaymentEnabled,
|
||||
this.disbursedAmountPercentageForDownPayment, this.isAutoRepaymentForDownPaymentEnabled, this.loanScheduleType,
|
||||
this.loanScheduleProcessingType, this.fixedLength, this.enableAccrualActivityPosting, this.supportedInterestRefundTypes,
|
||||
this.chargeOffBehaviour);
|
||||
this.chargeOffBehaviour, this.interestRecognitionOnDisbursementDate);
|
||||
}
|
||||
|
||||
public LoanProductMinimumRepaymentScheduleRelatedDetail toLoanProductRelatedDetailMinimumData() {
|
||||
|
||||
+1
@@ -169,4 +169,5 @@ public interface LoanProductConstants {
|
||||
String SUPPORTED_INTEREST_REFUND_TYPES = "supportedInterestRefundTypes";
|
||||
String CHARGE_OFF_BEHAVIOUR = "chargeOffBehaviour";
|
||||
|
||||
String INTEREST_RECOGNITION_ON_DISBURSEMENT_DATE = "interestRecognitionOnDisbursementDate";
|
||||
}
|
||||
|
||||
+6
@@ -172,6 +172,8 @@ final class LoanProductsApiResourceSwagger {
|
||||
public Integer repaymentStartDateType;
|
||||
@Schema(example = "false")
|
||||
public Boolean enableAccrualActivityPosting;
|
||||
@Schema(example = "false")
|
||||
public Boolean interestRecognitionOnDisbursementDate;
|
||||
|
||||
// Interest Recalculation
|
||||
@Schema(example = "false")
|
||||
@@ -1421,6 +1423,8 @@ final class LoanProductsApiResourceSwagger {
|
||||
public List<StringEnumOptionData> supportedInterestRefundTypes;
|
||||
public List<GetLoanProductsTemplateResponse.GetLoanProductsChargeOffReasonOptions> chargeOffReasonOptions;
|
||||
public StringEnumOptionData chargeOffBehaviour;
|
||||
@Schema(example = "false")
|
||||
public Boolean interestRecognitionOnDisbursementDate;
|
||||
}
|
||||
|
||||
@Schema(description = "PutLoanProductsProductIdRequest")
|
||||
@@ -1558,6 +1562,8 @@ final class LoanProductsApiResourceSwagger {
|
||||
public Boolean enableAutoRepaymentForDownPayment;
|
||||
@Schema(example = "1")
|
||||
public Integer repaymentStartDateType;
|
||||
@Schema(example = "false")
|
||||
public Boolean interestRecognitionOnDisbursementDate;
|
||||
|
||||
// Interest Recalculation
|
||||
@Schema(example = "false")
|
||||
|
||||
+16
-5
@@ -234,6 +234,7 @@ public class LoanProductData implements Serializable {
|
||||
|
||||
private final EnumOptionData loanScheduleType;
|
||||
private final EnumOptionData loanScheduleProcessingType;
|
||||
private final boolean interestRecognitionOnDisbursementDate;
|
||||
|
||||
/**
|
||||
* Used when returning lookup information about loan product for dropdowns.
|
||||
@@ -338,6 +339,7 @@ public class LoanProductData implements Serializable {
|
||||
final boolean enableAccrualActivityPosting = false;
|
||||
final List<StringEnumOptionData> supportedInterestRefundTypes = null;
|
||||
final StringEnumOptionData chargeOffBehaviour = null;
|
||||
final boolean interestRecognitionOnDisbursementDate = false;
|
||||
|
||||
return new LoanProductData(id, name, shortName, description, currency, principal, minPrincipal, maxPrincipal, tolerance,
|
||||
numberOfRepayments, minNumberOfRepayments, maxNumberOfRepayments, repaymentEvery, interestRatePerPeriod,
|
||||
@@ -358,7 +360,8 @@ public class LoanProductData implements Serializable {
|
||||
fixedPrincipalPercentagePerInstallment, delinquencyBucketOptions, delinquencyBucket, dueDaysForRepaymentEvent,
|
||||
overDueDaysForRepaymentEvent, enableDownPayment, disbursedAmountPercentageDownPayment, enableAutoRepaymentForDownPayment,
|
||||
paymentAllocation, creditAllocation, repaymentStartDateType, enableInstallmentLevelDelinquency, loanScheduleType,
|
||||
loanScheduleProcessingType, fixedLength, enableAccrualActivityPosting, supportedInterestRefundTypes, chargeOffBehaviour);
|
||||
loanScheduleProcessingType, fixedLength, enableAccrualActivityPosting, supportedInterestRefundTypes, chargeOffBehaviour,
|
||||
interestRecognitionOnDisbursementDate);
|
||||
|
||||
}
|
||||
|
||||
@@ -461,6 +464,7 @@ public class LoanProductData implements Serializable {
|
||||
final boolean enableAccrualActivityPosting = false;
|
||||
final List<StringEnumOptionData> supportedInterestRefundTypes = null;
|
||||
final StringEnumOptionData chargeOffBehaviour = null;
|
||||
final boolean interestRecognitionOnDisbursementDate = false;
|
||||
|
||||
return new LoanProductData(id, name, shortName, description, currency, principal, minPrincipal, maxPrincipal, tolerance,
|
||||
numberOfRepayments, minNumberOfRepayments, maxNumberOfRepayments, repaymentEvery, interestRatePerPeriod,
|
||||
@@ -481,7 +485,8 @@ public class LoanProductData implements Serializable {
|
||||
fixedPrincipalPercentagePerInstallment, delinquencyBucketOptions, delinquencyBucket, dueDaysForRepaymentEvent,
|
||||
overDueDaysForRepaymentEvent, enableDownPayment, disbursedAmountPercentageDownPayment, enableAutoRepaymentForDownPayment,
|
||||
paymentAllocation, creditAllocation, repaymentStartDateType, enableInstallmentLevelDelinquency, loanScheduleType,
|
||||
loanScheduleProcessingType, fixedLength, enableAccrualActivityPosting, supportedInterestRefundTypes, chargeOffBehaviour);
|
||||
loanScheduleProcessingType, fixedLength, enableAccrualActivityPosting, supportedInterestRefundTypes, chargeOffBehaviour,
|
||||
interestRecognitionOnDisbursementDate);
|
||||
|
||||
}
|
||||
|
||||
@@ -591,6 +596,7 @@ public class LoanProductData implements Serializable {
|
||||
final boolean enableAccrualActivityPosting = false;
|
||||
final List<StringEnumOptionData> supportedInterestRefundTypes = null;
|
||||
final StringEnumOptionData chargeOffBehaviour = LoanChargeOffBehaviour.REGULAR.getValueAsStringEnumOptionData();
|
||||
final boolean interestRecognitionOnDisbursementDate = false;
|
||||
|
||||
return new LoanProductData(id, name, shortName, description, currency, principal, minPrincipal, maxPrincipal, tolerance,
|
||||
numberOfRepayments, minNumberOfRepayments, maxNumberOfRepayments, repaymentEvery, interestRatePerPeriod,
|
||||
@@ -611,7 +617,8 @@ public class LoanProductData implements Serializable {
|
||||
fixedPrincipalPercentagePerInstallment, delinquencyBucketOptions, delinquencyBucket, dueDaysForRepaymentEvent,
|
||||
overDueDaysForRepaymentEvent, enableDownPayment, disbursedAmountPercentageDownPayment, enableAutoRepaymentForDownPayment,
|
||||
paymentAllocation, creditAllocation, repaymentStartDateType, enableInstallmentLevelDelinquency, loanScheduleType,
|
||||
loanScheduleProcessingType, fixedLength, enableAccrualActivityPosting, supportedInterestRefundTypes, chargeOffBehaviour);
|
||||
loanScheduleProcessingType, fixedLength, enableAccrualActivityPosting, supportedInterestRefundTypes, chargeOffBehaviour,
|
||||
interestRecognitionOnDisbursementDate);
|
||||
|
||||
}
|
||||
|
||||
@@ -715,6 +722,7 @@ public class LoanProductData implements Serializable {
|
||||
final boolean enableAccrualActivityPosting = false;
|
||||
final List<StringEnumOptionData> supportedInterestRefundTypes = null;
|
||||
final StringEnumOptionData chargeOffBehaviour = null;
|
||||
final boolean interestRecognitionOnDisbursementDate = false;
|
||||
|
||||
return new LoanProductData(id, name, shortName, description, currency, principal, minPrincipal, maxPrincipal, tolerance,
|
||||
numberOfRepayments, minNumberOfRepayments, maxNumberOfRepayments, repaymentEvery, interestRatePerPeriod,
|
||||
@@ -735,7 +743,8 @@ public class LoanProductData implements Serializable {
|
||||
fixedPrincipalPercentagePerInstallment, delinquencyBucketOptions, delinquencyBucket, dueDaysForRepaymentEvent,
|
||||
overDueDaysForRepaymentEvent, enableDownPayment, disbursedAmountPercentageDownPayment, enableAutoRepaymentForDownPayment,
|
||||
paymentAllocation, creditAllocationData, repaymentStartDateType, enableInstallmentLevelDelinquency, loanScheduleType,
|
||||
loanScheduleProcessingType, fixedLength, enableAccrualActivityPosting, supportedInterestRefundTypes, chargeOffBehaviour);
|
||||
loanScheduleProcessingType, fixedLength, enableAccrualActivityPosting, supportedInterestRefundTypes, chargeOffBehaviour,
|
||||
interestRecognitionOnDisbursementDate);
|
||||
}
|
||||
|
||||
public static LoanProductData withAccountingDetails(final LoanProductData productData, final Map<String, Object> accountingMappings,
|
||||
@@ -789,7 +798,7 @@ public class LoanProductData implements Serializable {
|
||||
final EnumOptionData repaymentStartDateType, final boolean enableInstallmentLevelDelinquency,
|
||||
final EnumOptionData loanScheduleType, final EnumOptionData loanScheduleProcessingType, final Integer fixedLength,
|
||||
final boolean enableAccrualActivityPosting, final List<StringEnumOptionData> supportedInterestRefundTypes,
|
||||
StringEnumOptionData chargeOffBehaviour) {
|
||||
StringEnumOptionData chargeOffBehaviour, final boolean interestRecognitionOnDisbursementDate) {
|
||||
this.id = id;
|
||||
this.name = name;
|
||||
this.shortName = shortName;
|
||||
@@ -932,6 +941,7 @@ public class LoanProductData implements Serializable {
|
||||
this.chargeOffBehaviour = chargeOffBehaviour;
|
||||
this.chargeOffBehaviourOptions = null;
|
||||
this.chargeOffReasonOptions = null;
|
||||
this.interestRecognitionOnDisbursementDate = interestRecognitionOnDisbursementDate;
|
||||
}
|
||||
|
||||
public LoanProductData(final LoanProductData productData, final Collection<ChargeData> chargeOptions,
|
||||
@@ -1116,6 +1126,7 @@ public class LoanProductData implements Serializable {
|
||||
this.chargeOffBehaviour = productData.chargeOffBehaviour;
|
||||
this.chargeOffBehaviourOptions = chargeOffBehaviourOptions;
|
||||
this.chargeOffReasonOptions = chargeOffReasonOptions;
|
||||
this.interestRecognitionOnDisbursementDate = productData.interestRecognitionOnDisbursementDate;
|
||||
}
|
||||
|
||||
private Collection<ChargeData> nullIfEmpty(final Collection<ChargeData> charges) {
|
||||
|
||||
+18
-4
@@ -443,6 +443,12 @@ public class LoanProduct extends AbstractPersistableCustom<Long> {
|
||||
final boolean enableAccrualActivityPosting = command
|
||||
.booleanPrimitiveValueOfParameterNamed(LoanProductConstants.ENABLE_ACCRUAL_ACTIVITY_POSTING);
|
||||
|
||||
boolean interestRecognitionOnDisbursementDate = false;
|
||||
if (command.parameterExists(LoanProductConstants.INTEREST_RECOGNITION_ON_DISBURSEMENT_DATE)) {
|
||||
interestRecognitionOnDisbursementDate = command
|
||||
.booleanPrimitiveValueOfParameterNamed(LoanProductConstants.INTEREST_RECOGNITION_ON_DISBURSEMENT_DATE);
|
||||
}
|
||||
|
||||
List<LoanSupportedInterestRefundTypes> supportedInterestRefundTypes = new ArrayList<>();
|
||||
if (command.parameterExists(LoanProductConstants.SUPPORTED_INTEREST_REFUND_TYPES)) {
|
||||
JsonArray supportedTransactionsForInterestRefund = command
|
||||
@@ -480,7 +486,7 @@ public class LoanProduct extends AbstractPersistableCustom<Long> {
|
||||
allowApprovedDisbursedAmountsOverApplied, overAppliedCalculationType, overAppliedNumber, dueDaysForRepaymentEvent,
|
||||
overDueDaysForRepaymentEvent, enableDownPayment, disbursedAmountPercentageDownPayment, enableAutoRepaymentForDownPayment,
|
||||
repaymentStartDateType, enableInstallmentLevelDelinquency, loanScheduleType, loanScheduleProcessingType, fixedLength,
|
||||
enableAccrualActivityPosting, supportedInterestRefundTypes, chargeOffBehaviour);
|
||||
enableAccrualActivityPosting, supportedInterestRefundTypes, chargeOffBehaviour, interestRecognitionOnDisbursementDate);
|
||||
|
||||
}
|
||||
|
||||
@@ -699,7 +705,7 @@ public class LoanProduct extends AbstractPersistableCustom<Long> {
|
||||
final boolean enableInstallmentLevelDelinquency, final LoanScheduleType loanScheduleType,
|
||||
final LoanScheduleProcessingType loanScheduleProcessingType, final Integer fixedLength,
|
||||
final boolean enableAccrualActivityPosting, final List<LoanSupportedInterestRefundTypes> supportedInterestRefundTypes,
|
||||
final LoanChargeOffBehaviour chargeOffBehaviour) {
|
||||
final LoanChargeOffBehaviour chargeOffBehaviour, final boolean isInterestRecognitionOnDisbursementDate) {
|
||||
this.fund = fund;
|
||||
this.transactionProcessingStrategyCode = transactionProcessingStrategyCode;
|
||||
|
||||
@@ -749,7 +755,7 @@ public class LoanProduct extends AbstractPersistableCustom<Long> {
|
||||
inArrearsTolerance, graceOnArrearsAgeing, daysInMonthType.getValue(), daysInYearType.getValue(),
|
||||
isInterestRecalculationEnabled, isEqualAmortization, enableDownPayment, disbursedAmountPercentageForDownPayment,
|
||||
enableAutoRepaymentForDownPayment, loanScheduleType, loanScheduleProcessingType, fixedLength, enableAccrualActivityPosting,
|
||||
supportedInterestRefundTypes, chargeOffBehaviour);
|
||||
supportedInterestRefundTypes, chargeOffBehaviour, isInterestRecognitionOnDisbursementDate);
|
||||
|
||||
this.loanProductMinMaxConstraints = new LoanProductMinMaxConstraints(defaultMinPrincipal, defaultMaxPrincipal,
|
||||
defaultMinNominalInterestRatePerPeriod, defaultMaxNominalInterestRatePerPeriod, defaultMinNumberOfInstallments,
|
||||
@@ -802,7 +808,6 @@ public class LoanProduct extends AbstractPersistableCustom<Long> {
|
||||
this.repaymentStartDateType = repaymentStartDateType;
|
||||
|
||||
this.enableInstallmentLevelDelinquency = enableInstallmentLevelDelinquency;
|
||||
|
||||
validateLoanProductPreSave();
|
||||
}
|
||||
|
||||
@@ -870,6 +875,14 @@ public class LoanProduct extends AbstractPersistableCustom<Long> {
|
||||
}
|
||||
}
|
||||
|
||||
if (this.getLoanProductRelatedDetail().isInterestRecognitionOnDisbursementDate()
|
||||
&& this.getLoanProductRelatedDetail().getLoanScheduleType().equals(LoanScheduleType.CUMULATIVE)) {
|
||||
throw new LoanProductGeneralRuleException(
|
||||
"interestRecognitionOnDisbursementDate.is.only.supported.for.progressive.loan.schedule.type",
|
||||
"interestRecognitionOnDisbursementDate is only supported for progressive loan schedule type");
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public MonetaryCurrency getCurrency() {
|
||||
@@ -1621,4 +1634,5 @@ public class LoanProduct extends AbstractPersistableCustom<Long> {
|
||||
public void updateEnableInstallmentLevelDelinquency(boolean enableInstallmentLevelDelinquency) {
|
||||
this.enableInstallmentLevelDelinquency = enableInstallmentLevelDelinquency;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
+19
-3
@@ -165,6 +165,9 @@ public class LoanProductRelatedDetail implements LoanProductMinimumRepaymentSche
|
||||
@Enumerated(EnumType.STRING)
|
||||
private LoanChargeOffBehaviour chargeOffBehaviour;
|
||||
|
||||
@Column(name = "interest_recognition_on_disbursement_date", nullable = false)
|
||||
private boolean interestRecognitionOnDisbursementDate = false;
|
||||
|
||||
public static LoanProductRelatedDetail createFrom(final CurrencyData currencyData, final BigDecimal principal,
|
||||
final BigDecimal nominalInterestRatePerPeriod, final PeriodFrequencyType interestRatePeriodFrequencyType,
|
||||
final BigDecimal nominalAnnualInterestRate, final InterestMethod interestMethod,
|
||||
@@ -178,7 +181,7 @@ public class LoanProductRelatedDetail implements LoanProductMinimumRepaymentSche
|
||||
final boolean enableAutoRepaymentForDownPayment, final LoanScheduleType loanScheduleType,
|
||||
final LoanScheduleProcessingType loanScheduleProcessingType, final Integer fixedLength,
|
||||
final boolean enableAccrualActivityPosting, final List<LoanSupportedInterestRefundTypes> supportedInterestRefundTypes,
|
||||
final LoanChargeOffBehaviour chargeOffBehaviour) {
|
||||
final LoanChargeOffBehaviour chargeOffBehaviour, final boolean interestRecognitionOnDisbursementDate) {
|
||||
|
||||
final MonetaryCurrency currency = MonetaryCurrency.fromCurrencyData(currencyData);
|
||||
return new LoanProductRelatedDetail(currency, principal, nominalInterestRatePerPeriod, interestRatePeriodFrequencyType,
|
||||
@@ -188,7 +191,7 @@ public class LoanProductRelatedDetail implements LoanProductMinimumRepaymentSche
|
||||
inArrearsTolerance, graceOnArrearsAgeing, daysInMonthType, daysInYearType, isInterestRecalculationEnabled,
|
||||
isEqualAmortization, enableDownPayment, disbursedAmountPercentageForDownPayment, enableAutoRepaymentForDownPayment,
|
||||
loanScheduleType, loanScheduleProcessingType, fixedLength, enableAccrualActivityPosting, supportedInterestRefundTypes,
|
||||
chargeOffBehaviour);
|
||||
chargeOffBehaviour, interestRecognitionOnDisbursementDate);
|
||||
}
|
||||
|
||||
protected LoanProductRelatedDetail() {
|
||||
@@ -208,7 +211,7 @@ public class LoanProductRelatedDetail implements LoanProductMinimumRepaymentSche
|
||||
final boolean enableAutoRepaymentForDownPayment, final LoanScheduleType loanScheduleType,
|
||||
final LoanScheduleProcessingType loanScheduleProcessingType, final Integer fixedLength,
|
||||
final boolean enableAccrualActivityPosting, List<LoanSupportedInterestRefundTypes> supportedInterestRefundTypes,
|
||||
final LoanChargeOffBehaviour chargeOffBehaviour) {
|
||||
final LoanChargeOffBehaviour chargeOffBehaviour, final boolean interestRecognitionOnDisbursementDate) {
|
||||
this.currency = currency;
|
||||
this.principal = defaultPrincipal;
|
||||
this.nominalInterestRatePerPeriod = defaultNominalInterestRatePerPeriod;
|
||||
@@ -244,6 +247,7 @@ public class LoanProductRelatedDetail implements LoanProductMinimumRepaymentSche
|
||||
this.enableAccrualActivityPosting = enableAccrualActivityPosting;
|
||||
this.supportedInterestRefundTypes = supportedInterestRefundTypes;
|
||||
this.chargeOffBehaviour = chargeOffBehaviour;
|
||||
this.interestRecognitionOnDisbursementDate = interestRecognitionOnDisbursementDate;
|
||||
}
|
||||
|
||||
private Integer defaultToNullIfZero(final Integer value) {
|
||||
@@ -520,6 +524,14 @@ public class LoanProductRelatedDetail implements LoanProductMinimumRepaymentSche
|
||||
this.isEqualAmortization = newValue;
|
||||
}
|
||||
|
||||
if (command.isChangeInBooleanParameterNamed(LoanProductConstants.INTEREST_RECOGNITION_ON_DISBURSEMENT_DATE,
|
||||
this.isInterestRecognitionOnDisbursementDate())) {
|
||||
final boolean newValue = command
|
||||
.booleanPrimitiveValueOfParameterNamed(LoanProductConstants.INTEREST_RECOGNITION_ON_DISBURSEMENT_DATE);
|
||||
actualChanges.put(LoanProductConstants.INTEREST_RECOGNITION_ON_DISBURSEMENT_DATE, newValue);
|
||||
this.updateInterestRecognitionOnDisbursementDate(newValue);
|
||||
}
|
||||
|
||||
return actualChanges;
|
||||
}
|
||||
|
||||
@@ -546,4 +558,8 @@ public class LoanProductRelatedDetail implements LoanProductMinimumRepaymentSche
|
||||
this.interestPeriodFrequencyType = PeriodFrequencyType.INVALID;
|
||||
this.annualNominalInterestRate = null;
|
||||
}
|
||||
|
||||
public void updateInterestRecognitionOnDisbursementDate(boolean interestRecognitionOnDisbursementDate) {
|
||||
this.interestRecognitionOnDisbursementDate = interestRecognitionOnDisbursementDate;
|
||||
}
|
||||
}
|
||||
|
||||
+1
@@ -48,4 +48,5 @@
|
||||
<include relativeToChangelogFile="true" file="parts/1023_add_charge_off_behaviour.xml"/>
|
||||
<include relativeToChangelogFile="true" file="parts/1024_accrual_adjustment_transaction_type.xml"/>
|
||||
<include relativeToChangelogFile="true" file="parts/1025_store_pre_closure_strategy_to_loan_level.xml"/>
|
||||
<include relativeToChangelogFile="true" file="parts/1026_add_interest_recognition_flag.xml"/>
|
||||
</databaseChangeLog>
|
||||
|
||||
+40
@@ -0,0 +1,40 @@
|
||||
<?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.
|
||||
|
||||
-->
|
||||
<databaseChangeLog xmlns="http://www.liquibase.org/xml/ns/dbchangelog"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://www.liquibase.org/xml/ns/dbchangelog http://www.liquibase.org/xml/ns/dbchangelog/dbchangelog-4.3.xsd">
|
||||
|
||||
<changeSet author="fineract" id="1026-1">
|
||||
<addColumn tableName="m_product_loan">
|
||||
<column name="interest_recognition_on_disbursement_date" type="boolean" defaultValueBoolean="false">
|
||||
<constraints nullable="false"/>
|
||||
</column>
|
||||
</addColumn>
|
||||
</changeSet>
|
||||
<changeSet author="fineract" id="1026-2">
|
||||
<addColumn tableName="m_loan">
|
||||
<column name="interest_recognition_on_disbursement_date" type="boolean" defaultValueBoolean="false">
|
||||
<constraints nullable="false"/>
|
||||
</column>
|
||||
</addColumn>
|
||||
</changeSet>
|
||||
</databaseChangeLog>
|
||||
+1
-1
@@ -244,7 +244,7 @@ public class LoansApiResource {
|
||||
LoanApiConstants.isTopup, LoanApiConstants.loanIdToClose, LoanApiConstants.topupAmount,
|
||||
LoanApiConstants.clientActiveLoanOptions, LoanApiConstants.datatables, LoanProductConstants.RATES_PARAM_NAME,
|
||||
LoanApiConstants.MULTIDISBURSE_DETAILS_PARAMNAME, LoanApiConstants.EMI_AMOUNT_VARIATIONS_PARAMNAME,
|
||||
LoanApiConstants.COLLECTION_PARAMNAME));
|
||||
LoanApiConstants.COLLECTION_PARAMNAME, LoanApiConstants.INTEREST_RECOGNITION_ON_DISBURSEMENT_DATE));
|
||||
|
||||
private static final Set<String> LOAN_APPROVAL_DATA_PARAMETERS = new HashSet<>(Arrays.asList("approvalDate", "approvalAmount"));
|
||||
private static final Set<String> GLIM_ACCOUNTS_DATA_PARAMETERS = new HashSet<>(Arrays.asList("glimId", "groupId", "clientId",
|
||||
|
||||
+6
@@ -1204,6 +1204,8 @@ final class LoansApiResourceSwagger {
|
||||
@Schema(description = "List of GetLoansLoanIdLoanTermVariations")
|
||||
public List<GetLoansLoanIdLoanTermVariations> loanTermVariations;
|
||||
public StringEnumOptionData chargeOffBehaviour;
|
||||
@Schema(example = "false")
|
||||
public Boolean interestRecognitionOnDisbursementDate;
|
||||
}
|
||||
|
||||
@Schema(description = "GetLoansResponse")
|
||||
@@ -1303,6 +1305,8 @@ final class LoansApiResourceSwagger {
|
||||
public Boolean enableAutoRepaymentForDownPayment;
|
||||
@Schema(example = "10.00")
|
||||
public BigDecimal fixedEmiAmount;
|
||||
@Schema(example = "false")
|
||||
public Boolean interestRecognitionOnDisbursementDate;
|
||||
|
||||
public List<PostLoansRequestChargeData> charges;
|
||||
|
||||
@@ -1473,6 +1477,8 @@ final class LoansApiResourceSwagger {
|
||||
public BigDecimal disbursedAmountPercentageForDownPayment;
|
||||
@Schema(example = "false")
|
||||
public Boolean enableAutoRepaymentForDownPayment;
|
||||
@Schema(example = "false")
|
||||
public Boolean interestRecognitionOnDisbursementDate;
|
||||
|
||||
static final class PutLoansLoanIdChanges {
|
||||
|
||||
|
||||
+7
-3
@@ -266,6 +266,7 @@ public class LoanAccountData {
|
||||
private Boolean enableDownPayment;
|
||||
private BigDecimal disbursedAmountPercentageForDownPayment;
|
||||
private Boolean enableAutoRepaymentForDownPayment;
|
||||
private Boolean interestRecognitionOnDisbursementDate;
|
||||
|
||||
private EnumOptionData loanScheduleType;
|
||||
private EnumOptionData loanScheduleProcessingType;
|
||||
@@ -419,7 +420,8 @@ public class LoanAccountData {
|
||||
.setIsEqualAmortization(product.isEqualAmortization())
|
||||
.setFixedPrincipalPercentagePerInstallment(product.getFixedPrincipalPercentagePerInstallment())
|
||||
.setDelinquent(CollectionData.template()).setDisallowExpectedDisbursements(product.getDisallowExpectedDisbursements())
|
||||
.setLoanScheduleType(product.getLoanScheduleType()).setLoanScheduleProcessingType(product.getLoanScheduleProcessingType());
|
||||
.setLoanScheduleType(product.getLoanScheduleType()).setLoanScheduleProcessingType(product.getLoanScheduleProcessingType())
|
||||
.setInterestRecognitionOnDisbursementDate(product.isInterestRecognitionOnDisbursementDate());
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -456,7 +458,8 @@ public class LoanAccountData {
|
||||
LocalDate lastClosedBusinessDate, LocalDate overpaidOnDate, final boolean chargedOff, final boolean enableDownPayment,
|
||||
final BigDecimal disbursedAmountPercentageForDownPayment, final boolean enableAutoRepaymentForDownPayment,
|
||||
final boolean enableInstallmentLevelDelinquency, final EnumOptionData loanScheduleType,
|
||||
final EnumOptionData loanScheduleProcessingType, final Integer fixedLength, final StringEnumOptionData chargeOffBehaviour) {
|
||||
final EnumOptionData loanScheduleProcessingType, final Integer fixedLength, final StringEnumOptionData chargeOffBehaviour,
|
||||
final boolean isInterestRecognitionOnDisbursementDate) {
|
||||
|
||||
final CollectionData delinquent = CollectionData.template();
|
||||
|
||||
@@ -501,7 +504,8 @@ public class LoanAccountData {
|
||||
.setEnableAutoRepaymentForDownPayment(enableAutoRepaymentForDownPayment)
|
||||
.setEnableInstallmentLevelDelinquency(enableInstallmentLevelDelinquency).setLoanScheduleType(loanScheduleType)
|
||||
.setLoanScheduleProcessingType(loanScheduleProcessingType).setFixedLength(fixedLength)
|
||||
.setChargeOffBehaviour(chargeOffBehaviour);
|
||||
.setChargeOffBehaviour(chargeOffBehaviour)
|
||||
.setInterestRecognitionOnDisbursementDate(isInterestRecognitionOnDisbursementDate);
|
||||
}
|
||||
|
||||
/*
|
||||
|
||||
+15
-1
@@ -518,6 +518,12 @@ public class LoanScheduleAssembler {
|
||||
fixedLength = this.fromApiJsonHelper.extractIntegerWithLocaleNamed(LoanProductConstants.FIXED_LENGTH, element);
|
||||
}
|
||||
|
||||
Boolean interestRecognitionOnDisbursementDate = loanProduct.getLoanProductRelatedDetail().isInterestRecognitionOnDisbursementDate();
|
||||
if (this.fromApiJsonHelper.parameterExists(LoanApiConstants.INTEREST_RECOGNITION_ON_DISBURSEMENT_DATE, element)) {
|
||||
interestRecognitionOnDisbursementDate = this.fromApiJsonHelper
|
||||
.extractBooleanNamed(LoanApiConstants.INTEREST_RECOGNITION_ON_DISBURSEMENT_DATE, element);
|
||||
}
|
||||
|
||||
return LoanApplicationTerms.assembleFrom(applicationCurrency.toData(), loanTermFrequency, loanTermPeriodFrequencyType,
|
||||
numberOfRepayments, repaymentEvery, repaymentPeriodFrequencyType, nthDay, weekDayType, amortizationMethod, interestMethod,
|
||||
interestRatePerPeriod, interestRatePeriodFrequencyType, annualNominalInterestRate, interestCalculationPeriodMethod,
|
||||
@@ -535,7 +541,7 @@ public class LoanScheduleAssembler {
|
||||
loanScheduleType, loanScheduleProcessingType, fixedLength,
|
||||
loanProduct.getLoanProductRelatedDetail().isEnableAccrualActivityPosting(),
|
||||
loanProduct.getLoanProductRelatedDetail().getSupportedInterestRefundTypes(),
|
||||
loanProduct.getLoanProductRelatedDetail().getChargeOffBehaviour());
|
||||
loanProduct.getLoanProductRelatedDetail().getChargeOffBehaviour(), interestRecognitionOnDisbursementDate);
|
||||
}
|
||||
|
||||
private CalendarInstance createCalendarForSameAsRepayment(final Integer repaymentEvery,
|
||||
@@ -1452,6 +1458,14 @@ public class LoanScheduleAssembler {
|
||||
}
|
||||
loanProductRelatedDetail.setDisbursedAmountPercentageForDownPayment(disbursedAmountPercentageDownPayment);
|
||||
}
|
||||
|
||||
if (command.isChangeInBooleanParameterNamed(LoanProductConstants.INTEREST_RECOGNITION_ON_DISBURSEMENT_DATE,
|
||||
loanProductRelatedDetail.isInterestRecognitionOnDisbursementDate())) {
|
||||
final boolean newValue = command
|
||||
.booleanPrimitiveValueOfParameterNamed(LoanProductConstants.INTEREST_RECOGNITION_ON_DISBURSEMENT_DATE);
|
||||
changes.put(LoanProductConstants.INTEREST_RECOGNITION_ON_DISBURSEMENT_DATE, newValue);
|
||||
loanProductRelatedDetail.updateInterestRecognitionOnDisbursementDate(newValue);
|
||||
}
|
||||
}
|
||||
|
||||
public Pair<Loan, Map<String, Object>> assembleLoanApproval(AppUser currentUser, JsonCommand command, Long loanId) {
|
||||
|
||||
+18
-1
@@ -169,7 +169,8 @@ public final class LoanApplicationValidator {
|
||||
LoanApiConstants.DISALLOW_EXPECTED_DISBURSEMENTS, LoanApiConstants.FRAUD_ATTRIBUTE_NAME,
|
||||
LoanProductConstants.LOAN_SCHEDULE_PROCESSING_TYPE, LoanProductConstants.FIXED_LENGTH,
|
||||
LoanProductConstants.ENABLE_INSTALLMENT_LEVEL_DELINQUENCY, LoanProductConstants.ENABLE_DOWN_PAYMENT,
|
||||
LoanProductConstants.ENABLE_AUTO_REPAYMENT_DOWN_PAYMENT, LoanProductConstants.DISBURSED_AMOUNT_PERCENTAGE_DOWN_PAYMENT));
|
||||
LoanProductConstants.ENABLE_AUTO_REPAYMENT_DOWN_PAYMENT, LoanProductConstants.DISBURSED_AMOUNT_PERCENTAGE_DOWN_PAYMENT,
|
||||
LoanApiConstants.INTEREST_RECOGNITION_ON_DISBURSEMENT_DATE));
|
||||
public static final String LOANAPPLICATION_UNDO = "loanapplication.undo";
|
||||
|
||||
private final FromJsonHelper fromApiJsonHelper;
|
||||
@@ -760,6 +761,14 @@ public final class LoanApplicationValidator {
|
||||
validateTransactionProcessingStrategy(transactionProcessingStrategy, loanProduct);
|
||||
|
||||
fixedLengthValidations(element);
|
||||
|
||||
if (this.fromApiJsonHelper.parameterExists(LoanApiConstants.INTEREST_RECOGNITION_ON_DISBURSEMENT_DATE, element)) {
|
||||
if (!LoanScheduleType.PROGRESSIVE.equals(loanProduct.getLoanProductRelatedDetail().getLoanScheduleType())) {
|
||||
List<String> unsupportedParameterList = new ArrayList<>();
|
||||
unsupportedParameterList.add(LoanApiConstants.INTEREST_RECOGNITION_ON_DISBURSEMENT_DATE);
|
||||
throw new UnsupportedParameterException(unsupportedParameterList);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void fixedLengthValidations(final JsonElement element) {
|
||||
@@ -1442,6 +1451,14 @@ public final class LoanApplicationValidator {
|
||||
|
||||
loanProductDataValidator.validateRepaymentPeriodWithGraceSettings(numberOfRepayments, graceOnPrincipalPayment,
|
||||
graceOnInterestPayment, graceOnInterestCharged, recurringMoratoriumOnPrincipalPeriods, baseDataValidator);
|
||||
|
||||
if (this.fromApiJsonHelper.parameterExists(LoanApiConstants.INTEREST_RECOGNITION_ON_DISBURSEMENT_DATE, element)) {
|
||||
if (!LoanScheduleType.PROGRESSIVE.equals(loanProduct.getLoanProductRelatedDetail().getLoanScheduleType())) {
|
||||
List<String> unsupportedParameterList = new ArrayList<>();
|
||||
unsupportedParameterList.add(LoanApiConstants.INTEREST_RECOGNITION_ON_DISBURSEMENT_DATE);
|
||||
throw new UnsupportedParameterException(unsupportedParameterList);
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
+1
-1
@@ -75,7 +75,7 @@ public final class LoanScheduleValidator {
|
||||
LoanApiConstants.daysInYearTypeParameterName, LoanApiConstants.fixedPrincipalPercentagePerInstallmentParamName,
|
||||
LoanProductConstants.FIXED_LENGTH, LoanProductConstants.ENABLE_INSTALLMENT_LEVEL_DELINQUENCY,
|
||||
LoanProductConstants.ENABLE_DOWN_PAYMENT, LoanProductConstants.DISBURSED_AMOUNT_PERCENTAGE_DOWN_PAYMENT,
|
||||
LoanProductConstants.ENABLE_AUTO_REPAYMENT_DOWN_PAYMENT));
|
||||
LoanProductConstants.ENABLE_AUTO_REPAYMENT_DOWN_PAYMENT, LoanProductConstants.INTEREST_RECOGNITION_ON_DISBURSEMENT_DATE));
|
||||
|
||||
private final FromJsonHelper fromApiJsonHelper;
|
||||
|
||||
|
||||
+4
-2
@@ -702,7 +702,7 @@ public class LoanReadPlatformServiceImpl implements LoanReadPlatformService, Loa
|
||||
+ " topup.topup_amount as topupAmount, l.last_closed_business_date as lastClosedBusinessDate,l.overpaidon_date as overpaidOnDate, "
|
||||
+ " l.is_charged_off as isChargedOff, l.charge_off_reason_cv_id as chargeOffReasonId, codec.code_value as chargeOffReason, l.charged_off_on_date as chargedOffOnDate, l.enable_down_payment as enableDownPayment, l.disbursed_amount_percentage_for_down_payment as disbursedAmountPercentageForDownPayment, l.enable_auto_repayment_for_down_payment as enableAutoRepaymentForDownPayment,"
|
||||
+ " cobu.username as chargedOffByUsername, cobu.firstname as chargedOffByFirstname, cobu.lastname as chargedOffByLastname, l.loan_schedule_type as loanScheduleType, l.loan_schedule_processing_type as loanScheduleProcessingType, "
|
||||
+ " l.charge_off_behaviour as chargeOffBehaviour " //
|
||||
+ " l.charge_off_behaviour as chargeOffBehaviour, l.interest_recognition_on_disbursement_date as interestRecognitionOnDisbursementDate " //
|
||||
+ " from m_loan l" //
|
||||
+ " join m_product_loan lp on lp.id = l.product_id" //
|
||||
+ " left join m_loan_recalculation_details lir on lir.loan_id = l.id join m_currency rc on rc."
|
||||
@@ -1068,6 +1068,7 @@ public class LoanReadPlatformServiceImpl implements LoanReadPlatformService, Loa
|
||||
final LoanScheduleProcessingType loanScheduleProcessingType = LoanScheduleProcessingType.valueOf(loanScheduleProcessingTypeStr);
|
||||
final Integer fixedLength = JdbcSupport.getInteger(rs, "fixedLength");
|
||||
final LoanChargeOffBehaviour chargeOffBehaviour = LoanChargeOffBehaviour.valueOf(rs.getString("chargeOffBehaviour"));
|
||||
final boolean interestRecognitionOnDisbursementDate = rs.getBoolean("interestRecognitionOnDisbursementDate");
|
||||
|
||||
return LoanAccountData.basicLoanDetails(id, accountNo, status, externalId, clientId, clientAccountNo, clientName,
|
||||
clientOfficeId, clientExternalId, groupData, loanType, loanProductId, loanProductName, loanProductDescription,
|
||||
@@ -1086,7 +1087,8 @@ public class LoanReadPlatformServiceImpl implements LoanReadPlatformService, Loa
|
||||
fixedPrincipalPercentagePerInstallment, delinquencyRange, disallowExpectedDisbursements, isFraud,
|
||||
lastClosedBusinessDate, overpaidOnDate, isChargedOff, enableDownPayment, disbursedAmountPercentageForDownPayment,
|
||||
enableAutoRepaymentForDownPayment, enableInstallmentLevelDelinquency, loanScheduleType.asEnumOptionData(),
|
||||
loanScheduleProcessingType.asEnumOptionData(), fixedLength, chargeOffBehaviour.getValueAsStringEnumOptionData());
|
||||
loanScheduleProcessingType.asEnumOptionData(), fixedLength, chargeOffBehaviour.getValueAsStringEnumOptionData(),
|
||||
interestRecognitionOnDisbursementDate);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+1
-1
@@ -185,7 +185,7 @@ public final class LoanProductDataValidator {
|
||||
LoanProductConstants.ENABLE_INSTALLMENT_LEVEL_DELINQUENCY, LoanProductConstants.LOAN_SCHEDULE_TYPE,
|
||||
LoanProductConstants.LOAN_SCHEDULE_PROCESSING_TYPE, LoanProductConstants.FIXED_LENGTH,
|
||||
LoanProductConstants.ENABLE_ACCRUAL_ACTIVITY_POSTING, LoanProductConstants.SUPPORTED_INTEREST_REFUND_TYPES,
|
||||
LoanProductConstants.CHARGE_OFF_BEHAVIOUR));
|
||||
LoanProductConstants.CHARGE_OFF_BEHAVIOUR, LoanProductConstants.INTEREST_RECOGNITION_ON_DISBURSEMENT_DATE));
|
||||
|
||||
private static final String[] SUPPORTED_LOAN_CONFIGURABLE_ATTRIBUTES = { LoanProductConstants.amortizationTypeParamName,
|
||||
LoanProductConstants.interestTypeParamName, LoanProductConstants.transactionProcessingStrategyCodeParamName,
|
||||
|
||||
+3
-2
@@ -265,7 +265,7 @@ public class LoanProductReadPlatformServiceImpl implements LoanProductReadPlatfo
|
||||
+ "lpr.is_compounding_to_be_posted_as_transaction as isCompoundingToBePostedAsTransaction, "
|
||||
+ "lpr.allow_compounding_on_eod as allowCompoundingOnEod, "
|
||||
+ "lpr.disallow_interest_calc_on_past_due as disallowInterestCalculationOnPastDue, "
|
||||
+ "lp.hold_guarantee_funds as holdGuaranteeFunds, "
|
||||
+ "lp.hold_guarantee_funds as holdGuaranteeFunds, lp.interest_recognition_on_disbursement_date as interestRecognitionOnDisbursementDate, "
|
||||
+ "lp.principal_threshold_for_last_installment as principalThresholdForLastInstallment, "
|
||||
+ "lp.fixed_principal_percentage_per_installment fixedPrincipalPercentagePerInstallment, "
|
||||
+ "lp.sync_expected_with_disbursement_date as syncExpectedWithDisbursementDate, "
|
||||
@@ -547,6 +547,7 @@ public class LoanProductReadPlatformServiceImpl implements LoanProductReadPlatfo
|
||||
}
|
||||
final String chargeOffBehaviourStr = rs.getString("chargeOffBehaviour");
|
||||
final LoanChargeOffBehaviour loanChargeOffBehaviour = LoanChargeOffBehaviour.valueOf(chargeOffBehaviourStr);
|
||||
final boolean interestRecognitionOnDisbursementDate = rs.getBoolean("interestRecognitionOnDisbursementDate");
|
||||
|
||||
return new LoanProductData(id, name, shortName, description, currency, principal, minPrincipal, maxPrincipal, tolerance,
|
||||
numberOfRepayments, minNumberOfRepayments, maxNumberOfRepayments, repaymentEvery, interestRatePerPeriod,
|
||||
@@ -570,7 +571,7 @@ public class LoanProductReadPlatformServiceImpl implements LoanProductReadPlatfo
|
||||
enableAutoRepaymentForDownPayment, advancedPaymentData, creditAllocationData, repaymentStartDateType,
|
||||
enableInstallmentLevelDelinquency, loanScheduleType.asEnumOptionData(), loanScheduleProcessingType.asEnumOptionData(),
|
||||
fixedLength, enableAccrualActivityPosting, supportedInterestRefundTypes,
|
||||
loanChargeOffBehaviour.getValueAsStringEnumOptionData());
|
||||
loanChargeOffBehaviour.getValueAsStringEnumOptionData(), interestRecognitionOnDisbursementDate);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+3
-3
@@ -98,7 +98,7 @@ public class DefaultScheduledDateGeneratorTest {
|
||||
Money.of(fromApplicationCurrency(dollarCurrency), ZERO), false, null, EMPTY_LIST, BigDecimal.valueOf(36_000L), null,
|
||||
DaysInMonthType.ACTUAL, DaysInYearType.ACTUAL, false, null, null, null, null, null, ZERO, null, NONE, null, ZERO,
|
||||
EMPTY_LIST, true, 0, false, holidayDetailDTO, false, false, false, null, false, false, null, false, DISBURSEMENT_DATE,
|
||||
submittedOnDate, CUMULATIVE, LoanScheduleProcessingType.HORIZONTAL, null, false, null, null);
|
||||
submittedOnDate, CUMULATIVE, LoanScheduleProcessingType.HORIZONTAL, null, false, null, null, false);
|
||||
|
||||
// when
|
||||
List<? extends LoanScheduleModelPeriod> result = underTest.generateRepaymentPeriods(mathContext, expectedDisbursementDate,
|
||||
@@ -169,8 +169,8 @@ public class DefaultScheduledDateGeneratorTest {
|
||||
dueRepaymentPeriodDate, null, null, null, null, null, Money.of(fromApplicationCurrency(dollarCurrency), ZERO), false, null,
|
||||
EMPTY_LIST, BigDecimal.valueOf(36_000L), null, DaysInMonthType.ACTUAL, DaysInYearType.ACTUAL, false, null, null, null, null,
|
||||
null, ZERO, null, NONE, null, ZERO, EMPTY_LIST, true, 0, false, holidayDetailDTO, false, false, false, null, false, false,
|
||||
null, false, DISBURSEMENT_DATE, submittedOnDate, CUMULATIVE, LoanScheduleProcessingType.HORIZONTAL, null, false, null,
|
||||
null);
|
||||
null, false, DISBURSEMENT_DATE, submittedOnDate, CUMULATIVE, LoanScheduleProcessingType.HORIZONTAL, null, false, null, null,
|
||||
false);
|
||||
}
|
||||
|
||||
private HolidayDetailDTO createHolidayDTO() {
|
||||
|
||||
-41
@@ -41,7 +41,6 @@ import java.util.Map;
|
||||
import java.util.UUID;
|
||||
import java.util.concurrent.atomic.AtomicInteger;
|
||||
import java.util.concurrent.atomic.AtomicLong;
|
||||
import java.util.stream.Collectors;
|
||||
import org.apache.fineract.client.models.AdvancedPaymentData;
|
||||
import org.apache.fineract.client.models.BusinessDateRequest;
|
||||
import org.apache.fineract.client.models.CreditAllocationData;
|
||||
@@ -6036,16 +6035,6 @@ public class AdvancedPaymentAllocationLoanRepaymentScheduleTest extends BaseLoan
|
||||
}
|
||||
}
|
||||
|
||||
private static List<PaymentAllocationOrder> getPaymentAllocationOrder(PaymentAllocationType... paymentAllocationTypes) {
|
||||
AtomicInteger integer = new AtomicInteger(1);
|
||||
return Arrays.stream(paymentAllocationTypes).map(pat -> {
|
||||
PaymentAllocationOrder paymentAllocationOrder = new PaymentAllocationOrder();
|
||||
paymentAllocationOrder.setPaymentAllocationRule(pat.name());
|
||||
paymentAllocationOrder.setOrder(integer.getAndIncrement());
|
||||
return paymentAllocationOrder;
|
||||
}).collect(Collectors.toList());
|
||||
}
|
||||
|
||||
private static AdvancedPaymentData createDefaultPaymentAllocationWithMixedGrouping() {
|
||||
AdvancedPaymentData advancedPaymentData = new AdvancedPaymentData();
|
||||
advancedPaymentData.setTransactionType("DEFAULT");
|
||||
@@ -6061,36 +6050,6 @@ public class AdvancedPaymentAllocationLoanRepaymentScheduleTest extends BaseLoan
|
||||
return advancedPaymentData;
|
||||
}
|
||||
|
||||
private static AdvancedPaymentData createDefaultPaymentAllocation() {
|
||||
AdvancedPaymentData advancedPaymentData = new AdvancedPaymentData();
|
||||
advancedPaymentData.setTransactionType("DEFAULT");
|
||||
advancedPaymentData.setFutureInstallmentAllocationRule("NEXT_INSTALLMENT");
|
||||
|
||||
List<PaymentAllocationOrder> paymentAllocationOrders = getPaymentAllocationOrder(PaymentAllocationType.PAST_DUE_PENALTY,
|
||||
PaymentAllocationType.PAST_DUE_FEE, PaymentAllocationType.PAST_DUE_PRINCIPAL, PaymentAllocationType.PAST_DUE_INTEREST,
|
||||
PaymentAllocationType.DUE_PENALTY, PaymentAllocationType.DUE_FEE, PaymentAllocationType.DUE_PRINCIPAL,
|
||||
PaymentAllocationType.DUE_INTEREST, PaymentAllocationType.IN_ADVANCE_PENALTY, PaymentAllocationType.IN_ADVANCE_FEE,
|
||||
PaymentAllocationType.IN_ADVANCE_PRINCIPAL, PaymentAllocationType.IN_ADVANCE_INTEREST);
|
||||
|
||||
advancedPaymentData.setPaymentAllocationOrder(paymentAllocationOrders);
|
||||
return advancedPaymentData;
|
||||
}
|
||||
|
||||
private static AdvancedPaymentData createPaymentAllocation(String transactionType, String futureInstallmentAllocationRule) {
|
||||
AdvancedPaymentData advancedPaymentData = new AdvancedPaymentData();
|
||||
advancedPaymentData.setTransactionType(transactionType);
|
||||
advancedPaymentData.setFutureInstallmentAllocationRule(futureInstallmentAllocationRule);
|
||||
|
||||
List<PaymentAllocationOrder> paymentAllocationOrders = getPaymentAllocationOrder(PaymentAllocationType.PAST_DUE_PENALTY,
|
||||
PaymentAllocationType.PAST_DUE_FEE, PaymentAllocationType.PAST_DUE_PRINCIPAL, PaymentAllocationType.PAST_DUE_INTEREST,
|
||||
PaymentAllocationType.DUE_PENALTY, PaymentAllocationType.DUE_FEE, PaymentAllocationType.DUE_PRINCIPAL,
|
||||
PaymentAllocationType.DUE_INTEREST, PaymentAllocationType.IN_ADVANCE_PENALTY, PaymentAllocationType.IN_ADVANCE_FEE,
|
||||
PaymentAllocationType.IN_ADVANCE_PRINCIPAL, PaymentAllocationType.IN_ADVANCE_INTEREST);
|
||||
|
||||
advancedPaymentData.setPaymentAllocationOrder(paymentAllocationOrders);
|
||||
return advancedPaymentData;
|
||||
}
|
||||
|
||||
private static Integer createLoanProduct(final String principal, final String repaymentAfterEvery, final String numberOfRepayments,
|
||||
boolean autoPayForDownPayment, LoanScheduleType loanScheduleType, LoanScheduleProcessingType loanScheduleProcessingType,
|
||||
AdvancedPaymentData allocationRuleData, final Account... accounts) {
|
||||
|
||||
-13
@@ -21,10 +21,7 @@ package org.apache.fineract.integrationtests;
|
||||
import static org.apache.fineract.portfolio.loanaccount.domain.transactionprocessor.impl.AdvancedPaymentScheduleTransactionProcessor.ADVANCED_PAYMENT_ALLOCATION_STRATEGY;
|
||||
|
||||
import java.math.BigDecimal;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
import java.util.concurrent.atomic.AtomicInteger;
|
||||
import java.util.stream.Collectors;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.apache.fineract.client.models.AdvancedPaymentData;
|
||||
import org.apache.fineract.client.models.GetLoansLoanIdResponse;
|
||||
@@ -173,16 +170,6 @@ public class AdvancedPaymentAllocationWaiveLoanCharges extends BaseLoanIntegrati
|
||||
return advancedPaymentData;
|
||||
}
|
||||
|
||||
private List<PaymentAllocationOrder> getPaymentAllocationOrder(PaymentAllocationType... paymentAllocationTypes) {
|
||||
AtomicInteger integer = new AtomicInteger(1);
|
||||
return Arrays.stream(paymentAllocationTypes).map(pat -> {
|
||||
PaymentAllocationOrder paymentAllocationOrder = new PaymentAllocationOrder();
|
||||
paymentAllocationOrder.setPaymentAllocationRule(pat.name());
|
||||
paymentAllocationOrder.setOrder(integer.getAndIncrement());
|
||||
return paymentAllocationOrder;
|
||||
}).collect(Collectors.toList());
|
||||
}
|
||||
|
||||
protected Long createLoanProductWithAdvancedAllocation() {
|
||||
PostLoanProductsRequest req = createOnePeriod30DaysLongNoInterestPeriodicAccrualProduct();
|
||||
req.transactionProcessingStrategyCode(ADVANCED_PAYMENT_ALLOCATION_STRATEGY).loanScheduleType(LoanScheduleType.PROGRESSIVE.name())
|
||||
|
||||
+32
-1
@@ -495,7 +495,7 @@ public abstract class BaseLoanIntegrationTest extends IntegrationTest {
|
||||
.rescheduleStrategyMethod(rescheduleStrategyMethod);
|
||||
}
|
||||
|
||||
private List<PaymentAllocationOrder> getPaymentAllocationOrder(PaymentAllocationType... paymentAllocationTypes) {
|
||||
protected static List<PaymentAllocationOrder> getPaymentAllocationOrder(PaymentAllocationType... paymentAllocationTypes) {
|
||||
AtomicInteger integer = new AtomicInteger(1);
|
||||
return Arrays.stream(paymentAllocationTypes).map(pat -> {
|
||||
PaymentAllocationOrder paymentAllocationOrder = new PaymentAllocationOrder();
|
||||
@@ -1382,4 +1382,35 @@ public abstract class BaseLoanIntegrationTest extends IntegrationTest {
|
||||
public static final String MERCHANT_ISSUED_REFUND = "MERCHANT_ISSUED_REFUND";
|
||||
public static final String PAYOUT_REFUND = "PAYOUT_REFUND";
|
||||
}
|
||||
|
||||
protected static AdvancedPaymentData createDefaultPaymentAllocation() {
|
||||
AdvancedPaymentData advancedPaymentData = new AdvancedPaymentData();
|
||||
advancedPaymentData.setTransactionType("DEFAULT");
|
||||
advancedPaymentData.setFutureInstallmentAllocationRule("NEXT_INSTALLMENT");
|
||||
|
||||
List<PaymentAllocationOrder> paymentAllocationOrders = getPaymentAllocationOrder(PaymentAllocationType.PAST_DUE_PENALTY,
|
||||
PaymentAllocationType.PAST_DUE_FEE, PaymentAllocationType.PAST_DUE_PRINCIPAL, PaymentAllocationType.PAST_DUE_INTEREST,
|
||||
PaymentAllocationType.DUE_PENALTY, PaymentAllocationType.DUE_FEE, PaymentAllocationType.DUE_PRINCIPAL,
|
||||
PaymentAllocationType.DUE_INTEREST, PaymentAllocationType.IN_ADVANCE_PENALTY, PaymentAllocationType.IN_ADVANCE_FEE,
|
||||
PaymentAllocationType.IN_ADVANCE_PRINCIPAL, PaymentAllocationType.IN_ADVANCE_INTEREST);
|
||||
|
||||
advancedPaymentData.setPaymentAllocationOrder(paymentAllocationOrders);
|
||||
return advancedPaymentData;
|
||||
}
|
||||
|
||||
protected static AdvancedPaymentData createPaymentAllocation(String transactionType, String futureInstallmentAllocationRule) {
|
||||
AdvancedPaymentData advancedPaymentData = new AdvancedPaymentData();
|
||||
advancedPaymentData.setTransactionType(transactionType);
|
||||
advancedPaymentData.setFutureInstallmentAllocationRule(futureInstallmentAllocationRule);
|
||||
|
||||
List<PaymentAllocationOrder> paymentAllocationOrders = getPaymentAllocationOrder(PaymentAllocationType.PAST_DUE_PENALTY,
|
||||
PaymentAllocationType.PAST_DUE_FEE, PaymentAllocationType.PAST_DUE_PRINCIPAL, PaymentAllocationType.PAST_DUE_INTEREST,
|
||||
PaymentAllocationType.DUE_PENALTY, PaymentAllocationType.DUE_FEE, PaymentAllocationType.DUE_PRINCIPAL,
|
||||
PaymentAllocationType.DUE_INTEREST, PaymentAllocationType.IN_ADVANCE_PENALTY, PaymentAllocationType.IN_ADVANCE_FEE,
|
||||
PaymentAllocationType.IN_ADVANCE_PRINCIPAL, PaymentAllocationType.IN_ADVANCE_INTEREST);
|
||||
|
||||
advancedPaymentData.setPaymentAllocationOrder(paymentAllocationOrders);
|
||||
return advancedPaymentData;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
-27
@@ -31,11 +31,9 @@ import io.restassured.specification.ResponseSpecification;
|
||||
import java.math.BigDecimal;
|
||||
import java.time.LocalDate;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.UUID;
|
||||
import java.util.concurrent.atomic.AtomicInteger;
|
||||
import java.util.stream.Stream;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.apache.fineract.client.models.AdvancedPaymentData;
|
||||
@@ -908,31 +906,6 @@ public class ClientLoanCreditBalanceRefundandRepaymentTypeIntegrationTest extend
|
||||
return advancedPaymentData;
|
||||
}
|
||||
|
||||
private static AdvancedPaymentData createDefaultPaymentAllocation() {
|
||||
AdvancedPaymentData advancedPaymentData = new AdvancedPaymentData();
|
||||
advancedPaymentData.setTransactionType("DEFAULT");
|
||||
advancedPaymentData.setFutureInstallmentAllocationRule("NEXT_INSTALLMENT");
|
||||
|
||||
List<PaymentAllocationOrder> paymentAllocationOrders = getPaymentAllocationOrder(PaymentAllocationType.PAST_DUE_PENALTY,
|
||||
PaymentAllocationType.PAST_DUE_FEE, PaymentAllocationType.PAST_DUE_PRINCIPAL, PaymentAllocationType.PAST_DUE_INTEREST,
|
||||
PaymentAllocationType.DUE_PENALTY, PaymentAllocationType.DUE_FEE, PaymentAllocationType.DUE_PRINCIPAL,
|
||||
PaymentAllocationType.DUE_INTEREST, PaymentAllocationType.IN_ADVANCE_PENALTY, PaymentAllocationType.IN_ADVANCE_FEE,
|
||||
PaymentAllocationType.IN_ADVANCE_PRINCIPAL, PaymentAllocationType.IN_ADVANCE_INTEREST);
|
||||
|
||||
advancedPaymentData.setPaymentAllocationOrder(paymentAllocationOrders);
|
||||
return advancedPaymentData;
|
||||
}
|
||||
|
||||
private static List<PaymentAllocationOrder> getPaymentAllocationOrder(PaymentAllocationType... paymentAllocationTypes) {
|
||||
AtomicInteger integer = new AtomicInteger(1);
|
||||
return Arrays.stream(paymentAllocationTypes).map(pat -> {
|
||||
PaymentAllocationOrder paymentAllocationOrder = new PaymentAllocationOrder();
|
||||
paymentAllocationOrder.setPaymentAllocationRule(pat.name());
|
||||
paymentAllocationOrder.setOrder(integer.getAndIncrement());
|
||||
return paymentAllocationOrder;
|
||||
}).toList();
|
||||
}
|
||||
|
||||
private static Stream<Arguments> loanProductFactory() {
|
||||
return Stream.of(Arguments.of(Named.of("DEFAULT_STRATEGY", new LoanProductTestBuilder().withRepaymentStrategy(DEFAULT_STRATEGY))),
|
||||
Arguments.of(Named.of("ADVANCED_PAYMENT_ALLOCATION_STRATEGY",
|
||||
|
||||
-27
@@ -31,10 +31,8 @@ import io.restassured.specification.RequestSpecification;
|
||||
import io.restassured.specification.ResponseSpecification;
|
||||
import java.time.LocalDate;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.concurrent.atomic.AtomicInteger;
|
||||
import java.util.stream.Stream;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.apache.fineract.client.models.AdvancedPaymentData;
|
||||
@@ -399,31 +397,6 @@ public class DelinquencyAndChargebackIntegrationTest extends BaseLoanIntegration
|
||||
return advancedPaymentData;
|
||||
}
|
||||
|
||||
private static AdvancedPaymentData createDefaultPaymentAllocation() {
|
||||
AdvancedPaymentData advancedPaymentData = new AdvancedPaymentData();
|
||||
advancedPaymentData.setTransactionType("DEFAULT");
|
||||
advancedPaymentData.setFutureInstallmentAllocationRule("NEXT_INSTALLMENT");
|
||||
|
||||
List<PaymentAllocationOrder> paymentAllocationOrders = getPaymentAllocationOrder(PaymentAllocationType.PAST_DUE_PENALTY,
|
||||
PaymentAllocationType.PAST_DUE_FEE, PaymentAllocationType.PAST_DUE_PRINCIPAL, PaymentAllocationType.PAST_DUE_INTEREST,
|
||||
PaymentAllocationType.DUE_PENALTY, PaymentAllocationType.DUE_FEE, PaymentAllocationType.DUE_PRINCIPAL,
|
||||
PaymentAllocationType.DUE_INTEREST, PaymentAllocationType.IN_ADVANCE_PENALTY, PaymentAllocationType.IN_ADVANCE_FEE,
|
||||
PaymentAllocationType.IN_ADVANCE_PRINCIPAL, PaymentAllocationType.IN_ADVANCE_INTEREST);
|
||||
|
||||
advancedPaymentData.setPaymentAllocationOrder(paymentAllocationOrders);
|
||||
return advancedPaymentData;
|
||||
}
|
||||
|
||||
private static List<PaymentAllocationOrder> getPaymentAllocationOrder(PaymentAllocationType... paymentAllocationTypes) {
|
||||
AtomicInteger integer = new AtomicInteger(1);
|
||||
return Arrays.stream(paymentAllocationTypes).map(pat -> {
|
||||
PaymentAllocationOrder paymentAllocationOrder = new PaymentAllocationOrder();
|
||||
paymentAllocationOrder.setPaymentAllocationRule(pat.name());
|
||||
paymentAllocationOrder.setOrder(integer.getAndIncrement());
|
||||
return paymentAllocationOrder;
|
||||
}).toList();
|
||||
}
|
||||
|
||||
private static Stream<Arguments> loanProductFactory() {
|
||||
return Stream.of(Arguments.of(Named.of("DEFAULT_STRATEGY", new LoanProductTestBuilder().withRepaymentStrategy(DEFAULT_STRATEGY))),
|
||||
Arguments.of(Named.of("ADVANCED_PAYMENT_ALLOCATION_STRATEGY",
|
||||
|
||||
+142
@@ -0,0 +1,142 @@
|
||||
/**
|
||||
* 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.
|
||||
*/
|
||||
package org.apache.fineract.integrationtests;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||
import static org.junit.jupiter.api.Assertions.assertNotEquals;
|
||||
import static org.junit.jupiter.api.Assertions.assertThrows;
|
||||
import static org.junit.jupiter.api.Assertions.assertTrue;
|
||||
|
||||
import io.restassured.builder.RequestSpecBuilder;
|
||||
import io.restassured.builder.ResponseSpecBuilder;
|
||||
import io.restassured.http.ContentType;
|
||||
import io.restassured.specification.RequestSpecification;
|
||||
import io.restassured.specification.ResponseSpecification;
|
||||
import org.apache.fineract.client.models.GetLoanProductsProductIdResponse;
|
||||
import org.apache.fineract.client.models.GetLoansLoanIdResponse;
|
||||
import org.apache.fineract.client.models.PostClientsResponse;
|
||||
import org.apache.fineract.client.models.PostLoanProductsRequest;
|
||||
import org.apache.fineract.client.models.PostLoanProductsResponse;
|
||||
import org.apache.fineract.client.models.PostLoansRequest;
|
||||
import org.apache.fineract.client.models.PostLoansResponse;
|
||||
import org.apache.fineract.client.util.CallFailedRuntimeException;
|
||||
import org.apache.fineract.integrationtests.common.ClientHelper;
|
||||
import org.apache.fineract.integrationtests.common.Utils;
|
||||
import org.apache.fineract.integrationtests.common.loans.LoanProductTestBuilder;
|
||||
import org.apache.fineract.integrationtests.common.loans.LoanTransactionHelper;
|
||||
import org.junit.jupiter.api.BeforeAll;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
public class InterestRecognitionFromDistbusementDateTest extends BaseLoanIntegrationTest {
|
||||
|
||||
private static final Logger LOG = LoggerFactory.getLogger(InterestRecognitionFromDistbusementDateTest.class);
|
||||
private static final String DATETIME_PATTERN = "dd MMMM yyyy";
|
||||
private static ResponseSpecification responseSpec;
|
||||
private static RequestSpecification requestSpec;
|
||||
private static LoanTransactionHelper loanTransactionHelper;
|
||||
private static Integer commonLoanProductId;
|
||||
private static PostClientsResponse client;
|
||||
|
||||
@BeforeAll
|
||||
public static void setup() {
|
||||
Utils.initializeRESTAssured();
|
||||
requestSpec = new RequestSpecBuilder().setContentType(ContentType.JSON).build();
|
||||
requestSpec.header("Authorization", "Basic " + Utils.loginIntoServerAndGetBase64EncodedAuthenticationKey());
|
||||
requestSpec.header("Fineract-Platform-TenantId", "default");
|
||||
responseSpec = new ResponseSpecBuilder().expectStatusCode(200).build();
|
||||
loanTransactionHelper = new LoanTransactionHelper(requestSpec, responseSpec);
|
||||
ClientHelper clientHelper = new ClientHelper(requestSpec, responseSpec);
|
||||
}
|
||||
|
||||
// UC1: Create Loan Product using Progressive Loan Schedule Type and interestChargedFromDisbursementDate flag
|
||||
// 1. Create a Loan product with Adv. Pment. Alloc. (PROGRESSIVE) without interestChargedFromDisbursementDate
|
||||
// 2. Create a Loan product with Adv. Pment. Alloc. (PROGRESSIVE) and interestChargedFromDisbursementDate
|
||||
// 3. Create a Loan product with Cumulative Loan Schedule and interestChargedFromDisbursementDate
|
||||
@Test
|
||||
public void uc1() {
|
||||
final String operationDate = "1 January 2025";
|
||||
runAt(operationDate, () -> {
|
||||
// Create a Loan Product Adv. Pment. Alloc. (PROGRESSIVE) withou interestChargedFromDisbursementDate
|
||||
LOG.info("Create a Loan Product Adv. Pment. Alloc. (PROGRESSIVE) not using interestChargedFromDisbursementDate flag");
|
||||
PostLoanProductsRequest product = createOnePeriod30DaysLongNoInterestPeriodicAccrualProductWithAdvancedPaymentAllocation()
|
||||
.numberOfRepayments(6);
|
||||
PostLoanProductsResponse loanProductResponse = loanProductHelper.createLoanProduct(product);
|
||||
GetLoanProductsProductIdResponse loanProductData = loanProductHelper
|
||||
.retrieveLoanProductById(loanProductResponse.getResourceId());
|
||||
assertEquals(Boolean.FALSE, loanProductData.getInterestRecognitionOnDisbursementDate());
|
||||
|
||||
// Create a Loan Product Adv. Pment. Alloc. (PROGRESSIVE) using interestChargedFromDisbursementDate in true
|
||||
LOG.info("Create a Loan Product Adv. Pment. Alloc. (PROGRESSIVE) using interestChargedFromDisbursementDate flag");
|
||||
product = createOnePeriod30DaysLongNoInterestPeriodicAccrualProductWithAdvancedPaymentAllocation().numberOfRepayments(6)
|
||||
.interestRecognitionOnDisbursementDate(true);
|
||||
loanProductResponse = loanProductHelper.createLoanProduct(product);
|
||||
loanProductData = loanProductHelper.retrieveLoanProductById(loanProductResponse.getResourceId());
|
||||
assertEquals(Boolean.TRUE, loanProductData.getInterestRecognitionOnDisbursementDate());
|
||||
|
||||
// Try to create a Loan Product (CUMULATIVE) using interestChargedFromDisbursementDate in true
|
||||
LOG.info("Try to create a Loan Product (CUMULATIVE) using interestChargedFromDisbursementDate flag");
|
||||
CallFailedRuntimeException exception = assertThrows(CallFailedRuntimeException.class, () -> loanProductHelper.createLoanProduct(
|
||||
createOnePeriod30DaysPeriodicAccrualProduct(8.0).numberOfRepayments(6).interestRecognitionOnDisbursementDate(true)));
|
||||
assertEquals(403, exception.getResponse().code());
|
||||
assertTrue(exception.getMessage()
|
||||
.contains("interestRecognitionOnDisbursementDate.is.only.supported.for.progressive.loan.schedule.type"));
|
||||
});
|
||||
}
|
||||
|
||||
// UC2: Create Loan Product using Progressive Loan Schedule Type and interestChargedFromDisbursementDate flag
|
||||
// 1. Create a Loan product with Adv. Pment. Alloc. (PROGRESSIVE) and interestChargedFromDisbursementDate
|
||||
// 2. Create a Loan account and inherit the interestChargedFromDisbursementDate flag
|
||||
// 3. Create a Loan account and override the interestChargedFromDisbursementDate flag
|
||||
@Test
|
||||
public void uc2() {
|
||||
final String operationDate = "1 January 2025";
|
||||
runAt(operationDate, () -> {
|
||||
PostLoanProductsRequest product = createOnePeriod30DaysLongNoInterestPeriodicAccrualProductWithAdvancedPaymentAllocation()
|
||||
.numberOfRepayments(6).interestRecognitionOnDisbursementDate(true);
|
||||
PostLoanProductsResponse loanProductResponse = loanProductHelper.createLoanProduct(product);
|
||||
GetLoanProductsProductIdResponse loanProductData = loanProductHelper
|
||||
.retrieveLoanProductById(loanProductResponse.getResourceId());
|
||||
|
||||
client = clientHelper.createClient(ClientHelper.defaultClientCreationRequest());
|
||||
|
||||
PostLoansRequest applicationRequest = applyLoanRequest(client.getClientId(), loanProductResponse.getResourceId(), operationDate,
|
||||
100.0, 4).transactionProcessingStrategyCode(LoanProductTestBuilder.ADVANCED_PAYMENT_ALLOCATION_STRATEGY);
|
||||
PostLoansResponse loanResponse = loanTransactionHelper.applyLoan(applicationRequest);
|
||||
|
||||
// Create a Loan account and inherit the interestChargedFromDisbursementDate flag
|
||||
GetLoansLoanIdResponse loanDetails = loanTransactionHelper.getLoanDetails(loanResponse.getLoanId());
|
||||
assertEquals(loanProductData.getInterestRecognitionOnDisbursementDate(),
|
||||
loanDetails.getInterestRecognitionOnDisbursementDate());
|
||||
|
||||
// Create a Loan account and override the interestChargedFromDisbursementDate flag
|
||||
applicationRequest = applyLoanRequest(client.getClientId(), loanProductResponse.getResourceId(), operationDate, 100.0, 4)
|
||||
.transactionProcessingStrategyCode(LoanProductTestBuilder.ADVANCED_PAYMENT_ALLOCATION_STRATEGY)
|
||||
.interestRecognitionOnDisbursementDate(false);
|
||||
loanResponse = loanTransactionHelper.applyLoan(applicationRequest);
|
||||
|
||||
// Create a Loan account and inherit the interestChargedFromDisbursementDate flag
|
||||
loanDetails = loanTransactionHelper.getLoanDetails(loanResponse.getLoanId());
|
||||
assertNotEquals(loanProductData.getInterestRecognitionOnDisbursementDate(),
|
||||
loanDetails.getInterestRecognitionOnDisbursementDate());
|
||||
});
|
||||
}
|
||||
|
||||
}
|
||||
-44
@@ -31,15 +31,12 @@ import java.time.LocalDate;
|
||||
import java.time.format.DateTimeFormatter;
|
||||
import java.time.format.DateTimeFormatterBuilder;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.concurrent.atomic.AtomicInteger;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.apache.fineract.client.models.AdvancedPaymentData;
|
||||
import org.apache.fineract.client.models.BusinessDateRequest;
|
||||
import org.apache.fineract.client.models.GetLoansLoanIdResponse;
|
||||
import org.apache.fineract.client.models.PaymentAllocationOrder;
|
||||
import org.apache.fineract.client.models.PostClientsResponse;
|
||||
import org.apache.fineract.client.models.PostLoansLoanIdRequest;
|
||||
import org.apache.fineract.client.models.PostLoansRequest;
|
||||
@@ -66,7 +63,6 @@ import org.apache.fineract.integrationtests.common.savings.SavingsStatusChecker;
|
||||
import org.apache.fineract.portfolio.loanaccount.domain.transactionprocessor.impl.AdvancedPaymentScheduleTransactionProcessor;
|
||||
import org.apache.fineract.portfolio.loanaccount.loanschedule.domain.LoanScheduleProcessingType;
|
||||
import org.apache.fineract.portfolio.loanaccount.loanschedule.domain.LoanScheduleType;
|
||||
import org.apache.fineract.portfolio.loanproduct.domain.PaymentAllocationType;
|
||||
import org.junit.jupiter.api.AfterAll;
|
||||
import org.junit.jupiter.api.Assertions;
|
||||
import org.junit.jupiter.api.BeforeAll;
|
||||
@@ -334,44 +330,4 @@ public class LoanChargePaymentWithAdvancedPaymentAllocationTest extends BaseLoan
|
||||
collateral.put("quantity", quantity.toString());
|
||||
return collateral;
|
||||
}
|
||||
|
||||
private static AdvancedPaymentData createPaymentAllocation(String transactionType, String futureInstallmentAllocationRule) {
|
||||
AdvancedPaymentData advancedPaymentData = new AdvancedPaymentData();
|
||||
advancedPaymentData.setTransactionType(transactionType);
|
||||
advancedPaymentData.setFutureInstallmentAllocationRule(futureInstallmentAllocationRule);
|
||||
|
||||
List<PaymentAllocationOrder> paymentAllocationOrders = getPaymentAllocationOrder(PaymentAllocationType.PAST_DUE_PENALTY,
|
||||
PaymentAllocationType.PAST_DUE_FEE, PaymentAllocationType.PAST_DUE_PRINCIPAL, PaymentAllocationType.PAST_DUE_INTEREST,
|
||||
PaymentAllocationType.DUE_PENALTY, PaymentAllocationType.DUE_FEE, PaymentAllocationType.DUE_PRINCIPAL,
|
||||
PaymentAllocationType.DUE_INTEREST, PaymentAllocationType.IN_ADVANCE_PENALTY, PaymentAllocationType.IN_ADVANCE_FEE,
|
||||
PaymentAllocationType.IN_ADVANCE_PRINCIPAL, PaymentAllocationType.IN_ADVANCE_INTEREST);
|
||||
|
||||
advancedPaymentData.setPaymentAllocationOrder(paymentAllocationOrders);
|
||||
return advancedPaymentData;
|
||||
}
|
||||
|
||||
private static AdvancedPaymentData createDefaultPaymentAllocation() {
|
||||
AdvancedPaymentData advancedPaymentData = new AdvancedPaymentData();
|
||||
advancedPaymentData.setTransactionType("DEFAULT");
|
||||
advancedPaymentData.setFutureInstallmentAllocationRule("NEXT_INSTALLMENT");
|
||||
|
||||
List<PaymentAllocationOrder> paymentAllocationOrders = getPaymentAllocationOrder(PaymentAllocationType.PAST_DUE_PENALTY,
|
||||
PaymentAllocationType.PAST_DUE_FEE, PaymentAllocationType.PAST_DUE_PRINCIPAL, PaymentAllocationType.PAST_DUE_INTEREST,
|
||||
PaymentAllocationType.DUE_PENALTY, PaymentAllocationType.DUE_FEE, PaymentAllocationType.DUE_PRINCIPAL,
|
||||
PaymentAllocationType.DUE_INTEREST, PaymentAllocationType.IN_ADVANCE_PENALTY, PaymentAllocationType.IN_ADVANCE_FEE,
|
||||
PaymentAllocationType.IN_ADVANCE_PRINCIPAL, PaymentAllocationType.IN_ADVANCE_INTEREST);
|
||||
|
||||
advancedPaymentData.setPaymentAllocationOrder(paymentAllocationOrders);
|
||||
return advancedPaymentData;
|
||||
}
|
||||
|
||||
private static List<PaymentAllocationOrder> getPaymentAllocationOrder(PaymentAllocationType... paymentAllocationTypes) {
|
||||
AtomicInteger integer = new AtomicInteger(1);
|
||||
return Arrays.stream(paymentAllocationTypes).map(pat -> {
|
||||
PaymentAllocationOrder paymentAllocationOrder = new PaymentAllocationOrder();
|
||||
paymentAllocationOrder.setPaymentAllocationRule(pat.name());
|
||||
paymentAllocationOrder.setOrder(integer.getAndIncrement());
|
||||
return paymentAllocationOrder;
|
||||
}).toList();
|
||||
}
|
||||
}
|
||||
|
||||
-25
@@ -1824,21 +1824,6 @@ public class LoanChargebackWithCreditAllocationsIntegrationTests extends BaseLoa
|
||||
.creditAllocation(List.of(creditAllocationData));
|
||||
}
|
||||
|
||||
private AdvancedPaymentData createDefaultPaymentAllocation() {
|
||||
AdvancedPaymentData advancedPaymentData = new AdvancedPaymentData();
|
||||
advancedPaymentData.setTransactionType("DEFAULT");
|
||||
advancedPaymentData.setFutureInstallmentAllocationRule("NEXT_INSTALLMENT");
|
||||
|
||||
List<PaymentAllocationOrder> paymentAllocationOrders = getPaymentAllocationOrder(PaymentAllocationType.PAST_DUE_PENALTY,
|
||||
PaymentAllocationType.PAST_DUE_FEE, PaymentAllocationType.PAST_DUE_PRINCIPAL, PaymentAllocationType.PAST_DUE_INTEREST,
|
||||
PaymentAllocationType.DUE_PENALTY, PaymentAllocationType.DUE_FEE, PaymentAllocationType.DUE_PRINCIPAL,
|
||||
PaymentAllocationType.DUE_INTEREST, PaymentAllocationType.IN_ADVANCE_PENALTY, PaymentAllocationType.IN_ADVANCE_FEE,
|
||||
PaymentAllocationType.IN_ADVANCE_PRINCIPAL, PaymentAllocationType.IN_ADVANCE_INTEREST);
|
||||
|
||||
advancedPaymentData.setPaymentAllocationOrder(paymentAllocationOrders);
|
||||
return advancedPaymentData;
|
||||
}
|
||||
|
||||
private AdvancedPaymentData createDefaultPaymentAllocationPrincipalFirst() {
|
||||
AdvancedPaymentData advancedPaymentData = new AdvancedPaymentData();
|
||||
advancedPaymentData.setTransactionType("DEFAULT");
|
||||
@@ -1886,14 +1871,4 @@ public class LoanChargebackWithCreditAllocationsIntegrationTests extends BaseLoa
|
||||
}).toList();
|
||||
}
|
||||
|
||||
private List<PaymentAllocationOrder> getPaymentAllocationOrder(PaymentAllocationType... paymentAllocationTypes) {
|
||||
AtomicInteger integer = new AtomicInteger(1);
|
||||
return Arrays.stream(paymentAllocationTypes).map(pat -> {
|
||||
PaymentAllocationOrder paymentAllocationOrder = new PaymentAllocationOrder();
|
||||
paymentAllocationOrder.setPaymentAllocationRule(pat.name());
|
||||
paymentAllocationOrder.setOrder(integer.getAndIncrement());
|
||||
return paymentAllocationOrder;
|
||||
}).toList();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
-26
@@ -21,9 +21,7 @@ package org.apache.fineract.integrationtests;
|
||||
import static org.apache.fineract.portfolio.loanaccount.domain.transactionprocessor.impl.AdvancedPaymentScheduleTransactionProcessor.ADVANCED_PAYMENT_ALLOCATION_STRATEGY;
|
||||
|
||||
import java.math.BigDecimal;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
import java.util.concurrent.atomic.AtomicInteger;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.apache.fineract.client.models.AdvancedPaymentData;
|
||||
import org.apache.fineract.client.models.GetLoansLoanIdResponse;
|
||||
@@ -130,28 +128,4 @@ public class LoanInterestRateFrequencyTest extends BaseLoanIntegrationTest {
|
||||
return advancedPaymentData;
|
||||
}
|
||||
|
||||
private AdvancedPaymentData createDefaultPaymentAllocation() {
|
||||
AdvancedPaymentData advancedPaymentData = new AdvancedPaymentData();
|
||||
advancedPaymentData.setTransactionType("DEFAULT");
|
||||
advancedPaymentData.setFutureInstallmentAllocationRule("NEXT_INSTALLMENT");
|
||||
|
||||
List<PaymentAllocationOrder> paymentAllocationOrders = getPaymentAllocationOrder(PaymentAllocationType.PAST_DUE_PENALTY,
|
||||
PaymentAllocationType.PAST_DUE_FEE, PaymentAllocationType.PAST_DUE_PRINCIPAL, PaymentAllocationType.PAST_DUE_INTEREST,
|
||||
PaymentAllocationType.DUE_PENALTY, PaymentAllocationType.DUE_FEE, PaymentAllocationType.DUE_PRINCIPAL,
|
||||
PaymentAllocationType.DUE_INTEREST, PaymentAllocationType.IN_ADVANCE_PENALTY, PaymentAllocationType.IN_ADVANCE_FEE,
|
||||
PaymentAllocationType.IN_ADVANCE_PRINCIPAL, PaymentAllocationType.IN_ADVANCE_INTEREST);
|
||||
|
||||
advancedPaymentData.setPaymentAllocationOrder(paymentAllocationOrders);
|
||||
return advancedPaymentData;
|
||||
}
|
||||
|
||||
private List<PaymentAllocationOrder> getPaymentAllocationOrder(PaymentAllocationType... paymentAllocationTypes) {
|
||||
AtomicInteger integer = new AtomicInteger(1);
|
||||
return Arrays.stream(paymentAllocationTypes).map(pat -> {
|
||||
PaymentAllocationOrder paymentAllocationOrder = new PaymentAllocationOrder();
|
||||
paymentAllocationOrder.setPaymentAllocationRule(pat.name());
|
||||
paymentAllocationOrder.setOrder(integer.getAndIncrement());
|
||||
return paymentAllocationOrder;
|
||||
}).toList();
|
||||
}
|
||||
}
|
||||
|
||||
-46
@@ -26,12 +26,7 @@ import io.restassured.http.ContentType;
|
||||
import io.restassured.specification.RequestSpecification;
|
||||
import io.restassured.specification.ResponseSpecification;
|
||||
import java.math.BigDecimal;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
import java.util.concurrent.atomic.AtomicInteger;
|
||||
import java.util.stream.Collectors;
|
||||
import org.apache.fineract.client.models.AdvancedPaymentData;
|
||||
import org.apache.fineract.client.models.PaymentAllocationOrder;
|
||||
import org.apache.fineract.client.models.PostClientsResponse;
|
||||
import org.apache.fineract.client.models.PostLoanProductsResponse;
|
||||
import org.apache.fineract.client.models.PostLoansLoanIdRequest;
|
||||
@@ -50,7 +45,6 @@ import org.apache.fineract.integrationtests.common.loans.LoanTransactionHelper;
|
||||
import org.apache.fineract.portfolio.loanaccount.domain.transactionprocessor.impl.AdvancedPaymentScheduleTransactionProcessor;
|
||||
import org.apache.fineract.portfolio.loanaccount.loanschedule.domain.LoanScheduleProcessingType;
|
||||
import org.apache.fineract.portfolio.loanaccount.loanschedule.domain.LoanScheduleType;
|
||||
import org.apache.fineract.portfolio.loanproduct.domain.PaymentAllocationType;
|
||||
import org.junit.jupiter.api.Assertions;
|
||||
import org.junit.jupiter.api.BeforeAll;
|
||||
import org.junit.jupiter.api.Test;
|
||||
@@ -282,44 +276,4 @@ public class LoanOriginationValidationTest extends BaseLoanIntegrationTest {
|
||||
return loanTransactionHelper.getLoanProductId(loanProductJSON);
|
||||
}
|
||||
|
||||
private static AdvancedPaymentData createDefaultPaymentAllocation() {
|
||||
AdvancedPaymentData advancedPaymentData = new AdvancedPaymentData();
|
||||
advancedPaymentData.setTransactionType("DEFAULT");
|
||||
advancedPaymentData.setFutureInstallmentAllocationRule("NEXT_INSTALLMENT");
|
||||
|
||||
List<PaymentAllocationOrder> paymentAllocationOrders = getPaymentAllocationOrder(PaymentAllocationType.PAST_DUE_PENALTY,
|
||||
PaymentAllocationType.PAST_DUE_FEE, PaymentAllocationType.PAST_DUE_PRINCIPAL, PaymentAllocationType.PAST_DUE_INTEREST,
|
||||
PaymentAllocationType.DUE_PENALTY, PaymentAllocationType.DUE_FEE, PaymentAllocationType.DUE_PRINCIPAL,
|
||||
PaymentAllocationType.DUE_INTEREST, PaymentAllocationType.IN_ADVANCE_PENALTY, PaymentAllocationType.IN_ADVANCE_FEE,
|
||||
PaymentAllocationType.IN_ADVANCE_PRINCIPAL, PaymentAllocationType.IN_ADVANCE_INTEREST);
|
||||
|
||||
advancedPaymentData.setPaymentAllocationOrder(paymentAllocationOrders);
|
||||
return advancedPaymentData;
|
||||
}
|
||||
|
||||
private static AdvancedPaymentData createPaymentAllocation(String transactionType, String futureInstallmentAllocationRule) {
|
||||
AdvancedPaymentData advancedPaymentData = new AdvancedPaymentData();
|
||||
advancedPaymentData.setTransactionType(transactionType);
|
||||
advancedPaymentData.setFutureInstallmentAllocationRule(futureInstallmentAllocationRule);
|
||||
|
||||
List<PaymentAllocationOrder> paymentAllocationOrders = getPaymentAllocationOrder(PaymentAllocationType.PAST_DUE_PENALTY,
|
||||
PaymentAllocationType.PAST_DUE_FEE, PaymentAllocationType.PAST_DUE_PRINCIPAL, PaymentAllocationType.PAST_DUE_INTEREST,
|
||||
PaymentAllocationType.DUE_PENALTY, PaymentAllocationType.DUE_FEE, PaymentAllocationType.DUE_PRINCIPAL,
|
||||
PaymentAllocationType.DUE_INTEREST, PaymentAllocationType.IN_ADVANCE_PENALTY, PaymentAllocationType.IN_ADVANCE_FEE,
|
||||
PaymentAllocationType.IN_ADVANCE_PRINCIPAL, PaymentAllocationType.IN_ADVANCE_INTEREST);
|
||||
|
||||
advancedPaymentData.setPaymentAllocationOrder(paymentAllocationOrders);
|
||||
return advancedPaymentData;
|
||||
}
|
||||
|
||||
private static List<PaymentAllocationOrder> getPaymentAllocationOrder(PaymentAllocationType... paymentAllocationTypes) {
|
||||
AtomicInteger integer = new AtomicInteger(1);
|
||||
return Arrays.stream(paymentAllocationTypes).map(pat -> {
|
||||
PaymentAllocationOrder paymentAllocationOrder = new PaymentAllocationOrder();
|
||||
paymentAllocationOrder.setPaymentAllocationRule(pat.name());
|
||||
paymentAllocationOrder.setOrder(integer.getAndIncrement());
|
||||
return paymentAllocationOrder;
|
||||
}).collect(Collectors.toList());
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
-30
@@ -30,12 +30,9 @@ import io.restassured.specification.RequestSpecification;
|
||||
import io.restassured.specification.ResponseSpecification;
|
||||
import java.math.BigDecimal;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.Calendar;
|
||||
import java.util.List;
|
||||
import java.util.concurrent.atomic.AtomicInteger;
|
||||
import java.util.concurrent.atomic.AtomicReference;
|
||||
import java.util.stream.Collectors;
|
||||
import org.apache.fineract.client.models.AdvancedPaymentData;
|
||||
import org.apache.fineract.client.models.AllowAttributeOverrides;
|
||||
import org.apache.fineract.client.models.ChargeData;
|
||||
@@ -44,7 +41,6 @@ import org.apache.fineract.client.models.GetLoanFeeToIncomeAccountMappings;
|
||||
import org.apache.fineract.client.models.GetLoanPaymentChannelToFundSourceMappings;
|
||||
import org.apache.fineract.client.models.GetLoansLoanIdResponse;
|
||||
import org.apache.fineract.client.models.GetLoansLoanIdStatus;
|
||||
import org.apache.fineract.client.models.PaymentAllocationOrder;
|
||||
import org.apache.fineract.client.models.PostChargesRequest;
|
||||
import org.apache.fineract.client.models.PostChargesResponse;
|
||||
import org.apache.fineract.client.models.PostClientsResponse;
|
||||
@@ -67,7 +63,6 @@ import org.apache.fineract.portfolio.charge.domain.ChargeCalculationType;
|
||||
import org.apache.fineract.portfolio.charge.domain.ChargePaymentMode;
|
||||
import org.apache.fineract.portfolio.charge.domain.ChargeTimeType;
|
||||
import org.apache.fineract.portfolio.loanaccount.loanschedule.domain.LoanScheduleType;
|
||||
import org.apache.fineract.portfolio.loanproduct.domain.PaymentAllocationType;
|
||||
import org.junit.jupiter.api.Assertions;
|
||||
import org.junit.jupiter.api.BeforeAll;
|
||||
import org.junit.jupiter.api.Test;
|
||||
@@ -1675,31 +1670,6 @@ public class LoanTransactionAccrualActivityPostingTest extends BaseLoanIntegrati
|
||||
return resourceId;
|
||||
}
|
||||
|
||||
private static List<PaymentAllocationOrder> getPaymentAllocationOrder(PaymentAllocationType... paymentAllocationTypes) {
|
||||
AtomicInteger integer = new AtomicInteger(1);
|
||||
return Arrays.stream(paymentAllocationTypes).map(pat -> {
|
||||
PaymentAllocationOrder paymentAllocationOrder = new PaymentAllocationOrder();
|
||||
paymentAllocationOrder.setPaymentAllocationRule(pat.name());
|
||||
paymentAllocationOrder.setOrder(integer.getAndIncrement());
|
||||
return paymentAllocationOrder;
|
||||
}).collect(Collectors.toList());
|
||||
}
|
||||
|
||||
private static AdvancedPaymentData createDefaultPaymentAllocation() {
|
||||
AdvancedPaymentData advancedPaymentData = new AdvancedPaymentData();
|
||||
advancedPaymentData.setTransactionType("DEFAULT");
|
||||
advancedPaymentData.setFutureInstallmentAllocationRule("NEXT_INSTALLMENT");
|
||||
|
||||
List<PaymentAllocationOrder> paymentAllocationOrders = getPaymentAllocationOrder(PaymentAllocationType.PAST_DUE_PENALTY,
|
||||
PaymentAllocationType.PAST_DUE_FEE, PaymentAllocationType.PAST_DUE_PRINCIPAL, PaymentAllocationType.PAST_DUE_INTEREST,
|
||||
PaymentAllocationType.DUE_PENALTY, PaymentAllocationType.DUE_FEE, PaymentAllocationType.DUE_PRINCIPAL,
|
||||
PaymentAllocationType.DUE_INTEREST, PaymentAllocationType.IN_ADVANCE_PENALTY, PaymentAllocationType.IN_ADVANCE_FEE,
|
||||
PaymentAllocationType.IN_ADVANCE_PRINCIPAL, PaymentAllocationType.IN_ADVANCE_INTEREST);
|
||||
|
||||
advancedPaymentData.setPaymentAllocationOrder(paymentAllocationOrders);
|
||||
return advancedPaymentData;
|
||||
}
|
||||
|
||||
private static Long applyForLoanApplicationAdvancedPaymentAllocation(final Long clientID, final Long loanProductID,
|
||||
BigDecimal principal, String applicationDisbursementDate) {
|
||||
final PostLoansRequest loanRequest = new PostLoansRequest() //
|
||||
|
||||
-27
@@ -31,10 +31,8 @@ import io.restassured.http.ContentType;
|
||||
import io.restassured.specification.RequestSpecification;
|
||||
import io.restassured.specification.ResponseSpecification;
|
||||
import java.time.LocalDate;
|
||||
import java.util.Arrays;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.concurrent.atomic.AtomicInteger;
|
||||
import java.util.stream.Stream;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.apache.fineract.client.models.AdvancedPaymentData;
|
||||
@@ -690,31 +688,6 @@ public class LoanTransactionChargebackTest extends BaseLoanIntegrationTest {
|
||||
return advancedPaymentData;
|
||||
}
|
||||
|
||||
private static AdvancedPaymentData createDefaultPaymentAllocation() {
|
||||
AdvancedPaymentData advancedPaymentData = new AdvancedPaymentData();
|
||||
advancedPaymentData.setTransactionType("DEFAULT");
|
||||
advancedPaymentData.setFutureInstallmentAllocationRule("NEXT_INSTALLMENT");
|
||||
|
||||
List<PaymentAllocationOrder> paymentAllocationOrders = getPaymentAllocationOrder(PaymentAllocationType.PAST_DUE_PENALTY,
|
||||
PaymentAllocationType.PAST_DUE_FEE, PaymentAllocationType.PAST_DUE_PRINCIPAL, PaymentAllocationType.PAST_DUE_INTEREST,
|
||||
PaymentAllocationType.DUE_PENALTY, PaymentAllocationType.DUE_FEE, PaymentAllocationType.DUE_PRINCIPAL,
|
||||
PaymentAllocationType.DUE_INTEREST, PaymentAllocationType.IN_ADVANCE_PENALTY, PaymentAllocationType.IN_ADVANCE_FEE,
|
||||
PaymentAllocationType.IN_ADVANCE_PRINCIPAL, PaymentAllocationType.IN_ADVANCE_INTEREST);
|
||||
|
||||
advancedPaymentData.setPaymentAllocationOrder(paymentAllocationOrders);
|
||||
return advancedPaymentData;
|
||||
}
|
||||
|
||||
private static List<PaymentAllocationOrder> getPaymentAllocationOrder(PaymentAllocationType... paymentAllocationTypes) {
|
||||
AtomicInteger integer = new AtomicInteger(1);
|
||||
return Arrays.stream(paymentAllocationTypes).map(pat -> {
|
||||
PaymentAllocationOrder paymentAllocationOrder = new PaymentAllocationOrder();
|
||||
paymentAllocationOrder.setPaymentAllocationRule(pat.name());
|
||||
paymentAllocationOrder.setOrder(integer.getAndIncrement());
|
||||
return paymentAllocationOrder;
|
||||
}).toList();
|
||||
}
|
||||
|
||||
private static Stream<Arguments> loanProductFactory() {
|
||||
return Stream.of(Arguments.of(Named.of("DEFAULT_STRATEGY", new LoanProductTestBuilder().withRepaymentStrategy(DEFAULT_STRATEGY))),
|
||||
Arguments.of(Named.of("ADVANCED_PAYMENT_ALLOCATION_STRATEGY",
|
||||
|
||||
-45
@@ -33,12 +33,9 @@ import io.restassured.specification.ResponseSpecification;
|
||||
import java.math.BigDecimal;
|
||||
import java.time.LocalDate;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.Calendar;
|
||||
import java.util.List;
|
||||
import java.util.UUID;
|
||||
import java.util.concurrent.atomic.AtomicInteger;
|
||||
import java.util.stream.Collectors;
|
||||
import org.apache.fineract.batch.command.internal.CreateTransactionLoanCommandStrategy;
|
||||
import org.apache.fineract.batch.domain.BatchRequest;
|
||||
import org.apache.fineract.batch.domain.BatchResponse;
|
||||
@@ -47,7 +44,6 @@ import org.apache.fineract.client.models.BusinessDateRequest;
|
||||
import org.apache.fineract.client.models.GetLoansLoanIdLoanChargeData;
|
||||
import org.apache.fineract.client.models.GetLoansLoanIdResponse;
|
||||
import org.apache.fineract.client.models.GetLoansLoanIdTransactionsTransactionIdResponse;
|
||||
import org.apache.fineract.client.models.PaymentAllocationOrder;
|
||||
import org.apache.fineract.client.models.PostChargesRequest;
|
||||
import org.apache.fineract.client.models.PostChargesResponse;
|
||||
import org.apache.fineract.client.models.PostClientsResponse;
|
||||
@@ -80,7 +76,6 @@ import org.apache.fineract.portfolio.charge.domain.ChargeTimeType;
|
||||
import org.apache.fineract.portfolio.loanaccount.domain.transactionprocessor.impl.AdvancedPaymentScheduleTransactionProcessor;
|
||||
import org.apache.fineract.portfolio.loanaccount.loanschedule.domain.LoanScheduleProcessingType;
|
||||
import org.apache.fineract.portfolio.loanaccount.loanschedule.domain.LoanScheduleType;
|
||||
import org.apache.fineract.portfolio.loanproduct.domain.PaymentAllocationType;
|
||||
import org.apache.http.HttpStatus;
|
||||
import org.junit.jupiter.api.Assertions;
|
||||
import org.junit.jupiter.api.BeforeAll;
|
||||
@@ -1720,46 +1715,6 @@ public class LoanTransactionInterestPaymentWaiverTest extends BaseLoanIntegratio
|
||||
return loanTransactionHelper.getLoanProductId(loanProductJSON);
|
||||
}
|
||||
|
||||
private static List<PaymentAllocationOrder> getPaymentAllocationOrder(PaymentAllocationType... paymentAllocationTypes) {
|
||||
AtomicInteger integer = new AtomicInteger(1);
|
||||
return Arrays.stream(paymentAllocationTypes).map(pat -> {
|
||||
PaymentAllocationOrder paymentAllocationOrder = new PaymentAllocationOrder();
|
||||
paymentAllocationOrder.setPaymentAllocationRule(pat.name());
|
||||
paymentAllocationOrder.setOrder(integer.getAndIncrement());
|
||||
return paymentAllocationOrder;
|
||||
}).collect(Collectors.toList());
|
||||
}
|
||||
|
||||
private static AdvancedPaymentData createDefaultPaymentAllocation() {
|
||||
AdvancedPaymentData advancedPaymentData = new AdvancedPaymentData();
|
||||
advancedPaymentData.setTransactionType("DEFAULT");
|
||||
advancedPaymentData.setFutureInstallmentAllocationRule("NEXT_INSTALLMENT");
|
||||
|
||||
List<PaymentAllocationOrder> paymentAllocationOrders = getPaymentAllocationOrder(PaymentAllocationType.PAST_DUE_PENALTY,
|
||||
PaymentAllocationType.PAST_DUE_FEE, PaymentAllocationType.PAST_DUE_PRINCIPAL, PaymentAllocationType.PAST_DUE_INTEREST,
|
||||
PaymentAllocationType.DUE_PENALTY, PaymentAllocationType.DUE_FEE, PaymentAllocationType.DUE_PRINCIPAL,
|
||||
PaymentAllocationType.DUE_INTEREST, PaymentAllocationType.IN_ADVANCE_PENALTY, PaymentAllocationType.IN_ADVANCE_FEE,
|
||||
PaymentAllocationType.IN_ADVANCE_PRINCIPAL, PaymentAllocationType.IN_ADVANCE_INTEREST);
|
||||
|
||||
advancedPaymentData.setPaymentAllocationOrder(paymentAllocationOrders);
|
||||
return advancedPaymentData;
|
||||
}
|
||||
|
||||
private static AdvancedPaymentData createPaymentAllocation(String transactionType, String futureInstallmentAllocationRule) {
|
||||
AdvancedPaymentData advancedPaymentData = new AdvancedPaymentData();
|
||||
advancedPaymentData.setTransactionType(transactionType);
|
||||
advancedPaymentData.setFutureInstallmentAllocationRule(futureInstallmentAllocationRule);
|
||||
|
||||
List<PaymentAllocationOrder> paymentAllocationOrders = getPaymentAllocationOrder(PaymentAllocationType.PAST_DUE_PENALTY,
|
||||
PaymentAllocationType.PAST_DUE_FEE, PaymentAllocationType.PAST_DUE_PRINCIPAL, PaymentAllocationType.PAST_DUE_INTEREST,
|
||||
PaymentAllocationType.DUE_PENALTY, PaymentAllocationType.DUE_FEE, PaymentAllocationType.DUE_PRINCIPAL,
|
||||
PaymentAllocationType.DUE_INTEREST, PaymentAllocationType.IN_ADVANCE_PENALTY, PaymentAllocationType.IN_ADVANCE_FEE,
|
||||
PaymentAllocationType.IN_ADVANCE_PRINCIPAL, PaymentAllocationType.IN_ADVANCE_INTEREST);
|
||||
|
||||
advancedPaymentData.setPaymentAllocationOrder(paymentAllocationOrders);
|
||||
return advancedPaymentData;
|
||||
}
|
||||
|
||||
private static PostLoansResponse applyForLoanApplication(final Long clientId, final Integer loanProductId, final BigDecimal principal,
|
||||
final int loanTermFrequency, final int repaymentAfterEvery, final int numberOfRepayments, final BigDecimal interestRate,
|
||||
final String expectedDisbursementDate, final String submittedOnDate, String transactionProcessorCode,
|
||||
|
||||
-30
@@ -29,15 +29,11 @@ import java.math.BigDecimal;
|
||||
import java.time.LocalDate;
|
||||
import java.time.format.DateTimeFormatter;
|
||||
import java.time.format.DateTimeFormatterBuilder;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
import java.util.concurrent.atomic.AtomicInteger;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.apache.fineract.client.models.AdvancedPaymentData;
|
||||
import org.apache.fineract.client.models.BusinessDateRequest;
|
||||
import org.apache.fineract.client.models.GetLoansLoanIdRepaymentPeriod;
|
||||
import org.apache.fineract.client.models.GetLoansLoanIdResponse;
|
||||
import org.apache.fineract.client.models.PaymentAllocationOrder;
|
||||
import org.apache.fineract.client.models.PostClientsResponse;
|
||||
import org.apache.fineract.client.models.PostLoansLoanIdRequest;
|
||||
import org.apache.fineract.client.models.PostLoansRequest;
|
||||
@@ -56,7 +52,6 @@ import org.apache.fineract.integrationtests.common.loans.LoanTransactionHelper;
|
||||
import org.apache.fineract.portfolio.loanaccount.domain.transactionprocessor.impl.AdvancedPaymentScheduleTransactionProcessor;
|
||||
import org.apache.fineract.portfolio.loanaccount.loanschedule.domain.LoanScheduleProcessingType;
|
||||
import org.apache.fineract.portfolio.loanaccount.loanschedule.domain.LoanScheduleType;
|
||||
import org.apache.fineract.portfolio.loanproduct.domain.PaymentAllocationType;
|
||||
import org.junit.jupiter.api.BeforeAll;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
@@ -505,31 +500,6 @@ public class RefundForActiveLoansWithAdvancedPaymentAllocationTest extends BaseL
|
||||
return loanTransactionHelper.getLoanProductId(loanProductJSON);
|
||||
}
|
||||
|
||||
private static AdvancedPaymentData createDefaultPaymentAllocation() {
|
||||
AdvancedPaymentData advancedPaymentData = new AdvancedPaymentData();
|
||||
advancedPaymentData.setTransactionType("DEFAULT");
|
||||
advancedPaymentData.setFutureInstallmentAllocationRule("NEXT_INSTALLMENT");
|
||||
|
||||
List<PaymentAllocationOrder> paymentAllocationOrders = getPaymentAllocationOrder(PaymentAllocationType.PAST_DUE_PENALTY,
|
||||
PaymentAllocationType.PAST_DUE_FEE, PaymentAllocationType.PAST_DUE_INTEREST, PaymentAllocationType.PAST_DUE_PRINCIPAL,
|
||||
PaymentAllocationType.DUE_PENALTY, PaymentAllocationType.DUE_FEE, PaymentAllocationType.DUE_INTEREST,
|
||||
PaymentAllocationType.DUE_PRINCIPAL, PaymentAllocationType.IN_ADVANCE_PENALTY, PaymentAllocationType.IN_ADVANCE_FEE,
|
||||
PaymentAllocationType.IN_ADVANCE_INTEREST, PaymentAllocationType.IN_ADVANCE_PRINCIPAL);
|
||||
|
||||
advancedPaymentData.setPaymentAllocationOrder(paymentAllocationOrders);
|
||||
return advancedPaymentData;
|
||||
}
|
||||
|
||||
private static List<PaymentAllocationOrder> getPaymentAllocationOrder(PaymentAllocationType... paymentAllocationTypes) {
|
||||
AtomicInteger integer = new AtomicInteger(1);
|
||||
return Arrays.stream(paymentAllocationTypes).map(pat -> {
|
||||
PaymentAllocationOrder paymentAllocationOrder = new PaymentAllocationOrder();
|
||||
paymentAllocationOrder.setPaymentAllocationRule(pat.name());
|
||||
paymentAllocationOrder.setOrder(integer.getAndIncrement());
|
||||
return paymentAllocationOrder;
|
||||
}).toList();
|
||||
}
|
||||
|
||||
private static PostLoansResponse applyForLoanApplication(final Long clientId, final Integer loanProductId, final Long principal,
|
||||
final int loanTermFrequency, final int repaymentAfterEvery, final int numberOfRepayments, final BigDecimal interestRate,
|
||||
final String expectedDisbursementDate, final String submittedOnDate) {
|
||||
|
||||
+4
@@ -165,6 +165,7 @@ public class LoanProductTestBuilder {
|
||||
private FullAccountingConfig fullAccountingConfig;
|
||||
private List<String> supportedInterestRefundTypes = null;
|
||||
private String chargeOffBehaviour;
|
||||
private boolean interestRecognitionOnDisbursementDate = false;
|
||||
|
||||
public String build() {
|
||||
final HashMap<String, Object> map = build(null, null);
|
||||
@@ -324,6 +325,9 @@ public class LoanProductTestBuilder {
|
||||
if (enableAutoRepaymentForDownPayment) {
|
||||
map.put("enableAutoRepaymentForDownPayment", enableAutoRepaymentForDownPayment);
|
||||
}
|
||||
if (interestRecognitionOnDisbursementDate) {
|
||||
map.put("interestRecognitionOnDisbursementDate", interestRecognitionOnDisbursementDate);
|
||||
}
|
||||
|
||||
if (this.repaymentStartDateType != null) {
|
||||
map.put("repaymentStartDateType", repaymentStartDateType);
|
||||
|
||||
Reference in New Issue
Block a user