diff --git a/fineract-e2e-tests-core/src/test/java/org/apache/fineract/test/data/AdvancePaymentsAdjustmentType.java b/fineract-e2e-tests-core/src/test/java/org/apache/fineract/test/data/AdvancePaymentsAdjustmentType.java index e236191a46e..1c73e94d671 100644 --- a/fineract-e2e-tests-core/src/test/java/org/apache/fineract/test/data/AdvancePaymentsAdjustmentType.java +++ b/fineract-e2e-tests-core/src/test/java/org/apache/fineract/test/data/AdvancePaymentsAdjustmentType.java @@ -20,7 +20,10 @@ public enum AdvancePaymentsAdjustmentType { - RESCHEDULE_NEXT_REPAYMENTS(1), REDUCE_NUMBER_OF_INSTALLMENTS(2), REDUCE_EMI_AMOUNT(3), ADJUST_LAST_UNPAID_PERIOD(4); + RESCHEDULE_NEXT_REPAYMENTS(1), // + REDUCE_NUMBER_OF_INSTALLMENTS(2), // + REDUCE_EMI_AMOUNT(3), // + ADJUST_LAST_UNPAID_PERIOD(4);// public final Integer value; diff --git a/fineract-e2e-tests-core/src/test/java/org/apache/fineract/test/data/CobBusinessStep.java b/fineract-e2e-tests-core/src/test/java/org/apache/fineract/test/data/CobBusinessStep.java new file mode 100644 index 00000000000..37f52c4b7d1 --- /dev/null +++ b/fineract-e2e-tests-core/src/test/java/org/apache/fineract/test/data/CobBusinessStep.java @@ -0,0 +1,43 @@ +/** + * 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.test.data; + +public enum CobBusinessStep { + + APPLY_CHARGE_TO_OVERDUE_LOANS("APPLY_CHARGE_TO_OVERDUE_LOANS"), // + LOAN_DELINQUENCY_CLASSIFICATION("LOAN_DELINQUENCY_CLASSIFICATION"), // + CHECK_LOAN_REPAYMENT_DUE("CHECK_LOAN_REPAYMENT_DUE"), // + CHECK_LOAN_REPAYMENT_OVERDUE("CHECK_LOAN_REPAYMENT_OVERDUE"), // + UPDATE_LOAN_ARREARS_AGING("UPDATE_LOAN_ARREARS_AGING"), // + ADD_PERIODIC_ACCRUAL_ENTRIES("ADD_PERIODIC_ACCRUAL_ENTRIES"), // + EXTERNAL_ASSET_OWNER_TRANSFER("EXTERNAL_ASSET_OWNER_TRANSFER"), // + CHECK_DUE_INSTALLMENTS("CHECK_DUE_INSTALLMENTS"), // + ACCRUAL_ACTIVITY_POSTING("ACCRUAL_ACTIVITY_POSTING"), // + LOAN_INTEREST_RECALCULATION("LOAN_INTEREST_RECALCULATION");// + + public final String value; + + CobBusinessStep(String value) { + this.value = value; + } + + public String getValue() { + return value; + } +} diff --git a/fineract-e2e-tests-core/src/test/java/org/apache/fineract/test/data/LoanRescheduleErrorMessage.java b/fineract-e2e-tests-core/src/test/java/org/apache/fineract/test/data/LoanRescheduleErrorMessage.java index 148cd2c83a5..bf2655d6706 100644 --- a/fineract-e2e-tests-core/src/test/java/org/apache/fineract/test/data/LoanRescheduleErrorMessage.java +++ b/fineract-e2e-tests-core/src/test/java/org/apache/fineract/test/data/LoanRescheduleErrorMessage.java @@ -20,16 +20,29 @@ public enum LoanRescheduleErrorMessage { - LOAN_CHARGED_OFF("Loan: %s reschedule installment is not allowed. Loan Account is Charged-off"), LOAN_LOCKED_BY_COB( - "Loan is locked by the COB job. Loan ID: %s"); + LOAN_CHARGED_OFF("Loan: %s reschedule installment is not allowed. Loan Account is Charged-off"), // + LOAN_RESCHEDULE_DATE_NOT_IN_FUTURE("Loan Reschedule From date (%s) for Loan: %s should be in the future."), // + LOAN_LOCKED_BY_COB("Loan is locked by the COB job. Loan ID: %s");// - public final String value; + private final String messageTemplate; - LoanRescheduleErrorMessage(String value) { - this.value = value; + LoanRescheduleErrorMessage(String messageTemplate) { + this.messageTemplate = messageTemplate; } public String getValue(Object... params) { - return String.format(this.value, params); + if (params.length != getExpectedParameterCount()) { + throw new IllegalArgumentException("Expected " + getExpectedParameterCount() + " parameters, but got " + params.length); + } + return String.format(this.messageTemplate, params); + } + + public int getExpectedParameterCount() { + // Count the number of placeholders (%s) in the message template + return (int) messageTemplate.chars().filter(ch -> ch == '%').count(); + } + + public String getMessageTemplate() { + return messageTemplate; } } diff --git a/fineract-e2e-tests-core/src/test/java/org/apache/fineract/test/data/LoanStatus.java b/fineract-e2e-tests-core/src/test/java/org/apache/fineract/test/data/LoanStatus.java index a90e101a9fe..5a02805d7f0 100644 --- a/fineract-e2e-tests-core/src/test/java/org/apache/fineract/test/data/LoanStatus.java +++ b/fineract-e2e-tests-core/src/test/java/org/apache/fineract/test/data/LoanStatus.java @@ -23,8 +23,15 @@ public enum LoanStatus { - NONE(0), SUBMITTED_AND_PENDING_APPROVAL(100), APPROVED(200), ACTIVE(300), CLOSED_OBLIGATIONS_MET(600), OVERPAID( - 700), CLOSED_WRITTEN_OFF(601); + NONE(0), // + SUBMITTED_AND_PENDING_APPROVAL(100), // + APPROVED(200), // + ACTIVE(300), // + WITHDRAWN(400), // + REJECTED(500), // + CLOSED_OBLIGATIONS_MET(600), // + OVERPAID(700), // + CLOSED_WRITTEN_OFF(601);// public final Integer value; diff --git a/fineract-e2e-tests-core/src/test/java/org/apache/fineract/test/data/TransactionType.java b/fineract-e2e-tests-core/src/test/java/org/apache/fineract/test/data/TransactionType.java index 127833e404f..b493da518f3 100644 --- a/fineract-e2e-tests-core/src/test/java/org/apache/fineract/test/data/TransactionType.java +++ b/fineract-e2e-tests-core/src/test/java/org/apache/fineract/test/data/TransactionType.java @@ -20,9 +20,19 @@ public enum TransactionType { - DISBURSEMENT("disbursement"), REPAYMENT("repayment"), DOWN_PAYMENT("downPayment"), GOODWILL_CREDIT("goodwillCredit"), PAYOUT_REFUND( - "payoutRefund"), REFUND_BY_CASH("refundByCash"), MERCHANT_ISSUED_REFUND("merchantIssuedRefund"), CREDIT_BALANCE_REFUND( - "creditBalanceRefund"), CHARGEBACK("chargeback"), ACCRUAL("accrual"), CHARGE_OFF("chargeOff"); + DISBURSEMENT("disbursement"), // + REPAYMENT("repayment"), // + DOWN_PAYMENT("downPayment"), // + GOODWILL_CREDIT("goodwillCredit"), // + PAYOUT_REFUND("payoutRefund"), // + REFUND_BY_CASH("refundByCash"), // + MERCHANT_ISSUED_REFUND("merchantIssuedRefund"), // + CREDIT_BALANCE_REFUND("creditBalanceRefund"), // + CHARGEBACK("chargeback"), // + ACCRUAL("accrual"), // + CHARGE_OFF("chargeOff"), // + CHARGE_ADJUSTMENT("chargeAdjustment"), // + INTEREST_PAYMENT_WAIVER("interestPaymentWaiver");// public final String value; diff --git a/fineract-e2e-tests-core/src/test/java/org/apache/fineract/test/data/job/DefaultJob.java b/fineract-e2e-tests-core/src/test/java/org/apache/fineract/test/data/job/DefaultJob.java index 58d2a910096..1798e8783f8 100644 --- a/fineract-e2e-tests-core/src/test/java/org/apache/fineract/test/data/job/DefaultJob.java +++ b/fineract-e2e-tests-core/src/test/java/org/apache/fineract/test/data/job/DefaultJob.java @@ -25,7 +25,7 @@ public enum DefaultJob implements Job { INCREASE_BUSINESS_DAY("Increase Business Date by 1 day", "BDT_INC1"), // LOAN_DELINQUENCY_CLASSIFICATION("Loan Delinquency Classification", "LA_DECL"), // LOAN_COB("Loan COB", "LA_ECOB"), // - ; + ACCRUAL_ACTIVITY_POSTING("Accrual Activity Posting", "ACC_ACPO"); private final String customName; private final String shortName; diff --git a/fineract-e2e-tests-core/src/test/java/org/apache/fineract/test/data/loanproduct/DefaultLoanProduct.java b/fineract-e2e-tests-core/src/test/java/org/apache/fineract/test/data/loanproduct/DefaultLoanProduct.java index 122ff7af08d..82972057dae 100644 --- a/fineract-e2e-tests-core/src/test/java/org/apache/fineract/test/data/loanproduct/DefaultLoanProduct.java +++ b/fineract-e2e-tests-core/src/test/java/org/apache/fineract/test/data/loanproduct/DefaultLoanProduct.java @@ -25,6 +25,8 @@ public enum DefaultLoanProduct implements LoanProduct { LP1_INTEREST_FLAT, // LP1_INTEREST_DECLINING_BALANCE_PERIOD_SAME_AS_PAYMENT, // LP1_INTEREST_DECLINING_BALANCE_PERIOD_DAILY, // + LP1_INTEREST_DECLINING_BALANCE_PERIOD_DAILY_ACCRUAL_ACTIVITY, // + LP1_INTEREST_DECLINING_BALANCE_DAILY_RECALCULATION_COMPOUNDING_NONE_ACCRUAL_ACTIVITY, // LP1_1MONTH_INTEREST_DECLINING_BALANCE_DAILY_RECALCULATION_COMPOUNDING_MONTHLY, // LP1_INTEREST_DECLINING_BALANCE_DAILY_RECALCULATION_COMPOUNDING_NONE, // LP1_INTEREST_DECLINING_BALANCE_DAILY_RECALCULATION_COMPOUNDING_NONE_RESCHEDULE_REDUCE_NR_INST, // @@ -37,21 +39,37 @@ public enum DefaultLoanProduct implements LoanProduct { LP1_PAYMENT_STRATEGY_DUE_IN_ADVANCE_PENALTY_INTEREST_PRINCIPAL_FEE_INTEREST_FLAT, // LP1_INTEREST_FLAT_OVERDUE_FROM_AMOUNT, // LP1_INTEREST_FLAT_OVERDUE_FROM_AMOUNT_INTEREST, // - LP2_DOWNPAYMENT, LP2_DOWNPAYMENT_AUTO, // + LP2_DOWNPAYMENT, // + LP2_DOWNPAYMENT_AUTO, // LP2_DOWNPAYMENT_AUTO_ADVANCED_PAYMENT_ALLOCATION, // LP2_DOWNPAYMENT_ADVANCED_PAYMENT_ALLOCATION, // - LP2_DOWNPAYMENT_INTEREST, LP2_DOWNPAYMENT_INTEREST_AUTO, // - LP2_ADV_CUST_PMT_ALLOC_PROGRESSIVE_LOAN_SCHEDULE_HORIZONTAL, // + LP2_DOWNPAYMENT_INTEREST, // + LP2_DOWNPAYMENT_INTEREST_AUTO, // LP2_DOWNPAYMENT_ADV_PMT_ALLOC_PROGRESSIVE_LOAN_SCHEDULE_HORIZONTAL, // LP2_DOWNPAYMENT_ADV_PMT_ALLOC_PROGRESSIVE_LOAN_SCHEDULE_VERTICAL, // LP2_DOWNPAYMENT_ADV_PMT_ALLOC_PROGRESSIVE_LOAN_SCHEDULE_HORIZONTAL_INSTALLMENT_LEVEL_DELINQUENCY, // LP2_DOWNPAYMENT_ADV_PMT_ALLOC_PROG_SCHEDULE_HOR_INST_LVL_DELINQUENCY_CREDIT_ALLOCATION, // LP2_DOWNPAYMENT_ADV_PMT_ALLOC_FIXED_LENGTH, // - LP2_ADV_PYMNT_INTEREST_DAILY_EMI_360_30_INTEREST_RECALCULATION_TILL_PRECLOSE, // - LP2_ADV_PYMNT_INTEREST_DAILY_EMI_360_30_INTEREST_RECALCULATION_TILL_REST_FREQUENCY, // - LP2_ADV_PYMNT_INTEREST_DAILY_EMI_360_30_IR_DAILY_TILL_PRECLOSE_LAST_INSTALLMENT_STRATEGY, // - LP2_ADV_PMT_ALLOC_PROGRESSIVE_LOAN_SCHEDULE_HORIZONTAL, // - ; + LP2_DOWNPAYMENT_AUTO_ADVANCED_PAYMENT_ALLOCATION_REPAYMENT_START_SUBMITTED, // + LP2_DOWNPAYMENT_INTEREST_FLAT_ADV_PMT_ALLOC, // + LP2_ADV_PYMNT_INTEREST_DAILY_EMI_ACTUAL_ACTUAL, // + LP2_ADV_PYMNT_INTEREST_DAILY_EMI_ACTUAL_ACTUAL_ACCRUAL_ACTIVITY, // + LP2_ADV_PYMNT_INTEREST_DAILY_EMI_360_30, // + LP2_ADV_PYMNT_INTEREST_DAILY_EMI_360_30_INTEREST_RECALCULATION_DAILY_TILL_PRECLOSE, // + LP2_ADV_PYMNT_INTEREST_DAILY_EMI_360_30_INTEREST_RECALCULATION_DAILY_TILL_PRECLOSE_PMT_ALLOC_1, // + LP2_ADV_PYMNT_INTEREST_DAILY_EMI_360_30_INTEREST_RECALCULATION_SARP_TILL_PRECLOSE, // + LP2_ADV_PYMNT_INTEREST_DAILY_EMI_360_30_INTEREST_RECALCULATION_DAILY_TILL_REST_FREQUENCY_DATE, // + LP2_ADV_PYMNT_INTEREST_DAILY_EMI_360_30_INTEREST_RECALCULATION_SARP_TILL_REST_FREQUENCY_DATE, // + LP2_ADV_PYMNT_INTEREST_DAILY_EMI_ACTUAL_ACTUAL_INTEREST_REFUND_FULL, // + LP2_ADV_PYMNT_INTEREST_DAILY_EMI_360_30_MULTIDISBURSE, // + LP2_ADV_PYMNT_INTEREST_DAILY_EMI_360_30_MULTIDISBURSE_DOWNPAYMENT, // + LP2_ADV_PYMNT_INTEREST_DAILY_EMI_360_30_DOWNPAYMENT, // + LP2_ADV_PYMNT_INTEREST_DAILY_EMI_365_ACTUAL, // + LP2_ADV_PYMNT_INTEREST_DAILY_EMI_ACTUAL_ACTUAL_INTEREST_REFUND, // + LP1_ADV_PMT_ALLOC_PROGRESSIVE_LOAN_SCHEDULE_HORIZONTAL, // + LP2_ADV_CUSTOM_PMT_ALLOC_PROGRESSIVE_LOAN_SCHEDULE_HORIZONTAL, // + LP2_ADV_PYMNT_INTEREST_DAILY_EMI_360_30_INTEREST_RECALCULATION_DAILY_TILL_PRECLOSE_WHOLE_TERM, // + LP2_ADV_PYMNT_INTEREST_DAILY_EMI_360_30_IR_DAILY_TILL_PRECLOSE_LAST_INSTALLMENT_STRATEGY;// @Override public String getName() { diff --git a/fineract-e2e-tests-core/src/test/java/org/apache/fineract/test/factory/LoanProductsRequestFactory.java b/fineract-e2e-tests-core/src/test/java/org/apache/fineract/test/factory/LoanProductsRequestFactory.java index 376813d58e7..beb83efd5ad 100644 --- a/fineract-e2e-tests-core/src/test/java/org/apache/fineract/test/factory/LoanProductsRequestFactory.java +++ b/fineract-e2e-tests-core/src/test/java/org/apache/fineract/test/factory/LoanProductsRequestFactory.java @@ -62,29 +62,30 @@ public class LoanProductsRequestFactory { public static final String NAME_PREFIX = "LP1-"; public static final String NAME_PREFIX_LP2 = "LP2-"; + public static final String NAME_PREFIX_LP2_EMI = "LP2Emi-"; public static final String NAME_PREFIX_INTEREST_FLAT = "LP1InterestFlat-"; public static final String NAME_PREFIX_INTEREST_FLAT_LP2 = "LP2InterestFlat-"; public static final String NAME_PREFIX_INTEREST_DECLINING = "LP1InterestDeclining-"; public static final String NAME_PREFIX_INTEREST_DECLINING_RECALCULATION = "LP1InterestDecliningRecalculation-"; - public static final String NAME_PREFIX_INTEREST_RECALCULATION_WITH_DOWN_PAYMENT_LP3 = "LP3InterestRecalculationWithDownPayment-"; - public static final String NAME_PREFIX_LP2_EMI = "LP2Emi-"; + public static final String NAME_PREFIX_INTEREST_RECALCULATION = "LP2InterestRecalculation-"; public static final String SHORT_NAME_PREFIX = "p"; public static final String SHORT_NAME_PREFIX_INTEREST = "i"; public static final String SHORT_NAME_PREFIX_EMI = "e"; public static final String DATE_FORMAT = "dd MMMM yyyy"; public static final String LOCALE_EN = "en"; - public static final String DESCRIPTION = "LP1 product"; - public static final String DESCRIPTION_LP2 = "LP2 product"; - public static final String DESCRIPTION_INTEREST_FLAT = "LP1 product with 12% interest - FLAT"; - public static final String DESCRIPTION_INTEREST_FLAT_LP2 = "LP2 product with 12% interest - FLAT"; - public static final String DESCRIPTION_INTEREST_DECLINING = "LP1 product with 12% interest - DECLINING BALANCE"; + public static final String DESCRIPTION = "30 days repayment"; + public static final String DESCRIPTION_LP2 = "4 installments repayment"; + public static final String DESCRIPTION_LP2_EMI = "4 installments repayment with EMI"; + public static final String DESCRIPTION_INTEREST_FLAT = "30 days repayment with 12% interest - FLAT"; + public static final String DESCRIPTION_INTEREST_FLAT_LP2 = "4 installments repayment with 12% interest - FLAT"; + public static final String DESCRIPTION_INTEREST_DECLINING = "30 days repayment with 12% interest - DECLINING BALANCE"; public static final String DESCRIPTION_INTEREST_DECLINING_BALANCE_DAILY_RECALCULATION_COMPOUNDING_MONTHLY = "LP1-1MONTH with 12% DECLINING BALANCE interest, interest period: Daily, Interest recalculation-Monthly, Compounding:Interest"; public static final String DESCRIPTION_INTEREST_DECLINING_BALANCE_DAILY_RECALCULATION_COMPOUNDING_NONE = "LP1 with 12% DECLINING BALANCE interest, interest period: Daily, Interest recalculation-Daily, Compounding:none"; - public static final String DESCRIPTION_LP2_EMI = "LP2 product with EMI"; public static final Long FUND_ID = FundId.LENDER_A.value; public static final String CURRENCY_CODE = "EUR"; public static final Integer INTEREST_RATE_FREQUENCY_TYPE_MONTH = InterestRateFrequencyType.MONTH.value; public static final Integer INTEREST_RATE_FREQUENCY_TYPE_YEAR = InterestRateFrequencyType.YEAR.value; + public static final Integer INTEREST_RATE_FREQUENCY_TYPE_WHOLE_TERM = InterestRateFrequencyType.WHOLE_TERM.value; public static final Long REPAYMENT_FREQUENCY_TYPE_DAYS = RepaymentFrequencyType.DAYS.value.longValue(); public static final Long REPAYMENT_FREQUENCY_TYPE_MONTHS = RepaymentFrequencyType.MONTHS.value.longValue(); public static final Integer AMORTIZATION_TYPE = AmortizationType.EQUAL_INSTALLMENTS.value; @@ -94,10 +95,10 @@ public class LoanProductsRequestFactory { public static final Integer INTEREST_CALCULATION_PERIOD_TYPE_DAILY = InterestCalculationPeriodTime.DAILY.value; public static final String TRANSACTION_PROCESSING_STRATEGY_CODE = TransactionProcessingStrategyCode.PENALTIES_FEES_INTEREST_PRINCIPAL_ORDER.value; public static final String TRANSACTION_PROCESSING_STRATEGY_CODE_ADVANCED = TransactionProcessingStrategyCode.ADVANCED_PAYMENT_ALLOCATION.value; - public static final Integer DAYS_IN_YEAR_TYPE = DaysInYearType.ACTUAL.value; public static final Integer DAYS_IN_YEAR_TYPE_360 = DaysInYearType.DAYS360.value; - public static final Integer DAYS_IN_MONTH_TYPE = DaysInMonthType.ACTUAL.value; + public static final Integer DAYS_IN_YEAR_TYPE = DaysInYearType.ACTUAL.value; public static final Integer DAYS_IN_MONTH_TYPE_30 = DaysInMonthType.DAYS30.value; + public static final Integer DAYS_IN_MONTH_TYPE = DaysInMonthType.ACTUAL.value; public static final Integer LOAN_ACCOUNTING_RULE = AccountingRule.ACCRUAL_PERIODIC.value; public static final Integer LOAN_ACCOUNTING_RULE_NONE = AccountingRule.NONE.value; public static final String OVER_APPLIED_CALCULATION_TYPE = "percentage"; @@ -661,46 +662,10 @@ public PostLoanProductsRequest defaultLoanProductsRequestLP1InterestDecliningBal .recalculationRestFrequencyInterval(1);// } - public PostLoanProductsRequest defaultLoanProductsRequestLP2InterestDailyRecalculationWithDownPayment() { - final String name = Utils.randomNameGenerator(NAME_PREFIX_INTEREST_RECALCULATION_WITH_DOWN_PAYMENT_LP3, 4); + public PostLoanProductsRequest defaultLoanProductsRequestLP2InterestDailyRecalculation() { + final String name = Utils.randomNameGenerator(NAME_PREFIX_INTEREST_RECALCULATION, 4); final String shortName = Utils.randomNameGenerator(SHORT_NAME_PREFIX_INTEREST, 3); - return new PostLoanProductsRequest().name(name).shortName(shortName) - .description(DESCRIPTION_INTEREST_DECLINING_BALANCE_DAILY_RECALCULATION_COMPOUNDING_NONE).startDate(null).closeDate(null) - .accountMovesOutOfNPAOnlyOnArrearsCompletion(false).accountingRule(LOAN_ACCOUNTING_RULE_NONE) - .allowApprovedDisbursedAmountsOverApplied(true) - .allowAttributeOverrides(new AllowAttributeOverrides().amortizationType(true).interestType(true) - .transactionProcessingStrategyCode(true).interestCalculationPeriodType(true).inArrearsTolerance(true) - .repaymentEvery(true).graceOnPrincipalAndInterestPayment(true).graceOnArrearsAgeing(true)) - .allowPartialPeriodInterestCalcualtion(false).allowVariableInstallments(false).amortizationType(AMORTIZATION_TYPE) - .canDefineInstallmentAmount(true).canUseForTopup(false).charges(new ArrayList<>()).creditAllocation(new ArrayList<>()) - .currencyCode(CURRENCY_CODE).dateFormat(DATE_FORMAT).daysInMonthType(DAYS_IN_MONTH_TYPE_30) - .daysInYearType(DAYS_IN_YEAR_TYPE_360).delinquencyBucketId(DELINQUENCY_BUCKET_ID.longValue()).digitsAfterDecimal(2) - .disallowExpectedDisbursements(true).dueDaysForRepaymentEvent(1).enableDownPayment(false) - .enableInstallmentLevelDelinquency(true).fixedLength(null).holdGuaranteeFunds(false).inMultiplesOf(0) - .includeInBorrowerCycle(false).interestCalculationPeriodType(0).interestRateFrequencyType(3).interestRatePerPeriod(9.99) - .interestRateVariationsForBorrowerCycle(new ArrayList<>()).interestRecalculationCompoundingMethod(0).interestType(0) - .isArrearsBasedOnOriginalSchedule(false).isEqualAmortization(false).isInterestRecalculationEnabled(true) - .isLinkedToFloatingInterestRates(false).loanScheduleProcessingType("HORIZONTAL").loanScheduleType("PROGRESSIVE") - .locale(LOCALE_EN).maxInterestRatePerPeriod((double) 50).maxNumberOfRepayments(48).maxPrincipal((double) 10000) - .maxTrancheCount(10).minInterestRatePerPeriod((double) 0).minNumberOfRepayments(1).minPrincipal((double) 1) - .multiDisburseLoan(true).numberOfRepaymentVariationsForBorrowerCycle(new ArrayList<>()).numberOfRepayments(3) - .outstandingLoanBalance((double) 10000).overAppliedCalculationType("flat").overAppliedNumber(10000) - .overDueDaysForRepaymentEvent(2).preClosureInterestCalculationStrategy(1).principal((double) 40) - .principalThresholdForLastInstallment(50).principalVariationsForBorrowerCycle(new ArrayList<>()) - .recalculationRestFrequencyInterval(1).recalculationRestFrequencyType(2).repaymentEvery(1).repaymentFrequencyType(2L) - .repaymentStartDateType(2).rescheduleStrategyMethod(4).supportedInterestRefundTypes(new ArrayList<>()) - .transactionProcessingStrategyCode(TRANSACTION_PROCESSING_STRATEGY_CODE_ADVANCED).useBorrowerCycle(false); - } - - public PostLoanProductsRequest defaultLoanProductsRequestLP2() { - String name = Utils.randomNameGenerator(NAME_PREFIX_LP2, 4); - String shortName = Utils.randomNameGenerator(SHORT_NAME_PREFIX, 3); - - List principalVariationsForBorrowerCycle = new ArrayList<>(); - List numberOfRepaymentVariationsForBorrowerCycle = new ArrayList<>(); - List interestRateVariationsForBorrowerCycle = new ArrayList<>(); - List charges = new ArrayList<>(); List penaltyToIncomeAccountMappings = new ArrayList<>(); List feeToIncomeAccountMappings = new ArrayList<>(); @@ -710,55 +675,13 @@ public PostLoanProductsRequest defaultLoanProductsRequestLP2() { loanPaymentChannelToFundSourceMappings.paymentTypeId(paymentTypeResolver.resolve(DefaultPaymentType.MONEY_TRANSFER)); paymentChannelToFundSourceMappings.add(loanPaymentChannelToFundSourceMappings); - return new PostLoanProductsRequest()// - .name(name)// + return new PostLoanProductsRequest().name(name)// .shortName(shortName)// - .description(DESCRIPTION_LP2)// - .enableDownPayment(true)// - .enableAutoRepaymentForDownPayment(true)// - .disbursedAmountPercentageForDownPayment(new BigDecimal(25))// - .fundId(FUND_ID)// + .description(DESCRIPTION_INTEREST_DECLINING_BALANCE_DAILY_RECALCULATION_COMPOUNDING_NONE)// .startDate(null)// .closeDate(null)// - .includeInBorrowerCycle(false)// - .currencyCode(CURRENCY_CODE)// - .digitsAfterDecimal(2)// - .inMultiplesOf(0)// - .installmentAmountInMultiplesOf(1)// - .useBorrowerCycle(false)// - .minPrincipal(100.0)// - .principal(1000.0)// - .maxPrincipal(10000.0)// - .minNumberOfRepayments(1)// - .numberOfRepayments(3)// - .maxNumberOfRepayments(30)// - .isLinkedToFloatingInterestRates(false)// - .minInterestRatePerPeriod((double) 0)// - .interestRatePerPeriod((double) 0)// - .maxInterestRatePerPeriod((double) 0)// - .interestRateFrequencyType(INTEREST_RATE_FREQUENCY_TYPE_MONTH)// - .repaymentEvery(15)// - .repaymentFrequencyType(REPAYMENT_FREQUENCY_TYPE_DAYS)// - .principalVariationsForBorrowerCycle(principalVariationsForBorrowerCycle)// - .numberOfRepaymentVariationsForBorrowerCycle(numberOfRepaymentVariationsForBorrowerCycle)// - .interestRateVariationsForBorrowerCycle(interestRateVariationsForBorrowerCycle)// - .amortizationType(AMORTIZATION_TYPE)// - .interestType(INTEREST_TYPE_DECLINING_BALANCE)// - .isEqualAmortization(false)// - .interestCalculationPeriodType(INTEREST_CALCULATION_PERIOD_TYPE_SAME_AS_REPAYMENT)// - .transactionProcessingStrategyCode(TRANSACTION_PROCESSING_STRATEGY_CODE)// - .daysInYearType(DAYS_IN_YEAR_TYPE)// - .daysInMonthType(DAYS_IN_MONTH_TYPE)// - .canDefineInstallmentAmount(true)// - .graceOnArrearsAgeing(3)// - .overdueDaysForNPA(179)// .accountMovesOutOfNPAOnlyOnArrearsCompletion(false)// - .principalThresholdForLastInstallment(50)// - .allowVariableInstallments(false)// - .canUseForTopup(false)// - .isInterestRecalculationEnabled(false)// - .holdGuaranteeFunds(false)// - .multiDisburseLoan(true)// + .allowApprovedDisbursedAmountsOverApplied(true)// .allowAttributeOverrides(new AllowAttributeOverrides()// .amortizationType(true)// .interestType(true)// @@ -768,10 +691,65 @@ public PostLoanProductsRequest defaultLoanProductsRequestLP2() { .repaymentEvery(true)// .graceOnPrincipalAndInterestPayment(true)// .graceOnArrearsAgeing(true))// - .allowPartialPeriodInterestCalcualtion(true)// + .allowPartialPeriodInterestCalcualtion(false)// + .allowVariableInstallments(false)// + .amortizationType(AMORTIZATION_TYPE)// + .canDefineInstallmentAmount(true)// + .canUseForTopup(false)// + .charges(new ArrayList<>()).creditAllocation(new ArrayList<>())// + .currencyCode(CURRENCY_CODE)// + .dateFormat(DATE_FORMAT)// + .daysInMonthType(DAYS_IN_MONTH_TYPE_30)// + .daysInYearType(DAYS_IN_YEAR_TYPE_360)// + .delinquencyBucketId(DELINQUENCY_BUCKET_ID.longValue())// + .digitsAfterDecimal(2)// + .disallowExpectedDisbursements(true)// + .dueDaysForRepaymentEvent(1)// + .enableDownPayment(false)// + .enableInstallmentLevelDelinquency(true)// + .fixedLength(null).holdGuaranteeFunds(false)// + .inMultiplesOf(0)// + .includeInBorrowerCycle(false)// + .interestCalculationPeriodType(0)// + .interestRateFrequencyType(3)// + .interestRatePerPeriod(9.99)// + .interestRateVariationsForBorrowerCycle(new ArrayList<>())// + .interestRecalculationCompoundingMethod(0)// + .interestType(0)// + .isArrearsBasedOnOriginalSchedule(false)// + .isEqualAmortization(false)// + .isInterestRecalculationEnabled(true)// + .isLinkedToFloatingInterestRates(false)// + .loanScheduleProcessingType("HORIZONTAL")// + .loanScheduleType("PROGRESSIVE")// + .locale(LOCALE_EN)// + .maxInterestRatePerPeriod((double) 50)// + .maxNumberOfRepayments(48)// + .maxPrincipal((double) 10000)// .maxTrancheCount(10)// - .outstandingLoanBalance(10000.0)// - .charges(charges)// + .minInterestRatePerPeriod((double) 0)// + .minNumberOfRepayments(1)// + .minPrincipal((double) 1)// + .multiDisburseLoan(true)// + .numberOfRepaymentVariationsForBorrowerCycle(new ArrayList<>())// + .numberOfRepayments(3)// + .outstandingLoanBalance((double) 10000)// + .overAppliedCalculationType("flat")// + .overAppliedNumber(10000)// + .overDueDaysForRepaymentEvent(2)// + .preClosureInterestCalculationStrategy(1)// + .principal((double) 40)// + .principalThresholdForLastInstallment(50)// + .principalVariationsForBorrowerCycle(new ArrayList<>())// + .recalculationRestFrequencyInterval(1)// + .recalculationRestFrequencyType(2)// + .repaymentEvery(1)// + .repaymentFrequencyType(2L)// + .repaymentStartDateType(2)// + .rescheduleStrategyMethod(4)// + .supportedInterestRefundTypes(new ArrayList<>())// + .transactionProcessingStrategyCode(TRANSACTION_PROCESSING_STRATEGY_CODE_ADVANCED)// + .useBorrowerCycle(false)// .accountingRule(LOAN_ACCOUNTING_RULE)// .fundSourceAccountId(accountTypeResolver.resolve(DefaultAccountType.SUSPENSE_CLEARING_ACCOUNT))// .loanPortfolioAccountId(accountTypeResolver.resolve(DefaultAccountType.LOANS_RECEIVABLE))// @@ -785,13 +763,6 @@ public PostLoanProductsRequest defaultLoanProductsRequestLP2() { .receivableInterestAccountId(accountTypeResolver.resolve(DefaultAccountType.INTEREST_FEE_RECEIVABLE))// .receivableFeeAccountId(accountTypeResolver.resolve(DefaultAccountType.INTEREST_FEE_RECEIVABLE))// .receivablePenaltyAccountId(accountTypeResolver.resolve(DefaultAccountType.INTEREST_FEE_RECEIVABLE))// - .dateFormat(DATE_FORMAT)// - .locale(LOCALE_EN)// - .disallowExpectedDisbursements(true)// - .allowApprovedDisbursedAmountsOverApplied(true)// - .overAppliedCalculationType(OVER_APPLIED_CALCULATION_TYPE)// - .overAppliedNumber(OVER_APPLIED_NUMBER)// - .delinquencyBucketId(DELINQUENCY_BUCKET_ID.longValue())// .goodwillCreditAccountId(accountTypeResolver.resolve(DefaultAccountType.GOODWILL_EXPENSE_ACCOUNT))// .incomeFromGoodwillCreditInterestAccountId(accountTypeResolver.resolve(DefaultAccountType.INTEREST_INCOME_CHARGE_OFF))// .incomeFromGoodwillCreditFeesAccountId(accountTypeResolver.resolve(DefaultAccountType.FEE_CHARGE_OFF))// @@ -806,8 +777,8 @@ public PostLoanProductsRequest defaultLoanProductsRequestLP2() { .incomeFromChargeOffPenaltyAccountId(accountTypeResolver.resolve(DefaultAccountType.FEE_CHARGE_OFF));// } - public PostLoanProductsRequest defaultLoanProductsRequestLP2NoDown() { - String name = Utils.randomNameGenerator(NAME_PREFIX, 4); + public PostLoanProductsRequest defaultLoanProductsRequestLP2() { + String name = Utils.randomNameGenerator(NAME_PREFIX_LP2, 4); String shortName = Utils.randomNameGenerator(SHORT_NAME_PREFIX, 3); List principalVariationsForBorrowerCycle = new ArrayList<>(); @@ -827,6 +798,9 @@ public PostLoanProductsRequest defaultLoanProductsRequestLP2NoDown() { .name(name)// .shortName(shortName)// .description(DESCRIPTION_LP2)// + .enableDownPayment(true)// + .enableAutoRepaymentForDownPayment(true)// + .disbursedAmountPercentageForDownPayment(new BigDecimal(25))// .fundId(FUND_ID)// .startDate(null)// .closeDate(null)// @@ -840,14 +814,14 @@ public PostLoanProductsRequest defaultLoanProductsRequestLP2NoDown() { .principal(1000.0)// .maxPrincipal(10000.0)// .minNumberOfRepayments(1)// - .numberOfRepayments(1)// + .numberOfRepayments(3)// .maxNumberOfRepayments(30)// .isLinkedToFloatingInterestRates(false)// .minInterestRatePerPeriod((double) 0)// .interestRatePerPeriod((double) 0)// .maxInterestRatePerPeriod((double) 0)// .interestRateFrequencyType(INTEREST_RATE_FREQUENCY_TYPE_MONTH)// - .repaymentEvery(30)// + .repaymentEvery(15)// .repaymentFrequencyType(REPAYMENT_FREQUENCY_TYPE_DAYS)// .principalVariationsForBorrowerCycle(principalVariationsForBorrowerCycle)// .numberOfRepaymentVariationsForBorrowerCycle(numberOfRepaymentVariationsForBorrowerCycle)// @@ -1136,5 +1110,4 @@ public PostLoanProductsRequest defaultLoanProductsRequestLP2Emi() { .chargeOffFraudExpenseAccountId(accountTypeResolver.resolve(DefaultAccountType.CREDIT_LOSS_BAD_DEBT_FRAUD))// .incomeFromChargeOffPenaltyAccountId(accountTypeResolver.resolve(DefaultAccountType.FEE_CHARGE_OFF));// } - } diff --git a/fineract-e2e-tests-core/src/test/java/org/apache/fineract/test/factory/LoanRequestFactory.java b/fineract-e2e-tests-core/src/test/java/org/apache/fineract/test/factory/LoanRequestFactory.java index 6de4bcb6c50..c6e604b58cc 100644 --- a/fineract-e2e-tests-core/src/test/java/org/apache/fineract/test/factory/LoanRequestFactory.java +++ b/fineract-e2e-tests-core/src/test/java/org/apache/fineract/test/factory/LoanRequestFactory.java @@ -19,8 +19,6 @@ package org.apache.fineract.test.factory; import java.math.BigDecimal; -import java.time.Clock; -import java.time.LocalDate; import java.time.format.DateTimeFormatter; import java.util.ArrayList; import lombok.RequiredArgsConstructor; @@ -39,6 +37,7 @@ import org.apache.fineract.test.data.TransactionProcessingStrategyCode; import org.apache.fineract.test.data.loanproduct.DefaultLoanProduct; import org.apache.fineract.test.data.loanproduct.LoanProductResolver; +import org.apache.fineract.test.helper.Utils; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Component; @@ -79,8 +78,10 @@ public class LoanRequestFactory { public static final String DEFAULT_TRANSACTION_PROCESSING_STRATEGY_CODE = TransactionProcessingStrategyCode.PENALTIES_FEES_INTEREST_PRINCIPAL_ORDER.value; public static final DateTimeFormatter FORMATTER = DateTimeFormatter.ofPattern(DATE_FORMAT); - public static final String DATE_SUBMIT_STRING = FORMATTER.format(LocalDate.now(Clock.systemUTC()).minusMonths(1L)); - public static final String DEFAULT_TRANSACTION_DATE = FORMATTER.format(LocalDate.now(Clock.systemUTC()).minusMonths(1L)); + public static final String DATE_SUBMIT_STRING = FORMATTER.format(Utils.now().minusMonths(1L)); + public static final String DATE_REJECT_STRING = FORMATTER.format(Utils.now().minusMonths(1L)); + public static final String DATE_WITHDRAWN_STRING = FORMATTER.format(Utils.now().minusMonths(1L)); + public static final String DEFAULT_TRANSACTION_DATE = FORMATTER.format(Utils.now().minusMonths(1L)); public PostLoansRequest defaultLoansRequest(Long clientId) { return new PostLoansRequest()// @@ -108,7 +109,7 @@ public PostLoansRequest defaultLoansRequest(Long clientId) { public PutLoansLoanIdRequest modifySubmittedOnDateOnLoan(Long clientId, String newSubmittedOnDate) { DateTimeFormatter formatter = DateTimeFormatter.ofPattern(DATE_FORMAT); - String dateDisburseStr = formatter.format(LocalDate.now(Clock.systemUTC())); + String dateDisburseStr = formatter.format(Utils.now()); return new PutLoansLoanIdRequest()// .productId(loanProductResolver.resolve(DEFAULT_LOAN_PRODUCT))// @@ -162,6 +163,20 @@ public static PostLoansLoanIdRequest defaultLoanApproveRequest() { .locale(DEFAULT_LOCALE);// } + public static PostLoansLoanIdRequest defaultLoanRejectRequest() { + return new PostLoansLoanIdRequest()// + .rejectedOnDate(DATE_REJECT_STRING)// + .dateFormat(DATE_FORMAT)// + .locale(DEFAULT_LOCALE);// + } + + public static PostLoansLoanIdRequest defaultLoanWithdrawnRequest() { + return new PostLoansLoanIdRequest()// + .withdrawnOnDate(DATE_WITHDRAWN_STRING)// + .dateFormat(DATE_FORMAT)// + .locale(DEFAULT_LOCALE);// + } + public static PostLoansLoanIdRequest defaultLoanDisburseRequest() { return new PostLoansLoanIdRequest().actualDisbursementDate(DATE_SUBMIT_STRING).transactionAmount(DEFAULT_DISBURSED_AMOUNT) .paymentTypeId(Math.toIntExact(DEFAULT_PAYMENT_TYPE_ID)).dateFormat(DATE_FORMAT).locale(DEFAULT_LOCALE); diff --git a/fineract-e2e-tests-core/src/test/java/org/apache/fineract/test/factory/SavingsAccountRequestFactory.java b/fineract-e2e-tests-core/src/test/java/org/apache/fineract/test/factory/SavingsAccountRequestFactory.java new file mode 100644 index 00000000000..bb4564e215f --- /dev/null +++ b/fineract-e2e-tests-core/src/test/java/org/apache/fineract/test/factory/SavingsAccountRequestFactory.java @@ -0,0 +1,91 @@ +/** + * 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.test.factory; + +import java.math.BigDecimal; +import org.apache.fineract.client.models.PostSavingsAccountTransactionsRequest; +import org.apache.fineract.client.models.PostSavingsAccountsAccountIdRequest; +import org.apache.fineract.client.models.PostSavingsAccountsRequest; + +public final class SavingsAccountRequestFactory { + + public static final String DATE_FORMAT = "dd MMMM yyyy"; + public static final String DEFAULT_LOCALE = "en"; + public static final String DEFAULT_TRANSACTION_DATE = ""; + public static final Integer DEFAULT_CLIENT_ID = 1; + public static final String DEFAULT_SUBMITTED_ON_DATE = ""; + public static final String DEFAULT_APPROVED_ON_DATE = ""; + public static final String DEFAULT_ACTIVATED_ON_DATE = ""; + public static final BigDecimal DEFAULT_REPAYMENT_TRANSACTION_AMOUNT = new BigDecimal(1); + public static final Integer DEFAULT_PAYMENT_TYPE_ID = 2; + public static final Integer EUR_SAVING_PRODUCT_ID = 1; + public static final Integer USD_SAVING_PRODUCT_ID = 2; + + private SavingsAccountRequestFactory() {} + + public static PostSavingsAccountsRequest defaultEURSavingsAccountRequest() { + return new PostSavingsAccountsRequest()// + .clientId(DEFAULT_CLIENT_ID)// + .dateFormat(DATE_FORMAT)// + .productId(EUR_SAVING_PRODUCT_ID)// + .submittedOnDate(DEFAULT_SUBMITTED_ON_DATE)// + .locale(DEFAULT_LOCALE);// + } + + public static PostSavingsAccountsRequest defaultUSDSavingsAccountRequest() { + return new PostSavingsAccountsRequest()// + .clientId(DEFAULT_CLIENT_ID)// + .dateFormat(DATE_FORMAT)// + .productId(USD_SAVING_PRODUCT_ID)// + .submittedOnDate(DEFAULT_SUBMITTED_ON_DATE)// + .locale(DEFAULT_LOCALE);// + } + + public static PostSavingsAccountsAccountIdRequest defaultApproveRequest() { + return new PostSavingsAccountsAccountIdRequest()// + .approvedOnDate(DEFAULT_APPROVED_ON_DATE)// + .dateFormat(DATE_FORMAT)// + .locale(DEFAULT_LOCALE);// + } + + public static PostSavingsAccountsAccountIdRequest defaultActivateRequest() { + return new PostSavingsAccountsAccountIdRequest()// + .activatedOnDate(DEFAULT_ACTIVATED_ON_DATE)// + .dateFormat(DATE_FORMAT)// + .locale(DEFAULT_LOCALE);// + } + + public static PostSavingsAccountTransactionsRequest defaultDepositRequest() { + return new PostSavingsAccountTransactionsRequest()// + .transactionDate(DEFAULT_TRANSACTION_DATE)// + .transactionAmount(DEFAULT_REPAYMENT_TRANSACTION_AMOUNT)// + .paymentTypeId(DEFAULT_PAYMENT_TYPE_ID)// + .dateFormat(DATE_FORMAT)// + .locale(DEFAULT_LOCALE);// + } + + public static PostSavingsAccountTransactionsRequest defaultWithdrawRequest() { + return new PostSavingsAccountTransactionsRequest()// + .transactionDate(DEFAULT_TRANSACTION_DATE)// + .transactionAmount(DEFAULT_REPAYMENT_TRANSACTION_AMOUNT)// + .paymentTypeId(DEFAULT_PAYMENT_TYPE_ID)// + .dateFormat(DATE_FORMAT)// + .locale(DEFAULT_LOCALE);// + } +} diff --git a/fineract-e2e-tests-core/src/test/java/org/apache/fineract/test/factory/SavingsProductRequestFactory.java b/fineract-e2e-tests-core/src/test/java/org/apache/fineract/test/factory/SavingsProductRequestFactory.java new file mode 100644 index 00000000000..54baa519bfb --- /dev/null +++ b/fineract-e2e-tests-core/src/test/java/org/apache/fineract/test/factory/SavingsProductRequestFactory.java @@ -0,0 +1,63 @@ +/** + * 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.test.factory; + +import java.util.HashSet; +import java.util.Set; +import org.apache.fineract.client.models.PostSavingsCharges; +import org.apache.fineract.client.models.PostSavingsProductsRequest; + +public final class SavingsProductRequestFactory { + + public static final String DEFAULT_SAVINGS_PRODUCT_NAME = "CEUR"; + + public static final String DEFAULT_SAVINGS_PRODUCT_SHORT_NAME = "CEU"; + public static final String DEFAULT_SAVINGS_PRODUCT_DESCRIPTION = ""; + public static final String DEFAULT_SAVINGS_PRODUCT_CURRENCY_CODE = "EUR"; + public static final Integer DEFAULT_SAVINGS_PRODUCT_DIGITS_AFTER_DECIMAL = 2; + public static final Integer DEFAULT_SAVINGS_PRODUCT_IN_MULTIPLES_OF = 0; + public static final Double DEFAULT_SAVINGS_PRODUCT_NOMINAL_ANNUAL_INTEREST_RATE = 0.0; + public static final Integer DEFAULT_SAVINGS_PRODUCT_INTEREST_COMPOUNDING_PERIOD_TIME = 1; + public static final Integer DEFAULT_SAVINGS_PRODUCT_INTEREST_POSTING_PERIOD_TIME = 4; + public static final Integer DEFAULT_SAVINGS_PRODUCT_INTEREST_CALCULATION_TYPE = 1; + public static final Integer DEFAULT_SAVINGS_PRODUCT_INTEREST_CALCULATION_DAYS_IN_YEAR_TYPE = 365; + public static final Integer DEFAULT_SAVINGS_PRODUCT_ACCOUNTING_RULE = 1; + public static final String LOCALE_EN = "en"; + + private SavingsProductRequestFactory() {} + + public static PostSavingsProductsRequest defaultSavingsProductRequest() { + Set charges = new HashSet<>(); + + return new PostSavingsProductsRequest().name(DEFAULT_SAVINGS_PRODUCT_NAME)// + .shortName(DEFAULT_SAVINGS_PRODUCT_SHORT_NAME)// + .description(DEFAULT_SAVINGS_PRODUCT_DESCRIPTION)// + .currencyCode(DEFAULT_SAVINGS_PRODUCT_CURRENCY_CODE)// + .digitsAfterDecimal(DEFAULT_SAVINGS_PRODUCT_DIGITS_AFTER_DECIMAL)// + .inMultiplesOf(DEFAULT_SAVINGS_PRODUCT_IN_MULTIPLES_OF)// + .nominalAnnualInterestRate(DEFAULT_SAVINGS_PRODUCT_NOMINAL_ANNUAL_INTEREST_RATE)// + .interestCompoundingPeriodType(DEFAULT_SAVINGS_PRODUCT_INTEREST_COMPOUNDING_PERIOD_TIME)// + .interestPostingPeriodType(DEFAULT_SAVINGS_PRODUCT_INTEREST_POSTING_PERIOD_TIME)// + .interestCalculationType(DEFAULT_SAVINGS_PRODUCT_INTEREST_CALCULATION_TYPE)// + .interestCalculationDaysInYearType(DEFAULT_SAVINGS_PRODUCT_INTEREST_CALCULATION_DAYS_IN_YEAR_TYPE)// + .charges(charges)// + .accountingRule(DEFAULT_SAVINGS_PRODUCT_ACCOUNTING_RULE)// + .locale(LOCALE_EN);// + } +} diff --git a/fineract-e2e-tests-core/src/test/java/org/apache/fineract/test/helper/BusinessDateHelper.java b/fineract-e2e-tests-core/src/test/java/org/apache/fineract/test/helper/BusinessDateHelper.java index 5553b9a11ad..c4411ffc132 100644 --- a/fineract-e2e-tests-core/src/test/java/org/apache/fineract/test/helper/BusinessDateHelper.java +++ b/fineract-e2e-tests-core/src/test/java/org/apache/fineract/test/helper/BusinessDateHelper.java @@ -19,8 +19,6 @@ package org.apache.fineract.test.helper; import java.io.IOException; -import java.time.Clock; -import java.time.LocalDate; import java.time.format.DateTimeFormatter; import lombok.RequiredArgsConstructor; import org.apache.fineract.client.models.BusinessDateRequest; @@ -53,7 +51,7 @@ public void setBusinessDate(String businessDate) throws IOException { public void setBusinessDateToday() throws IOException { DateTimeFormatter formatter = DateTimeFormatter.ofPattern(DATE_FORMAT); - String today = formatter.format(LocalDate.now(Clock.systemUTC())); + String today = formatter.format(Utils.now()); setBusinessDate(today); } diff --git a/fineract-e2e-tests-core/src/test/java/org/apache/fineract/test/helper/ErrorMessageHelper.java b/fineract-e2e-tests-core/src/test/java/org/apache/fineract/test/helper/ErrorMessageHelper.java index 469c96d9b25..bd8b43c7302 100644 --- a/fineract-e2e-tests-core/src/test/java/org/apache/fineract/test/helper/ErrorMessageHelper.java +++ b/fineract-e2e-tests-core/src/test/java/org/apache/fineract/test/helper/ErrorMessageHelper.java @@ -24,7 +24,6 @@ import java.time.format.DateTimeFormatter; import java.util.List; import java.util.Map; -import java.util.stream.Collectors; import org.apache.commons.lang3.StringUtils; import org.apache.fineract.client.models.BatchResponse; import org.apache.fineract.client.models.GetJournalEntriesTransactionIdResponse; @@ -63,14 +62,14 @@ public static String disburseDateFailure(Integer loanId) { return String.format("The date on which a loan with identifier : %s is disbursed cannot be in the future.", loanIdStr); } - public static String disburseMaxAmountFailure() { - return "Loan disbursal amount can't be greater than maximum applied loan amount calculation. Total disbursed amount: [0-9]* Maximum disbursal amount: [0-9]*"; - } - public static String disbursePastDateFailure(Integer loanId, String actualDisbursementDate) { return String.format("The date on which a loan is disbursed cannot be before its approval date: %s", actualDisbursementDate); } + public static String disburseMaxAmountFailure() { + return "Loan disbursal amount can't be greater than maximum applied loan amount calculation. Total disbursed amount: [0-9]* Maximum disbursal amount: [0-9]*"; + } + public static String loanSubmitDateInFutureFailureMsg() { return "The date on which a loan is submitted cannot be in the future."; } @@ -866,17 +865,7 @@ public static String wrongfixedLength(Integer actual, Integer expected) { expectedToStr); } - public static String wrongValueInLineInLoanTermVariations(final int line, final List> actual, - final List expected) { - final String actualValues = actual.stream().map(List::toString).collect(Collectors.joining(System.lineSeparator())); - - return String.format( - "%nWrong value in loan term variations tab line %d.%nActual values in line (with the same term variation applicable from) are:%n%s%nExpected values in line:%n%s", - line, actualValues, expected); - } - - public static String wrongNumberOfLinesInLoanTermVariations(final int actual, final int expected) { - return String.format("Number of lines in loan term variations is not correct. Actual value is: %d - Expected value is: %d", actual, - expected); + public static String downpaymentDisabledOnProductErrorCodeMsg() { + return "The Loan can not override the downpayment properties because in the Loan Product the downpayment is disabled"; } } diff --git a/fineract-e2e-tests-core/src/test/java/org/apache/fineract/test/helper/Utils.java b/fineract-e2e-tests-core/src/test/java/org/apache/fineract/test/helper/Utils.java index f4e882ddc80..70cfa180275 100644 --- a/fineract-e2e-tests-core/src/test/java/org/apache/fineract/test/helper/Utils.java +++ b/fineract-e2e-tests-core/src/test/java/org/apache/fineract/test/helper/Utils.java @@ -19,6 +19,8 @@ package org.apache.fineract.test.helper; import java.security.SecureRandom; +import java.time.Clock; +import java.time.LocalDate; public final class Utils { @@ -42,4 +44,8 @@ public static String randomStringGenerator(final String prefix, final int len) { public static String randomNameGenerator(final String prefix, final int lenOfRandomSuffix) { return randomStringGenerator(prefix, lenOfRandomSuffix); } + + public static LocalDate now() { + return LocalDate.now(Clock.systemUTC()); + } } diff --git a/fineract-e2e-tests-core/src/test/java/org/apache/fineract/test/helper/WorkFlowJobHelper.java b/fineract-e2e-tests-core/src/test/java/org/apache/fineract/test/helper/WorkFlowJobHelper.java new file mode 100644 index 00000000000..c77b2e92177 --- /dev/null +++ b/fineract-e2e-tests-core/src/test/java/org/apache/fineract/test/helper/WorkFlowJobHelper.java @@ -0,0 +1,49 @@ +/** + * 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.test.helper; + +import java.io.IOException; +import java.util.Comparator; +import java.util.List; +import lombok.RequiredArgsConstructor; +import org.apache.fineract.client.models.BusinessStep; +import org.apache.fineract.client.models.GetBusinessStepConfigResponse; +import org.apache.fineract.client.services.BusinessStepConfigurationApi; +import org.apache.fineract.test.support.TestContext; +import org.apache.fineract.test.support.TestContextKey; +import org.springframework.stereotype.Component; +import retrofit2.Response; + +@RequiredArgsConstructor +@Component +public class WorkFlowJobHelper { + + private static final String WORKFLOW_NAME_LOAN_CLOSE_OF_BUSINESS = "LOAN_CLOSE_OF_BUSINESS"; + + private final BusinessStepConfigurationApi businessStepConfigurationApi; + + public void saveOriginalCOBWorkflowJobBusinessStepList() throws IOException { + Response businessStepConfigResponse = businessStepConfigurationApi + .retrieveAllConfiguredBusinessStep(WORKFLOW_NAME_LOAN_CLOSE_OF_BUSINESS).execute(); + ErrorHelper.checkSuccessfulApiCall(businessStepConfigResponse); + List businessSteps = businessStepConfigResponse.body().getBusinessSteps(); + businessSteps.sort(Comparator.comparingLong(BusinessStep::getOrder)); + TestContext.GLOBAL.set(TestContextKey.ORIGINAL_COB_WORKFLOW_JOB_BUSINESS_STEP_LIST, businessSteps); + } +} diff --git a/fineract-e2e-tests-core/src/test/java/org/apache/fineract/test/initializer/base/BaseFineractInitializerConfiguration.java b/fineract-e2e-tests-core/src/test/java/org/apache/fineract/test/initializer/base/BaseFineractInitializerConfiguration.java index f1a624e9705..afb74e3ecb9 100644 --- a/fineract-e2e-tests-core/src/test/java/org/apache/fineract/test/initializer/base/BaseFineractInitializerConfiguration.java +++ b/fineract-e2e-tests-core/src/test/java/org/apache/fineract/test/initializer/base/BaseFineractInitializerConfiguration.java @@ -21,6 +21,7 @@ import java.util.List; import org.apache.fineract.test.config.CacheConfiguration; import org.apache.fineract.test.helper.BusinessDateHelper; +import org.apache.fineract.test.helper.WorkFlowJobHelper; import org.apache.fineract.test.initializer.global.FineractGlobalInitializerStep; import org.apache.fineract.test.initializer.scenario.FineractScenarioInitializerStep; import org.apache.fineract.test.initializer.suite.FineractSuiteInitializerStep; @@ -39,7 +40,8 @@ public class BaseFineractInitializerConfiguration { @Bean public FineractInitializer fineractInitializer(List globalInitializerSteps, List suiteInitializerSteps, List scenarioInitializerSteps, - BusinessDateHelper businessDateHelper) { - return new FineractInitializer(globalInitializerSteps, suiteInitializerSteps, scenarioInitializerSteps, businessDateHelper); + BusinessDateHelper businessDateHelper, WorkFlowJobHelper workFlowJobHelper) { + return new FineractInitializer(globalInitializerSteps, suiteInitializerSteps, scenarioInitializerSteps, businessDateHelper, + workFlowJobHelper); } } diff --git a/fineract-e2e-tests-core/src/test/java/org/apache/fineract/test/initializer/base/FineractInitializer.java b/fineract-e2e-tests-core/src/test/java/org/apache/fineract/test/initializer/base/FineractInitializer.java index 4e5d680d000..a67ce2125bf 100644 --- a/fineract-e2e-tests-core/src/test/java/org/apache/fineract/test/initializer/base/FineractInitializer.java +++ b/fineract-e2e-tests-core/src/test/java/org/apache/fineract/test/initializer/base/FineractInitializer.java @@ -23,6 +23,7 @@ import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; import org.apache.fineract.test.helper.BusinessDateHelper; +import org.apache.fineract.test.helper.WorkFlowJobHelper; import org.apache.fineract.test.initializer.global.FineractGlobalInitializerStep; import org.apache.fineract.test.initializer.scenario.FineractScenarioInitializerStep; import org.apache.fineract.test.initializer.suite.FineractSuiteInitializerStep; @@ -38,6 +39,7 @@ public class FineractInitializer implements InitializingBean { private final List suiteInitializerSteps; private final List scenarioInitializerSteps; private final BusinessDateHelper businessDateHelper; + private final WorkFlowJobHelper workFlowJobHelper; @Override public void afterPropertiesSet() throws Exception { @@ -71,6 +73,7 @@ public void setupDefaultsForSuite() throws Exception { } businessDateHelper.setBusinessDateToday(); + workFlowJobHelper.saveOriginalCOBWorkflowJobBusinessStepList(); } public void setupDefaultsForScenario() throws Exception { diff --git a/fineract-e2e-tests-core/src/test/java/org/apache/fineract/test/initializer/global/CobBusinessStepInitializerStep.java b/fineract-e2e-tests-core/src/test/java/org/apache/fineract/test/initializer/global/CobBusinessStepInitializerStep.java new file mode 100644 index 00000000000..4167d36cc2c --- /dev/null +++ b/fineract-e2e-tests-core/src/test/java/org/apache/fineract/test/initializer/global/CobBusinessStepInitializerStep.java @@ -0,0 +1,59 @@ +/** + * 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.test.initializer.global; + +import java.util.Comparator; +import java.util.List; +import lombok.RequiredArgsConstructor; +import org.apache.fineract.client.models.BusinessStep; +import org.apache.fineract.client.models.GetBusinessStepConfigResponse; +import org.apache.fineract.client.models.UpdateBusinessStepConfigRequest; +import org.apache.fineract.client.services.BusinessStepConfigurationApi; +import org.apache.fineract.test.helper.ErrorHelper; +import org.springframework.stereotype.Component; +import retrofit2.Response; + +@RequiredArgsConstructor +@Component +public class CobBusinessStepInitializerStep implements FineractGlobalInitializerStep { + + private static final String WORKFLOW_NAME_LOAN_CLOSE_OF_BUSINESS = "LOAN_CLOSE_OF_BUSINESS"; + private static final String BUSINESS_STEP_NAME_ACCRUAL_ACTIVITY_POSTING = "ACCRUAL_ACTIVITY_POSTING"; + private final BusinessStepConfigurationApi businessStepConfigurationApi; + + @Override + public void initialize() throws Exception { + // --- Adding ACCRUAL_ACTIVITY_POSTING to default COB steps --- + Response businessStepConfigResponse = businessStepConfigurationApi + .retrieveAllConfiguredBusinessStep(WORKFLOW_NAME_LOAN_CLOSE_OF_BUSINESS).execute(); + ErrorHelper.checkSuccessfulApiCall(businessStepConfigResponse); + List businessSteps = businessStepConfigResponse.body().getBusinessSteps(); + businessSteps.sort(Comparator.comparingLong(BusinessStep::getOrder)); + Long lastOrder = businessSteps.get(businessSteps.size() - 1).getOrder(); + + BusinessStep accrualActivityPosting = new BusinessStep().stepName(BUSINESS_STEP_NAME_ACCRUAL_ACTIVITY_POSTING).order(lastOrder + 1); + businessSteps.add(accrualActivityPosting); + + UpdateBusinessStepConfigRequest request = new UpdateBusinessStepConfigRequest().businessSteps(businessSteps); + + Response response = businessStepConfigurationApi.updateJobBusinessStepConfig(WORKFLOW_NAME_LOAN_CLOSE_OF_BUSINESS, request) + .execute(); + ErrorHelper.checkSuccessfulApiCall(response); + } +} diff --git a/fineract-e2e-tests-core/src/test/java/org/apache/fineract/test/initializer/global/LoanProductGlobalInitializerStep.java b/fineract-e2e-tests-core/src/test/java/org/apache/fineract/test/initializer/global/LoanProductGlobalInitializerStep.java index 4d873d9dc21..0fecd42a66f 100644 --- a/fineract-e2e-tests-core/src/test/java/org/apache/fineract/test/initializer/global/LoanProductGlobalInitializerStep.java +++ b/fineract-e2e-tests-core/src/test/java/org/apache/fineract/test/initializer/global/LoanProductGlobalInitializerStep.java @@ -19,7 +19,9 @@ package org.apache.fineract.test.initializer.global; import static org.apache.fineract.test.data.TransactionProcessingStrategyCode.ADVANCED_PAYMENT_ALLOCATION; +import static org.apache.fineract.test.factory.LoanProductsRequestFactory.INTEREST_RATE_FREQUENCY_TYPE_WHOLE_TERM; +import java.math.BigDecimal; import java.util.ArrayList; import java.util.Arrays; import java.util.List; @@ -479,13 +481,243 @@ public void initialize() throws Exception { TestContext.INSTANCE.set(TestContextKey.DEFAULT_LOAN_PRODUCT_CREATE_RESPONSE_LP2_DOWNPAYMENT_ADV_PMT_ALLOC_FIXED_LENGTH, responseLoanProductsRequestDownPaymentAdvPmtAllocFixedLength); + // LP2 with Down-payment+autopayment + advanced payment allocation + repayment start date SUBMITTED ON DATE + // (LP2_DOWNPAYMENT_AUTO_ADVANCED_PAYMENT_ALLOCATION_REPAYMENT_START_SUBMITTED) + String name26 = DefaultLoanProduct.LP2_DOWNPAYMENT_AUTO_ADVANCED_PAYMENT_ALLOCATION_REPAYMENT_START_SUBMITTED.getName(); + PostLoanProductsRequest loanProductsRequestDownPaymentAutoAdvPaymentAllocationRepaymentStartSubmitted = loanProductsRequestFactory + .defaultLoanProductsRequestLP2()// + .name(name26)// + .transactionProcessingStrategyCode(ADVANCED_PAYMENT_ALLOCATION.getValue())// + .loanScheduleType("PROGRESSIVE") // + .repaymentStartDateType(2)// + .paymentAllocation(List.of(// + createPaymentAllocation("DEFAULT", "NEXT_INSTALLMENT"), // + createPaymentAllocation("GOODWILL_CREDIT", "LAST_INSTALLMENT"), // + createPaymentAllocation("MERCHANT_ISSUED_REFUND", "REAMORTIZATION"), // + createPaymentAllocation("PAYOUT_REFUND", "NEXT_INSTALLMENT")));// + Response responseLoanProductsRequestDownPaymentAutoAdvPaymentAllocationRepaymentStartSubmitted = loanProductsApi + .createLoanProduct(loanProductsRequestDownPaymentAutoAdvPaymentAllocationRepaymentStartSubmitted).execute(); + TestContext.INSTANCE.set( + TestContextKey.DEFAULT_LOAN_PRODUCT_CREATE_RESPONSE_LP2_DOWNPAYMENT_AUTO_ADVANCED_REPAYMENT_ALLOCATION_PAYMENT_START_SUBMITTED, + responseLoanProductsRequestDownPaymentAutoAdvPaymentAllocationRepaymentStartSubmitted); + + // LP2 with Down-payment + advanced payment allocation + progressive loan schedule + horizontal + interest Flat + // (LP2_DOWNPAYMENT_INTEREST_FLAT_ADV_PMT_ALLOC) + String name27 = DefaultLoanProduct.LP2_DOWNPAYMENT_INTEREST_FLAT_ADV_PMT_ALLOC.getName(); + PostLoanProductsRequest loanProductsRequestDownPaymentAdvPaymentAllocationInterestFlat = loanProductsRequestFactory + .defaultLoanProductsRequestLP2InterestFlat()// + .name(name27)// + .transactionProcessingStrategyCode(ADVANCED_PAYMENT_ALLOCATION.getValue())// + .loanScheduleType("PROGRESSIVE") // + .loanScheduleProcessingType("HORIZONTAL")// + .enableAutoRepaymentForDownPayment(false)// + .installmentAmountInMultiplesOf(null)// + .paymentAllocation(List.of(// + createPaymentAllocation("DEFAULT", "NEXT_INSTALLMENT"), // + createPaymentAllocation("GOODWILL_CREDIT", "LAST_INSTALLMENT"), // + createPaymentAllocation("MERCHANT_ISSUED_REFUND", "REAMORTIZATION"), // + createPaymentAllocation("PAYOUT_REFUND", "NEXT_INSTALLMENT")));// + Response responseLoanProductsRequestDownPaymentAdvPaymentAllocationInterestFlat = loanProductsApi + .createLoanProduct(loanProductsRequestDownPaymentAdvPaymentAllocationInterestFlat).execute(); + TestContext.INSTANCE.set(TestContextKey.DEFAULT_LOAN_PRODUCT_CREATE_RESPONSE_LP2_DOWNPAYMENT_INTEREST_FLAT_ADV_PMT_ALLOC, + responseLoanProductsRequestDownPaymentAdvPaymentAllocationInterestFlat); + + // LP2 with progressive loan schedule + horizontal + interest EMI + actual/actual + // (LP2_ADV_PYMNT_INTEREST_DAILY_EMI_ACTUAL_ACTUAL) + String name28 = DefaultLoanProduct.LP2_ADV_PYMNT_INTEREST_DAILY_EMI_ACTUAL_ACTUAL.getName(); + PostLoanProductsRequest loanProductsRequestLP2AdvancedpaymentInterestEmiActualActual = loanProductsRequestFactory + .defaultLoanProductsRequestLP2Emi()// + .name(name28)// + .paymentAllocation(List.of(// + createPaymentAllocation("DEFAULT", "NEXT_INSTALLMENT"), // + createPaymentAllocation("GOODWILL_CREDIT", "LAST_INSTALLMENT"), // + createPaymentAllocation("MERCHANT_ISSUED_REFUND", "REAMORTIZATION"), // + createPaymentAllocation("PAYOUT_REFUND", "NEXT_INSTALLMENT")));// + Response responseLoanProductsRequestLP2AdvancedpaymentInterestEmiActualActual = loanProductsApi + .createLoanProduct(loanProductsRequestLP2AdvancedpaymentInterestEmiActualActual).execute(); + TestContext.INSTANCE.set(TestContextKey.DEFAULT_LOAN_PRODUCT_CREATE_RESPONSE_LP2_ADV_PYMNT_INTEREST_DAILY_EMI_ACTUAL_ACTUAL, + responseLoanProductsRequestLP2AdvancedpaymentInterestEmiActualActual); + + // LP2 with progressive loan schedule + horizontal + interest EMI + 360/30 + // (LP2_ADV_PYMNT_INTEREST_DAILY_EMI_360_30) + String name29 = DefaultLoanProduct.LP2_ADV_PYMNT_INTEREST_DAILY_EMI_360_30.getName(); + PostLoanProductsRequest loanProductsRequestLP2AdvancedpaymentInterestEmi36030 = loanProductsRequestFactory + .defaultLoanProductsRequestLP2Emi()// + .name(name29)// + .daysInYearType(DaysInYearType.DAYS360.value)// + .daysInMonthType(DaysInMonthType.DAYS30.value)// + .paymentAllocation(List.of(// + createPaymentAllocation("DEFAULT", "NEXT_INSTALLMENT"), // + createPaymentAllocation("GOODWILL_CREDIT", "LAST_INSTALLMENT"), // + createPaymentAllocation("MERCHANT_ISSUED_REFUND", "REAMORTIZATION"), // + createPaymentAllocation("PAYOUT_REFUND", "NEXT_INSTALLMENT")));// + Response responseLoanProductsRequestLP2AdvancedpaymentInterest36030 = loanProductsApi + .createLoanProduct(loanProductsRequestLP2AdvancedpaymentInterestEmi36030).execute(); + TestContext.INSTANCE.set(TestContextKey.DEFAULT_LOAN_PRODUCT_CREATE_RESPONSE_LP2_ADV_PYMNT_INTEREST_DAILY_EMI_360_30, + responseLoanProductsRequestLP2AdvancedpaymentInterest36030); + + // LP2 with progressive loan schedule + horizontal + interest EMI + 360/30 + multidisbursement + // (LP2_ADV_PYMNT_INTEREST_DAILY_EMI_360_30_MULTIDISBURSE) + String name36 = DefaultLoanProduct.LP2_ADV_PYMNT_INTEREST_DAILY_EMI_360_30_MULTIDISBURSE.getName(); + PostLoanProductsRequest loanProductsRequestLP2AdvancedpaymentInterestEmi36030MultiDisburse = loanProductsRequestFactory + .defaultLoanProductsRequestLP2Emi()// + .name(name36)// + .daysInYearType(DaysInYearType.DAYS360.value)// + .daysInMonthType(DaysInMonthType.DAYS30.value)// + .paymentAllocation(List.of(// + createPaymentAllocation("DEFAULT", "NEXT_INSTALLMENT"), // + createPaymentAllocation("GOODWILL_CREDIT", "LAST_INSTALLMENT"), // + createPaymentAllocation("MERCHANT_ISSUED_REFUND", "REAMORTIZATION"), // + createPaymentAllocation("PAYOUT_REFUND", "NEXT_INSTALLMENT")))// + .multiDisburseLoan(true)// + .disallowExpectedDisbursements(true)// + .maxTrancheCount(10)// + .outstandingLoanBalance(10000.0);// + Response responseLoanProductsRequestLP2AdvancedpaymentInterest36030MultiDisburse = loanProductsApi + .createLoanProduct(loanProductsRequestLP2AdvancedpaymentInterestEmi36030MultiDisburse).execute(); + TestContext.INSTANCE.set(TestContextKey.DEFAULT_LOAN_PRODUCT_CREATE_RESPONSE_LP2_ADV_PYMNT_INTEREST_DAILY_EMI_360_30_MULTIDISBURSE, + responseLoanProductsRequestLP2AdvancedpaymentInterest36030MultiDisburse); + + // LP2 with progressive loan schedule + horizontal + interest EMI + 360/30 + multidisbursement + downpayment + // 25%, auto disabled + // (LP2_ADV_PYMNT_INTEREST_DAILY_EMI_360_30_MULTIDISBURSE_DOWNPAYMENT) + String name37 = DefaultLoanProduct.LP2_ADV_PYMNT_INTEREST_DAILY_EMI_360_30_MULTIDISBURSE_DOWNPAYMENT.getName(); + PostLoanProductsRequest loanProductsRequestLP2AdvancedpaymentInterestEmi36030MultiDisburseDownPayment = loanProductsRequestFactory + .defaultLoanProductsRequestLP2Emi()// + .name(name37)// + .enableDownPayment(true)// + .disbursedAmountPercentageForDownPayment(new BigDecimal(25))// + .daysInYearType(DaysInYearType.DAYS360.value)// + .daysInMonthType(DaysInMonthType.DAYS30.value)// + .paymentAllocation(List.of(// + createPaymentAllocation("DEFAULT", "NEXT_INSTALLMENT"), // + createPaymentAllocation("GOODWILL_CREDIT", "LAST_INSTALLMENT"), // + createPaymentAllocation("MERCHANT_ISSUED_REFUND", "REAMORTIZATION"), // + createPaymentAllocation("PAYOUT_REFUND", "NEXT_INSTALLMENT")))// + .multiDisburseLoan(true)// + .disallowExpectedDisbursements(true)// + .maxTrancheCount(10)// + .outstandingLoanBalance(10000.0);// + Response responseLoanProductsRequestLP2AdvancedpaymentInterest36030MultiDisburseDownPayment = loanProductsApi + .createLoanProduct(loanProductsRequestLP2AdvancedpaymentInterestEmi36030MultiDisburseDownPayment).execute(); + TestContext.INSTANCE.set( + TestContextKey.DEFAULT_LOAN_PRODUCT_CREATE_RESPONSE_LP2_ADV_PYMNT_INTEREST_DAILY_EMI_360_30_MULTIDISBURSE_DOWNPAYMENT, + responseLoanProductsRequestLP2AdvancedpaymentInterest36030MultiDisburseDownPayment); + + // LP2 with progressive loan schedule + horizontal + interest EMI + 365/Actual + // (LP2_ADV_PYMNT_INTEREST_DAILY_EMI_365_ACTUAL) + String name30 = DefaultLoanProduct.LP2_ADV_PYMNT_INTEREST_DAILY_EMI_365_ACTUAL.getName(); + PostLoanProductsRequest loanProductsRequestLP2AdvancedpaymentInterest365Actual = loanProductsRequestFactory + .defaultLoanProductsRequestLP2Emi()// + .name(name30)// + .daysInYearType(DaysInYearType.DAYS365.value)// + .daysInMonthType(DaysInMonthType.ACTUAL.value)// + .paymentAllocation(List.of(// + createPaymentAllocation("DEFAULT", "NEXT_INSTALLMENT"), // + createPaymentAllocation("GOODWILL_CREDIT", "LAST_INSTALLMENT"), // + createPaymentAllocation("MERCHANT_ISSUED_REFUND", "REAMORTIZATION"), // + createPaymentAllocation("PAYOUT_REFUND", "NEXT_INSTALLMENT")));// + Response responseLoanProductsRequestLP2AdvancedpaymentInterestEmi365Actual = loanProductsApi + .createLoanProduct(loanProductsRequestLP2AdvancedpaymentInterest365Actual).execute(); + TestContext.INSTANCE.set(TestContextKey.DEFAULT_LOAN_PRODUCT_CREATE_RESPONSE_LP2_ADV_PYMNT_INTEREST_DAILY_EMI_365_ACTUAL, + responseLoanProductsRequestLP2AdvancedpaymentInterestEmi365Actual); + + // LP2 with progressive loan schedule + horizontal + interest EMI + 360/30 + downpayment 25% + // (LP2_ADV_PYMNT_INTEREST_DAILY_EMI_360_30_DOWNPAYMENT) + String name31 = DefaultLoanProduct.LP2_ADV_PYMNT_INTEREST_DAILY_EMI_360_30_DOWNPAYMENT.getName(); + PostLoanProductsRequest loanProductsRequestLP2AdvancedpaymentInterest36030Downpayment = loanProductsRequestFactory + .defaultLoanProductsRequestLP2Emi()// + .name(name31)// + .enableDownPayment(true)// + .disbursedAmountPercentageForDownPayment(new BigDecimal(25))// + .daysInYearType(DaysInYearType.DAYS360.value)// + .daysInMonthType(DaysInMonthType.DAYS30.value)// + .paymentAllocation(List.of(// + createPaymentAllocation("DEFAULT", "NEXT_INSTALLMENT"), // + createPaymentAllocation("GOODWILL_CREDIT", "LAST_INSTALLMENT"), // + createPaymentAllocation("MERCHANT_ISSUED_REFUND", "REAMORTIZATION"), // + createPaymentAllocation("PAYOUT_REFUND", "NEXT_INSTALLMENT")));// + Response responseLoanProductsRequestLP2AdvancedpaymentInterestEmi36030Downpayment = loanProductsApi + .createLoanProduct(loanProductsRequestLP2AdvancedpaymentInterest36030Downpayment).execute(); + TestContext.INSTANCE.set(TestContextKey.DEFAULT_LOAN_PRODUCT_CREATE_RESPONSE_LP2_ADV_PYMNT_INTEREST_DAILY_EMI_360_30_DOWNPAYMENT, + responseLoanProductsRequestLP2AdvancedpaymentInterestEmi36030Downpayment); + + // LP2 with progressive loan schedule + horizontal + interest EMI + actual/actual + + // enableAccrualActivityPosting + // (LP2_ADV_PYMNT_INTEREST_DAILY_EMI_ACTUAL_ACTUAL_ACCRUAL_ACTIVITY) + String name32 = DefaultLoanProduct.LP2_ADV_PYMNT_INTEREST_DAILY_EMI_ACTUAL_ACTUAL_ACCRUAL_ACTIVITY.getName(); + PostLoanProductsRequest loanProductsRequestLP2AdvancedpaymentInterestEmiActualActualAccrualActivity = loanProductsRequestFactory + .defaultLoanProductsRequestLP2Emi()// + .name(name32)// + .enableAccrualActivityPosting(true)// + .paymentAllocation(List.of(// + createPaymentAllocation("DEFAULT", "NEXT_INSTALLMENT"), // + createPaymentAllocation("GOODWILL_CREDIT", "LAST_INSTALLMENT"), // + createPaymentAllocation("MERCHANT_ISSUED_REFUND", "REAMORTIZATION"), // + createPaymentAllocation("PAYOUT_REFUND", "NEXT_INSTALLMENT")));// + Response responseLoanProductsRequestLP2AdvancedpaymentInterestEmiActualActualAccrualActivity = loanProductsApi + .createLoanProduct(loanProductsRequestLP2AdvancedpaymentInterestEmiActualActualAccrualActivity).execute(); + TestContext.INSTANCE.set(TestContextKey.DEFAULT_LOAN_PRODUCT_CREATE_RESPONSE_LP2_ADV_PYMNT_INTEREST_DAILY_EMI_ACTUAL_ACTUAL, + responseLoanProductsRequestLP2AdvancedpaymentInterestEmiActualActualAccrualActivity); + + // LP1 with 12% DECLINING BALANCE interest, interest period: Daily + enableAccrualActivityPosting + // (LP1_INTEREST_DECLINING_BALANCE_PERIOD_DAILY_ACCRUAL_ACTIVITY) + String name33 = DefaultLoanProduct.LP1_INTEREST_DECLINING_BALANCE_PERIOD_DAILY_ACCRUAL_ACTIVITY.getName(); + PostLoanProductsRequest loanProductsRequestInterestDecliningPeriodDailyAccrualActivity = loanProductsRequestFactory + .defaultLoanProductsRequestLP1InterestDeclining()// + .name(name33)// + .enableAccrualActivityPosting(true)// + .interestCalculationPeriodType(InterestCalculationPeriodTime.DAILY.value)// + .allowPartialPeriodInterestCalcualtion(false);// + Response responseInterestDecliningPeriodDailyAccrualActivity = loanProductsApi + .createLoanProduct(loanProductsRequestInterestDecliningPeriodDailyAccrualActivity).execute(); + TestContext.INSTANCE.set(TestContextKey.DEFAULT_LOAN_PRODUCT_CREATE_RESPONSE_LP1_INTEREST_DECLINING_PERIOD_DAILY_ACCRUAL_ACTIVITY, + responseInterestDecliningPeriodDailyAccrualActivity); + + // LP1 with 12% DECLINING BALANCE interest, interest period: Daily, Interest + // recalculation-Daily, Compounding:none + enableAccrualActivityPosting + // (LP1_INTEREST_DECLINING_BALANCE_DAILY_RECALCULATION_COMPOUNDING_NONE_ACCRUAL_ACTIVITY) + String name34 = DefaultLoanProduct.LP1_INTEREST_DECLINING_BALANCE_DAILY_RECALCULATION_COMPOUNDING_NONE_ACCRUAL_ACTIVITY.getName(); + PostLoanProductsRequest loanProductsRequestLP1InterestDecliningBalanceDailyRecalculationCompoundingNoneAccrualActivity = loanProductsRequestFactory + .defaultLoanProductsRequestLP1InterestDecliningBalanceDailyRecalculationCompoundingNone()// + .name(name34)// + .enableAccrualActivityPosting(true)// + .interestCalculationPeriodType(InterestCalculationPeriodTime.DAILY.value)// + .allowPartialPeriodInterestCalcualtion(false);// + Response responseLP1InterestDecliningBalanceDailyRecalculationCompoundingNoneAccrualActivity = loanProductsApi + .createLoanProduct(loanProductsRequestLP1InterestDecliningBalanceDailyRecalculationCompoundingNoneAccrualActivity) + .execute(); + TestContext.INSTANCE.set( + TestContextKey.DEFAULT_LOAN_PRODUCT_CREATE_RESPONSE_LP1_INTEREST_DECLINING_BALANCE_DAILY_RECALCULATION_COMPOUNDING_NONE_ACCRUAL_ACTIVITY, + responseLP1InterestDecliningBalanceDailyRecalculationCompoundingNoneAccrualActivity); + + // LP2 with progressive loan schedule + horizontal + interest EMI + actual/actual + interest refund with + // Merchant issued and Payment refund + // (LP2_ADV_PYMNT_INTEREST_DAILY_EMI_ACTUAL_ACTUAL_INTEREST_REFUND) + String name35 = DefaultLoanProduct.LP2_ADV_PYMNT_INTEREST_DAILY_EMI_ACTUAL_ACTUAL_INTEREST_REFUND.getName(); + List supportedInterestRefundTypes = Arrays.asList("MERCHANT_ISSUED_REFUND", "PAYOUT_REFUND"); + PostLoanProductsRequest loanProductsRequestLP2AdvancedpaymentInterestEmiActualActualInterestRefund = loanProductsRequestFactory + .defaultLoanProductsRequestLP2Emi()// + .name(name35)// + .supportedInterestRefundTypes(supportedInterestRefundTypes).paymentAllocation(List.of(// + createPaymentAllocation("DEFAULT", "NEXT_INSTALLMENT"), // + createPaymentAllocation("GOODWILL_CREDIT", "LAST_INSTALLMENT"), // + createPaymentAllocation("MERCHANT_ISSUED_REFUND", "REAMORTIZATION"), // + createPaymentAllocation("PAYOUT_REFUND", "NEXT_INSTALLMENT"), // + createPaymentAllocation("INTEREST_REFUND", "NEXT_INSTALLMENT")));// + Response responseLoanProductsRequestLP2AdvancedpaymentInterestEmiActualActualInterestRefund = loanProductsApi + .createLoanProduct(loanProductsRequestLP2AdvancedpaymentInterestEmiActualActualInterestRefund).execute(); + TestContext.INSTANCE.set( + TestContextKey.DEFAULT_LOAN_PRODUCT_CREATE_RESPONSE_LP2_ADV_PYMNT_INTEREST_DAILY_EMI_ACTUAL_ACTUAL_INTEREST_REFUND, + responseLoanProductsRequestLP2AdvancedpaymentInterestEmiActualActualInterestRefund); + // LP2 with progressive loan schedule + horizontal + interest EMI + 360/30 // + interest recalculation, preClosureInterestCalculationStrategy= till preclose, // interestRecalculationCompoundingMethod = none // Frequency for recalculate Outstanding Principal: Daily, Frequency Interval for recalculation: 1 - // (LP2_ADV_PYMNT_INTEREST_DAILY_EMI_360_30_INTEREST_RECALCULATION_TILL_PRECLOSE) - String name38 = DefaultLoanProduct.LP2_ADV_PYMNT_INTEREST_DAILY_EMI_360_30_INTEREST_RECALCULATION_TILL_PRECLOSE.getName(); - PostLoanProductsRequest loanProductsRequestLP2AdvancedpaymentInterestEmi36030InterestRecalcTillPreclose = loanProductsRequestFactory + // (LP2_ADV_PYMNT_INTEREST_DAILY_EMI_360_30_INTEREST_RECALCULATION_DAILY_TILL_PRECLOSE) + String name38 = DefaultLoanProduct.LP2_ADV_PYMNT_INTEREST_DAILY_EMI_360_30_INTEREST_RECALCULATION_DAILY_TILL_PRECLOSE.getName(); + PostLoanProductsRequest loanProductsRequestLP2AdvancedpaymentInterestEmi36030InterestRecalcDailyTillPreclose = loanProductsRequestFactory .defaultLoanProductsRequestLP2Emi()// .name(name38)// .daysInYearType(DaysInYearType.DAYS360.value)// @@ -497,20 +729,24 @@ public void initialize() throws Exception { .recalculationRestFrequencyType(2)// .recalculationRestFrequencyInterval(1)// .paymentAllocation(List.of(// - createPaymentAllocation("DEFAULT", "NEXT_INSTALLMENT")));// - Response responseLoanProductsRequestLP2AdvancedpaymentInterest36030InterestRecalcTillPreClose = loanProductsApi - .createLoanProduct(loanProductsRequestLP2AdvancedpaymentInterestEmi36030InterestRecalcTillPreclose).execute(); + createPaymentAllocation("DEFAULT", "NEXT_INSTALLMENT"), // + createPaymentAllocation("GOODWILL_CREDIT", "LAST_INSTALLMENT"), // + createPaymentAllocation("MERCHANT_ISSUED_REFUND", "REAMORTIZATION"), // + createPaymentAllocation("PAYOUT_REFUND", "NEXT_INSTALLMENT")));// + Response responseLoanProductsRequestLP2AdvancedpaymentInterest36030InterestRecalcDailyTillPreCloese = loanProductsApi + .createLoanProduct(loanProductsRequestLP2AdvancedpaymentInterestEmi36030InterestRecalcDailyTillPreclose).execute(); TestContext.INSTANCE.set( - TestContextKey.DEFAULT_LOAN_PRODUCT_CREATE_RESPONSE_LP2_ADV_PYMNT_INTEREST_DAILY_EMI_360_30_INTEREST_RECALCULATION_TILL_PRECLOSE, - responseLoanProductsRequestLP2AdvancedpaymentInterest36030InterestRecalcTillPreClose); + TestContextKey.DEFAULT_LOAN_PRODUCT_CREATE_RESPONSE_LP2_ADV_PYMNT_INTEREST_DAILY_EMI_360_30_INTEREST_RECALCULATION_DAILY_TILL_PRECLOSE, + responseLoanProductsRequestLP2AdvancedpaymentInterest36030InterestRecalcDailyTillPreCloese); // LP2 with progressive loan schedule + horizontal + interest EMI + 360/30 - // + interest recalculation, preClosureInterestCalculationStrategy= till rest frequency, + // + interest recalculation, preClosureInterestCalculationStrategy= till rest frequency date, // interestRecalculationCompoundingMethod = none // Frequency for recalculate Outstanding Principal: Daily, Frequency Interval for recalculation: 1 - // (LP2_ADV_PYMNT_INTEREST_DAILY_EMI_360_30_INTEREST_RECALCULATION_TILL_REST_FREQUENCY) - String name39 = DefaultLoanProduct.LP2_ADV_PYMNT_INTEREST_DAILY_EMI_360_30_INTEREST_RECALCULATION_TILL_REST_FREQUENCY.getName(); - PostLoanProductsRequest loanProductsRequestLP2AdvancedpaymentInterestEmi36030InterestRecalcTillRestFrequency = loanProductsRequestFactory + // (LP2_ADV_PYMNT_INTEREST_DAILY_EMI_360_30_INTEREST_RECALCULATION_DAILY_TILL_REST_FREQUENCY_DATE) + String name39 = DefaultLoanProduct.LP2_ADV_PYMNT_INTEREST_DAILY_EMI_360_30_INTEREST_RECALCULATION_DAILY_TILL_REST_FREQUENCY_DATE + .getName(); + PostLoanProductsRequest loanProductsRequestLP2AdvancedpaymentInterestEmi36030InterestRecalcDailyTillRestFrequencyDate = loanProductsRequestFactory .defaultLoanProductsRequestLP2Emi()// .name(name39)// .daysInYearType(DaysInYearType.DAYS360.value)// @@ -526,16 +762,78 @@ public void initialize() throws Exception { createPaymentAllocation("GOODWILL_CREDIT", "LAST_INSTALLMENT"), // createPaymentAllocation("MERCHANT_ISSUED_REFUND", "REAMORTIZATION"), // createPaymentAllocation("PAYOUT_REFUND", "NEXT_INSTALLMENT")));// - Response responseLoanProductsRequestLP2AdvancedpaymentInterest36030InterestRecalcTillRestFrequency = loanProductsApi - .createLoanProduct(loanProductsRequestLP2AdvancedpaymentInterestEmi36030InterestRecalcTillRestFrequency).execute(); + Response responseLoanProductsRequestLP2AdvancedpaymentInterest36030InterestRecalcDailyTillRestFrequencyDate = loanProductsApi + .createLoanProduct(loanProductsRequestLP2AdvancedpaymentInterestEmi36030InterestRecalcDailyTillRestFrequencyDate).execute(); TestContext.INSTANCE.set( - TestContextKey.DEFAULT_LOAN_PRODUCT_CREATE_RESPONSE_LP2_ADV_PYMNT_INTEREST_DAILY_EMI_360_30_INTEREST_RECALCULATION_TILL_REST_FREQUENCY, - responseLoanProductsRequestLP2AdvancedpaymentInterest36030InterestRecalcTillRestFrequency); + TestContextKey.DEFAULT_LOAN_PRODUCT_CREATE_RESPONSE_LP2_ADV_PYMNT_INTEREST_DAILY_EMI_360_30_INTEREST_RECALCULATION_DAILY_TILL_REST_FREQUENCY_DATE, + responseLoanProductsRequestLP2AdvancedpaymentInterest36030InterestRecalcDailyTillRestFrequencyDate); - String name40 = DefaultLoanProduct.LP2_ADV_PMT_ALLOC_PROGRESSIVE_LOAN_SCHEDULE_HORIZONTAL.getName(); - PostLoanProductsRequest loanProductsRequestLP2AdvPmtAllocProgressiveLoanScheduleHorizontal = loanProductsRequestFactory - .defaultLoanProductsRequestLP2NoDown()// + // LP2 with progressive loan schedule + horizontal + interest EMI + 360/30 + // + interest recalculation, preClosureInterestCalculationStrategy= till preclose, + // interestRecalculationCompoundingMethod = none + // Frequency for recalculate Outstanding Principal: Same as repayment period, Frequency Interval for + // recalculation: 1 + // (LP2_ADV_PYMNT_INTEREST_DAILY_EMI_360_30_INTEREST_RECALCULATION_SARP_TILL_PRECLOSE) + String name40 = DefaultLoanProduct.LP2_ADV_PYMNT_INTEREST_DAILY_EMI_360_30_INTEREST_RECALCULATION_SARP_TILL_PRECLOSE.getName(); + PostLoanProductsRequest loanProductsRequestLP2AdvancedpaymentInterestEmi36030InterestRecalcSameAsRepTillPreclose = loanProductsRequestFactory + .defaultLoanProductsRequestLP2Emi()// .name(name40)// + .daysInYearType(DaysInYearType.DAYS360.value)// + .daysInMonthType(DaysInMonthType.DAYS30.value)// + .isInterestRecalculationEnabled(true)// + .preClosureInterestCalculationStrategy(1)// + .rescheduleStrategyMethod(4)// + .interestRecalculationCompoundingMethod(0)// + .recalculationRestFrequencyType(1)// + .recalculationRestFrequencyInterval(1)// + .paymentAllocation(List.of(// + createPaymentAllocation("DEFAULT", "NEXT_INSTALLMENT"), // + createPaymentAllocation("GOODWILL_CREDIT", "LAST_INSTALLMENT"), // + createPaymentAllocation("MERCHANT_ISSUED_REFUND", "REAMORTIZATION"), // + createPaymentAllocation("PAYOUT_REFUND", "NEXT_INSTALLMENT")));// + Response responseLoanProductsRequestLP2AdvancedpaymentInterest36030InterestRecalcSameAsRepTillPreCloese = loanProductsApi + .createLoanProduct(loanProductsRequestLP2AdvancedpaymentInterestEmi36030InterestRecalcSameAsRepTillPreclose).execute(); + TestContext.INSTANCE.set( + TestContextKey.DEFAULT_LOAN_PRODUCT_CREATE_RESPONSE_LP2_ADV_PYMNT_INTEREST_DAILY_EMI_360_30_INTEREST_RECALCULATION_SAME_AS_REP_TILL_PRECLOSE, + responseLoanProductsRequestLP2AdvancedpaymentInterest36030InterestRecalcSameAsRepTillPreCloese); + + // LP2 with progressive loan schedule + horizontal + interest EMI + 360/30 + // + interest recalculation, preClosureInterestCalculationStrategy= till rest frequency date, + // interestRecalculationCompoundingMethod = none + // Frequency for recalculate Outstanding Principal: Same as repayment period, Frequency Interval for + // recalculation: 1 + // (LP2_ADV_PYMNT_INTEREST_DAILY_EMI_360_30_INTEREST_RECALCULATION_SARP_TILL_REST_FREQUENCY_DATE) + String name41 = DefaultLoanProduct.LP2_ADV_PYMNT_INTEREST_DAILY_EMI_360_30_INTEREST_RECALCULATION_SARP_TILL_REST_FREQUENCY_DATE + .getName(); + PostLoanProductsRequest loanProductsRequestLP2AdvancedpaymentInterestEmi36030InterestRecalcSameAsRepTillRestFrequencyDate = loanProductsRequestFactory + .defaultLoanProductsRequestLP2Emi()// + .name(name41)// + .daysInYearType(DaysInYearType.DAYS360.value)// + .daysInMonthType(DaysInMonthType.DAYS30.value)// + .isInterestRecalculationEnabled(true)// + .preClosureInterestCalculationStrategy(2)// + .rescheduleStrategyMethod(4)// + .interestRecalculationCompoundingMethod(0)// + .recalculationRestFrequencyType(1)// + .recalculationRestFrequencyInterval(1)// + .paymentAllocation(List.of(// + createPaymentAllocation("DEFAULT", "NEXT_INSTALLMENT"), // + createPaymentAllocation("GOODWILL_CREDIT", "LAST_INSTALLMENT"), // + createPaymentAllocation("MERCHANT_ISSUED_REFUND", "REAMORTIZATION"), // + createPaymentAllocation("PAYOUT_REFUND", "NEXT_INSTALLMENT")));// + Response responseLoanProductsRequestLP2AdvancedpaymentInterest36030InterestRecalcSameAsRepTillRestFrequencyDate = loanProductsApi + .createLoanProduct(loanProductsRequestLP2AdvancedpaymentInterestEmi36030InterestRecalcSameAsRepTillRestFrequencyDate) + .execute(); + TestContext.INSTANCE.set( + TestContextKey.DEFAULT_LOAN_PRODUCT_CREATE_RESPONSE_LP2_ADV_PYMNT_INTEREST_DAILY_EMI_360_30_INTEREST_RECALCULATION_SAME_AS_REP_TILL_REST_FREQUENCY_DATE, + responseLoanProductsRequestLP2AdvancedpaymentInterest36030InterestRecalcSameAsRepTillRestFrequencyDate); + + // LP1 advanced payment allocation + progressive loan schedule + horizontal + // (LP1_ADV_PMT_ALLOC_PROGRESSIVE_LOAN_SCHEDULE_HORIZONTAL) + String name42 = DefaultLoanProduct.LP1_ADV_PMT_ALLOC_PROGRESSIVE_LOAN_SCHEDULE_HORIZONTAL.getName(); + PostLoanProductsRequest loanProductsRequestLP1AdvPmtAllocProgressiveLoanScheduleHorizontal = loanProductsRequestFactory// + .defaultLoanProductsRequestLP1()// + .name(name42)// .transactionProcessingStrategyCode(ADVANCED_PAYMENT_ALLOCATION.getValue())// .loanScheduleType("PROGRESSIVE") // .loanScheduleProcessingType("HORIZONTAL")// @@ -544,20 +842,22 @@ public void initialize() throws Exception { createPaymentAllocation("GOODWILL_CREDIT", "NEXT_INSTALLMENT"), // createPaymentAllocation("MERCHANT_ISSUED_REFUND", "NEXT_INSTALLMENT"), // createPaymentAllocation("PAYOUT_REFUND", "NEXT_INSTALLMENT")));// - Response responseLP2AdvPmtAllocProgressiveLoanScheduleHorizontal = loanProductsApi - .createLoanProduct(loanProductsRequestLP2AdvPmtAllocProgressiveLoanScheduleHorizontal).execute(); - TestContext.INSTANCE.set(TestContextKey.DEFAULT_LOAN_PRODUCT_CREATE_RESPONSE_LP2_ADV_PMT_ALLOC_PROGRESSIVE_LOAN_SCHEDULE_HORIZONTAL, - responseLP2AdvPmtAllocProgressiveLoanScheduleHorizontal); + Response responseLP1AdvPmtAllocProgressiveLoanScheduleHorizontal = loanProductsApi + .createLoanProduct(loanProductsRequestLP1AdvPmtAllocProgressiveLoanScheduleHorizontal).execute(); + TestContext.INSTANCE.set( + TestContextKey.DEFAULT_LOAN_PRODUCT_CREATE_RESPONSE_LP1_ADVANCED_PAYMENT_ALLOCATION_PROGRESSIVE_LOAN_SCHEDULE_HORIZONTAL, + responseLP1AdvPmtAllocProgressiveLoanScheduleHorizontal); - // LP2 with progressive loan schedule + horizontal + interest EMI + 360/30 // + interest recalculation, preClosureInterestCalculationStrategy= till preclose, // interestRecalculationCompoundingMethod = none // Frequency for recalculate Outstanding Principal: Daily, Frequency Interval for recalculation: 1 - // (LP2_ADV_PYMNT_INTEREST_DAILY_EMI_360_30_INTEREST_RECALCULATION_TILL_PRECLOSE) - String name41 = DefaultLoanProduct.LP2_ADV_PYMNT_INTEREST_DAILY_EMI_360_30_IR_DAILY_TILL_PRECLOSE_LAST_INSTALLMENT_STRATEGY + // Frequency for Interest rate - Whole Year + // (LP2_ADV_PYMNT_INTEREST_DAILY_EMI_360_30_INTEREST_RECALCULATION_DAILY_TILL_PRECLOSE_WHOLE_TERM) + String name43 = DefaultLoanProduct.LP2_ADV_PYMNT_INTEREST_DAILY_EMI_360_30_INTEREST_RECALCULATION_DAILY_TILL_PRECLOSE_WHOLE_TERM .getName(); - PostLoanProductsRequest product41 = loanProductsRequestFactory.defaultLoanProductsRequestLP2Emi()// - .name(name41)// + PostLoanProductsRequest loanProductsRequestLP2AdvancedpaymentInterestEmi36030InterestRecalcDailyTillPrecloseWholeTerm = loanProductsRequestFactory// + .defaultLoanProductsRequestLP2Emi()// + .name(name43)// .daysInYearType(DaysInYearType.DAYS360.value)// .daysInMonthType(DaysInMonthType.DAYS30.value)// .isInterestRecalculationEnabled(true)// @@ -566,19 +866,25 @@ public void initialize() throws Exception { .interestRecalculationCompoundingMethod(0)// .recalculationRestFrequencyType(2)// .recalculationRestFrequencyInterval(1)// + .interestRatePerPeriod((double) 4)// + .interestRateFrequencyType(INTEREST_RATE_FREQUENCY_TYPE_WHOLE_TERM)// .paymentAllocation(List.of(// - createPaymentAllocation("DEFAULT", "LAST_INSTALLMENT")));// - Response response41 = loanProductsApi.createLoanProduct(product41).execute(); + createPaymentAllocation("DEFAULT", "NEXT_INSTALLMENT"), // + createPaymentAllocation("GOODWILL_CREDIT", "LAST_INSTALLMENT"), // + createPaymentAllocation("MERCHANT_ISSUED_REFUND", "REAMORTIZATION"), // + createPaymentAllocation("PAYOUT_REFUND", "NEXT_INSTALLMENT")));// + Response responseLP2AdvancedpaymentInterestEmi36030InterestRecalcDailyTillPrecloseWholeTerm = loanProductsApi + .createLoanProduct(loanProductsRequestLP2AdvancedpaymentInterestEmi36030InterestRecalcDailyTillPrecloseWholeTerm).execute(); TestContext.INSTANCE.set( - TestContextKey.DEFAULT_LOAN_PRODUCT_CREATE_RESPONSE_LP2_ADV_PMT_ALLOC_PROGRESSIVE_LOAN_SCHEDULE_HORIZONTAL_LAST, - response41); + TestContextKey.DEFAULT_LOAN_PRODUCT_CREATE_RESPONSE_LP2_ADV_PYMNT_INTEREST_DAILY_EMI_360_30_INTEREST_RECALCULATION_DAILY_TILL_PRECLOSE_WHOLE_TERM, + responseLP2AdvancedpaymentInterestEmi36030InterestRecalcDailyTillPrecloseWholeTerm); - // LP2 with Down-payment + advanced custom payment allocation + progressive loan schedule + horizontal - // (LP2_DOWNPAYMENT_ADV_CUSTOM_PMT_ALLOC_PROGRESSIVE_LOAN_SCHEDULE_HORIZONTAL) - String name44 = DefaultLoanProduct.LP2_ADV_CUST_PMT_ALLOC_PROGRESSIVE_LOAN_SCHEDULE_HORIZONTAL.getName(); + // LP2 + interest recalculation + advanced custom payment allocation + progressive loan schedule + horizontal + // (LP2_ADV_CUSTOM_PMT_ALLOC_PROGRESSIVE_LOAN_SCHEDULE_HORIZONTAL) + String name44 = DefaultLoanProduct.LP2_ADV_CUSTOM_PMT_ALLOC_PROGRESSIVE_LOAN_SCHEDULE_HORIZONTAL.getName(); PostLoanProductsRequest loanProductsRequestAdvCustomPaymentAllocationProgressiveLoanSchedule = loanProductsRequestFactory - .defaultLoanProductsRequestLP2InterestDailyRecalculationWithDownPayment()// + .defaultLoanProductsRequestLP2InterestDailyRecalculation()// .name(name44)// .paymentAllocation(List.of(// createPaymentAllocation("DEFAULT", "NEXT_INSTALLMENT", @@ -602,6 +908,88 @@ public void initialize() throws Exception { TestContext.INSTANCE.set( TestContextKey.DEFAULT_LOAN_PRODUCT_CREATE_RESPONSE_LP2_ADVANCED_CUSTOM_PAYMENT_ALLOCATION_PROGRESSIVE_LOAN_SCHEDULE, responseLoanProductsRequestAdvCustomPaymentAllocationProgressiveLoanSchedule); + + String name45 = DefaultLoanProduct.LP2_ADV_PYMNT_INTEREST_DAILY_EMI_ACTUAL_ACTUAL_INTEREST_REFUND_FULL.getName(); + PostLoanProductsRequest loanProductsRequestLP2AdvancedpaymentInterestEmiActualActualInterestRefundFull = loanProductsRequestFactory + .defaultLoanProductsRequestLP2Emi()// + .name(name45)// + .multiDisburseLoan(true)// + .disallowExpectedDisbursements(true)// + .maxTrancheCount(10)// + .isInterestRecalculationEnabled(true)// + .preClosureInterestCalculationStrategy(1)// + .rescheduleStrategyMethod(4)// + .interestRecalculationCompoundingMethod(0)// + .recalculationRestFrequencyType(2)// + .recalculationRestFrequencyInterval(1)// + .supportedInterestRefundTypes(supportedInterestRefundTypes).paymentAllocation(List.of(// + createPaymentAllocation("DEFAULT", "NEXT_INSTALLMENT"), // + createPaymentAllocation("GOODWILL_CREDIT", "NEXT_INSTALLMENT"), // + createPaymentAllocation("MERCHANT_ISSUED_REFUND", "NEXT_INSTALLMENT"), // + createPaymentAllocation("PAYOUT_REFUND", "NEXT_INSTALLMENT"), // + createPaymentAllocation("INTEREST_REFUND", "NEXT_INSTALLMENT")));// + Response responseLoanProductsRequestLP2AdvancedpaymentInterestEmiActualActualInterestRefundFull = loanProductsApi + .createLoanProduct(loanProductsRequestLP2AdvancedpaymentInterestEmiActualActualInterestRefundFull).execute(); + TestContext.INSTANCE.set( + TestContextKey.DEFAULT_LOAN_PRODUCT_CREATE_RESPONSE_LP2_ADV_PYMNT_INTEREST_DAILY_EMI_ACTUAL_ACTUAL_INTEREST_REFUND_FULL, + responseLoanProductsRequestLP2AdvancedpaymentInterestEmiActualActualInterestRefundFull); + + // LP2 with progressive loan schedule + horizontal + interest EMI + 360/30 + // + interest recalculation, preClosureInterestCalculationStrategy= till preclose, + // interestRecalculationCompoundingMethod = none + // payment allocation order: penalty-fee-interest-principal + // Frequency for recalculate Outstanding Principal: Daily, Frequency Interval for recalculation: 1 + // (LP2_ADV_PYMNT_INTEREST_DAILY_EMI_360_30_INTEREST_RECALCULATION_DAILY_TILL_PRECLOSE_PMT_ALLOC_1) + String name46 = DefaultLoanProduct.LP2_ADV_PYMNT_INTEREST_DAILY_EMI_360_30_INTEREST_RECALCULATION_DAILY_TILL_PRECLOSE_PMT_ALLOC_1 + .getName(); + PostLoanProductsRequest loanProductsRequestLP2AdvancedpaymentInterestEmi36030InterestRecalcDailyTillPreclosePmtAlloc1 = loanProductsRequestFactory + .defaultLoanProductsRequestLP2Emi()// + .name(name46)// + .daysInYearType(DaysInYearType.DAYS360.value)// + .daysInMonthType(DaysInMonthType.DAYS30.value)// + .isInterestRecalculationEnabled(true)// + .preClosureInterestCalculationStrategy(1)// + .rescheduleStrategyMethod(4)// + .interestRecalculationCompoundingMethod(0)// + .recalculationRestFrequencyType(2)// + .recalculationRestFrequencyInterval(1)// + .paymentAllocation(List.of(// + createPaymentAllocationPenFeeIntPrincipal("DEFAULT", "NEXT_INSTALLMENT"), // + createPaymentAllocationPenFeeIntPrincipal("GOODWILL_CREDIT", "LAST_INSTALLMENT"), // + createPaymentAllocationPenFeeIntPrincipal("MERCHANT_ISSUED_REFUND", "REAMORTIZATION"), // + createPaymentAllocationPenFeeIntPrincipal("PAYOUT_REFUND", "NEXT_INSTALLMENT")));// + Response responseLoanProductsRequestLP2AdvancedpaymentInterest36030InterestRecalcDailyTillPreCloesePmtAlloc1 = loanProductsApi + .createLoanProduct(loanProductsRequestLP2AdvancedpaymentInterestEmi36030InterestRecalcDailyTillPreclosePmtAlloc1).execute(); + TestContext.INSTANCE.set( + TestContextKey.DEFAULT_LOAN_PRODUCT_CREATE_RESPONSE_LP2_ADV_PYMNT_INTEREST_DAILY_EMI_360_30_INTEREST_RECALCULATION_DAILY_TILL_PRECLOSE_PMT_ALLOC_1, + responseLoanProductsRequestLP2AdvancedpaymentInterest36030InterestRecalcDailyTillPreCloesePmtAlloc1); + + // LP2 with progressive loan schedule + horizontal + interest EMI + 360/30, LAST INSTALLMENT strategy + // + interest recalculation, preClosureInterestCalculationStrategy= till preclose, + // interestRecalculationCompoundingMethod = none + // Frequency for recalculate Outstanding Principal: Daily, Frequency Interval for recalculation: 1 + // (LP2_ADV_PYMNT_INTEREST_DAILY_EMI_360_30_IR_DAILY_TILL_PRECLOSE_LAST_INSTALLMENT_STRATEGY) + String name47 = DefaultLoanProduct.LP2_ADV_PYMNT_INTEREST_DAILY_EMI_360_30_IR_DAILY_TILL_PRECLOSE_LAST_INSTALLMENT_STRATEGY + .getName(); + PostLoanProductsRequest loanProductsRequestLP2AdvancedpaymentInterestEmi36030InterestRecalcDailyTillPrecloseLastInstallment = loanProductsRequestFactory + .defaultLoanProductsRequestLP2Emi()// + .name(name47)// + .daysInYearType(DaysInYearType.DAYS360.value)// + .daysInMonthType(DaysInMonthType.DAYS30.value)// + .isInterestRecalculationEnabled(true)// + .preClosureInterestCalculationStrategy(1)// + .rescheduleStrategyMethod(4)// + .interestRecalculationCompoundingMethod(0)// + .recalculationRestFrequencyType(2)// + .recalculationRestFrequencyInterval(1)// + .paymentAllocation(List.of(// + createPaymentAllocation("DEFAULT", "LAST_INSTALLMENT")));// + Response loanProductsRequestLP2AdvancedpaymentInterestEmi36030InterestRecalcDailyTillPrecloseLastInstallmentResponse = loanProductsApi + .createLoanProduct(loanProductsRequestLP2AdvancedpaymentInterestEmi36030InterestRecalcDailyTillPrecloseLastInstallment) + .execute(); + TestContext.INSTANCE.set( + TestContextKey.DEFAULT_LOAN_PRODUCT_CREATE_RESPONSE_LP2_ADV_PYMNT_INTEREST_DAILY_EMI_360_30_INTEREST_RECALCULATION_DAILY_TILL_PRECLOSE_LAST_INSTALLMENT, + loanProductsRequestLP2AdvancedpaymentInterestEmi36030InterestRecalcDailyTillPrecloseLastInstallmentResponse); } public static AdvancedPaymentData createPaymentAllocation(String transactionType, String futureInstallmentAllocationRule, @@ -634,6 +1022,46 @@ public static AdvancedPaymentData createPaymentAllocation(String transactionType return advancedPaymentData; } + public static AdvancedPaymentData createPaymentAllocationPenFeeIntPrincipal(String transactionType, + String futureInstallmentAllocationRule, LoanProductPaymentAllocationRule.AllocationTypesEnum... rules) { + AdvancedPaymentData advancedPaymentData = new AdvancedPaymentData(); + advancedPaymentData.setTransactionType(transactionType); + advancedPaymentData.setFutureInstallmentAllocationRule(futureInstallmentAllocationRule); + + List paymentAllocationOrders; + if (rules.length == 0) { + paymentAllocationOrders = getPaymentAllocationOrder(// + LoanProductPaymentAllocationRule.AllocationTypesEnum.PAST_DUE_PENALTY, // + LoanProductPaymentAllocationRule.AllocationTypesEnum.PAST_DUE_FEE, // + LoanProductPaymentAllocationRule.AllocationTypesEnum.PAST_DUE_INTEREST, // + LoanProductPaymentAllocationRule.AllocationTypesEnum.PAST_DUE_PRINCIPAL, // + LoanProductPaymentAllocationRule.AllocationTypesEnum.DUE_PENALTY, // + LoanProductPaymentAllocationRule.AllocationTypesEnum.DUE_FEE, // + LoanProductPaymentAllocationRule.AllocationTypesEnum.DUE_INTEREST, // + LoanProductPaymentAllocationRule.AllocationTypesEnum.DUE_PRINCIPAL, // + LoanProductPaymentAllocationRule.AllocationTypesEnum.IN_ADVANCE_PENALTY, // + LoanProductPaymentAllocationRule.AllocationTypesEnum.IN_ADVANCE_FEE, // + LoanProductPaymentAllocationRule.AllocationTypesEnum.IN_ADVANCE_INTEREST, // + LoanProductPaymentAllocationRule.AllocationTypesEnum.IN_ADVANCE_PRINCIPAL);// + } else { + paymentAllocationOrders = getPaymentAllocationOrder(rules); + } + + advancedPaymentData.setPaymentAllocationOrder(paymentAllocationOrders); + + return advancedPaymentData; + } + + public static AdvancedPaymentData editPaymentAllocationFutureInstallment(String transactionType, String futureInstallmentAllocationRule, + List paymentAllocationOrder) { + AdvancedPaymentData advancedPaymentData = new AdvancedPaymentData(); + advancedPaymentData.setTransactionType(transactionType); + advancedPaymentData.setFutureInstallmentAllocationRule(futureInstallmentAllocationRule); + advancedPaymentData.setPaymentAllocationOrder(paymentAllocationOrder); + + return advancedPaymentData; + } + private static CreditAllocationData createCreditAllocation(String transactionType, List creditAllocationRules) { CreditAllocationData creditAllocationData = new CreditAllocationData(); creditAllocationData.setTransactionType(transactionType); diff --git a/fineract-e2e-tests-core/src/test/java/org/apache/fineract/test/initializer/global/SavingsProductGlobalInitializer.java b/fineract-e2e-tests-core/src/test/java/org/apache/fineract/test/initializer/global/SavingsProductGlobalInitializer.java new file mode 100644 index 00000000000..8121807963e --- /dev/null +++ b/fineract-e2e-tests-core/src/test/java/org/apache/fineract/test/initializer/global/SavingsProductGlobalInitializer.java @@ -0,0 +1,53 @@ +/** + * 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.test.initializer.global; + +import lombok.RequiredArgsConstructor; +import org.springframework.stereotype.Component; + +@RequiredArgsConstructor +@Component +public class SavingsProductGlobalInitializer implements FineractGlobalInitializerStep { + + @Override + public void initialize() throws Exception { + /** + * TODO uncomment and check when PS-1088 is done + */ + // //EUR + // PostSavingsProductsRequest savingsProductsRequestEUR = + // SavingsProductRequestFactory.defaultSavingsProductRequest(); + // + // Response savingsProductsResponseEUR = + // savingsProductApi.create13(savingsProductsRequestEUR).execute(); + // testContext().set(TestContextKey.DEFAULT_SAVINGS_PRODUCT_CREATE_RESPONSE_EUR, savingsProductsResponseEUR); + // + // //USD + // PostSavingsProductsRequest savingsProductsRequestUSD = + // SavingsProductRequestFactory.defaultSavingsProductRequest() + // .name("CUSD") + // .shortName("CUS") + // .currencyCode("USD"); + // + // Response savingsProductsResponseUSD = + // savingsProductApi.create13(savingsProductsRequestUSD).execute(); + // testContext().set(TestContextKey.DEFAULT_SAVINGS_PRODUCT_CREATE_RESPONSE_USD, savingsProductsResponseUSD); + + } +} diff --git a/fineract-e2e-tests-core/src/test/java/org/apache/fineract/test/messaging/EmptyEventMessage.java b/fineract-e2e-tests-core/src/test/java/org/apache/fineract/test/messaging/EmptyEventMessage.java index 402261dc5b1..22601e78f74 100644 --- a/fineract-e2e-tests-core/src/test/java/org/apache/fineract/test/messaging/EmptyEventMessage.java +++ b/fineract-e2e-tests-core/src/test/java/org/apache/fineract/test/messaging/EmptyEventMessage.java @@ -21,6 +21,6 @@ public class EmptyEventMessage extends EventMessage { public EmptyEventMessage() { - super(null, null, null); + super(null, null, null, null); } } diff --git a/fineract-e2e-tests-core/src/test/java/org/apache/fineract/test/messaging/EventAssertion.java b/fineract-e2e-tests-core/src/test/java/org/apache/fineract/test/messaging/EventAssertion.java index 3cc7bd0bb86..aac1cd885a8 100644 --- a/fineract-e2e-tests-core/src/test/java/org/apache/fineract/test/messaging/EventAssertion.java +++ b/fineract-e2e-tests-core/src/test/java/org/apache/fineract/test/messaging/EventAssertion.java @@ -21,13 +21,13 @@ import static java.lang.String.format; import static org.awaitility.Awaitility.await; -import edu.umd.cs.findbugs.annotations.SuppressFBWarnings; import java.math.BigDecimal; import java.time.Duration; import java.time.LocalDate; import java.util.function.Function; import lombok.AccessLevel; import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; import org.apache.fineract.test.messaging.config.EventProperties; import org.apache.fineract.test.messaging.event.Event; import org.apache.fineract.test.messaging.event.EventFactory; @@ -39,7 +39,7 @@ @RequiredArgsConstructor @Component -@SuppressFBWarnings({ "VA_FORMAT_STRING_USES_NEWLINE" }) +@Slf4j public class EventAssertion { private final EventStore eventStore; @@ -85,11 +85,8 @@ private > void internalAssertEventNotRaised(Class event String receivedEventsLogParam = eventStore.getReceivedEvents().stream().map(LoggedEvent::new).map(LoggedEvent::toString) .reduce("", (s, e) -> format("%s%s%n", s, e)); - Assertions.fail(""" - %s has been received, but it was unexpected. - Events received but not verified: - %s - """.formatted(event.getEventName(), receivedEventsLogParam)); + Assertions.fail("%s has been received, but it was unexpected. Events received but not verified: %s", event.getEventName(), + receivedEventsLogParam); } catch (ConditionTimeoutException e) { // This is the expected outcome here! } @@ -104,6 +101,7 @@ public > EventAssertionBuilder assertEvent(Class eve } else { eventMessage = (EventMessage) new EmptyEventMessage(); } + log.info("Assert event: {}", eventMessage.getIdempotencyKey()); return new EventAssertionBuilder<>(eventMessage); } diff --git a/fineract-e2e-tests-core/src/test/java/org/apache/fineract/test/messaging/EventMessage.java b/fineract-e2e-tests-core/src/test/java/org/apache/fineract/test/messaging/EventMessage.java index ca039edaaa1..85939f1a9e6 100644 --- a/fineract-e2e-tests-core/src/test/java/org/apache/fineract/test/messaging/EventMessage.java +++ b/fineract-e2e-tests-core/src/test/java/org/apache/fineract/test/messaging/EventMessage.java @@ -29,4 +29,5 @@ public class EventMessage { private final String type; private final LocalDate businessDate; private final T data; + private final String idempotencyKey; } diff --git a/fineract-e2e-tests-core/src/test/java/org/apache/fineract/test/messaging/event/EventCheckHelper.java b/fineract-e2e-tests-core/src/test/java/org/apache/fineract/test/messaging/event/EventCheckHelper.java index 83eedb213dd..eba050c479f 100644 --- a/fineract-e2e-tests-core/src/test/java/org/apache/fineract/test/messaging/event/EventCheckHelper.java +++ b/fineract-e2e-tests-core/src/test/java/org/apache/fineract/test/messaging/event/EventCheckHelper.java @@ -22,6 +22,7 @@ import java.io.IOException; import java.math.BigDecimal; +import java.math.MathContext; import java.time.format.DateTimeFormatter; import java.util.List; import lombok.RequiredArgsConstructor; @@ -55,15 +56,21 @@ import org.apache.fineract.test.messaging.event.assetexternalization.LoanOwnershipTransferEvent; import org.apache.fineract.test.messaging.event.client.ClientActivatedEvent; import org.apache.fineract.test.messaging.event.client.ClientCreatedEvent; +import org.apache.fineract.test.messaging.event.loan.AbstractLoanEvent; import org.apache.fineract.test.messaging.event.loan.LoanApprovedEvent; +import org.apache.fineract.test.messaging.event.loan.LoanBalanceChangedEvent; import org.apache.fineract.test.messaging.event.loan.LoanCreatedEvent; import org.apache.fineract.test.messaging.event.loan.LoanDisbursalEvent; +import org.apache.fineract.test.messaging.event.loan.LoanRejectedEvent; +import org.apache.fineract.test.messaging.event.loan.LoanStatusChangedEvent; +import org.apache.fineract.test.messaging.event.loan.LoanUndoApprovalEvent; import org.apache.fineract.test.messaging.event.loan.delinquency.LoanDelinquencyPauseChangedEvent; import org.apache.fineract.test.messaging.event.loan.delinquency.LoanDelinquencyRangeChangeEvent; import org.apache.fineract.test.messaging.event.loan.transaction.AbstractLoanTransactionEvent; import org.apache.fineract.test.messaging.event.loan.transaction.LoanDisbursalTransactionEvent; import org.apache.fineract.test.messaging.event.loan.transaction.LoanRefundPostBusinessEvent; import org.apache.fineract.test.messaging.event.loan.transaction.LoanTransactionGoodwillCreditPostEvent; +import org.apache.fineract.test.messaging.event.loan.transaction.LoanTransactionInterestPaymentWaiverPostEvent; import org.apache.fineract.test.messaging.event.loan.transaction.LoanTransactionMakeRepaymentPostEvent; import org.apache.fineract.test.messaging.event.loan.transaction.LoanTransactionMerchantIssuedRefundPostEvent; import org.apache.fineract.test.messaging.event.loan.transaction.LoanTransactionPayoutRefundPostEvent; @@ -111,22 +118,21 @@ public void clientEventCheck(Response clientCreationRespons eventAssertion.assertEvent(ClientActivatedEvent.class, clientCreationResponse.body().getClientId())// .extractingData(ClientDataV1::getActive).isEqualTo(true)// .extractingData(clientDataV1 -> clientDataV1.getStatus().getId()).isEqualTo(status);// - } public void createLoanEventCheck(Response createLoanResponse) throws IOException { - Response loanDetails = loansApi.retrieveLoan(createLoanResponse.body().getLoanId(), false, "", "", "") + Response loanDetails = loansApi.retrieveLoan(createLoanResponse.body().getLoanId(), false, "all", "", "") .execute(); GetLoansLoanIdResponse body = loanDetails.body(); - eventAssertion.assertEvent(LoanCreatedEvent.class, createLoanResponse.body().getLoanId()).extractingData(LoanAccountDataV1::getId) - .isEqualTo(body.getId()).extractingData(loanAccountDataV1 -> loanAccountDataV1.getStatus().getId()) - .isEqualTo(body.getStatus().getId()).extractingData(LoanAccountDataV1::getClientId) - .isEqualTo(Long.valueOf(body.getClientId())) - .extractingData(loanAccountDataV11 -> loanAccountDataV11.getPrincipal().longValue()) - .isEqualTo(body.getPrincipal().longValue()) + eventAssertion.assertEvent(LoanCreatedEvent.class, createLoanResponse.body().getLoanId())// + .extractingData(LoanAccountDataV1::getId).isEqualTo(body.getId())// + .extractingData(loanAccountDataV1 -> loanAccountDataV1.getStatus().getId()).isEqualTo(body.getStatus().getId())// + .extractingData(LoanAccountDataV1::getClientId).isEqualTo(Long.valueOf(body.getClientId()))// + .extractingData(loanAccountDataV1 -> loanAccountDataV1.getPrincipal().longValue()) + .isEqualTo(body.getPrincipal().longValue())// .extractingData(loanAccountDataV1 -> loanAccountDataV1.getSummary().getCurrency().getCode()) - .isEqualTo(body.getCurrency().getCode()); + .isEqualTo(body.getCurrency().getCode());// } public void approveLoanEventCheck(Response loanApproveResponse) throws IOException { @@ -134,35 +140,109 @@ public void approveLoanEventCheck(Response loanApproveR .execute(); GetLoansLoanIdResponse body = loanDetails.body(); - eventAssertion.assertEvent(LoanApprovedEvent.class, loanApproveResponse.body().getLoanId()).extractingData(LoanAccountDataV1::getId) - .isEqualTo(body.getId()).extractingData(loanAccountDataV1 -> loanAccountDataV1.getStatus().getId()) - .isEqualTo(body.getStatus().getId()).extractingData(loanAccountDataV1 -> loanAccountDataV1.getStatus().getCode()) - .isEqualTo(body.getStatus().getCode()).extractingData(LoanAccountDataV1::getClientId) - .isEqualTo(Long.valueOf(body.getClientId())) + eventAssertion.assertEvent(LoanApprovedEvent.class, loanApproveResponse.body().getLoanId())// + .extractingData(LoanAccountDataV1::getId).isEqualTo(body.getId())// + .extractingData(loanAccountDataV1 -> loanAccountDataV1.getStatus().getId()).isEqualTo(body.getStatus().getId())// + .extractingData(loanAccountDataV1 -> loanAccountDataV1.getStatus().getCode()).isEqualTo(body.getStatus().getCode())// + .extractingData(LoanAccountDataV1::getClientId).isEqualTo(Long.valueOf(body.getClientId()))// .extractingData(loanAccountDataV1 -> loanAccountDataV1.getApprovedPrincipal().longValue()) - .isEqualTo(body.getApprovedPrincipal().longValue()) - .extractingData(loanAccountDataV1 -> loanAccountDataV1.getTimeline().getApprovedOnDate()) - .isEqualTo(FORMATTER_EVENTS.format(body.getTimeline().getApprovedOnDate())) + .isEqualTo(body.getApprovedPrincipal().longValue())// + .extractingData(loanAccountDataV1 -> loanAccountDataV1.getTimeline().getApprovedOnDate())// + .isEqualTo(FORMATTER_EVENTS.format(body.getTimeline().getApprovedOnDate()))// .extractingData(loanAccountDataV1 -> loanAccountDataV1.getSummary().getCurrency().getCode()) - .isEqualTo(body.getCurrency().getCode()); + .isEqualTo(body.getCurrency().getCode());// } - public void disburseLoanEventCheck(Response loanDisburseResponse) throws IOException { - Response loanDetails = loansApi.retrieveLoan(loanDisburseResponse.body().getLoanId(), false, "", "", "") + public void undoApproveLoanEventCheck(Response loanUndoApproveResponse) throws IOException { + Response loanDetails = loansApi.retrieveLoan(loanUndoApproveResponse.body().getLoanId(), false, "", "", "") .execute(); GetLoansLoanIdResponse body = loanDetails.body(); - eventAssertion.assertEvent(LoanDisbursalEvent.class, loanDisburseResponse.body().getLoanId())// - .extractingData(LoanAccountDataV1::getId).isEqualTo(body.getId())// - .extractingData(loanAccountDataV1 -> loanAccountDataV1.getStatus().getId()).isEqualTo(body.getStatus().getId())// - .extractingData(loanAccountDataV1 -> loanAccountDataV1.getStatus().getCode()).isEqualTo(body.getStatus().getCode())// - .extractingData(LoanAccountDataV1::getClientId).isEqualTo(Long.valueOf(body.getClientId()))// - .extractingData(loanAccountDataV1 -> loanAccountDataV1.getSummary().getPrincipalDisbursed().longValue()) - .isEqualTo(body.getSummary().getPrincipalDisbursed().longValue())// - .extractingData(loanAccountDataV1 -> loanAccountDataV1.getTimeline().getActualDisbursementDate()) - .isEqualTo(FORMATTER_EVENTS.format(body.getTimeline().getActualDisbursementDate())) - .extractingData(loanAccountDataV1 -> loanAccountDataV1.getSummary().getCurrency().getCode()) - .isEqualTo(body.getCurrency().getCode());// + eventAssertion.assertEventRaised(LoanUndoApprovalEvent.class, body.getId()); + } + + public void loanRejectedEventCheck(Response loanRejectedResponse) throws IOException { + Response loanDetails = loansApi.retrieveLoan(loanRejectedResponse.body().getLoanId(), false, "", "", "") + .execute(); + GetLoansLoanIdResponse body = loanDetails.body(); + + eventAssertion.assertEventRaised(LoanRejectedEvent.class, body.getId()); + } + + public void disburseLoanEventCheck(Long loanId) throws IOException { + loanAccountDataV1Check(LoanDisbursalEvent.class, loanId); + } + + public void loanBalanceChangedEventCheck(Long loanId) throws IOException { + loanAccountDataV1Check(LoanBalanceChangedEvent.class, loanId); + } + + public void loanStatusChangedEventCheck(Long loanId) throws IOException { + loanAccountDataV1Check(LoanStatusChangedEvent.class, loanId); + } + + private void loanAccountDataV1Check(Class eventClazz, Long loanId) throws IOException { + Response loanDetails = loansApi.retrieveLoan(loanId, false, "all", "", "").execute(); + GetLoansLoanIdResponse body = loanDetails.body(); + + eventAssertion.assertEvent(eventClazz, loanId)// + .extractingData(loanAccountDataV1 -> { + Long idActual = loanAccountDataV1.getId(); + Long idExpected = body.getId(); + Integer statusIdActual = loanAccountDataV1.getStatus().getId(); + Integer statusIdExpected = body.getStatus().getId(); + String statusCodeActual = loanAccountDataV1.getStatus().getCode(); + String statusCodeExpected = body.getStatus().getCode(); + Long clientIdActual = loanAccountDataV1.getClientId(); + Long clientIdExpected = body.getClientId(); + BigDecimal principalDisbursedActual = loanAccountDataV1.getSummary().getPrincipalDisbursed(); + Double principalDisbursedExpectedDouble = body.getSummary().getPrincipalDisbursed(); + BigDecimal principalDisbursedExpected = new BigDecimal(principalDisbursedExpectedDouble, MathContext.DECIMAL64); + String actualDisbursementDateActual = loanAccountDataV1.getTimeline().getActualDisbursementDate(); + String actualDisbursementDateExpected = FORMATTER_EVENTS.format(body.getTimeline().getActualDisbursementDate()); + String currencyCodeActual = loanAccountDataV1.getSummary().getCurrency().getCode(); + String currencyCodeExpected = body.getSummary().getCurrency().getCode(); + BigDecimal totalUnpaidPayableDueInterestActual = loanAccountDataV1.getSummary().getTotalUnpaidPayableDueInterest(); + BigDecimal totalUnpaidPayableDueInterestExpected = body.getSummary().getTotalUnpaidPayableDueInterest(); + BigDecimal totalUnpaidPayableNotDueInterestActual = loanAccountDataV1.getSummary() + .getTotalUnpaidPayableNotDueInterest(); + BigDecimal totalUnpaidPayableNotDueInterestExpected = body.getSummary().getTotalUnpaidPayableNotDueInterest(); + BigDecimal totalInterestPaymentWaiverActual = loanAccountDataV1.getSummary().getTotalInterestPaymentWaiver(); + Double totalInterestPaymentWaiverExpectedDouble = body.getSummary().getTotalInterestPaymentWaiver(); + BigDecimal totalInterestPaymentWaiverExpected = new BigDecimal(totalInterestPaymentWaiverExpectedDouble, + MathContext.DECIMAL64); + BigDecimal delinquentInterestActual = loanAccountDataV1.getDelinquent().getDelinquentInterest(); + BigDecimal delinquentInterestExpected = body.getDelinquent().getDelinquentInterest(); + BigDecimal delinquentFeeActual = loanAccountDataV1.getDelinquent().getDelinquentFee(); + BigDecimal delinquentFeeExpected = body.getDelinquent().getDelinquentFee(); + BigDecimal delinquentPenaltyActual = loanAccountDataV1.getDelinquent().getDelinquentPenalty(); + BigDecimal delinquentPenaltyExpected = body.getDelinquent().getDelinquentPenalty(); + + assertThat(idActual).isEqualTo(idExpected); + assertThat(statusIdActual).isEqualTo(statusIdExpected); + assertThat(statusCodeActual).isEqualTo(statusCodeExpected); + assertThat(clientIdActual).isEqualTo(clientIdExpected); + assertThat(areBigDecimalValuesEqual(principalDisbursedActual, principalDisbursedExpected)).isTrue(); + assertThat(actualDisbursementDateActual).isEqualTo(actualDisbursementDateExpected); + assertThat(currencyCodeActual).isEqualTo(currencyCodeExpected); + assertThat(areBigDecimalValuesEqual(totalUnpaidPayableDueInterestActual, totalUnpaidPayableDueInterestExpected)) + .isTrue(); + assertThat(areBigDecimalValuesEqual(totalUnpaidPayableNotDueInterestActual, totalUnpaidPayableNotDueInterestExpected)) + .isTrue(); + assertThat(areBigDecimalValuesEqual(totalInterestPaymentWaiverActual, totalInterestPaymentWaiverExpected)).isTrue(); + assertThat(areBigDecimalValuesEqual(delinquentInterestActual, delinquentInterestExpected)).isTrue(); + assertThat(areBigDecimalValuesEqual(delinquentFeeActual, delinquentFeeExpected)).isTrue(); + assertThat(areBigDecimalValuesEqual(delinquentPenaltyActual, delinquentPenaltyExpected)).isTrue(); + + return null; + }); + } + + private boolean areBigDecimalValuesEqual(BigDecimal actual, BigDecimal expected) { + log.info("--- Checking BigDecimal values.... ---"); + log.info("Actual: {}", actual); + log.info("Expected: {}", expected); + return actual.compareTo(expected) == 0; } public void loanDisbursalTransactionEventCheck(Response loanDisburseResponse) throws IOException { @@ -204,6 +284,7 @@ public EventAssertion.EventAssertionBuilder transactionEv case PAYOUT_REFUND -> LoanTransactionPayoutRefundPostEvent.class; case MERCHANT_ISSUED_REFUND -> LoanTransactionMerchantIssuedRefundPostEvent.class; case REFUND_BY_CASH -> LoanRefundPostBusinessEvent.class; + case INTEREST_PAYMENT_WAIVER -> LoanTransactionInterestPaymentWaiverPostEvent.class; default -> throw new IllegalStateException(String.format("transaction type %s cannot be found", transactionType.getValue())); }; @@ -404,6 +485,6 @@ public void installmentLevelDelinquencyRangeChangeEventCheck(Long loanId) throws } private BigDecimal zeroConversion(BigDecimal input) { - return input.compareTo(BigDecimal.ZERO) == 0 ? new BigDecimal(input.toEngineeringString()) : input.setScale(8); + return input.compareTo(new BigDecimal("0.000000")) == 0 ? new BigDecimal(input.toEngineeringString()) : input.setScale(8); } } diff --git a/fineract-e2e-tests-core/src/test/java/org/apache/fineract/test/messaging/event/loan/LoanRejectedEvent.java b/fineract-e2e-tests-core/src/test/java/org/apache/fineract/test/messaging/event/loan/LoanRejectedEvent.java new file mode 100644 index 00000000000..1c66b54d9ee --- /dev/null +++ b/fineract-e2e-tests-core/src/test/java/org/apache/fineract/test/messaging/event/loan/LoanRejectedEvent.java @@ -0,0 +1,27 @@ +/** + * 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.test.messaging.event.loan; + +public class LoanRejectedEvent extends AbstractLoanEvent { + + @Override + public String getEventName() { + return "LoanRejectedBusinessEvent"; + } +} diff --git a/fineract-e2e-tests-core/src/test/java/org/apache/fineract/test/messaging/event/loan/LoanUndoApprovalEvent.java b/fineract-e2e-tests-core/src/test/java/org/apache/fineract/test/messaging/event/loan/LoanUndoApprovalEvent.java new file mode 100644 index 00000000000..fbbf04c7043 --- /dev/null +++ b/fineract-e2e-tests-core/src/test/java/org/apache/fineract/test/messaging/event/loan/LoanUndoApprovalEvent.java @@ -0,0 +1,27 @@ +/** + * 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.test.messaging.event.loan; + +public class LoanUndoApprovalEvent extends AbstractLoanEvent { + + @Override + public String getEventName() { + return "LoanUndoApprovalBusinessEvent"; + } +} diff --git a/fineract-e2e-tests-core/src/test/java/org/apache/fineract/test/messaging/event/loan/transaction/LoanTransactionAccrualActivityPostEvent.java b/fineract-e2e-tests-core/src/test/java/org/apache/fineract/test/messaging/event/loan/transaction/LoanTransactionAccrualActivityPostEvent.java new file mode 100644 index 00000000000..71aaa2c857d --- /dev/null +++ b/fineract-e2e-tests-core/src/test/java/org/apache/fineract/test/messaging/event/loan/transaction/LoanTransactionAccrualActivityPostEvent.java @@ -0,0 +1,27 @@ +/** + * 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.test.messaging.event.loan.transaction; + +public class LoanTransactionAccrualActivityPostEvent extends AbstractLoanTransactionEvent { + + @Override + public String getEventName() { + return "LoanTransactionAccrualActivityPostBusinessEvent"; + } +} diff --git a/fineract-e2e-tests-core/src/test/java/org/apache/fineract/test/messaging/event/loan/transaction/LoanTransactionInterestPaymentWaiverPostEvent.java b/fineract-e2e-tests-core/src/test/java/org/apache/fineract/test/messaging/event/loan/transaction/LoanTransactionInterestPaymentWaiverPostEvent.java new file mode 100644 index 00000000000..38145b5f2f3 --- /dev/null +++ b/fineract-e2e-tests-core/src/test/java/org/apache/fineract/test/messaging/event/loan/transaction/LoanTransactionInterestPaymentWaiverPostEvent.java @@ -0,0 +1,27 @@ +/** + * 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.test.messaging.event.loan.transaction; + +public class LoanTransactionInterestPaymentWaiverPostEvent extends AbstractLoanTransactionEvent { + + @Override + public String getEventName() { + return "LoanTransactionInterestPaymentWaiverPostBusinessEvent"; + } +} diff --git a/fineract-e2e-tests-core/src/test/java/org/apache/fineract/test/messaging/store/EventStore.java b/fineract-e2e-tests-core/src/test/java/org/apache/fineract/test/messaging/store/EventStore.java index 91b4051bca2..53745f1841f 100644 --- a/fineract-e2e-tests-core/src/test/java/org/apache/fineract/test/messaging/store/EventStore.java +++ b/fineract-e2e-tests-core/src/test/java/org/apache/fineract/test/messaging/store/EventStore.java @@ -71,20 +71,21 @@ public List> getReceivedEvents() { void receive(byte[] message) throws Exception { MessageV1 msgObject = MessageV1.fromByteBuffer(ByteBuffer.wrap(message)); String type = msgObject.getType(); + String idempotencyKey = msgObject.getIdempotencyKey(); LocalDate businessDate = LocalDate.parse(msgObject.getBusinessDate(), DateTimeFormatter.ISO_LOCAL_DATE); Object dataObject = getDataObject(msgObject); if (BULK_BUSINESS_EVENT_TYPE.equals(type)) { BulkMessagePayloadV1 bulkPayload = (BulkMessagePayloadV1) dataObject; List> bulkEvents = bulkPayload.getDatas().stream() - .map((BulkMessageItemV1 item) -> getEventMessageFromBulkItem(item, businessDate)).toList(); + .map((BulkMessageItemV1 item) -> getEventMessageFromBulkItem(item, businessDate, idempotencyKey)).toList(); if (log.isDebugEnabled()) { bulkEvents.forEach(msg -> { - log.debug("Received event {}", new LoggedEvent(msg)); + log.debug("Received Bulk event {}", new LoggedEvent(msg)); }); } receivedEvents.addAll(bulkEvents); } else { - EventMessage msg = new EventMessage<>(type, businessDate, dataObject); + EventMessage msg = new EventMessage<>(type, businessDate, dataObject, idempotencyKey); if (log.isDebugEnabled()) { log.debug("Received event {}", new LoggedEvent(msg)); } @@ -93,12 +94,12 @@ void receive(byte[] message) throws Exception { log.trace("Data object within event {}", dataObject); } - private EventMessage getEventMessageFromBulkItem(BulkMessageItemV1 item, LocalDate businessDate) { + private EventMessage getEventMessageFromBulkItem(BulkMessageItemV1 item, LocalDate businessDate, String idempotencyKey) { try { String dataschema = item.getDataschema(); ByteBuffer data = item.getData(); Object deserialized = deserialize(dataschema, data); - return new EventMessage<>(item.getType(), businessDate, deserialized); + return new EventMessage<>(item.getType(), businessDate, deserialized, idempotencyKey); } catch (Exception e) { throw new RuntimeException(e); } diff --git a/fineract-e2e-tests-core/src/test/java/org/apache/fineract/test/messaging/store/LoggedEvent.java b/fineract-e2e-tests-core/src/test/java/org/apache/fineract/test/messaging/store/LoggedEvent.java index 869ccf44b10..dc32560cd02 100644 --- a/fineract-e2e-tests-core/src/test/java/org/apache/fineract/test/messaging/store/LoggedEvent.java +++ b/fineract-e2e-tests-core/src/test/java/org/apache/fineract/test/messaging/store/LoggedEvent.java @@ -25,15 +25,17 @@ public class LoggedEvent { private final String type; private final String businessDate; + private final String idempotencyKey; public LoggedEvent(EventMessage message) { this.type = message.getType(); this.businessDate = DateTimeFormatter.ISO_LOCAL_DATE.format(message.getBusinessDate()); + this.idempotencyKey = message.getIdempotencyKey(); } // Don't use Lombok @ToString since the class name isn't included in the msg @Override public String toString() { - return "{" + "type='" + type + '\'' + ", businessDate='" + businessDate + '\'' + '}'; + return "{" + "idempotencyKey='" + idempotencyKey + '\'' + ", type='" + type + "', businessDate='" + businessDate + '\'' + '}'; } } diff --git a/fineract-e2e-tests-core/src/test/java/org/apache/fineract/test/stepdef/common/BatchApiStepDef.java b/fineract-e2e-tests-core/src/test/java/org/apache/fineract/test/stepdef/common/BatchApiStepDef.java index 92d5dd3d940..7fdd1414b82 100644 --- a/fineract-e2e-tests-core/src/test/java/org/apache/fineract/test/stepdef/common/BatchApiStepDef.java +++ b/fineract-e2e-tests-core/src/test/java/org/apache/fineract/test/stepdef/common/BatchApiStepDef.java @@ -27,7 +27,6 @@ import io.cucumber.java.en.When; import java.io.IOException; import java.nio.charset.StandardCharsets; -import java.time.Clock; import java.time.LocalDate; import java.time.format.DateTimeFormatter; import java.util.ArrayList; @@ -75,6 +74,7 @@ import org.apache.fineract.test.helper.ErrorHelper; import org.apache.fineract.test.helper.ErrorMessageHelper; import org.apache.fineract.test.helper.ErrorResponse; +import org.apache.fineract.test.helper.Utils; import org.apache.fineract.test.messaging.EventAssertion; import org.apache.fineract.test.messaging.event.loan.LoanRescheduledDueAdjustScheduleEvent; import org.apache.fineract.test.stepdef.AbstractStepDef; @@ -175,7 +175,7 @@ public void runSampleBatchApiCall() throws IOException { // request 3 - charge Loan DateTimeFormatter formatter = DateTimeFormatter.ofPattern(DATE_FORMAT); - String dateOfCharge = formatter.format(LocalDate.now(Clock.systemUTC()).minusMonths(1L).plusDays(1L)); + String dateOfCharge = formatter.format(Utils.now().minusMonths(1L).plusDays(1L)); PostLoansLoanIdChargesRequest loanIdChargesRequest = new PostLoansLoanIdChargesRequest(); loanIdChargesRequest.chargeId(CHARGE_ID_NFS_FEE); @@ -448,11 +448,11 @@ public void runBatchApiCreateAndApproveLoanReschedule(String fromDateStr, String testContext().set(TestContextKey.BATCH_API_CALL_RESPONSE, batchResponseList); testContext().set(TestContextKey.BATCH_API_CALL_IDEMPOTENCY_KEY, idempotencyKey); eventAssertion.assertEvent(LoanRescheduledDueAdjustScheduleEvent.class, loanId).extractingData(loanAccountDataV1 -> { - Optional period = loanAccountDataV1.getRepaymentSchedule().getPeriods().stream() - .filter(p -> formatter.format(LocalDate.parse(p.getDueDate())).equals(toDateStr)).findFirst(); + LoanSchedulePeriodDataV1 period = loanAccountDataV1.getRepaymentSchedule().getPeriods().stream() + .filter(p -> formatter.format(LocalDate.parse(p.getDueDate())).equals(toDateStr)).findFirst().orElse(null); String dueDate = ""; - if (period.isPresent()) { - dueDate = formatter.format(LocalDate.parse(period.get().getDueDate())); + if (period != null) { + dueDate = formatter.format(LocalDate.parse(period.getDueDate())); } assertThat(dueDate).as(ErrorMessageHelper.wrongDataInLastPaymentAmount(dueDate, toDateStr)).isEqualTo(toDateStr); return null; diff --git a/fineract-e2e-tests-core/src/test/java/org/apache/fineract/test/stepdef/common/BusinessStepStepDef.java b/fineract-e2e-tests-core/src/test/java/org/apache/fineract/test/stepdef/common/BusinessStepStepDef.java index 9e32c13740c..1752fcc3caa 100644 --- a/fineract-e2e-tests-core/src/test/java/org/apache/fineract/test/stepdef/common/BusinessStepStepDef.java +++ b/fineract-e2e-tests-core/src/test/java/org/apache/fineract/test/stepdef/common/BusinessStepStepDef.java @@ -30,8 +30,11 @@ import org.apache.fineract.client.models.GetBusinessStepConfigResponse; import org.apache.fineract.client.models.UpdateBusinessStepConfigRequest; import org.apache.fineract.client.services.BusinessStepConfigurationApi; +import org.apache.fineract.test.data.CobBusinessStep; import org.apache.fineract.test.helper.ErrorHelper; import org.apache.fineract.test.stepdef.AbstractStepDef; +import org.apache.fineract.test.support.TestContext; +import org.apache.fineract.test.support.TestContextKey; import org.springframework.beans.factory.annotation.Autowired; import retrofit2.Response; @@ -47,28 +50,20 @@ public class BusinessStepStepDef extends AbstractStepDef { private static final String BUSINESS_STEP_NAME_ADD_PERIODIC_ACCRUAL_ENTRIES = "ADD_PERIODIC_ACCRUAL_ENTRIES"; private static final String BUSINESS_STEP_NAME_EXTERNAL_ASSET_OWNER_TRANSFER = "EXTERNAL_ASSET_OWNER_TRANSFER"; private static final String BUSINESS_STEP_NAME_CHECK_DUE_INSTALLMENTS = "CHECK_DUE_INSTALLMENTS"; + private static final String BUSINESS_STEP_NAME_ACCRUAL_ACTIVITY_POSTING = "ACCRUAL_ACTIVITY_POSTING"; + private static final List ORIGINAL_COB_BUSINESS_STEPS = TestContext.GLOBAL + .get(TestContextKey.ORIGINAL_COB_WORKFLOW_JOB_BUSINESS_STEP_LIST); @Autowired private BusinessStepConfigurationApi businessStepConfigurationApi; @Given("Admin puts EXTERNAL_ASSET_OWNER_TRANSFER job into LOAN_CLOSE_OF_BUSINESS workflow") public void putExternalAssetOwnerTransferJobInCOB() throws IOException { - BusinessStep applyChargeToOverdueLoans = new BusinessStep().stepName(BUSINESS_STEP_NAME_APPLY_CHARGE_TO_OVERDUE_LOANS).order(1L); - BusinessStep loanDelinquencyClassification = new BusinessStep().stepName(BUSINESS_STEP_NAME_LOAN_DELINQUENCY_CLASSIFICATION) - .order(2L); - BusinessStep checkLoanRepaymentDue = new BusinessStep().stepName(BUSINESS_STEP_NAME_CHECK_LOAN_REPAYMENT_DUE).order(3L); - BusinessStep checkLoanRepaymentOverdue = new BusinessStep().stepName(BUSINESS_STEP_NAME_CHECK_LOAN_REPAYMENT_OVERDUE).order(4L); - BusinessStep updateLoanArrearsAging = new BusinessStep().stepName(BUSINESS_STEP_NAME_UPDATE_LOAN_ARREARS_AGING).order(5L); - BusinessStep addPeriodicAccrualEntries = new BusinessStep().stepName(BUSINESS_STEP_NAME_ADD_PERIODIC_ACCRUAL_ENTRIES).order(6L); - BusinessStep externalAssetOwnerTransfer = new BusinessStep().stepName(BUSINESS_STEP_NAME_EXTERNAL_ASSET_OWNER_TRANSFER).order(7L); - - List businessSteps = new ArrayList<>(); - businessSteps.add(applyChargeToOverdueLoans); - businessSteps.add(loanDelinquencyClassification); - businessSteps.add(checkLoanRepaymentDue); - businessSteps.add(checkLoanRepaymentOverdue); - businessSteps.add(updateLoanArrearsAging); - businessSteps.add(addPeriodicAccrualEntries); + List businessSteps = new ArrayList<>(ORIGINAL_COB_BUSINESS_STEPS); + Long lastOrder = businessSteps.get(businessSteps.size() - 1).getOrder(); + + BusinessStep externalAssetOwnerTransfer = new BusinessStep().stepName(BUSINESS_STEP_NAME_EXTERNAL_ASSET_OWNER_TRANSFER) + .order(lastOrder + 1); businessSteps.add(externalAssetOwnerTransfer); UpdateBusinessStepConfigRequest request = new UpdateBusinessStepConfigRequest().businessSteps(businessSteps); @@ -76,51 +71,22 @@ public void putExternalAssetOwnerTransferJobInCOB() throws IOException { Response response = businessStepConfigurationApi.updateJobBusinessStepConfig(WORKFLOW_NAME_LOAN_CLOSE_OF_BUSINESS, request) .execute(); ErrorHelper.checkSuccessfulApiCall(response); + + // --- log changes --- + logChanges(); } @Then("Admin removes EXTERNAL_ASSET_OWNER_TRANSFER job from LOAN_CLOSE_OF_BUSINESS workflow") public void removeExternalAssetOwnerTransferJobInCOB() throws IOException { - BusinessStep applyChargeToOverdueLoans = new BusinessStep().stepName(BUSINESS_STEP_NAME_APPLY_CHARGE_TO_OVERDUE_LOANS).order(1L); - BusinessStep loanDelinquencyClassification = new BusinessStep().stepName(BUSINESS_STEP_NAME_LOAN_DELINQUENCY_CLASSIFICATION) - .order(2L); - BusinessStep checkLoanRepaymentDue = new BusinessStep().stepName(BUSINESS_STEP_NAME_CHECK_LOAN_REPAYMENT_DUE).order(3L); - BusinessStep checkLoanRepaymentOverdue = new BusinessStep().stepName(BUSINESS_STEP_NAME_CHECK_LOAN_REPAYMENT_OVERDUE).order(4L); - BusinessStep updateLoanArrearsAging = new BusinessStep().stepName(BUSINESS_STEP_NAME_UPDATE_LOAN_ARREARS_AGING).order(5L); - BusinessStep addPeriodicAccrualEntries = new BusinessStep().stepName(BUSINESS_STEP_NAME_ADD_PERIODIC_ACCRUAL_ENTRIES).order(6L); - - List businessSteps = new ArrayList<>(); - businessSteps.add(applyChargeToOverdueLoans); - businessSteps.add(loanDelinquencyClassification); - businessSteps.add(checkLoanRepaymentDue); - businessSteps.add(checkLoanRepaymentOverdue); - businessSteps.add(updateLoanArrearsAging); - businessSteps.add(addPeriodicAccrualEntries); - - UpdateBusinessStepConfigRequest request = new UpdateBusinessStepConfigRequest().businessSteps(businessSteps); - - Response response = businessStepConfigurationApi.updateJobBusinessStepConfig(WORKFLOW_NAME_LOAN_CLOSE_OF_BUSINESS, request) - .execute(); - ErrorHelper.checkSuccessfulApiCall(response); + setBackBusinessStepsToOriginal(); } @Given("Admin puts CHECK_DUE_INSTALLMENTS job into LOAN_CLOSE_OF_BUSINESS workflow") public void putCheckDueInstallmentsJobInCOB() throws IOException { - BusinessStep applyChargeToOverdueLoans = new BusinessStep().stepName(BUSINESS_STEP_NAME_APPLY_CHARGE_TO_OVERDUE_LOANS).order(1L); - BusinessStep loanDelinquencyClassification = new BusinessStep().stepName(BUSINESS_STEP_NAME_LOAN_DELINQUENCY_CLASSIFICATION) - .order(2L); - BusinessStep checkLoanRepaymentDue = new BusinessStep().stepName(BUSINESS_STEP_NAME_CHECK_LOAN_REPAYMENT_DUE).order(3L); - BusinessStep checkLoanRepaymentOverdue = new BusinessStep().stepName(BUSINESS_STEP_NAME_CHECK_LOAN_REPAYMENT_OVERDUE).order(4L); - BusinessStep updateLoanArrearsAging = new BusinessStep().stepName(BUSINESS_STEP_NAME_UPDATE_LOAN_ARREARS_AGING).order(5L); - BusinessStep addPeriodicAccrualEntries = new BusinessStep().stepName(BUSINESS_STEP_NAME_ADD_PERIODIC_ACCRUAL_ENTRIES).order(6L); - BusinessStep checkDueInstallments = new BusinessStep().stepName(BUSINESS_STEP_NAME_CHECK_DUE_INSTALLMENTS).order(7L); - - List businessSteps = new ArrayList<>(); - businessSteps.add(applyChargeToOverdueLoans); - businessSteps.add(loanDelinquencyClassification); - businessSteps.add(checkLoanRepaymentDue); - businessSteps.add(checkLoanRepaymentOverdue); - businessSteps.add(updateLoanArrearsAging); - businessSteps.add(addPeriodicAccrualEntries); + List businessSteps = new ArrayList<>(ORIGINAL_COB_BUSINESS_STEPS); + Long lastOrder = businessSteps.get(businessSteps.size() - 1).getOrder(); + + BusinessStep checkDueInstallments = new BusinessStep().stepName(BUSINESS_STEP_NAME_CHECK_DUE_INSTALLMENTS).order(lastOrder + 1); businessSteps.add(checkDueInstallments); UpdateBusinessStepConfigRequest request = new UpdateBusinessStepConfigRequest().businessSteps(businessSteps); @@ -128,68 +94,71 @@ public void putCheckDueInstallmentsJobInCOB() throws IOException { Response response = businessStepConfigurationApi.updateJobBusinessStepConfig(WORKFLOW_NAME_LOAN_CLOSE_OF_BUSINESS, request) .execute(); ErrorHelper.checkSuccessfulApiCall(response); + + // --- log changes --- + logChanges(); } @Then("Admin removes CHECK_DUE_INSTALLMENTS job from LOAN_CLOSE_OF_BUSINESS workflow") public void removeCheckDueInstallmentsJobInCOB() throws IOException { - BusinessStep applyChargeToOverdueLoans = new BusinessStep().stepName(BUSINESS_STEP_NAME_APPLY_CHARGE_TO_OVERDUE_LOANS).order(1L); - BusinessStep loanDelinquencyClassification = new BusinessStep().stepName(BUSINESS_STEP_NAME_LOAN_DELINQUENCY_CLASSIFICATION) - .order(2L); - BusinessStep checkLoanRepaymentDue = new BusinessStep().stepName(BUSINESS_STEP_NAME_CHECK_LOAN_REPAYMENT_DUE).order(3L); - BusinessStep checkLoanRepaymentOverdue = new BusinessStep().stepName(BUSINESS_STEP_NAME_CHECK_LOAN_REPAYMENT_OVERDUE).order(4L); - BusinessStep updateLoanArrearsAging = new BusinessStep().stepName(BUSINESS_STEP_NAME_UPDATE_LOAN_ARREARS_AGING).order(5L); - BusinessStep addPeriodicAccrualEntries = new BusinessStep().stepName(BUSINESS_STEP_NAME_ADD_PERIODIC_ACCRUAL_ENTRIES).order(6L); - - List businessSteps = new ArrayList<>(); - businessSteps.add(applyChargeToOverdueLoans); - businessSteps.add(loanDelinquencyClassification); - businessSteps.add(checkLoanRepaymentDue); - businessSteps.add(checkLoanRepaymentOverdue); - businessSteps.add(updateLoanArrearsAging); - businessSteps.add(addPeriodicAccrualEntries); - - UpdateBusinessStepConfigRequest request = new UpdateBusinessStepConfigRequest().businessSteps(businessSteps); - - Response response = businessStepConfigurationApi.updateJobBusinessStepConfig(WORKFLOW_NAME_LOAN_CLOSE_OF_BUSINESS, request) - .execute(); - ErrorHelper.checkSuccessfulApiCall(response); + setBackBusinessStepsToOriginal(); } @Given("Admin puts {string} business step into LOAN_CLOSE_OF_BUSINESS workflow") public void putGivenJobInCOB(String businessStepName) throws IOException { - List businessSteps = retrieveLoanCOBJobSteps(); - if (businessSteps.stream().anyMatch(businessStep -> businessStep.getStepName().equals(businessStepName))) { - return; - } + List businessSteps = new ArrayList<>(ORIGINAL_COB_BUSINESS_STEPS); + Long lastOrder = businessSteps.get(businessSteps.size() - 1).getOrder(); + + CobBusinessStep cobBusinessStep = CobBusinessStep.valueOf(businessStepName); + String stepName = cobBusinessStep.getValue(); - businessSteps.add(new BusinessStep().stepName(businessStepName).order((long) (1 + businessSteps.size()))); + BusinessStep businessStepToAdd = new BusinessStep().stepName(stepName).order(lastOrder + 1); + businessSteps.add(businessStepToAdd); UpdateBusinessStepConfigRequest request = new UpdateBusinessStepConfigRequest().businessSteps(businessSteps); + Response response = businessStepConfigurationApi.updateJobBusinessStepConfig(WORKFLOW_NAME_LOAN_CLOSE_OF_BUSINESS, request) .execute(); ErrorHelper.checkSuccessfulApiCall(response); + // --- log changes --- logChanges(); } + @Then("Admin sets back LOAN_CLOSE_OF_BUSINESS workflow to its initial state") + public void setBackCOBToInitialState() throws IOException { + setBackBusinessStepsToOriginal(); + } + @Then("Admin removes {string} business step into LOAN_CLOSE_OF_BUSINESS workflow") public void removeGivenJobInCOB(String businessStepName) throws IOException { - List businessSteps = retrieveLoanCOBJobSteps(); - businessSteps.removeIf(businessStep -> businessStep.getStepName().equals(businessStepName)); + List businessSteps = new ArrayList<>(ORIGINAL_COB_BUSINESS_STEPS); + + CobBusinessStep cobBusinessStep = CobBusinessStep.valueOf(businessStepName); + String stepName = cobBusinessStep.getValue(); + + businessSteps.removeIf(businessStep -> businessStep.getStepName().equals(stepName)); UpdateBusinessStepConfigRequest request = new UpdateBusinessStepConfigRequest().businessSteps(businessSteps); + Response response = businessStepConfigurationApi.updateJobBusinessStepConfig(WORKFLOW_NAME_LOAN_CLOSE_OF_BUSINESS, request) .execute(); ErrorHelper.checkSuccessfulApiCall(response); + // --- log changes --- logChanges(); } - private List retrieveLoanCOBJobSteps() throws IOException { - Response businessStepConfigResponse = businessStepConfigurationApi - .retrieveAllConfiguredBusinessStep(WORKFLOW_NAME_LOAN_CLOSE_OF_BUSINESS).execute(); - ErrorHelper.checkSuccessfulApiCall(businessStepConfigResponse); - return businessStepConfigResponse.body().getBusinessSteps(); + private void setBackBusinessStepsToOriginal() throws IOException { + log.info("Setting back Business steps to original..."); + UpdateBusinessStepConfigRequest request = new UpdateBusinessStepConfigRequest().businessSteps(ORIGINAL_COB_BUSINESS_STEPS); + + Response response = businessStepConfigurationApi.updateJobBusinessStepConfig(WORKFLOW_NAME_LOAN_CLOSE_OF_BUSINESS, request) + .execute(); + ErrorHelper.checkSuccessfulApiCall(response); + + // --- log changes --- + logChanges(); } private void logChanges() throws IOException { diff --git a/fineract-e2e-tests-core/src/test/java/org/apache/fineract/test/stepdef/common/GlobalConfigurationStepDef.java b/fineract-e2e-tests-core/src/test/java/org/apache/fineract/test/stepdef/common/GlobalConfigurationStepDef.java index 4631bf2b423..d692a7b2b2b 100644 --- a/fineract-e2e-tests-core/src/test/java/org/apache/fineract/test/stepdef/common/GlobalConfigurationStepDef.java +++ b/fineract-e2e-tests-core/src/test/java/org/apache/fineract/test/stepdef/common/GlobalConfigurationStepDef.java @@ -21,6 +21,7 @@ import io.cucumber.java.en.Given; import io.cucumber.java.en.When; import java.io.IOException; +import org.apache.fineract.client.services.DefaultApi; import org.apache.fineract.test.helper.GlobalConfigurationHelper; import org.springframework.beans.factory.annotation.Autowired; @@ -28,6 +29,8 @@ public class GlobalConfigurationStepDef { @Autowired private GlobalConfigurationHelper globalConfigurationHelper; + @Autowired + private DefaultApi defaultApi; @Given("Global configuration {string} is disabled") public void disableGlobalConfiguration(String configKey) throws IOException { @@ -42,6 +45,12 @@ public void enableGlobalConfiguration(String configKey) throws IOException { @When("Global config {string} value set to {string}") public void setGlobalConfigValueString(String configKey, String configValue) throws IOException { globalConfigurationHelper.setGlobalConfigValueString(configKey, configValue); + } + + @When("Global config {string} value set to {string} through DefaultApi") + public void setGlobalConfigValueStringDefaultApi(String configKey, String configValue) throws IOException { + Long configValueLong = Long.valueOf(configValue); + defaultApi.updateGlobalConfiguration(configKey, configValueLong); } } diff --git a/fineract-e2e-tests-core/src/test/java/org/apache/fineract/test/stepdef/common/JournalEntriesStepDef.java b/fineract-e2e-tests-core/src/test/java/org/apache/fineract/test/stepdef/common/JournalEntriesStepDef.java index 0e81930db00..97191a40a3d 100644 --- a/fineract-e2e-tests-core/src/test/java/org/apache/fineract/test/stepdef/common/JournalEntriesStepDef.java +++ b/fineract-e2e-tests-core/src/test/java/org/apache/fineract/test/stepdef/common/JournalEntriesStepDef.java @@ -67,7 +67,6 @@ public void journalEntryDataCheck(String transactionType, String transactionDate String transactionTypeExpected = transactionType1.getValue(); List transactions = loanDetailsResponse.body().getTransactions(); - List transactionsMatch = transactions.stream() .filter(t -> transactionDate.equals(formatter.format(t.getDate())) && transactionTypeExpected.equals(t.getType().getCode().substring(20))) diff --git a/fineract-e2e-tests-core/src/test/java/org/apache/fineract/test/stepdef/common/SchedulerStepDef.java b/fineract-e2e-tests-core/src/test/java/org/apache/fineract/test/stepdef/common/SchedulerStepDef.java index ac562f9e2c6..e0db1f4595f 100644 --- a/fineract-e2e-tests-core/src/test/java/org/apache/fineract/test/stepdef/common/SchedulerStepDef.java +++ b/fineract-e2e-tests-core/src/test/java/org/apache/fineract/test/stepdef/common/SchedulerStepDef.java @@ -56,4 +56,9 @@ public void runLoanDelinquencyClassification() { public void runCOB() { jobService.executeAndWait(DefaultJob.LOAN_COB); } + + @When("Admin runs the Accrual Activity Posting job") + public void runAccrualActivityPosting() { + jobService.executeAndWait(DefaultJob.ACCRUAL_ACTIVITY_POSTING); + } } diff --git a/fineract-e2e-tests-core/src/test/java/org/apache/fineract/test/stepdef/hook/TestRailLifecycleHook.java b/fineract-e2e-tests-core/src/test/java/org/apache/fineract/test/stepdef/hook/TestRailLifecycleHook.java new file mode 100644 index 00000000000..ab39f3bb70d --- /dev/null +++ b/fineract-e2e-tests-core/src/test/java/org/apache/fineract/test/stepdef/hook/TestRailLifecycleHook.java @@ -0,0 +1,45 @@ +/** + * 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.test.stepdef.hook; + +import io.cucumber.java.After; +import io.cucumber.java.Scenario; +import lombok.extern.slf4j.Slf4j; +import org.apache.fineract.test.testrail.TestRailClient; +import org.apache.fineract.test.testrail.TestRailProperties; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.context.ApplicationContext; + +@Slf4j +public class TestRailLifecycleHook { + + @Autowired + private TestRailProperties testRailProperties; + + @Autowired + private ApplicationContext applicationContext; + + @After + public void tearDown(Scenario scenario) { + if (testRailProperties.isEnabled()) { + TestRailClient testRailClient = applicationContext.getBean(TestRailClient.class); + testRailClient.saveScenarioResult(scenario); + } + } +} diff --git a/fineract-e2e-tests-core/src/test/java/org/apache/fineract/test/stepdef/loan/LoanChargeAdjustmentStepDef.java b/fineract-e2e-tests-core/src/test/java/org/apache/fineract/test/stepdef/loan/LoanChargeAdjustmentStepDef.java index 9e3aeaa1427..72cd37afdd2 100644 --- a/fineract-e2e-tests-core/src/test/java/org/apache/fineract/test/stepdef/loan/LoanChargeAdjustmentStepDef.java +++ b/fineract-e2e-tests-core/src/test/java/org/apache/fineract/test/stepdef/loan/LoanChargeAdjustmentStepDef.java @@ -21,12 +21,14 @@ import static org.assertj.core.api.Assertions.assertThat; import com.google.gson.Gson; +import io.cucumber.java.en.Then; import io.cucumber.java.en.When; import java.io.IOException; import java.time.LocalDate; import java.time.format.DateTimeFormatter; import java.util.ArrayList; import java.util.List; +import lombok.extern.slf4j.Slf4j; import org.apache.fineract.client.models.BusinessDateResponse; import org.apache.fineract.client.models.GetLoansLoanIdLoanChargeData; import org.apache.fineract.client.models.GetLoansLoanIdResponse; @@ -46,11 +48,14 @@ import org.apache.fineract.test.helper.ErrorHelper; import org.apache.fineract.test.helper.ErrorMessageHelper; import org.apache.fineract.test.helper.ErrorResponse; +import org.apache.fineract.test.messaging.event.EventCheckHelper; +import org.apache.fineract.test.messaging.store.EventStore; import org.apache.fineract.test.stepdef.AbstractStepDef; import org.apache.fineract.test.support.TestContextKey; import org.springframework.beans.factory.annotation.Autowired; import retrofit2.Response; +@Slf4j public class LoanChargeAdjustmentStepDef extends AbstractStepDef { public static final String DATE_FORMAT = "dd MMMM yyyy"; @@ -65,6 +70,10 @@ public class LoanChargeAdjustmentStepDef extends AbstractStepDef { private LoanTransactionsApi loanTransactionsApi; @Autowired private BusinessDateManagementApi businessDateManagementApi; + @Autowired + private EventCheckHelper eventCheckHelper; + @Autowired + private EventStore eventStore; @When("Admin makes a charge adjustment for the last {string} type charge which is due on {string} with {double} EUR transaction amount and externalId {string}") public void makeLoanChargeAdjustment(String chargeTypeEnum, String date, Double transactionAmount, String externalId) @@ -79,8 +88,8 @@ public void makeLoanChargeAdjustment(String chargeTypeEnum, String date, Double makeChargeAdjustmentCall(loanId, transactionId, externalId, transactionAmount); } - @When("Admin makes a charge adjustment for the last {string} type charge which is due on {string} with transaction amount higher than the available charge amount") - public void loanChargeAdjustmentFailedOnWrongAmount(String chargeTypeEnum, String date) throws IOException { + @Then("Charge adjustment for the last {string} type charge which is due on {string} with transaction amount {double} which is higher than the available charge amount results an ERROR") + public void loanChargeAdjustmentFailedOnWrongAmount(String chargeTypeEnum, String date, double amount) throws IOException { Response loanResponse = testContext().get(TestContextKey.LOAN_CREATE_RESPONSE); long loanId = loanResponse.body().getLoanId(); @@ -88,7 +97,7 @@ public void loanChargeAdjustmentFailedOnWrongAmount(String chargeTypeEnum, Strin ErrorHelper.checkSuccessfulApiCall(loanDetailsResponse); Long transactionId = getTransactionIdForLastChargeMetConditions(chargeTypeEnum, date, loanDetailsResponse); - PostLoansLoanIdChargesChargeIdRequest chargeAdjustmentRequest = LoanRequestFactory.defaultChargeAdjustmentRequest().amount(8.0) + PostLoansLoanIdChargesChargeIdRequest chargeAdjustmentRequest = LoanRequestFactory.defaultChargeAdjustmentRequest().amount(amount) .externalId(""); Response chargeAdjustmentResponseFail = loanChargesApi @@ -108,6 +117,9 @@ public void loanChargeAdjustmentFailedOnWrongAmount(String chargeTypeEnum, Strin assertThat(developerMessageActual) .as(ErrorMessageHelper.wrongErrorMessageInFailedChargeAdjustment(developerMessageActual, developerMessageExpected)) .isEqualTo(developerMessageExpected); + + log.info("Error code: {}", httpStatusCodeActual); + log.info("Error message: {}", developerMessageActual); } @When("Admin reverts the charge adjustment which was raised on {string} with {double} EUR transaction amount") @@ -153,6 +165,7 @@ private Long getTransactionIdForTransactionMetConditions(String transactionDate, } private void makeChargeAdjustmentCall(Long loanId, Long transactionId, String externalId, double transactionAmount) throws IOException { + eventStore.reset(); PostLoansLoanIdChargesChargeIdRequest chargeAdjustmentRequest = LoanRequestFactory.defaultChargeAdjustmentRequest() .amount(transactionAmount).externalId(externalId); @@ -160,6 +173,7 @@ private void makeChargeAdjustmentCall(Long loanId, Long transactionId, String ex .executeLoanCharge2(loanId, transactionId, chargeAdjustmentRequest, "adjustment").execute(); testContext().set(TestContextKey.LOAN_CHARGE_ADJUSTMENT_RESPONSE, chargeAdjustmentResponse); ErrorHelper.checkSuccessfulApiCall(chargeAdjustmentResponse); + eventCheckHelper.loanBalanceChangedEventCheck(loanId); } private Long getTransactionIdForLastChargeMetConditions(String chargeTypeEnum, String date, diff --git a/fineract-e2e-tests-core/src/test/java/org/apache/fineract/test/stepdef/loan/LoanChargeBackStepDef.java b/fineract-e2e-tests-core/src/test/java/org/apache/fineract/test/stepdef/loan/LoanChargeBackStepDef.java index 9eaf7c1edff..458cd9aa949 100644 --- a/fineract-e2e-tests-core/src/test/java/org/apache/fineract/test/stepdef/loan/LoanChargeBackStepDef.java +++ b/fineract-e2e-tests-core/src/test/java/org/apache/fineract/test/stepdef/loan/LoanChargeBackStepDef.java @@ -40,8 +40,9 @@ import org.apache.fineract.test.factory.LoanRequestFactory; import org.apache.fineract.test.helper.ErrorHelper; import org.apache.fineract.test.messaging.EventAssertion; -import org.apache.fineract.test.messaging.event.loan.LoanBalanceChangedEvent; +import org.apache.fineract.test.messaging.event.EventCheckHelper; import org.apache.fineract.test.messaging.event.loan.transaction.LoanChargebackTransactionEvent; +import org.apache.fineract.test.messaging.store.EventStore; import org.apache.fineract.test.stepdef.AbstractStepDef; import org.apache.fineract.test.support.TestContextKey; import org.springframework.beans.factory.annotation.Autowired; @@ -61,6 +62,12 @@ public class LoanChargeBackStepDef extends AbstractStepDef { @Autowired private PaymentTypeResolver paymentTypeResolver; + @Autowired + private EventCheckHelper eventCheckHelper; + + @Autowired + EventStore eventStore; + @When("Admin makes {string} chargeback with {double} EUR transaction amount") public void makeLoanChargeback(String repaymentType, double transactionAmount) throws IOException { Response loanResponse = testContext().get(TestContextKey.LOAN_CREATE_RESPONSE); @@ -116,6 +123,7 @@ public void makeLoanChargebackForDownpaymentayment(String repaymentType, double } private void makeChargebackCall(Long loanId, Long transactionId, String repaymentType, double transactionAmount) throws IOException { + eventStore.reset(); DefaultPaymentType paymentType = DefaultPaymentType.valueOf(repaymentType); Long paymentTypeValue = paymentTypeResolver.resolve(paymentType); @@ -134,8 +142,7 @@ private void checkEvents(Response chargebac PostLoansLoanIdTransactionsResponse responseBody = chargebackResponse.body(); Long loanId = responseBody.getLoanId(); - eventAssertion.assertEvent(LoanBalanceChangedEvent.class, loanId).extractingData(data -> data.getId()).isEqualTo(loanId); - + eventCheckHelper.loanBalanceChangedEventCheck(loanId); checkLoanChargebackTransactionEvent(responseBody); } diff --git a/fineract-e2e-tests-core/src/test/java/org/apache/fineract/test/stepdef/loan/LoanChargeStepDef.java b/fineract-e2e-tests-core/src/test/java/org/apache/fineract/test/stepdef/loan/LoanChargeStepDef.java index 51bd48e2787..9a2bccac293 100644 --- a/fineract-e2e-tests-core/src/test/java/org/apache/fineract/test/stepdef/loan/LoanChargeStepDef.java +++ b/fineract-e2e-tests-core/src/test/java/org/apache/fineract/test/stepdef/loan/LoanChargeStepDef.java @@ -51,7 +51,9 @@ import org.apache.fineract.test.helper.ErrorMessageHelper; import org.apache.fineract.test.helper.ErrorResponse; import org.apache.fineract.test.messaging.EventAssertion; +import org.apache.fineract.test.messaging.event.EventCheckHelper; import org.apache.fineract.test.messaging.event.loan.charge.LoanAddChargeEvent; +import org.apache.fineract.test.messaging.store.EventStore; import org.apache.fineract.test.stepdef.AbstractStepDef; import org.apache.fineract.test.support.TestContextKey; import org.springframework.beans.factory.annotation.Autowired; @@ -73,6 +75,10 @@ public class LoanChargeStepDef extends AbstractStepDef { private LoansApi loansApi; @Autowired private EventAssertion eventAssertion; + @Autowired + private EventCheckHelper eventCheckHelper; + @Autowired + private EventStore eventStore; @When("Admin adds {string} due date charge with {string} due date and {double} EUR transaction amount") public void addChargeDueDate(String chargeType, String transactionDate, double transactionAmount) throws IOException { @@ -142,6 +148,7 @@ public void addChargeDueDateOnChargedOff(String chargeType, String transactionDa @And("Admin adds a {double} % Processing charge to the loan with {string} locale on date: {string}") public void addProcessingFee(double chargeAmount, String locale, String date) throws IOException { + eventStore.reset(); Response loanResponse = testContext().get(TestContextKey.LOAN_CREATE_RESPONSE); long loanId = loanResponse.body().getLoanId(); PostLoansLoanIdChargesRequest loanIdChargesRequest = LoanChargeRequestFactory.defaultLoanChargeRequest() @@ -152,10 +159,12 @@ public void addProcessingFee(double chargeAmount, String locale, String date) th .execute(); ErrorHelper.checkSuccessfulApiCall(loanChargeResponse); testContext().set(TestContextKey.ADD_PROCESSING_FEE_RESPONSE, loanChargeResponse); + eventCheckHelper.loanBalanceChangedEventCheck(loanId); } @And("Admin adds an NSF fee because of payment bounce with {string} transaction date") public void addNSFfee(String date) throws IOException { + eventStore.reset(); Response loanResponse = testContext().get(TestContextKey.LOAN_CREATE_RESPONSE); long loanId = loanResponse.body().getLoanId(); PostLoansLoanIdChargesRequest loanIdChargesRequest = LoanChargeRequestFactory.defaultLoanChargeRequest() @@ -166,6 +175,7 @@ public void addNSFfee(String date) throws IOException { .execute(); ErrorHelper.checkSuccessfulApiCall(loanChargeResponse); testContext().set(TestContextKey.ADD_NSF_FEE_RESPONSE, loanChargeResponse); + eventCheckHelper.loanBalanceChangedEventCheck(loanId); } @And("Admin waives charge") diff --git a/fineract-e2e-tests-core/src/test/java/org/apache/fineract/test/stepdef/loan/LoanDelinquencyStepDef.java b/fineract-e2e-tests-core/src/test/java/org/apache/fineract/test/stepdef/loan/LoanDelinquencyStepDef.java index e55519460e1..d584e3a0bce 100644 --- a/fineract-e2e-tests-core/src/test/java/org/apache/fineract/test/stepdef/loan/LoanDelinquencyStepDef.java +++ b/fineract-e2e-tests-core/src/test/java/org/apache/fineract/test/stepdef/loan/LoanDelinquencyStepDef.java @@ -21,7 +21,6 @@ import static org.assertj.core.api.Assertions.assertThat; import com.google.gson.Gson; -import edu.umd.cs.findbugs.annotations.SuppressFBWarnings; import io.cucumber.datatable.DataTable; import io.cucumber.java.en.Then; import io.cucumber.java.en.When; @@ -629,7 +628,7 @@ public void checkDelinquencyRangeInEvent(String expectedRange) { String expectedDelinquencyRangeValue = expectedDelinquencyRange.getValue(); eventAssertion.assertEvent(LoanDelinquencyRangeChangeEvent.class, loanId)// - .extractingData(loanAccountDelinquencyRangeDataV1 -> { // + .extractingData(loanAccountDelinquencyRangeDataV1 -> { String actualDelinquencyRangeValue = loanAccountDelinquencyRangeDataV1.getDelinquencyRange().getClassification();// assertThat(actualDelinquencyRangeValue)// .as(ErrorMessageHelper.delinquencyRangeError(actualDelinquencyRangeValue, expectedDelinquencyRangeValue))// @@ -648,7 +647,8 @@ public void checkDelinquencyRangeInEvent() throws IOException { GetLoansLoanIdDelinquencySummary delinquent = loanDetails.body().getDelinquent(); eventAssertion.assertEvent(LoanDelinquencyRangeChangeEvent.class, loanId)// - .extractingData(loanAccountDelinquencyRangeDataV1 -> { // + .extractingData(loanAccountDelinquencyRangeDataV1 -> { + Long loanLevelDelinquencyRangeId = loanAccountDelinquencyRangeDataV1.getDelinquencyRange().getId(); String loanLevelDelinquencyRange = loanAccountDelinquencyRangeDataV1.getDelinquencyRange().getClassification(); String loanLevelDelinquentDate = loanAccountDelinquencyRangeDataV1.getDelinquentDate(); @@ -732,7 +732,6 @@ public void delinquentLastRepaymentAmountCheck(int expectedLastRepaymentAmount, log.info("loanDetails.delinquent.lastRepaymentDate: {}", actualLastRepaymentDate); } - @SuppressFBWarnings("SF_SWITCH_NO_DEFAULT") private List fetchValuesOfDelinquencyPausePeriods(List header, GetLoansLoanIdDelinquencyPausePeriod t) { List actualValues = new ArrayList<>(); for (String headerName : header) { @@ -741,6 +740,7 @@ private List fetchValuesOfDelinquencyPausePeriods(List header, G case "pausePeriodStart" -> actualValues.add(t.getPausePeriodStart() == null ? null : FORMATTER.format(t.getPausePeriodStart())); case "pausePeriodEnd" -> actualValues.add(t.getPausePeriodEnd() == null ? null : FORMATTER.format(t.getPausePeriodEnd())); + default -> throw new IllegalStateException(String.format("Header name %s cannot be found", headerName)); } } return actualValues; diff --git a/fineract-e2e-tests-core/src/test/java/org/apache/fineract/test/stepdef/loan/LoanReAgingStepDef.java b/fineract-e2e-tests-core/src/test/java/org/apache/fineract/test/stepdef/loan/LoanReAgingStepDef.java index 5f2f0a7e96a..327225d08a8 100644 --- a/fineract-e2e-tests-core/src/test/java/org/apache/fineract/test/stepdef/loan/LoanReAgingStepDef.java +++ b/fineract-e2e-tests-core/src/test/java/org/apache/fineract/test/stepdef/loan/LoanReAgingStepDef.java @@ -57,8 +57,12 @@ public void createReAgingTransaction(DataTable table) throws IOException { String startDate = data.get(2); int numberOfInstallments = Integer.parseInt(data.get(3)); - PostLoansLoanIdTransactionsRequest reAgingRequest = LoanRequestFactory.defaultReAgingRequest().frequencyNumber(frequencyNumber) - .frequencyType(frequencyType).startDate(startDate).numberOfInstallments(numberOfInstallments); + PostLoansLoanIdTransactionsRequest reAgingRequest = LoanRequestFactory// + .defaultReAgingRequest()// + .frequencyNumber(frequencyNumber)// + .frequencyType(frequencyType)// + .startDate(startDate)// + .numberOfInstallments(numberOfInstallments);// Response response = loanTransactionsApi.executeLoanTransaction(loanId, reAgingRequest, "reAge") .execute(); @@ -77,8 +81,12 @@ public void createReAgingTransactionByLoanExternalId(DataTable table) throws IOE String startDate = data.get(2); int numberOfInstallments = Integer.parseInt(data.get(3)); - PostLoansLoanIdTransactionsRequest reAgingRequest = LoanRequestFactory.defaultReAgingRequest().frequencyNumber(frequencyNumber) - .frequencyType(frequencyType).startDate(startDate).numberOfInstallments(numberOfInstallments); + PostLoansLoanIdTransactionsRequest reAgingRequest = LoanRequestFactory// + .defaultReAgingRequest()// + .frequencyNumber(frequencyNumber)// + .frequencyType(frequencyType)// + .startDate(startDate)// + .numberOfInstallments(numberOfInstallments);// Response response = loanTransactionsApi .executeLoanTransaction1(loanExternalId, reAgingRequest, "reAge").execute(); diff --git a/fineract-e2e-tests-core/src/test/java/org/apache/fineract/test/stepdef/loan/LoanRepaymentStepDef.java b/fineract-e2e-tests-core/src/test/java/org/apache/fineract/test/stepdef/loan/LoanRepaymentStepDef.java index 206abd1a014..992c4fd07b3 100644 --- a/fineract-e2e-tests-core/src/test/java/org/apache/fineract/test/stepdef/loan/LoanRepaymentStepDef.java +++ b/fineract-e2e-tests-core/src/test/java/org/apache/fineract/test/stepdef/loan/LoanRepaymentStepDef.java @@ -61,8 +61,8 @@ import org.apache.fineract.test.helper.ErrorResponse; import org.apache.fineract.test.messaging.EventAssertion; import org.apache.fineract.test.messaging.event.EventCheckHelper; -import org.apache.fineract.test.messaging.event.loan.LoanBalanceChangedEvent; import org.apache.fineract.test.messaging.event.loan.transaction.LoanAdjustTransactionBusinessEvent; +import org.apache.fineract.test.messaging.store.EventStore; import org.apache.fineract.test.stepdef.AbstractStepDef; import org.apache.fineract.test.support.TestContextKey; import org.springframework.beans.factory.annotation.Autowired; @@ -77,6 +77,7 @@ public class LoanRepaymentStepDef extends AbstractStepDef { public static final String DEFAULT_CHECK_NB = "1234567890"; public static final String DEFAULT_RECEIPT_NB = "1234567890"; public static final String DEFAULT_BANK_NB = "1234567890"; + public static final String DEFAULT_REPAYMENT_TYPE = "AUTOPAY"; @Autowired private LoanTransactionsApi loanTransactionsApi; @@ -98,6 +99,9 @@ public class LoanRepaymentStepDef extends AbstractStepDef { @Autowired private EventCheckHelper eventCheckHelper; + @Autowired + private EventStore eventStore; + @And("Customer makes {string} repayment on {string} with {double} EUR transaction amount") public void makeLoanRepayment(String repaymentType, String transactionDate, double transactionAmount) throws IOException { makeRepayment(repaymentType, transactionDate, transactionAmount, null); @@ -111,6 +115,7 @@ public void makeLoanRepaymentAndCheckOwner(String repaymentType, String transact private void makeRepayment(String repaymentType, String transactionDate, double transactionAmount, String transferExternalOwnerId) throws IOException { + eventStore.reset(); Response loanResponse = testContext().get(TestContextKey.LOAN_CREATE_RESPONSE); long loanId = loanResponse.body().getLoanId(); @@ -132,11 +137,12 @@ private void makeRepayment(String repaymentType, String transactionDate, double EventAssertion.EventAssertionBuilder transactionEvent = eventCheckHelper .transactionEventCheck(repaymentResponse, TransactionType.REPAYMENT, transferExternalOwnerId); testContext().set(TestContextKey.TRANSACTION_EVENT, transactionEvent); - eventAssertion.assertEventRaised(LoanBalanceChangedEvent.class, loanId); + eventCheckHelper.loanBalanceChangedEventCheck(loanId); } @And("Created user makes {string} repayment on {string} with {double} EUR transaction amount") public void makeRepaymentWithGivenUser(String repaymentType, String transactionDate, double transactionAmount) throws IOException { + eventStore.reset(); Response loanResponse = testContext().get(TestContextKey.LOAN_CREATE_RESPONSE); long loanId = loanResponse.body().getLoanId(); @@ -164,11 +170,12 @@ public void makeRepaymentWithGivenUser(String repaymentType, String transactionD .executeLoanTransaction(loanId, repaymentRequest, "repayment", headerMap).execute(); testContext().set(TestContextKey.LOAN_REPAYMENT_RESPONSE, repaymentResponse); ErrorHelper.checkSuccessfulApiCall(repaymentResponse); - eventAssertion.assertEventRaised(LoanBalanceChangedEvent.class, loanId); + eventCheckHelper.loanBalanceChangedEventCheck(loanId); } @And("Customer makes externalID controlled {string} repayment on {string} with {double} EUR transaction amount") public void makeRepaymentByExternalId(String repaymentType, String transactionDate, double transactionAmount) throws IOException { + eventStore.reset(); Response loanResponse = testContext().get(TestContextKey.LOAN_CREATE_RESPONSE); long loanId = loanResponse.body().getLoanId(); String resourceExternalId = loanResponse.body().getResourceExternalId(); @@ -189,12 +196,13 @@ public void makeRepaymentByExternalId(String repaymentType, String transactionDa testContext().set(TestContextKey.LOAN_REPAYMENT_RESPONSE, repaymentResponse); ErrorHelper.checkSuccessfulApiCall(repaymentResponse); - eventAssertion.assertEventRaised(LoanBalanceChangedEvent.class, loanId); + eventCheckHelper.loanBalanceChangedEventCheck(loanId); } @And("Created user makes externalID controlled {string} repayment on {string} with {double} EUR transaction amount") public void makeRepaymentWithGivenUserByExternalId(String repaymentType, String transactionDate, double transactionAmount) throws IOException { + eventStore.reset(); Response loanResponse = testContext().get(TestContextKey.LOAN_CREATE_RESPONSE); long loanId = loanResponse.body().getLoanId(); String resourceExternalId = loanResponse.body().getResourceExternalId(); @@ -223,7 +231,7 @@ public void makeRepaymentWithGivenUserByExternalId(String repaymentType, String .executeLoanTransaction1(resourceExternalId, repaymentRequest, "repayment", headerMap).execute(); testContext().set(TestContextKey.LOAN_REPAYMENT_RESPONSE, repaymentResponse); ErrorHelper.checkSuccessfulApiCall(repaymentResponse); - eventAssertion.assertEventRaised(LoanBalanceChangedEvent.class, loanId); + eventCheckHelper.loanBalanceChangedEventCheck(loanId); } @And("Customer not able to make {string} repayment on {string} with {double} EUR transaction amount") @@ -282,6 +290,7 @@ public void makeLoanRepaymentWithWrongDate(String repaymentType, String transact @When("Refund happens on {string} with {double} EUR transaction amount") public void makeRefund(String transactionDate, double transactionAmount) throws IOException { + eventStore.reset(); Response loanResponse = testContext().get(TestContextKey.LOAN_CREATE_RESPONSE); long loanId = loanResponse.body().getLoanId(); PostLoansLoanIdTransactionsRequest refundRequest = LoanRequestFactory.defaultRefundRequest().transactionDate(transactionDate) @@ -293,10 +302,12 @@ public void makeRefund(String transactionDate, double transactionAmount) throws .executeLoanTransaction(loanId, refundRequest, "payoutRefund").execute(); ErrorHelper.checkSuccessfulApiCall(refundResponse); testContext().set(TestContextKey.LOAN_REFUND_RESPONSE, refundResponse); + eventCheckHelper.loanBalanceChangedEventCheck(loanId); } @When("Refund undo happens on {string}") public void makeRefundUndo(String transactionDate) throws IOException { + eventStore.reset(); Response loanResponse = testContext().get(TestContextKey.LOAN_CREATE_RESPONSE); long loanId = loanResponse.body().getLoanId(); Response refundResponse = testContext().get(TestContextKey.LOAN_REFUND_RESPONSE); @@ -318,10 +329,12 @@ public void makeRefundUndo(String transactionDate) throws IOException { loanTransactionAdjustmentDataV1 -> loanTransactionAdjustmentDataV1.getTransactionToAdjust().getManuallyReversed()) .isEqualTo(Boolean.TRUE); eventAssertionBuilder.extractingData(LoanTransactionAdjustmentDataV1::getNewTransactionDetail).isEqualTo(null); + eventCheckHelper.loanBalanceChangedEventCheck(loanId); } @When("Customer makes a repayment undo on {string}") public void makeLoanRepaymentUndo(String transactionDate) throws IOException { + eventStore.reset(); Response loanResponse = testContext().get(TestContextKey.LOAN_CREATE_RESPONSE); long loanId = loanResponse.body().getLoanId(); Response repaymentResponse = testContext().get(TestContextKey.LOAN_REPAYMENT_RESPONSE); @@ -343,6 +356,7 @@ public void makeLoanRepaymentUndo(String transactionDate) throws IOException { loanTransactionAdjustmentDataV1 -> loanTransactionAdjustmentDataV1.getTransactionToAdjust().getManuallyReversed()) .isEqualTo(Boolean.TRUE); eventAssertionBuilder.extractingData(LoanTransactionAdjustmentDataV1::getNewTransactionDetail).isEqualTo(null); + eventCheckHelper.loanBalanceChangedEventCheck(loanId); } @Then("Loan {string} transaction adjust amount {double} must return {int} code") @@ -361,6 +375,7 @@ public void makeLoanRepaymentAdjustFail(String transactionType, double transacti @When("Customer undo {string}th repayment on {string}") public void undoNthRepayment(String nthItemStr, String transactionDate) throws IOException { + eventStore.reset(); Response loanResponse = testContext().get(TestContextKey.LOAN_CREATE_RESPONSE); long loanId = loanResponse.body().getLoanId(); List transactions = loansApi.retrieveLoan(loanId, false, "transactions", "", "").execute().body() @@ -387,10 +402,12 @@ public void undoNthRepayment(String nthItemStr, String transactionDate) throws I loanTransactionAdjustmentDataV1 -> loanTransactionAdjustmentDataV1.getTransactionToAdjust().getManuallyReversed()) .isEqualTo(Boolean.TRUE); eventAssertionBuilder.extractingData(LoanTransactionAdjustmentDataV1::getNewTransactionDetail).isEqualTo(null); + eventCheckHelper.loanBalanceChangedEventCheck(loanId); } @When("Customer undo {string}th transaction made on {string}") public void undoNthTransaction(String nthItemStr, String transactionDate) throws IOException { + eventStore.reset(); DateTimeFormatter formatter = DateTimeFormatter.ofPattern(DATE_FORMAT); Response loanResponse = testContext().get(TestContextKey.LOAN_CREATE_RESPONSE); long loanId = loanResponse.body().getLoanId(); @@ -418,10 +435,12 @@ public void undoNthTransaction(String nthItemStr, String transactionDate) throws loanTransactionAdjustmentDataV1 -> loanTransactionAdjustmentDataV1.getTransactionToAdjust().getManuallyReversed()) .isEqualTo(Boolean.TRUE); eventAssertionBuilder.extractingData(LoanTransactionAdjustmentDataV1::getNewTransactionDetail).isEqualTo(null); + eventCheckHelper.loanBalanceChangedEventCheck(loanId); } @When("Customer undo {string}th {string} transaction made on {string}") public void undoNthTransactionType(String nthItemStr, String transactionType, String transactionDate) throws IOException { + eventStore.reset(); DateTimeFormatter formatter = DateTimeFormatter.ofPattern(DATE_FORMAT); Response loanResponse = testContext().get(TestContextKey.LOAN_CREATE_RESPONSE); long loanId = loanResponse.body().getLoanId(); @@ -452,6 +471,7 @@ public void undoNthTransactionType(String nthItemStr, String transactionType, St loanTransactionAdjustmentDataV1 -> loanTransactionAdjustmentDataV1.getTransactionToAdjust().getManuallyReversed()) .isEqualTo(Boolean.TRUE); eventAssertionBuilder.extractingData(LoanTransactionAdjustmentDataV1::getNewTransactionDetail).isEqualTo(null); + eventCheckHelper.loanBalanceChangedEventCheck(loanId); } @Then("Repayment transaction is created with {double} amount and {string} type") @@ -516,6 +536,18 @@ public void adjustNthRepayment(String nthItemStr, String transactionDate, String adjustNthRepaymentWithExternalOwnerCheck(nthItemStr, transactionDate, amount, null); } + @When("Loan Pay-off is made on {string}") + public void makeLoanPayOff(String transactionDate) throws IOException { + Response loanResponse = testContext().get(TestContextKey.LOAN_CREATE_RESPONSE); + long loanId1 = loanResponse.body().getLoanId(); + Response response = loanTransactionsApi + .retrieveTransactionTemplate(loanId1, "prepayLoan", DATE_FORMAT, transactionDate, DEFAULT_LOCALE).execute(); + Double transactionAmount = response.body().getAmount(); + + log.info("%n--- Loan Pay-off with amount: {} ---", transactionAmount); + makeRepayment(DEFAULT_REPAYMENT_TYPE, transactionDate, transactionAmount, null); + } + private void adjustNthRepaymentWithExternalOwnerCheck(String nthItemStr, String transactionDate, String amount, String externalOwnerId) throws IOException { Response loanResponse = testContext().get(TestContextKey.LOAN_CREATE_RESPONSE); @@ -564,16 +596,4 @@ private void adjustNthRepaymentWithExternalOwnerCheck(String nthItemStr, String } } - - @When("Loan Pay-off is made on {string}") - public void makeLoanPayOff(String transactionDate) throws IOException { - Response loanResponse = testContext().get(TestContextKey.LOAN_CREATE_RESPONSE); - long loanId1 = loanResponse.body().getLoanId(); - Response response = loanTransactionsApi - .retrieveTransactionTemplate(loanId1, "prepayLoan", DATE_FORMAT, transactionDate, DEFAULT_LOCALE).execute(); - Double transactionAmount = response.body().getAmount(); - - log.info("--- Loan Pay-off with amount: {} ---", transactionAmount); - makeRepayment("AUTOPAY", transactionDate, transactionAmount, null); - } } diff --git a/fineract-e2e-tests-core/src/test/java/org/apache/fineract/test/stepdef/loan/LoanRescheduleStepDef.java b/fineract-e2e-tests-core/src/test/java/org/apache/fineract/test/stepdef/loan/LoanRescheduleStepDef.java index 8ae467cf955..31c64d90c70 100644 --- a/fineract-e2e-tests-core/src/test/java/org/apache/fineract/test/stepdef/loan/LoanRescheduleStepDef.java +++ b/fineract-e2e-tests-core/src/test/java/org/apache/fineract/test/stepdef/loan/LoanRescheduleStepDef.java @@ -26,6 +26,8 @@ import io.cucumber.java.en.When; import java.io.IOException; import java.math.BigDecimal; +import java.time.LocalDate; +import java.time.format.DateTimeFormatter; import java.util.List; import lombok.extern.slf4j.Slf4j; import org.apache.fineract.client.models.PostCreateRescheduleLoansRequest; @@ -48,6 +50,10 @@ public class LoanRescheduleStepDef extends AbstractStepDef { private static final Gson GSON = new JSON().getGson(); + public static final String DATE_FORMAT_HU = "yyyy-MM-dd"; + public static final String DATE_FORMAT_EN = "dd MMMM yyyy"; + public static final DateTimeFormatter FORMATTER_HU = DateTimeFormatter.ofPattern(DATE_FORMAT_HU); + public static final DateTimeFormatter FORMATTER_EN = DateTimeFormatter.ofPattern(DATE_FORMAT_EN); @Autowired private RescheduleLoansApi rescheduleLoansApi; @@ -59,13 +65,18 @@ public void createAndApproveLoanReschedule(DataTable table) throws IOException { List> data = table.asLists(); List rescheduleData = data.get(1); + String rescheduleFromDate = rescheduleData.get(0); String submittedOnDate = rescheduleData.get(1); String adjustedDueDate = rescheduleData.get(2); - Integer graceOfPrincipal = rescheduleData.get(3) != null ? Integer.parseInt(rescheduleData.get(3)) : null; - Integer graceOnInterest = rescheduleData.get(4) != null ? Integer.parseInt(rescheduleData.get(4)) : null; - Integer extraTerms = rescheduleData.get(5) != null ? Integer.parseInt(rescheduleData.get(5)) : null; - BigDecimal newInterestRate = rescheduleData.get(6) != null ? new BigDecimal(rescheduleData.get(6)) : null; + Integer graceOfPrincipal = (rescheduleData.get(3) == null || "0".equals(rescheduleData.get(3))) ? null + : Integer.valueOf(rescheduleData.get(3)); + Integer graceOnInterest = (rescheduleData.get(4) == null || "0".equals(rescheduleData.get(4))) ? null + : Integer.valueOf(rescheduleData.get(4)); + Integer extraTerms = (rescheduleData.get(5) == null || "0".equals(rescheduleData.get(5))) ? null + : Integer.valueOf(rescheduleData.get(5)); + BigDecimal newInterestRate = (rescheduleData.get(6) == null || "0".equals(rescheduleData.get(6))) ? null + : new BigDecimal(rescheduleData.get(6)); PostCreateRescheduleLoansRequest request = new PostCreateRescheduleLoansRequest()// .loanId(loanId)// @@ -105,10 +116,13 @@ public void createLoanRescheduleError(int errorCodeExpected, String errorMessage String rescheduleFromDate = rescheduleData.get(0); String submittedOnDate = rescheduleData.get(1); String adjustedDueDate = rescheduleData.get(2); - Integer graceOfPrincipal = rescheduleData.get(3) != null ? Integer.parseInt(rescheduleData.get(3)) : null; - Integer graceOnInterest = rescheduleData.get(4) != null ? Integer.parseInt(rescheduleData.get(4)) : null; - Integer extraTerms = rescheduleData.get(5) != null ? Integer.parseInt(rescheduleData.get(5)) : null; - BigDecimal newInterestRate = rescheduleData.get(6) != null ? new BigDecimal(rescheduleData.get(6)) : null; + Integer graceOfPrincipal = (rescheduleData.get(3) == null || "0".equals(rescheduleData.get(3))) ? null + : Integer.valueOf(rescheduleData.get(3)); + Integer graceOnInterest = (rescheduleData.get(4) == null || "0".equals(rescheduleData.get(4))) ? null + : Integer.valueOf(rescheduleData.get(4)); + Integer extraTerms = (rescheduleData.get(5) == null || "0".equals(rescheduleData.get(5))) ? null + : Integer.valueOf(rescheduleData.get(5)); + BigDecimal newInterestRate = rescheduleData.get(6) == null ? null : new BigDecimal(rescheduleData.get(6)); PostCreateRescheduleLoansRequest request = new PostCreateRescheduleLoansRequest()// .loanId(loanId)// @@ -127,7 +141,18 @@ public void createLoanRescheduleError(int errorCodeExpected, String errorMessage Response createResponse = rescheduleLoansApi.createLoanRescheduleRequest(request).execute(); LoanRescheduleErrorMessage loanRescheduleErrorMessage = LoanRescheduleErrorMessage.valueOf(errorMessageType); - String errorMessageExpected = loanRescheduleErrorMessage.getValue(loanId); + + LocalDate localDate = LocalDate.parse(rescheduleFromDate, FORMATTER_EN); + String rescheduleFromDateFormatted = localDate.format(FORMATTER_HU); + String errorMessageExpected = ""; + int expectedParameterCount = loanRescheduleErrorMessage.getExpectedParameterCount(); + if (expectedParameterCount == 1) { + errorMessageExpected = loanRescheduleErrorMessage.getValue(loanId); + } else if (expectedParameterCount == 2) { + errorMessageExpected = loanRescheduleErrorMessage.getValue(rescheduleFromDateFormatted, loanId); + } else { + throw new IllegalStateException("Parameter count in Error message does not met the criteria"); + } String errorToString = createResponse.errorBody().string(); ErrorResponse errorResponse = GSON.fromJson(errorToString, ErrorResponse.class); diff --git a/fineract-e2e-tests-core/src/test/java/org/apache/fineract/test/stepdef/loan/LoanStepDef.java b/fineract-e2e-tests-core/src/test/java/org/apache/fineract/test/stepdef/loan/LoanStepDef.java index b460e117e6a..6fa3f649dfb 100644 --- a/fineract-e2e-tests-core/src/test/java/org/apache/fineract/test/stepdef/loan/LoanStepDef.java +++ b/fineract-e2e-tests-core/src/test/java/org/apache/fineract/test/stepdef/loan/LoanStepDef.java @@ -21,7 +21,7 @@ import static org.apache.fineract.test.data.TransactionProcessingStrategyCode.ADVANCED_PAYMENT_ALLOCATION; import static org.assertj.core.api.Assertions.assertThat; import static org.awaitility.Awaitility.await; -import static org.junit.jupiter.api.Assertions.assertNotNull; +import static org.junit.Assert.assertNotNull; import com.google.gson.Gson; import edu.umd.cs.findbugs.annotations.SuppressFBWarnings; @@ -63,6 +63,7 @@ import org.apache.fineract.client.models.GetLoansLoanIdTransactions; import org.apache.fineract.client.models.GetLoansLoanIdTransactionsTransactionIdResponse; import org.apache.fineract.client.models.IsCatchUpRunningResponse; +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.PostLoansLoanIdResponse; @@ -100,10 +101,13 @@ import org.apache.fineract.test.initializer.global.LoanProductGlobalInitializerStep; import org.apache.fineract.test.messaging.EventAssertion; import org.apache.fineract.test.messaging.event.EventCheckHelper; +import org.apache.fineract.test.messaging.event.loan.LoanRescheduledDueAdjustScheduleEvent; import org.apache.fineract.test.messaging.event.loan.LoanStatusChangedEvent; import org.apache.fineract.test.messaging.event.loan.transaction.LoanAccrualTransactionCreatedBusinessEvent; import org.apache.fineract.test.messaging.event.loan.transaction.LoanChargeOffEvent; import org.apache.fineract.test.messaging.event.loan.transaction.LoanChargeOffUndoEvent; +import org.apache.fineract.test.messaging.event.loan.transaction.LoanTransactionAccrualActivityPostEvent; +import org.apache.fineract.test.messaging.store.EventStore; import org.apache.fineract.test.stepdef.AbstractStepDef; import org.apache.fineract.test.support.TestContextKey; import org.springframework.beans.factory.annotation.Autowired; @@ -117,6 +121,8 @@ public class LoanStepDef extends AbstractStepDef { public static final String DEFAULT_LOCALE = "en"; public static final String LOAN_STATE_SUBMITTED_AND_PENDING = "Submitted and pending approval"; public static final String LOAN_STATE_APPROVED = "Approved"; + public static final String LOAN_STATE_REJECTED = "Rejected"; + public static final String LOAN_STATE_WITHDRAWN = "Withdrawn by applicant"; public static final String LOAN_STATE_ACTIVE = "Active"; private static final Gson GSON = new JSON().getGson(); private static final DateTimeFormatter FORMATTER = DateTimeFormatter.ofPattern(DATE_FORMAT); @@ -149,6 +155,9 @@ public class LoanStepDef extends AbstractStepDef { @Autowired private LoanProductsApi loanProductsApi; + @Autowired + private EventStore eventStore; + @When("Admin creates a new Loan") public void createLoan() throws IOException { Response clientResponse = testContext().get(TestContextKey.CLIENT_CREATE_RESPONSE); @@ -240,6 +249,7 @@ public void createTransactionWithIdempotencyKeyAndWithExternalOwner(String trans private void createTransactionWithIdempotencyKeyAndExternalOwnerCheck(String transactionTypeInput, String transactionPaymentType, String transactionDate, double transactionAmount, String externalOwnerId) throws IOException { + eventStore.reset(); Response loanResponse = testContext().get(TestContextKey.LOAN_CREATE_RESPONSE); long loanId = loanResponse.body().getLoanId(); @@ -262,11 +272,13 @@ private void createTransactionWithIdempotencyKeyAndExternalOwnerCheck(String tra ErrorHelper.checkSuccessfulApiCall(paymentTransactionResponse); eventCheckHelper.transactionEventCheck(paymentTransactionResponse, transactionType, externalOwnerId); + eventCheckHelper.loanBalanceChangedEventCheck(loanId); } @When("Admin makes {string} transaction with {string} payment type on {string} with {double} EUR transaction amount") public void createTransactionForRefund(String transactionTypeInput, String transactionPaymentType, String transactionDate, double transactionAmount) throws IOException, InterruptedException { + eventStore.reset(); Response loanResponse = testContext().get(TestContextKey.LOAN_CREATE_RESPONSE); long loanId = loanResponse.body().getLoanId(); @@ -284,6 +296,7 @@ public void createTransactionForRefund(String transactionTypeInput, String trans ErrorHelper.checkSuccessfulApiCall(paymentTransactionResponse); eventCheckHelper.transactionEventCheck(paymentTransactionResponse, transactionType, null); + eventCheckHelper.loanBalanceChangedEventCheck(loanId); } @When("Customer makes {string} transaction with {string} payment type on {string} with {double} EUR transaction amount and system-generated Idempotency key") @@ -303,6 +316,7 @@ public void createTransactionWithAutoIdempotencyKeyWithExternalOwner(String tran private void createTransactionWithAutoIdempotencyKeyAndWithExternalOwner(String transactionTypeInput, String transactionPaymentType, String transactionDate, double transactionAmount, String externalOwnerId) throws IOException { + eventStore.reset(); Response loanResponse = testContext().get(TestContextKey.LOAN_CREATE_RESPONSE); long loanId = loanResponse.body().getLoanId(); @@ -321,10 +335,12 @@ private void createTransactionWithAutoIdempotencyKeyAndWithExternalOwner(String ErrorHelper.checkSuccessfulApiCall(paymentTransactionResponse); eventCheckHelper.transactionEventCheck(paymentTransactionResponse, transactionType, externalOwnerId); + eventCheckHelper.loanBalanceChangedEventCheck(loanId); } @When("Admin makes Credit Balance Refund transaction on {string} with {double} EUR transaction amount") public void createCBR(String transactionDate, double transactionAmount) throws IOException { + eventStore.reset(); Response loanResponse = testContext().get(TestContextKey.LOAN_CREATE_RESPONSE); long loanId = loanResponse.body().getLoanId(); @@ -337,6 +353,7 @@ public void createCBR(String transactionDate, double transactionAmount) throws I .executeLoanTransaction(loanId, paymentTransactionRequest, transactionTypeValue).execute(); testContext().set(TestContextKey.LOAN_PAYMENT_TRANSACTION_RESPONSE, paymentTransactionResponse); ErrorHelper.checkSuccessfulApiCall(paymentTransactionResponse); + eventCheckHelper.loanBalanceChangedEventCheck(loanId); } @Then("Credit Balance Refund transaction on future date {string} with {double} EUR transaction amount will result an error") @@ -444,7 +461,8 @@ public void createFullyCustomizedLoanFixedLength(int fixedLength, DataTable tabl .expectedDisbursementDate(submitDate)// .graceOnPrincipalPayment(graceOnPrincipalPayment)// .graceOnInterestPayment(graceOnInterestPayment)// - .graceOnInterestPayment(graceOnInterestCharged).transactionProcessingStrategyCode(transactionProcessingStrategyCodeValue)// + .graceOnInterestPayment(graceOnInterestCharged)// + .transactionProcessingStrategyCode(transactionProcessingStrategyCodeValue)// .fixedLength(fixedLength);// Response response = loansApi.calculateLoanScheduleOrSubmitLoanApplication(loansRequest, "").execute(); @@ -454,6 +472,84 @@ public void createFullyCustomizedLoanFixedLength(int fixedLength, DataTable tabl eventCheckHelper.createLoanEventCheck(response); } + @When("Trying to create a fully customized loan with fixed length {int} and with the following data will result a {int} ERROR:") + public void createFullyCustomizedLoanFixedLengthError(int fixedLength, int errorCodeExpected, DataTable table) throws IOException { + List> data = table.asLists(); + List loanData = data.get(1); + String loanProduct = loanData.get(0); + String submitDate = loanData.get(1); + String principal = loanData.get(2); + BigDecimal interestRate = new BigDecimal(loanData.get(3)); + String interestType = loanData.get(4); + String interestCalculationPeriod = loanData.get(5); + String amortizationType = loanData.get(6); + Integer loanTermFrequency = Integer.valueOf(loanData.get(7)); + String loanTermFrequencyType = loanData.get(8); + Integer repaymentFrequency = Integer.valueOf(loanData.get(9)); + String repaymentFrequencyType = loanData.get(10); + Integer numberOfRepayments = Integer.valueOf(loanData.get(11)); + Integer graceOnPrincipalPayment = Integer.valueOf(loanData.get(12)); + Integer graceOnInterestPayment = Integer.valueOf(loanData.get(13)); + Integer graceOnInterestCharged = Integer.valueOf(loanData.get(14)); + String transactionProcessingStrategyCode = loanData.get(15); + + Response clientResponse = testContext().get(TestContextKey.CLIENT_CREATE_RESPONSE); + Long clientId = clientResponse.body().getClientId(); + + DefaultLoanProduct product = DefaultLoanProduct.valueOf(loanProduct); + Long loanProductId = loanProductResolver.resolve(product); + + LoanTermFrequencyType termFrequencyType = LoanTermFrequencyType.valueOf(loanTermFrequencyType); + Integer loanTermFrequencyTypeValue = termFrequencyType.getValue(); + + RepaymentFrequencyType repaymentFrequencyType1 = RepaymentFrequencyType.valueOf(repaymentFrequencyType); + Integer repaymentFrequencyTypeValue = repaymentFrequencyType1.getValue(); + + InterestType interestType1 = InterestType.valueOf(interestType); + Integer interestTypeValue = interestType1.getValue(); + + InterestCalculationPeriodTime interestCalculationPeriod1 = InterestCalculationPeriodTime.valueOf(interestCalculationPeriod); + Integer interestCalculationPeriodValue = interestCalculationPeriod1.getValue(); + + AmortizationType amortizationType1 = AmortizationType.valueOf(amortizationType); + Integer amortizationTypeValue = amortizationType1.getValue(); + + TransactionProcessingStrategyCode processingStrategyCode = TransactionProcessingStrategyCode + .valueOf(transactionProcessingStrategyCode); + String transactionProcessingStrategyCodeValue = processingStrategyCode.getValue(); + + PostLoansRequest loansRequest = loanRequestFactory.defaultLoansRequest(clientId)// + .productId(loanProductId)// + .principal(new BigDecimal(principal))// + .interestRatePerPeriod(interestRate)// + .interestType(interestTypeValue)// + .interestCalculationPeriodType(interestCalculationPeriodValue)// + .amortizationType(amortizationTypeValue)// + .loanTermFrequency(loanTermFrequency)// + .loanTermFrequencyType(loanTermFrequencyTypeValue)// + .numberOfRepayments(numberOfRepayments)// + .repaymentEvery(repaymentFrequency)// + .repaymentFrequencyType(repaymentFrequencyTypeValue)// + .submittedOnDate(submitDate)// + .expectedDisbursementDate(submitDate)// + .graceOnPrincipalPayment(graceOnPrincipalPayment)// + .graceOnInterestPayment(graceOnInterestPayment)// + .graceOnInterestPayment(graceOnInterestCharged)// + .transactionProcessingStrategyCode(transactionProcessingStrategyCodeValue)// + .fixedLength(fixedLength);// + + Response response = loansApi.calculateLoanScheduleOrSubmitLoanApplication(loansRequest, "").execute(); + String errorToString = response.errorBody().string(); + ErrorResponse errorResponse = GSON.fromJson(errorToString, ErrorResponse.class); + String errorMessageActual = errorResponse.getErrors().get(0).getDeveloperMessage(); + int errorCodeActual = response.code(); + + assertThat(errorCodeActual).as(ErrorMessageHelper.wrongErrorCode(errorCodeActual, errorCodeExpected)).isEqualTo(errorCodeExpected); + + log.info("ERROR CODE: {}", errorCodeActual); + log.info("ERROR MESSAGE: {}", errorMessageActual); + } + @When("Admin creates a fully customized loan with Advanced payment allocation and with product no Advanced payment allocation set results an error:") public void createFullyCustomizedLoanNoAdvancedPaymentError(DataTable table) throws IOException { int errorCodeExpected = 403; @@ -519,7 +615,8 @@ public void createFullyCustomizedLoanNoAdvancedPaymentError(DataTable table) thr .expectedDisbursementDate(submitDate)// .graceOnPrincipalPayment(graceOnPrincipalPayment)// .graceOnInterestPayment(graceOnInterestPayment)// - .graceOnInterestPayment(graceOnInterestCharged).transactionProcessingStrategyCode(transactionProcessingStrategyCodeValue);// + .graceOnInterestPayment(graceOnInterestCharged)// + .transactionProcessingStrategyCode(transactionProcessingStrategyCodeValue);// Response response = loansApi.calculateLoanScheduleOrSubmitLoanApplication(loansRequest, "").execute(); int errorCodeActual = response.code(); @@ -535,6 +632,79 @@ public void createFullyCustomizedLoanNoAdvancedPaymentError(DataTable table) thr log.info("ERROR MESSAGE: {}", errorMessageActual); } + @When("Admin creates a fully customized loan with installment level delinquency and with the following data:") + public void createFullyCustomizedLoanWithInstallmentLvlDelinquency(DataTable table) throws IOException { + List> data = table.asLists(); + List loanData = data.get(1); + String loanProduct = loanData.get(0); + String submitDate = loanData.get(1); + String principal = loanData.get(2); + BigDecimal interestRate = new BigDecimal(loanData.get(3)); + String interestType = loanData.get(4); + String interestCalculationPeriod = loanData.get(5); + String amortizationType = loanData.get(6); + Integer loanTermFrequency = Integer.valueOf(loanData.get(7)); + String loanTermFrequencyType = loanData.get(8); + Integer repaymentFrequency = Integer.valueOf(loanData.get(9)); + String repaymentFrequencyType = loanData.get(10); + Integer numberOfRepayments = Integer.valueOf(loanData.get(11)); + Integer graceOnPrincipalPayment = Integer.valueOf(loanData.get(12)); + Integer graceOnInterestPayment = Integer.valueOf(loanData.get(13)); + Integer graceOnInterestCharged = Integer.valueOf(loanData.get(14)); + String transactionProcessingStrategyCode = loanData.get(15); + + Response clientResponse = testContext().get(TestContextKey.CLIENT_CREATE_RESPONSE); + Long clientId = clientResponse.body().getClientId(); + + DefaultLoanProduct product = DefaultLoanProduct.valueOf(loanProduct); + Long loanProductId = loanProductResolver.resolve(product); + + LoanTermFrequencyType termFrequencyType = LoanTermFrequencyType.valueOf(loanTermFrequencyType); + Integer loanTermFrequencyTypeValue = termFrequencyType.getValue(); + + RepaymentFrequencyType repaymentFrequencyType1 = RepaymentFrequencyType.valueOf(repaymentFrequencyType); + Integer repaymentFrequencyTypeValue = repaymentFrequencyType1.getValue(); + + InterestType interestType1 = InterestType.valueOf(interestType); + Integer interestTypeValue = interestType1.getValue(); + + InterestCalculationPeriodTime interestCalculationPeriod1 = InterestCalculationPeriodTime.valueOf(interestCalculationPeriod); + Integer interestCalculationPeriodValue = interestCalculationPeriod1.getValue(); + + AmortizationType amortizationType1 = AmortizationType.valueOf(amortizationType); + Integer amortizationTypeValue = amortizationType1.getValue(); + + TransactionProcessingStrategyCode processingStrategyCode = TransactionProcessingStrategyCode + .valueOf(transactionProcessingStrategyCode); + String transactionProcessingStrategyCodeValue = processingStrategyCode.getValue(); + + PostLoansRequest loansRequest = loanRequestFactory.defaultLoansRequest(clientId)// + .productId(loanProductId)// + .principal(new BigDecimal(principal))// + .interestRatePerPeriod(interestRate)// + .interestType(interestTypeValue)// + .interestCalculationPeriodType(interestCalculationPeriodValue)// + .amortizationType(amortizationTypeValue)// + .loanTermFrequency(loanTermFrequency)// + .loanTermFrequencyType(loanTermFrequencyTypeValue)// + .numberOfRepayments(numberOfRepayments)// + .repaymentEvery(repaymentFrequency)// + .repaymentFrequencyType(repaymentFrequencyTypeValue)// + .submittedOnDate(submitDate)// + .expectedDisbursementDate(submitDate)// + .graceOnPrincipalPayment(graceOnPrincipalPayment)// + .graceOnInterestPayment(graceOnInterestPayment)// + .graceOnInterestPayment(graceOnInterestCharged)// + .transactionProcessingStrategyCode(transactionProcessingStrategyCodeValue)// + .enableInstallmentLevelDelinquency(true);// + + Response response = loansApi.calculateLoanScheduleOrSubmitLoanApplication(loansRequest, "").execute(); + testContext().set(TestContextKey.LOAN_CREATE_RESPONSE, response); + ErrorHelper.checkSuccessfulApiCall(response); + + eventCheckHelper.createLoanEventCheck(response); + } + @Then("Loan details has the following last payment related data:") public void checkLastPaymentData(DataTable table) throws IOException { List> data = table.asLists(); @@ -730,6 +900,37 @@ public void approveLoan(String approveDate, String approvedAmount, String expect eventCheckHelper.approveLoanEventCheck(loanApproveResponse); } + @And("Admin successfully rejects the loan on {string}") + public void rejectLoan(String rejectDate) throws IOException { + Response loanResponse = testContext().get(TestContextKey.LOAN_CREATE_RESPONSE); + long loanId = loanResponse.body().getLoanId(); + PostLoansLoanIdRequest rejectRequest = LoanRequestFactory.defaultLoanRejectRequest().rejectedOnDate(rejectDate); + + Response loanRejectResponse = loansApi.stateTransitions(loanId, rejectRequest, "reject").execute(); + testContext().set(TestContextKey.LOAN_REJECT_RESPONSE, loanRejectResponse); + ErrorHelper.checkSuccessfulApiCall(loanRejectResponse); + assertThat(loanRejectResponse.body().getChanges().getStatus().getValue()).isEqualTo(LOAN_STATE_REJECTED); + assertThat(loanRejectResponse.body().getChanges().getStatus().getValue()).isEqualTo(LOAN_STATE_REJECTED); + + eventCheckHelper.loanRejectedEventCheck(loanRejectResponse); + } + + @And("Admin successfully withdrawn the loan on {string}") + public void withdrawnLoan(String withdrawnDate) throws IOException { + Response loanResponse = testContext().get(TestContextKey.LOAN_CREATE_RESPONSE); + long loanId = loanResponse.body().getLoanId(); + PostLoansLoanIdRequest withdawnRequest = LoanRequestFactory.defaultLoanWithdrawnRequest().withdrawnOnDate(withdrawnDate); + + Response loanWithdrawnResponse = loansApi.stateTransitions(loanId, withdawnRequest, "withdrawnByApplicant") + .execute(); + testContext().set(TestContextKey.LOAN_WITHDRAWN_RESPONSE, loanWithdrawnResponse); + ErrorHelper.checkSuccessfulApiCall(loanWithdrawnResponse); + assertThat(loanWithdrawnResponse.body().getChanges().getStatus().getValue()).isEqualTo(LOAN_STATE_WITHDRAWN); + assertThat(loanWithdrawnResponse.body().getChanges().getStatus().getValue()).isEqualTo(LOAN_STATE_WITHDRAWN); + + eventCheckHelper.undoApproveLoanEventCheck(loanWithdrawnResponse); + } + @And("Admin successfully approves the second loan on {string} with {string} amount and expected disbursement date on {string}") public void approveSecondLoan(String approveDate, String approvedAmount, String expectedDisbursementDate) throws IOException { Response loanResponse = testContext().get(TestContextKey.LOAN_CREATE_SECOND_LOAN_RESPONSE); @@ -785,10 +986,31 @@ public void failedLoanApproveWithAmount(String approveDate, String approvedAmoun @And("Admin successfully disburse the loan on {string} with {string} EUR transaction amount") public void disburseLoan(String actualDisbursementDate, String transactionAmount) throws IOException { - final Response loanResponse = testContext().get(TestContextKey.LOAN_CREATE_RESPONSE); - assertNotNull(loanResponse.body()); - final long loanId = loanResponse.body().getLoanId(); - final PostLoansLoanIdRequest disburseRequest = LoanRequestFactory.defaultLoanDisburseRequest() + Response loanResponse = testContext().get(TestContextKey.LOAN_CREATE_RESPONSE); + long loanId = loanResponse.body().getLoanId(); + PostLoansLoanIdRequest disburseRequest = LoanRequestFactory.defaultLoanDisburseRequest() + .actualDisbursementDate(actualDisbursementDate).transactionAmount(new BigDecimal(transactionAmount)); + + Response loanDisburseResponse = loansApi.stateTransitions(loanId, disburseRequest, "disburse").execute(); + testContext().set(TestContextKey.LOAN_DISBURSE_RESPONSE, loanDisburseResponse); + ErrorHelper.checkSuccessfulApiCall(loanDisburseResponse); + Long statusActual = loanDisburseResponse.body().getChanges().getStatus().getId(); + + Response loanDetails = loansApi.retrieveLoan(loanId, false, "", "", "").execute(); + Long statusExpected = Long.valueOf(loanDetails.body().getStatus().getId()); + + assertThat(statusActual)// + .as(ErrorMessageHelper.wrongLoanStatus(Math.toIntExact(statusActual), Math.toIntExact(statusExpected)))// + .isEqualTo(statusExpected);// + eventCheckHelper.disburseLoanEventCheck(loanId); + eventCheckHelper.loanDisbursalTransactionEventCheck(loanDisburseResponse); + } + + @And("Admin successfully disburse the loan without auto downpayment on {string} with {string} EUR transaction amount") + public void disburseLoanWithoutAutoDownpayment(String actualDisbursementDate, String transactionAmount) throws IOException { + Response loanResponse = testContext().get(TestContextKey.LOAN_CREATE_RESPONSE); + long loanId = loanResponse.body().getLoanId(); + PostLoansLoanIdRequest disburseRequest = LoanRequestFactory.defaultLoanDisburseRequest() .actualDisbursementDate(actualDisbursementDate).transactionAmount(new BigDecimal(transactionAmount)); performLoanDisbursementAndVerifyStatus(loanId, disburseRequest); } @@ -829,7 +1051,7 @@ public void disburseSecondLoan(String actualDisbursementDate, String transaction ErrorHelper.checkSuccessfulApiCall(loanDisburseResponse); assertThat(loanDisburseResponse.body().getChanges().getStatus().getValue()).isEqualTo(LOAN_STATE_ACTIVE); - eventCheckHelper.disburseLoanEventCheck(loanDisburseResponse); + eventCheckHelper.disburseLoanEventCheck(loanId); eventCheckHelper.loanDisbursalTransactionEventCheck(loanDisburseResponse); } @@ -1141,10 +1363,13 @@ public void loanTransactionsTabCheck(DataTable table) throws IOException { List> data = table.asLists(); for (int i = 1; i < data.size(); i++) { List expectedValues = data.get(i); + String transactionDateExpected = expectedValues.get(0); List> actualValuesList = transactions.stream()// + .filter(t -> transactionDateExpected.equals(FORMATTER.format(t.getDate())))// .map(t -> fetchValuesOfTransaction(table.row(0), t))// .collect(Collectors.toList());// - boolean containsExpectedValues = actualValuesList.get(i - 1).equals(expectedValues);// + boolean containsExpectedValues = actualValuesList.stream()// + .anyMatch(actualValues -> actualValues.equals(expectedValues));// assertThat(containsExpectedValues).as(ErrorMessageHelper.wrongValueInLineInTransactionsTab(i, actualValuesList, expectedValues)) .isTrue(); } @@ -1319,7 +1544,7 @@ public void loanInstallmentsObligationsMet() throws IOException { assertThat(allInstallmentsObligationsMet).isTrue(); } - @Then("Loan closedon_date is {}") + @Then("Loan closedon_date is {string}") public void loanClosedonDate(String date) throws IOException { Response loanCreateResponse = testContext().get(TestContextKey.LOAN_CREATE_RESPONSE); long loanId = loanCreateResponse.body().getLoanId(); @@ -1327,10 +1552,10 @@ public void loanClosedonDate(String date) throws IOException { Response loanDetailsResponse = loansApi.retrieveLoan(loanId, false, "", "", "").execute(); ErrorHelper.checkSuccessfulApiCall(loanDetailsResponse); testContext().set(TestContextKey.LOAN_RESPONSE, loanDetailsResponse); - if (date == null || "null".equals(date)) { + if ("null".equals(date)) { assertThat(loanDetailsResponse.body().getTimeline().getClosedOnDate()).isNull(); } else { - assertThat(loanDetailsResponse.body().getTimeline().getClosedOnDate()).isEqualTo(date); + assertThat(FORMATTER.format(loanDetailsResponse.body().getTimeline().getClosedOnDate())).isEqualTo(date); } } @@ -1555,7 +1780,7 @@ public void checkLoanCOBCatchUpRunningUntilCOBBusinessDate() { IsCatchUpRunningResponse isCatchUpRunning = isCatchUpRunningResponse.body(); return isCatchUpRunning.getIsCatchUpRunning(); }); - await().pollInterval(2, TimeUnit.SECONDS).atMost(Duration.ofSeconds(240)).until(() -> { + await().pollInterval(2, TimeUnit.SECONDS).atMost(Duration.ofMinutes(4)).until(() -> { Response isCatchUpRunningResponse = loanCobCatchUpApi.isCatchUpRunning().execute(); ErrorHelper.checkSuccessfulApiCall(isCatchUpRunningResponse); IsCatchUpRunningResponse isCatchUpRunning = isCatchUpRunningResponse.body(); @@ -1596,6 +1821,31 @@ public void checkLoanAccrualTransactionCreatedBusinessEvent(String date) throws eventAssertion.assertEventRaised(LoanAccrualTransactionCreatedBusinessEvent.class, accrualTransactionId); } + @Then("LoanTransactionAccrualActivityPostBusinessEvent is raised on {string}") + public void checkLoanTransactionAccrualActivityPostBusinessEvent(String date) throws IOException { + Response loanCreateResponse = testContext().get(TestContextKey.LOAN_CREATE_RESPONSE); + long loanId = loanCreateResponse.body().getLoanId(); + + Response loanDetailsResponse = loansApi.retrieveLoan(loanId, false, "transactions", "", "").execute(); + ErrorHelper.checkSuccessfulApiCall(loanDetailsResponse); + + List transactions = loanDetailsResponse.body().getTransactions(); + GetLoansLoanIdTransactions accrualTransaction = transactions.stream() + .filter(t -> date.equals(FORMATTER.format(t.getDate())) && "Accrual Activity".equals(t.getType().getValue())).findFirst() + .orElseThrow(() -> new IllegalStateException(String.format("No Accrual activity transaction found on %s", date))); + Long accrualTransactionId = accrualTransaction.getId(); + + eventAssertion.assertEventRaised(LoanTransactionAccrualActivityPostEvent.class, accrualTransactionId); + } + + @Then("LoanRescheduledDueAdjustScheduleBusinessEvent is raised on {string}") + public void checkLoanRescheduledDueAdjustScheduleBusinessEvent(String date) throws IOException { + Response loanCreateResponse = testContext().get(TestContextKey.LOAN_CREATE_RESPONSE); + long loanId = loanCreateResponse.body().getLoanId(); + + eventAssertion.assertEventRaised(LoanRescheduledDueAdjustScheduleEvent.class, loanId); + } + @Then("Loan details and event has the following last repayment related data:") public void checkLastRepaymentData(DataTable table) throws IOException { List> data = table.asLists(); @@ -1649,7 +1899,6 @@ public void checkLastRepaymentData(DataTable table) throws IOException { return null; }); - } @And("Admin does a charge-off undo the loan with reversal external Id") @@ -1741,7 +1990,7 @@ public void editFutureInstallmentAllocationTypeForLoanProduct(String loanProduct String futureInstallmentAllocationRuleNew) throws IOException { DefaultLoanProduct product = DefaultLoanProduct.valueOf(loanProductName); Long loanProductId = loanProductResolver.resolve(product); - log.info("loanProductId {}", loanProductId); + log.info("loanProductId: {}", loanProductId); Response loanProductDetails = loanProductsApi.retrieveLoanProductDetails(loanProductId).execute(); ErrorHelper.checkSuccessfulApiCall(loanProductDetails); @@ -1751,11 +2000,12 @@ public void editFutureInstallmentAllocationTypeForLoanProduct(String loanProduct paymentAllocation.forEach(e -> { String transactionTypeOriginal = e.getTransactionType(); String futureInstallmentAllocationRule = e.getFutureInstallmentAllocationRule(); + List paymentAllocationOrder = e.getPaymentAllocationOrder(); if (transactionTypeToChange.equals(transactionTypeOriginal)) { futureInstallmentAllocationRule = futureInstallmentAllocationRuleNew; } - newPaymentAllocation.add( - LoanProductGlobalInitializerStep.createPaymentAllocation(transactionTypeOriginal, futureInstallmentAllocationRule)); + newPaymentAllocation.add(LoanProductGlobalInitializerStep.editPaymentAllocationFutureInstallment(transactionTypeOriginal, + futureInstallmentAllocationRule, paymentAllocationOrder)); }); PutLoanProductsProductIdRequest putLoanProductsProductIdRequest = new PutLoanProductsProductIdRequest() @@ -1770,7 +2020,7 @@ public void editFutureInstallmentAllocationTypeForLoanProduct(String loanProduct public void editRepaymentStartDateType(String loanProductName, String repaymentStartDateType) throws IOException { DefaultLoanProduct product = DefaultLoanProduct.valueOf(loanProductName); Long loanProductId = loanProductResolver.resolve(product); - log.info("loanProductId {}", loanProductId); + log.info("loanProductId: {}", loanProductId); Map repaymentStartDateTypeMap = Map.of("DISBURSEMENT_DATE", 1, "SUBMITTED_ON_DATE", 2); @@ -1822,7 +2072,6 @@ public void undoTransaction(String nthTransaction, String transactionDate) throw .adjustLoanTransaction(loanId, targetTransaction.getId(), transactionUndoRequest, "").execute(); ErrorResponse errorDetails = ErrorResponse.from(transactionUndoResponse); assertThat(errorDetails.getHttpStatusCode()).as(ErrorMessageHelper.dateFailureErrorCodeMsg()).isEqualTo(503); - } @Then("Loan {string} repayment transaction on {string} with {double} EUR transaction amount results in error") @@ -1843,7 +2092,6 @@ public void loanTransactionWithErrorCheck(String repaymentType, String transacti ErrorResponse errorDetails = ErrorResponse.from(repaymentResponse); assertThat(errorDetails.getHttpStatusCode()).as(ErrorMessageHelper.dateFailureErrorCodeMsg()).isEqualTo(400); - } @Then("Loan details has the downpayment amount {string} in summary.totalRepaymentTransaction") @@ -2036,7 +2284,7 @@ private void performLoanDisbursementAndVerifyStatus(final long loanId, final Pos assertThat(statusActual).as(ErrorMessageHelper.wrongLoanStatus(Math.toIntExact(statusActual), Math.toIntExact(statusExpected))) .isEqualTo(statusExpected); - eventCheckHelper.disburseLoanEventCheck(loanDisburseResponse); + eventCheckHelper.disburseLoanEventCheck(loanId); eventCheckHelper.loanDisbursalTransactionEventCheck(loanDisburseResponse); } @@ -2114,7 +2362,6 @@ private LoanStatusEnumDataV1 getExpectedStatus(String loanStatus) { return result; } - @SuppressFBWarnings("SF_SWITCH_NO_DEFAULT") private List fetchValuesOfTransaction(List header, GetLoansLoanIdTransactions t) { List actualValues = new ArrayList<>(); for (String headerName : header) { @@ -2132,12 +2379,16 @@ private List fetchValuesOfTransaction(List header, GetLoansLoanI case "Overpayment" -> actualValues.add(t.getOverpaymentPortion() == null ? null : String.valueOf(t.getOverpaymentPortion())); case "Reverted" -> actualValues.add(t.getManuallyReversed() == null ? null : String.valueOf(t.getManuallyReversed())); + case "Replayed" -> { + boolean hasReplayed = t.getTransactionRelations().stream().anyMatch(e -> "REPLAYED".equals(e.getRelationType())); + actualValues.add(hasReplayed ? "true" : "false"); + } + default -> throw new IllegalStateException(String.format("Header name %s cannot be found", headerName)); } } return actualValues; } - @SuppressFBWarnings("SF_SWITCH_NO_DEFAULT") private List fetchValuesOfRepaymentSchedule(List header, GetLoansLoanIdRepaymentPeriod repaymentPeriod) { List actualValues = new ArrayList<>(); for (String headerName : header) { @@ -2171,6 +2422,7 @@ private List fetchValuesOfRepaymentSchedule(List header, GetLoan : String.valueOf(repaymentPeriod.getTotalWaivedForPeriod())); case "Outstanding" -> actualValues.add(repaymentPeriod.getTotalOutstandingForPeriod() == null ? null : String.valueOf(repaymentPeriod.getTotalOutstandingForPeriod())); + default -> throw new IllegalStateException(String.format("Header name %s cannot be found", headerName)); } } return actualValues; diff --git a/fineract-e2e-tests-core/src/test/java/org/apache/fineract/test/stepdef/saving/SavingsAccountStepDef.java b/fineract-e2e-tests-core/src/test/java/org/apache/fineract/test/stepdef/saving/SavingsAccountStepDef.java new file mode 100644 index 00000000000..6a66a162e3e --- /dev/null +++ b/fineract-e2e-tests-core/src/test/java/org/apache/fineract/test/stepdef/saving/SavingsAccountStepDef.java @@ -0,0 +1,184 @@ +/** + * 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.test.stepdef.saving; + +import io.cucumber.java.en.And; +import java.io.IOException; +import java.math.BigDecimal; +import org.apache.fineract.client.models.PostClientsResponse; +import org.apache.fineract.client.models.PostSavingsAccountTransactionsRequest; +import org.apache.fineract.client.models.PostSavingsAccountTransactionsResponse; +import org.apache.fineract.client.models.PostSavingsAccountsAccountIdRequest; +import org.apache.fineract.client.models.PostSavingsAccountsAccountIdResponse; +import org.apache.fineract.client.models.PostSavingsAccountsRequest; +import org.apache.fineract.client.models.PostSavingsAccountsResponse; +import org.apache.fineract.client.services.SavingsAccountApi; +import org.apache.fineract.client.services.SavingsAccountTransactionsApi; +import org.apache.fineract.test.factory.SavingsAccountRequestFactory; +import org.apache.fineract.test.stepdef.AbstractStepDef; +import org.apache.fineract.test.support.TestContextKey; +import org.springframework.beans.factory.annotation.Autowired; +import retrofit2.Response; + +public class SavingsAccountStepDef extends AbstractStepDef { + + @Autowired + private SavingsAccountTransactionsApi savingsAccountTransactionsApi; + + @Autowired + private SavingsAccountApi savingsAccountApi; + + @And("Client creates a new EUR savings account with {string} submitted on date") + public void createSavingsAccountEUR(String submittedOnDate) throws IOException { + Response clientResponse = testContext().get(TestContextKey.CLIENT_CREATE_RESPONSE); + long clientId = clientResponse.body().getClientId(); + + PostSavingsAccountsRequest createSavingsAccountRequest = SavingsAccountRequestFactory.defaultEURSavingsAccountRequest() + .clientId((int) clientId).submittedOnDate(submittedOnDate); + + Response createSavingsAccountResponse = savingsAccountApi + .submitApplication2(createSavingsAccountRequest).execute(); + testContext().set(TestContextKey.EUR_SAVINGS_ACCOUNT_CREATE_RESPONSE, createSavingsAccountResponse); + } + + @And("Client creates a new USD savings account with {string} submitted on date") + public void createSavingsAccountUSD(String submittedOnDate) throws IOException { + Response clientResponse = testContext().get(TestContextKey.CLIENT_CREATE_RESPONSE); + long clientId = clientResponse.body().getClientId(); + + PostSavingsAccountsRequest createSavingsAccountRequest = SavingsAccountRequestFactory.defaultUSDSavingsAccountRequest() + .clientId((int) clientId).submittedOnDate(submittedOnDate); + + Response createSavingsAccountResponse = savingsAccountApi + .submitApplication2(createSavingsAccountRequest).execute(); + testContext().set(TestContextKey.USD_SAVINGS_ACCOUNT_CREATE_RESPONSE, createSavingsAccountResponse); + } + + @And("Approve EUR savings account on {string} date") + public void approveEurSavingsAccount(String approvedOnDate) throws IOException { + Response savingsAccountResponse = testContext() + .get(TestContextKey.EUR_SAVINGS_ACCOUNT_CREATE_RESPONSE); + long savingsAccountID = savingsAccountResponse.body().getSavingsId(); + + PostSavingsAccountsAccountIdRequest approveSavingsAccountRequest = SavingsAccountRequestFactory.defaultApproveRequest() + .approvedOnDate(approvedOnDate); + + Response approveSavingsAccountResponse = savingsAccountApi + .handleCommands6(savingsAccountID, approveSavingsAccountRequest, "approve").execute(); + testContext().set(TestContextKey.EUR_SAVINGS_ACCOUNT_APPROVE_RESPONSE, approveSavingsAccountResponse); + } + + @And("Approve USD savings account on {string} date") + public void approveUsdSavingsAccount(String approvedOnDate) throws IOException { + Response savingsAccountResponse = testContext() + .get(TestContextKey.USD_SAVINGS_ACCOUNT_CREATE_RESPONSE); + long savingsAccountID = savingsAccountResponse.body().getSavingsId(); + + PostSavingsAccountsAccountIdRequest approveSavingsAccountRequest = SavingsAccountRequestFactory.defaultApproveRequest() + .approvedOnDate(approvedOnDate); + + Response approveSavingsAccountResponse = savingsAccountApi + .handleCommands6(savingsAccountID, approveSavingsAccountRequest, "approve").execute(); + testContext().set(TestContextKey.USD_SAVINGS_ACCOUNT_APPROVE_RESPONSE, approveSavingsAccountResponse); + } + + @And("Activate EUR savings account on {string} date") + public void activateSavingsAccount(String activatedOnDate) throws IOException { + Response savingsAccountResponse = testContext() + .get(TestContextKey.EUR_SAVINGS_ACCOUNT_CREATE_RESPONSE); + long savingsAccountID = savingsAccountResponse.body().getSavingsId(); + + PostSavingsAccountsAccountIdRequest activateSavingsAccountRequest = SavingsAccountRequestFactory.defaultActivateRequest() + .activatedOnDate(activatedOnDate); + + Response activateSavingsAccountResponse = savingsAccountApi + .handleCommands6(savingsAccountID, activateSavingsAccountRequest, "activate").execute(); + testContext().set(TestContextKey.EUR_SAVINGS_ACCOUNT_ACTIVATED_RESPONSE, activateSavingsAccountResponse); + } + + @And("Activate USD savings account on {string} date") + public void activateUsdSavingsAccount(String activatedOnDate) throws IOException { + Response savingsAccountResponse = testContext() + .get(TestContextKey.USD_SAVINGS_ACCOUNT_CREATE_RESPONSE); + long savingsAccountID = savingsAccountResponse.body().getSavingsId(); + + PostSavingsAccountsAccountIdRequest activateSavingsAccountRequest = SavingsAccountRequestFactory.defaultActivateRequest() + .activatedOnDate(activatedOnDate); + + Response activateSavingsAccountResponse = savingsAccountApi + .handleCommands6(savingsAccountID, activateSavingsAccountRequest, "activate").execute(); + testContext().set(TestContextKey.USD_SAVINGS_ACCOUNT_ACTIVATED_RESPONSE, activateSavingsAccountResponse); + } + + @And("Client successfully deposits {double} EUR to the savings account on {string} date") + public void createEurDeposit(double depositAmount, String depositDate) throws IOException { + Response savingsAccountResponse = testContext() + .get(TestContextKey.EUR_SAVINGS_ACCOUNT_CREATE_RESPONSE); + long savingsAccountID = savingsAccountResponse.body().getSavingsId(); + + PostSavingsAccountTransactionsRequest depositRequest = SavingsAccountRequestFactory.defaultDepositRequest() + .transactionDate(depositDate).transactionAmount(BigDecimal.valueOf(depositAmount)); + + Response depositResponse = savingsAccountTransactionsApi + .transaction2(savingsAccountID, depositRequest, "deposit").execute(); + testContext().set(TestContextKey.EUR_SAVINGS_ACCOUNT_DEPOSIT_RESPONSE, depositResponse); + } + + @And("Client successfully deposits {double} USD to the savings account on {string} date") + public void createUsdDeposit(double depositAmount, String depositDate) throws IOException { + Response savingsAccountResponse = testContext() + .get(TestContextKey.USD_SAVINGS_ACCOUNT_CREATE_RESPONSE); + long savingsAccountID = savingsAccountResponse.body().getSavingsId(); + + PostSavingsAccountTransactionsRequest depositRequest = SavingsAccountRequestFactory.defaultDepositRequest() + .transactionDate(depositDate).transactionAmount(BigDecimal.valueOf(depositAmount)); + + Response depositResponse = savingsAccountTransactionsApi + .transaction2(savingsAccountID, depositRequest, "deposit").execute(); + testContext().set(TestContextKey.USD_SAVINGS_ACCOUNT_DEPOSIT_RESPONSE, depositResponse); + } + + @And("Client successfully withdraw {double} EUR from the savings account on {string} date") + public void createEurWithdraw(double withdrawAmount, String transcationDate) throws IOException { + Response savingsAccountResponse = testContext() + .get(TestContextKey.EUR_SAVINGS_ACCOUNT_CREATE_RESPONSE); + long savingsAccountID = savingsAccountResponse.body().getSavingsId(); + + PostSavingsAccountTransactionsRequest withdrawRequest = SavingsAccountRequestFactory.defaultWithdrawRequest() + .transactionDate(transcationDate).transactionAmount(BigDecimal.valueOf(withdrawAmount)); + + Response withdrawalResponse = savingsAccountTransactionsApi + .transaction2(savingsAccountID, withdrawRequest, "withdrawal").execute(); + testContext().set(TestContextKey.EUR_SAVINGS_ACCOUNT_WITHDRAW_RESPONSE, withdrawalResponse); + } + + @And("Client successfully withdraw {double} USD from the savings account on {string} date") + public void createUsdWithdraw(double withdrawAmount, String transcationDate) throws IOException { + Response savingsAccountResponse = testContext() + .get(TestContextKey.USD_SAVINGS_ACCOUNT_CREATE_RESPONSE); + long savingsAccountID = savingsAccountResponse.body().getSavingsId(); + + PostSavingsAccountTransactionsRequest withdrawRequest = SavingsAccountRequestFactory.defaultWithdrawRequest() + .transactionDate(transcationDate).transactionAmount(BigDecimal.valueOf(withdrawAmount)); + + Response withdrawalResponse = savingsAccountTransactionsApi + .transaction2(savingsAccountID, withdrawRequest, "withdrawal").execute(); + testContext().set(TestContextKey.USD_SAVINGS_ACCOUNT_WITHDRAW_RESPONSE, withdrawalResponse); + } +} diff --git a/fineract-e2e-tests-core/src/test/java/org/apache/fineract/test/support/TestContext.java b/fineract-e2e-tests-core/src/test/java/org/apache/fineract/test/support/TestContext.java index f9beda2a56b..91ec17a93c0 100644 --- a/fineract-e2e-tests-core/src/test/java/org/apache/fineract/test/support/TestContext.java +++ b/fineract-e2e-tests-core/src/test/java/org/apache/fineract/test/support/TestContext.java @@ -25,7 +25,8 @@ public enum TestContext { - INSTANCE; + INSTANCE, // + GLOBAL;// @SuppressWarnings("ImmutableEnumChecker") private final ThreadLocal> testContexts = withInitial(HashMap::new); diff --git a/fineract-e2e-tests-core/src/test/java/org/apache/fineract/test/support/TestContextKey.java b/fineract-e2e-tests-core/src/test/java/org/apache/fineract/test/support/TestContextKey.java index 211947497ba..0502844ce86 100644 --- a/fineract-e2e-tests-core/src/test/java/org/apache/fineract/test/support/TestContextKey.java +++ b/fineract-e2e-tests-core/src/test/java/org/apache/fineract/test/support/TestContextKey.java @@ -24,6 +24,7 @@ @NoArgsConstructor(access = AccessLevel.PRIVATE) public abstract class TestContextKey { + public static final String ORIGINAL_COB_WORKFLOW_JOB_BUSINESS_STEP_LIST = "originalCOBWorkflowJobBusinessStepList"; public static final String CLIENT_CREATE_RESPONSE = "clientCreateResponse"; public static final String CLIENT_CREATE_SECOND_CLIENT_RESPONSE = "clientCreateSecondClientResponse"; public static final String LOAN_CREATE_RESPONSE = "loanCreateResponse"; @@ -35,6 +36,8 @@ public abstract class TestContextKey { public static final String WAIVE_CHARGE_RESPONSE = "waiveChargeResponse"; public static final String UNDO_WAIVE_RESPONSE = "waiveNsfFeeResponse"; public static final String LOAN_APPROVAL_RESPONSE = "loanApprovalResponse"; + public static final String LOAN_REJECT_RESPONSE = "loanRejectResponse"; + public static final String LOAN_WITHDRAWN_RESPONSE = "loanWithdrawnResponse"; public static final String LOAN_APPROVAL_SECOND_LOAN_RESPONSE = "loanApprovalSecondLoanResponse"; public static final String LOAN_UNDO_APPROVAL_RESPONSE = "loanUndoApprovalResponse"; public static final String LOAN_DISBURSE_RESPONSE = "loanDisburseResponse"; @@ -61,27 +64,44 @@ public abstract class TestContextKey { public static final String DEFAULT_LOAN_PRODUCT_CREATE_RESPONSE_LP1_INTEREST_DECLINING_PERIOD_SAME_AS_PAYMENT = "loanProductCreateResponseLP1InterestDecliningPeriodSameAsPayment"; public static final String DEFAULT_LOAN_PRODUCT_CREATE_RESPONSE_LP1_1MONTH_INTEREST_DECLINING_BALANCE_DAILY_RECALCULATION_COMPOUNDING_MONTHLY = "loanProductCreateResponseLP1InterestDecliningPeriodSameAsPaymentRecalculation"; public static final String DEFAULT_LOAN_PRODUCT_CREATE_RESPONSE_LP1_INTEREST_DECLINING_BALANCE_DAILY_RECALCULATION_COMPOUNDING_NONE = "loanProductCreateResponseLP1InterestDecliningBalanceDailyRecalculationCompoundingNone"; - public static final String DEFAULT_LOAN_PRODUCT_CREATE_RESPONSE_LP2_ADVANCED_CUSTOM_PAYMENT_ALLOCATION_PROGRESSIVE_LOAN_SCHEDULE = "loanProductCreateResponseLP2ProgressiveLoanScheduleCustomPaymentAllocation"; public static final String DEFAULT_LOAN_PRODUCT_CREATE_RESPONSE_LP1_INTEREST_DECLINING_BALANCE_DAILY_RECALCULATION_SAME_AS_REPAYMENT_COMPOUNDING_NONE = "loanProductCreateResponseLP1InterestDecliningBalanceDailyRecalculationSameAsRepaymentCompoundingNone"; public static final String DEFAULT_LOAN_PRODUCT_CREATE_RESPONSE_LP1_INTEREST_DECLINING_BALANCE_SAR_RECALCULATION_SAME_AS_REPAYMENT_COMPOUNDING_NONE_MULTI_DISBURSEMENT = "loanProductCreateResponseLP1InterestDecliningBalanceDailyRecalculationSameAsRepaymentCompoundingNoneMultiDisbursement"; public static final String DEFAULT_LOAN_PRODUCT_CREATE_RESPONSE_LP1_INTEREST_DECLINING_BALANCE_DAILY_RECALCULATION_COMPOUNDING_NONE_RESCHEDULE_REDUCE_NR_INSTALLMENTS = "loanProductCreateResponseLP1InterestDecliningBalanceDailyRecalculationCompoundingNoneRescheduleReduceNrInstallments"; public static final String DEFAULT_LOAN_PRODUCT_CREATE_RESPONSE_LP1_INTEREST_DECLINING_BALANCE_DAILY_RECALCULATION_COMPOUNDING_NONE_RESCHEDULE_NEXT_REPAYMENTS = "loanProductCreateResponseLP1InterestDecliningBalanceDailyRecalculationCompoundingNoneRescheduleNextRepayments"; public static final String DEFAULT_LOAN_PRODUCT_CREATE_RESPONSE_LP1_INTEREST_DECLINING_PERIOD_DAILY = "loanProductCreateResponseLP1InterestDecliningPeriodDaily"; + public static final String DEFAULT_LOAN_PRODUCT_CREATE_RESPONSE_LP1_INTEREST_DECLINING_PERIOD_DAILY_ACCRUAL_ACTIVITY = "loanProductCreateResponseLP1InterestDecliningPeriodDailyAccrualActivity"; + public static final String DEFAULT_LOAN_PRODUCT_CREATE_RESPONSE_LP1_INTEREST_DECLINING_BALANCE_DAILY_RECALCULATION_COMPOUNDING_NONE_ACCRUAL_ACTIVITY = "loanProductCreateResponseLP1InterestDecliningBalanceRecalculationCompoundingNoneAccrualActivity"; public static final String DEFAULT_LOAN_PRODUCT_CREATE_RESPONSE_LP2_DOWNPAYMENT_AUTO_ADVANCED_PAYMENT_ALLOCATION = "loanProductCreateResponseLP2DownPaymentAutoAdvancedPaymentAllocation"; + public static final String DEFAULT_LOAN_PRODUCT_CREATE_RESPONSE_LP2_DOWNPAYMENT_AUTO_ADVANCED_REPAYMENT_ALLOCATION_PAYMENT_START_SUBMITTED = "loanProductCreateResponseLP2DownPaymentAutoAdvancedPaymentAllocationPaymentStartSubmitted"; public static final String DEFAULT_LOAN_PRODUCT_CREATE_RESPONSE_LP2_DOWNPAYMENT_ADVANCED_PAYMENT_ALLOCATION = "loanProductCreateResponseLP2DownPaymentAdvancedPaymentAllocation"; public static final String DEFAULT_LOAN_PRODUCT_CREATE_RESPONSE_LP2_DOWNPAYMENT = "loanProductCreateResponseLP2DownPayment"; public static final String DEFAULT_LOAN_PRODUCT_CREATE_RESPONSE_LP2_DOWNPAYMENT_INTEREST = "loanProductCreateResponseLP2DownPaymentInterest"; public static final String DEFAULT_LOAN_PRODUCT_CREATE_RESPONSE_LP2_DOWNPAYMENT_INTEREST_AUTO = "loanProductCreateResponseLP2DownPaymentInterestAuto"; public static final String DEFAULT_LOAN_PRODUCT_CREATE_RESPONSE_LP2_DOWNPAYMENT_AUTO = "loanProductCreateResponseLP2DownPaymentAuto"; public static final String DEFAULT_LOAN_PRODUCT_CREATE_RESPONSE_LP2_DOWNPAYMENT_ADVANCED_PAYMENT_ALLOCATION_PROGRESSIVE_LOAN_SCHEDULE = "loanProductCreateResponseLP2DownPaymentProgressiveLoanSchedule"; + public static final String DEFAULT_LOAN_PRODUCT_CREATE_RESPONSE_LP2_ADVANCED_CUSTOM_PAYMENT_ALLOCATION_PROGRESSIVE_LOAN_SCHEDULE = "loanProductCreateResponseLP2ProgressiveLoanScheduleCustomPaymentAllocation"; public static final String DEFAULT_LOAN_PRODUCT_CREATE_RESPONSE_LP2_DOWNPAYMENT_ADVANCED_PAYMENT_ALLOCATION_PROGRESSIVE_LOAN_SCHEDULE_VERTICAL = "loanProductCreateResponseLP2DownPaymentProgressiveLoanScheduleVertical"; public static final String DEFAULT_LOAN_PRODUCT_CREATE_RESPONSE_LP2_DOWNPAYMENT_ADVANCED_PAYMENT_ALLOCATION_PROGRESSIVE_LOAN_SCHEDULE_INSTALLMENT_LEVEL_DELINQUENCY = "loanProductCreateResponseLP2DownPaymentProgressiveLoanScheduleInstallmentLevelDelinquency"; public static final String DEFAULT_LOAN_PRODUCT_CREATE_RESPONSE_LP2_DOWNPAYMENT_ADV_PMT_ALLOC_PROG_SCHEDULE_HOR_INST_LVL_DELINQUENCY_CREDIT_ALLOCATION = "loanProductCreateResponseLP2DownPaymentProgressiveLoanScheduleHorizontalInstallmentLevelDelinquencyCreditAllocation"; public static final String DEFAULT_LOAN_PRODUCT_CREATE_RESPONSE_LP2_DOWNPAYMENT_ADV_PMT_ALLOC_FIXED_LENGTH = "loanProductCreateResponseLP2DownPaymentProgressiveLoanScheduleFixedLength"; - public static final String DEFAULT_LOAN_PRODUCT_CREATE_RESPONSE_LP2_ADV_PYMNT_INTEREST_DAILY_EMI_360_30_INTEREST_RECALCULATION_TILL_PRECLOSE = "loanProductCreateResponseLP2AdvancedPaymentInterestDailyEmi36030InterestRecalculationTillPreClose"; - public static final String DEFAULT_LOAN_PRODUCT_CREATE_RESPONSE_LP2_ADV_PYMNT_INTEREST_DAILY_EMI_360_30_INTEREST_RECALCULATION_TILL_REST_FREQUENCY = "loanProductCreateResponseLP2AdvancedPaymentInterestDailyEmi36030InterestRecalculationTillRestFrequency"; - public static final String DEFAULT_LOAN_PRODUCT_CREATE_RESPONSE_LP2_ADV_PMT_ALLOC_PROGRESSIVE_LOAN_SCHEDULE_HORIZONTAL = "loanProductCreateResponseLP2ProgressiveLoanScheduleHorizontal"; - public static final String DEFAULT_LOAN_PRODUCT_CREATE_RESPONSE_LP2_ADV_PMT_ALLOC_PROGRESSIVE_LOAN_SCHEDULE_HORIZONTAL_LAST = "loanProductCreateResponseLP2ProgressiveLoanScheduleHorizontal"; + public static final String DEFAULT_LOAN_PRODUCT_CREATE_RESPONSE_LP2_DOWNPAYMENT_INTEREST_FLAT_ADV_PMT_ALLOC = "loanProductCreateResponseLP2DownPaymentInterestFlatAdvancedPaymentAllocation"; + public static final String DEFAULT_LOAN_PRODUCT_CREATE_RESPONSE_LP2_ADV_PYMNT_INTEREST_DAILY_EMI_ACTUAL_ACTUAL = "loanProductCreateResponseLP2AdvancedPaymentInterestDailyEmiActualActual"; + public static final String DEFAULT_LOAN_PRODUCT_CREATE_RESPONSE_LP2_ADV_PYMNT_INTEREST_DAILY_EMI_ACTUAL_ACTUAL_ACCRUAL_ACTIVITY = "loanProductCreateResponseLP2AdvancedPaymentInterestDailyEmiActualActualAccrualActivity"; + public static final String DEFAULT_LOAN_PRODUCT_CREATE_RESPONSE_LP2_ADV_PYMNT_INTEREST_DAILY_EMI_360_30 = "loanProductCreateResponseLP2AdvancedPaymentInterestDailyEmi36030"; + public static final String DEFAULT_LOAN_PRODUCT_CREATE_RESPONSE_LP2_ADV_PYMNT_INTEREST_DAILY_EMI_360_30_INTEREST_RECALCULATION_DAILY_TILL_PRECLOSE = "loanProductCreateResponseLP2AdvancedPaymentInterestDailyEmi36030InterestRecalculationDailyTillPreClose"; + public static final String DEFAULT_LOAN_PRODUCT_CREATE_RESPONSE_LP2_ADV_PYMNT_INTEREST_DAILY_EMI_360_30_INTEREST_RECALCULATION_DAILY_TILL_PRECLOSE_LAST_INSTALLMENT = "loanProductCreateResponseLP2AdvancedPaymentInterestDailyEmi36030InterestRecalculationDailyTillPreCloseLastInstallment"; + public static final String DEFAULT_LOAN_PRODUCT_CREATE_RESPONSE_LP2_ADV_PYMNT_INTEREST_DAILY_EMI_360_30_INTEREST_RECALCULATION_DAILY_TILL_PRECLOSE_PMT_ALLOC_1 = "loanProductCreateResponseLP2AdvancedPaymentInterestDailyEmi36030InterestRecalculationDailyTillPreClosePmtAlloc1"; + public static final String DEFAULT_LOAN_PRODUCT_CREATE_RESPONSE_LP2_ADV_PYMNT_INTEREST_DAILY_EMI_360_30_INTEREST_RECALCULATION_SAME_AS_REP_TILL_PRECLOSE = "loanProductCreateResponseLP2AdvancedPaymentInterestDailyEmi36030InterestRecalculationSameAsRepTillPreClose"; + public static final String DEFAULT_LOAN_PRODUCT_CREATE_RESPONSE_LP2_ADV_PYMNT_INTEREST_DAILY_EMI_360_30_INTEREST_RECALCULATION_DAILY_TILL_REST_FREQUENCY_DATE = "loanProductCreateResponseLP2AdvancedPaymentInterestDailyEmi36030InterestRecalculationDailyTillRestFrequencyDate"; + public static final String DEFAULT_LOAN_PRODUCT_CREATE_RESPONSE_LP2_ADV_PYMNT_INTEREST_DAILY_EMI_360_30_INTEREST_RECALCULATION_SAME_AS_REP_TILL_REST_FREQUENCY_DATE = "loanProductCreateResponseLP2AdvancedPaymentInterestDailyEmi36030InterestRecalculationSameAsRepTillRestFrequencyDate"; + public static final String DEFAULT_LOAN_PRODUCT_CREATE_RESPONSE_LP2_ADV_PYMNT_INTEREST_DAILY_EMI_ACTUAL_ACTUAL_INTEREST_REFUND_FULL = "loanProductCreateResponseLP2AdvancedPaymentInterestDailyEmiActualActualInterestRefundFull"; + public static final String DEFAULT_LOAN_PRODUCT_CREATE_RESPONSE_LP2_ADV_PYMNT_INTEREST_DAILY_EMI_360_30_MULTIDISBURSE = "loanProductCreateResponseLP2AdvancedPaymentInterestDailyEmi36030MultiDisburse"; + public static final String DEFAULT_LOAN_PRODUCT_CREATE_RESPONSE_LP2_ADV_PYMNT_INTEREST_DAILY_EMI_360_30_MULTIDISBURSE_DOWNPAYMENT = "loanProductCreateResponseLP2AdvancedPaymentInterestDailyEmi36030MultiDisburseDownPayment"; + public static final String DEFAULT_LOAN_PRODUCT_CREATE_RESPONSE_LP2_ADV_PYMNT_INTEREST_DAILY_EMI_365_ACTUAL = "loanProductCreateResponseLP2AdvancedPaymentInterestDailyEmi365Actual"; + public static final String DEFAULT_LOAN_PRODUCT_CREATE_RESPONSE_LP2_ADV_PYMNT_INTEREST_DAILY_EMI_360_30_DOWNPAYMENT = "loanProductCreateResponseLP2AdvancedPaymentInterestDailyEmi36030DownPayment"; + public static final String DEFAULT_LOAN_PRODUCT_CREATE_RESPONSE_LP2_ADV_PYMNT_INTEREST_DAILY_EMI_ACTUAL_ACTUAL_INTEREST_REFUND = "loanProductCreateResponseLP2AdvancedPaymentInterestDailyEmiActualActualInterestRefund"; + public static final String DEFAULT_LOAN_PRODUCT_CREATE_RESPONSE_LP1_ADVANCED_PAYMENT_ALLOCATION_PROGRESSIVE_LOAN_SCHEDULE_HORIZONTAL = "loanProductCreateResponseLP1ProgressiveLoanScheduleHorizontal"; + public static final String DEFAULT_LOAN_PRODUCT_CREATE_RESPONSE_LP2_ADV_PYMNT_INTEREST_DAILY_EMI_360_30_INTEREST_RECALCULATION_DAILY_TILL_PRECLOSE_WHOLE_TERM = "loanProductCreateResponseLP2AdvancedPaymentInterestDailyEmi36030InterestRecalculationSameAsRepTillPreCloseWholeTerm"; public static final String CHARGE_FOR_LOAN_PERCENT_LATE_CREATE_RESPONSE = "ChargeForLoanPercentLateCreateResponse"; public static final String CHARGE_FOR_LOAN_PERCENT_LATE_AMOUNT_PLUS_INTEREST_CREATE_RESPONSE = "ChargeForLoanPercentLateAmountPlusInterestCreateResponse"; public static final String CHARGE_FOR_LOAN_PERCENT_PROCESSING_CREATE_RESPONSE = "ChargeForLoanPercentProcessingCreateResponse"; @@ -132,5 +152,4 @@ public abstract class TestContextKey { public static final String TRANSACTION_EVENT = "transactionEvent"; public static final String LOAN_WRITE_OFF_RESPONSE = "loanWriteOffResponse"; public static final String LOAN_DELINQUENCY_ACTION_RESPONSE = "loanDelinquencyActionResponse"; - } diff --git a/fineract-e2e-tests-core/src/test/java/org/apache/fineract/test/testrail/AddResultForCaseRequest.java b/fineract-e2e-tests-core/src/test/java/org/apache/fineract/test/testrail/AddResultForCaseRequest.java new file mode 100644 index 00000000000..67b4453e4a0 --- /dev/null +++ b/fineract-e2e-tests-core/src/test/java/org/apache/fineract/test/testrail/AddResultForCaseRequest.java @@ -0,0 +1,37 @@ +/** + * 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.test.testrail; + +import com.google.gson.annotations.SerializedName; +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; + +@Builder +@Data +@AllArgsConstructor +@NoArgsConstructor +class AddResultForCaseRequest { + + @SerializedName("status_id") + private TestRailStatus statusId; + + private String comment; +} diff --git a/fineract-e2e-tests-core/src/test/java/org/apache/fineract/test/testrail/TestRailApiClient.java b/fineract-e2e-tests-core/src/test/java/org/apache/fineract/test/testrail/TestRailApiClient.java new file mode 100644 index 00000000000..29e943a181d --- /dev/null +++ b/fineract-e2e-tests-core/src/test/java/org/apache/fineract/test/testrail/TestRailApiClient.java @@ -0,0 +1,32 @@ +/** + * 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.test.testrail; + +import retrofit2.Call; +import retrofit2.http.Body; +import retrofit2.http.Headers; +import retrofit2.http.POST; +import retrofit2.http.Path; + +interface TestRailApiClient { + + @Headers({ "Content-Type:application/json" }) + @POST("/api/v2/add_result_for_case/{runId}/{caseId}") + Call addResultForCase(@Path("runId") int runId, @Path("caseId") int caseId, @Body AddResultForCaseRequest request); +} diff --git a/fineract-e2e-tests-core/src/test/java/org/apache/fineract/test/testrail/TestRailClient.java b/fineract-e2e-tests-core/src/test/java/org/apache/fineract/test/testrail/TestRailClient.java new file mode 100644 index 00000000000..ce0f605a307 --- /dev/null +++ b/fineract-e2e-tests-core/src/test/java/org/apache/fineract/test/testrail/TestRailClient.java @@ -0,0 +1,141 @@ +/** + * 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.test.testrail; + +import io.cucumber.java.Scenario; +import java.io.IOException; +import java.lang.reflect.Field; +import java.util.ArrayList; +import java.util.regex.Matcher; +import java.util.regex.Pattern; +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import okhttp3.ResponseBody; +import org.apache.commons.httpclient.HttpStatus; +import org.apache.commons.lang3.ClassUtils; +import org.apache.commons.lang3.reflect.FieldUtils; +import org.junit.runner.Result; +import org.springframework.beans.factory.InitializingBean; +import org.springframework.context.annotation.Conditional; +import org.springframework.stereotype.Component; +import retrofit2.Response; + +@Slf4j +@Component +@RequiredArgsConstructor +@Conditional(TestRailEnabledCondition.class) +public class TestRailClient implements InitializingBean { + + public static final Pattern TESTRAIL_TAG_PATTERN = Pattern.compile("@TestRailId:C([0-9]+)"); + private static final String SUCCESS_COMMENT = "Test passed"; + private static final String FAILED_COMMENT = "Test failed"; + + private final TestRailProperties testRailProperties; + private final TestRailApiClient apiClient; + + @Override + public void afterPropertiesSet() { + log.warn("Configured TestRail Run ID: '{}'", testRailProperties.getRunId()); + } + + public void saveScenarioResult(Scenario scenario) { + Integer caseId = getScenarioCaseId(scenario); + + AddResultForCaseRequest request; + if (scenario.isFailed()) { + request = createFailedRequest(scenario); + } else { + request = createSuccessRequest(scenario); + } + + if (caseId != null) { + try { + Response response = apiClient.addResultForCase(testRailProperties.getRunId(), caseId, request).execute(); + if (response.code() != HttpStatus.SC_OK) { + handleApiError(response); + } + } catch (IOException e) { + throw new RuntimeException("Error while reporting to TestRail", e); + } + } + } + + private Integer getScenarioCaseId(Scenario scenario) { + Integer caseId = null; + for (String s : scenario.getSourceTagNames()) { + if (s.contains("TestRail")) { + Matcher matcher = TESTRAIL_TAG_PATTERN.matcher(s); + if (matcher.matches()) { + caseId = Integer.parseInt(matcher.group(1)); + } + } + } + return caseId; + } + + private void handleApiError(Response response) throws IOException { + String exceptionMsg = "Error while reporting to TestRail"; + ResponseBody errorBody = response.errorBody(); + if (errorBody != null) { + exceptionMsg += " " + errorBody.string(); + } + throw new RuntimeException(exceptionMsg); + } + + private AddResultForCaseRequest createFailedRequest(Scenario scenario) { + return new AddResultForCaseRequest.AddResultForCaseRequestBuilder().statusId(TestRailStatus.FAILED) + .comment(createFailedComment(scenario)).build(); + } + + private AddResultForCaseRequest createSuccessRequest(Scenario scenario) { + return new AddResultForCaseRequest.AddResultForCaseRequestBuilder().statusId(TestRailStatus.PASSED) + .comment(createSuccessComment(scenario)).build(); + } + + private String createSuccessComment(Scenario scenario) { + return SUCCESS_COMMENT; + } + + private String createFailedComment(Scenario scenario) { + try { + Class c = ClassUtils.getClass("cucumber.runtime.java.JavaHookDefinition$ScenarioAdaptor"); + Field fieldScenario = FieldUtils.getField(c, "scenario", true); + if (fieldScenario != null) { + + fieldScenario.setAccessible(true); + Object objectScenario = fieldScenario.get(scenario); + + Field fieldStepResults = objectScenario.getClass().getDeclaredField("stepResults"); + fieldStepResults.setAccessible(true); + + ArrayList results = (ArrayList) fieldStepResults.get(objectScenario); + for (Result result : results) { + if (result.getFailures() != null) { + return FAILED_COMMENT + "%n" + result.getFailures(); + } + } + } + + return FAILED_COMMENT; + + } catch (IllegalAccessException | NoSuchFieldException | ClassNotFoundException e) { + return FAILED_COMMENT; + } + } +} diff --git a/fineract-e2e-tests-core/src/test/java/org/apache/fineract/test/testrail/TestRailConfiguration.java b/fineract-e2e-tests-core/src/test/java/org/apache/fineract/test/testrail/TestRailConfiguration.java new file mode 100644 index 00000000000..838e463be5c --- /dev/null +++ b/fineract-e2e-tests-core/src/test/java/org/apache/fineract/test/testrail/TestRailConfiguration.java @@ -0,0 +1,80 @@ +/** + * 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.test.testrail; + +import static org.apache.commons.lang3.StringUtils.isBlank; + +import java.io.IOException; +import okhttp3.Interceptor; +import okhttp3.OkHttpClient; +import okhttp3.Request; +import okhttp3.Response; +import org.apache.fineract.client.auth.HttpBasicAuth; +import org.apache.fineract.client.util.JSON; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Conditional; +import org.springframework.context.annotation.Configuration; +import retrofit2.Retrofit; + +@Configuration +@Conditional(TestRailEnabledCondition.class) +public class TestRailConfiguration { + + @Autowired + private TestRailProperties testRailProperties; + + @Bean + public TestRailApiClient testRailApiClient() { + String testRailBaseUrl = testRailProperties.getBaseUrl(); + String testRailUsername = testRailProperties.getUsername(); + String testRailPassword = testRailProperties.getPassword(); + + if (isBlank(testRailBaseUrl)) { + throw new IllegalStateException("TestRail base URL has not been set"); + } + if (isBlank(testRailUsername)) { + throw new IllegalStateException("TestRail username has not been set"); + } + if (isBlank(testRailPassword)) { + throw new IllegalStateException("TestRail password has not been set"); + } + + HttpBasicAuth httpBasicAuth = new HttpBasicAuth(); + httpBasicAuth.setCredentials(testRailUsername, testRailPassword); + OkHttpClient httpClient = new OkHttpClient.Builder().addInterceptor(httpBasicAuth).addInterceptor(new TestRailIndexPhpInterceptor()) + .build(); + + Retrofit retrofit = new Retrofit.Builder().addConverterFactory(JSON.GsonCustomConverterFactory.create(new JSON().getGson())) + .client(httpClient).baseUrl(testRailBaseUrl).build(); + + return retrofit.create(TestRailApiClient.class); + } + + // Needed otherwise Retrofit 2 will be mad on the URL query/path parameters + private static final class TestRailIndexPhpInterceptor implements Interceptor { + + @Override + public Response intercept(Chain chain) throws IOException { + Request request = chain.request(); + String finalUrl = request.url().toString().replace("api/v2", "index.php?/api/v2"); + return chain.proceed(request.newBuilder().url(finalUrl).build()); + } + } +} diff --git a/fineract-e2e-tests-core/src/test/java/org/apache/fineract/test/testrail/TestRailEnabledCondition.java b/fineract-e2e-tests-core/src/test/java/org/apache/fineract/test/testrail/TestRailEnabledCondition.java new file mode 100644 index 00000000000..161e47e5dde --- /dev/null +++ b/fineract-e2e-tests-core/src/test/java/org/apache/fineract/test/testrail/TestRailEnabledCondition.java @@ -0,0 +1,34 @@ +/** + * 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.test.testrail; + +import org.apache.fineract.test.support.PropertiesCondition; + +public class TestRailEnabledCondition extends PropertiesCondition { + + @Override + protected Class getPropertiesClass() { + return TestRailProperties.class; + } + + @Override + protected boolean matches(TestRailProperties properties) { + return properties.isEnabled(); + } +} diff --git a/fineract-e2e-tests-core/src/test/java/org/apache/fineract/test/testrail/TestRailProperties.java b/fineract-e2e-tests-core/src/test/java/org/apache/fineract/test/testrail/TestRailProperties.java new file mode 100644 index 00000000000..472182fbfe5 --- /dev/null +++ b/fineract-e2e-tests-core/src/test/java/org/apache/fineract/test/testrail/TestRailProperties.java @@ -0,0 +1,39 @@ +/** + * 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.test.testrail; + +import lombok.Getter; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.stereotype.Component; + +@Component +@Getter +public class TestRailProperties { + + @Value("${fineract-test.testrail.enabled}") + private boolean enabled; + @Value("${fineract-test.testrail.base-url}") + private String baseUrl; + @Value("${fineract-test.testrail.username}") + private String username; + @Value("${fineract-test.testrail.password}") + private String password; + @Value("${fineract-test.testrail.run-id}") + private int runId; +} diff --git a/fineract-e2e-tests-core/src/test/java/org/apache/fineract/test/testrail/TestRailStatus.java b/fineract-e2e-tests-core/src/test/java/org/apache/fineract/test/testrail/TestRailStatus.java new file mode 100644 index 00000000000..2dc659179b9 --- /dev/null +++ b/fineract-e2e-tests-core/src/test/java/org/apache/fineract/test/testrail/TestRailStatus.java @@ -0,0 +1,34 @@ +/** + * 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.test.testrail; + +import com.google.gson.annotations.SerializedName; + +enum TestRailStatus { + @SerializedName("1") // + PASSED, // + @SerializedName("2") // + BLOCKED, // + @SerializedName("3") // + UNTESTED, // + @SerializedName("4") // + RETEST, // + @SerializedName("5") // + FAILED// +} diff --git a/fineract-e2e-tests-runner/src/test/resources/features/Loan.feature b/fineract-e2e-tests-runner/src/test/resources/features/Loan.feature index 747fb3c1cfd..733812ca16c 100644 --- a/fineract-e2e-tests-runner/src/test/resources/features/Loan.feature +++ b/fineract-e2e-tests-runner/src/test/resources/features/Loan.feature @@ -1257,7 +1257,7 @@ Feature: Loan When Admin sets the business date to "20 June 2023" When Customer undo "1"th "Repayment" transaction made on "20 June 2023" Then Loan status will be "ACTIVE" - Then Loan closedon_date is null + Then Loan closedon_date is "null" Scenario: As an admin I would like to delete a loan using external id When Admin sets the business date to the actual date @@ -5541,7 +5541,7 @@ Feature: Loan When Admin creates a client with random data When Admin creates a fully customized loan with the following data: | LoanProduct | submitted on date | with Principal | ANNUAL interest rate % | interest type | interest calculation period | amortization type | loanTermFrequency | loanTermFrequencyType | repaymentEvery | repaymentFrequencyType | numberOfRepayments | graceOnPrincipalPayment | graceOnInterestPayment | interest free period | Payment strategy | - | LP2_ADV_PYMNT_INTEREST_DAILY_EMI_360_30_INTEREST_RECALCULATION_TILL_PRECLOSE | 01 January 2024 | 100 | 7 | DECLINING_BALANCE | DAILY | EQUAL_INSTALLMENTS | 6 | MONTHS | 1 | MONTHS | 6 | 0 | 0 | 0 | ADVANCED_PAYMENT_ALLOCATION | + | LP2_ADV_PYMNT_INTEREST_DAILY_EMI_360_30_INTEREST_RECALCULATION_DAILY_TILL_PRECLOSE | 01 January 2024 | 100 | 7 | DECLINING_BALANCE | DAILY | EQUAL_INSTALLMENTS | 6 | MONTHS | 1 | MONTHS | 6 | 0 | 0 | 0 | ADVANCED_PAYMENT_ALLOCATION | And Admin successfully approves the loan on "01 January 2024" with "100" amount and expected disbursement date on "01 January 2024" When Admin successfully disburse the loan on "01 January 2024" with "100" EUR transaction amount Then Loan Repayment schedule has 6 periods, with the following data for periods: @@ -5598,10 +5598,10 @@ Feature: Loan Scenario: Early pay-off loan with interest, TILL_REST_FREQUENCY_DATE product When Admin sets the business date to "01 January 2024" When Admin creates a client with random data - When Admin set "LP2_ADV_PYMNT_INTEREST_DAILY_EMI_360_30_INTEREST_RECALCULATION_TILL_REST_FREQUENCY" loan product "DEFAULT" transaction type to "NEXT_INSTALLMENT" future installment allocation rule + When Admin set "LP2_ADV_PYMNT_INTEREST_DAILY_EMI_360_30_INTEREST_RECALCULATION_DAILY_TILL_REST_FREQUENCY_DATE" loan product "DEFAULT" transaction type to "NEXT_INSTALLMENT" future installment allocation rule When Admin creates a fully customized loan with the following data: | LoanProduct | submitted on date | with Principal | ANNUAL interest rate % | interest type | interest calculation period | amortization type | loanTermFrequency | loanTermFrequencyType | repaymentEvery | repaymentFrequencyType | numberOfRepayments | graceOnPrincipalPayment | graceOnInterestPayment | interest free period | Payment strategy | - | LP2_ADV_PYMNT_INTEREST_DAILY_EMI_360_30_INTEREST_RECALCULATION_TILL_REST_FREQUENCY | 01 January 2024 | 100 | 7 | DECLINING_BALANCE | DAILY | EQUAL_INSTALLMENTS | 6 | MONTHS | 1 | MONTHS | 6 | 0 | 0 | 0 | ADVANCED_PAYMENT_ALLOCATION | + | LP2_ADV_PYMNT_INTEREST_DAILY_EMI_360_30_INTEREST_RECALCULATION_DAILY_TILL_REST_FREQUENCY_DATE | 01 January 2024 | 100 | 7 | DECLINING_BALANCE | DAILY | EQUAL_INSTALLMENTS | 6 | MONTHS | 1 | MONTHS | 6 | 0 | 0 | 0 | ADVANCED_PAYMENT_ALLOCATION | And Admin successfully approves the loan on "01 January 2024" with "100" amount and expected disbursement date on "01 January 2024" When Admin successfully disburse the loan on "01 January 2024" with "100" EUR transaction amount Then Loan Repayment schedule has 6 periods, with the following data for periods: @@ -5654,7 +5654,7 @@ Feature: Loan | 01 February 2024 | Repayment | 17.01 | 16.43 | 0.58 | 0.0 | 0.0 | 83.57 | false | | 15 February 2024 | Repayment | 84.06 | 83.57 | 0.49 | 0.0 | 0.0 | 0.0 | false | Then Loan's all installments have obligations met - When Admin set "LP2_ADV_PYMNT_INTEREST_DAILY_EMI_360_30_INTEREST_RECALCULATION_TILL_REST_FREQUENCY" loan product "DEFAULT" transaction type to "LAST_INSTALLMENT" future installment allocation rule + When Admin set "LP2_ADV_PYMNT_INTEREST_DAILY_EMI_360_30_INTEREST_RECALCULATION_DAILY_TILL_REST_FREQUENCY_DATE" loan product "DEFAULT" transaction type to "LAST_INSTALLMENT" future installment allocation rule Scenario: Interest recalculation - S1 daily for overdue loan Given Global configuration "enable-business-date" is enabled @@ -5662,7 +5662,7 @@ Feature: Loan When Admin creates a client with random data When Admin creates a fully customized loan with the following data: | LoanProduct | submitted on date | with Principal | ANNUAL interest rate % | interest type | interest calculation period | amortization type | loanTermFrequency | loanTermFrequencyType | repaymentEvery | repaymentFrequencyType | numberOfRepayments | graceOnPrincipalPayment | graceOnInterestPayment | interest free period | Payment strategy | - | LP2_ADV_PYMNT_INTEREST_DAILY_EMI_360_30_INTEREST_RECALCULATION_TILL_PRECLOSE | 01 January 2024 | 100 | 7.0 | DECLINING_BALANCE | DAILY | EQUAL_INSTALLMENTS | 6 | MONTHS | 1 | MONTHS | 6 | 0 | 0 | 0 | ADVANCED_PAYMENT_ALLOCATION | + | LP2_ADV_PYMNT_INTEREST_DAILY_EMI_360_30_INTEREST_RECALCULATION_DAILY_TILL_PRECLOSE | 01 January 2024 | 100 | 7.0 | DECLINING_BALANCE | DAILY | EQUAL_INSTALLMENTS | 6 | MONTHS | 1 | MONTHS | 6 | 0 | 0 | 0 | ADVANCED_PAYMENT_ALLOCATION | And Admin successfully approves the loan on "1 January 2024" with "100" amount and expected disbursement date on "1 January 2024" When Admin successfully disburse the loan on "1 January 2024" with "100" EUR transaction amount When Admin sets the business date to "15 July 2024" @@ -5685,7 +5685,7 @@ Feature: Loan When Admin creates a client with random data When Admin creates a fully customized loan with the following data: | LoanProduct | submitted on date | with Principal | ANNUAL interest rate % | interest type | interest calculation period | amortization type | loanTermFrequency | loanTermFrequencyType | repaymentEvery | repaymentFrequencyType | numberOfRepayments | graceOnPrincipalPayment | graceOnInterestPayment | interest free period | Payment strategy | - | LP2_ADV_PYMNT_INTEREST_DAILY_EMI_360_30_INTEREST_RECALCULATION_TILL_PRECLOSE | 01 January 2024 | 100 | 7.0 | DECLINING_BALANCE | DAILY | EQUAL_INSTALLMENTS | 6 | MONTHS | 1 | MONTHS | 6 | 0 | 0 | 0 | ADVANCED_PAYMENT_ALLOCATION | + | LP2_ADV_PYMNT_INTEREST_DAILY_EMI_360_30_INTEREST_RECALCULATION_DAILY_TILL_PRECLOSE | 01 January 2024 | 100 | 7.0 | DECLINING_BALANCE | DAILY | EQUAL_INSTALLMENTS | 6 | MONTHS | 1 | MONTHS | 6 | 0 | 0 | 0 | ADVANCED_PAYMENT_ALLOCATION | And Admin successfully approves the loan on "1 January 2024" with "100" amount and expected disbursement date on "1 January 2024" When Admin successfully disburse the loan on "1 January 2024" with "100" EUR transaction amount When Admin sets the business date to "10 March 2024" @@ -5708,7 +5708,7 @@ Feature: Loan When Admin creates a client with random data When Admin creates a fully customized loan with the following data: | LoanProduct | submitted on date | with Principal | ANNUAL interest rate % | interest type | interest calculation period | amortization type | loanTermFrequency | loanTermFrequencyType | repaymentEvery | repaymentFrequencyType | numberOfRepayments | graceOnPrincipalPayment | graceOnInterestPayment | interest free period | Payment strategy | - | LP2_ADV_PYMNT_INTEREST_DAILY_EMI_360_30_INTEREST_RECALCULATION_TILL_PRECLOSE | 01 January 2024 | 100 | 7.0 | DECLINING_BALANCE | DAILY | EQUAL_INSTALLMENTS | 6 | MONTHS | 1 | MONTHS | 6 | 0 | 0 | 0 | ADVANCED_PAYMENT_ALLOCATION | + | LP2_ADV_PYMNT_INTEREST_DAILY_EMI_360_30_INTEREST_RECALCULATION_DAILY_TILL_PRECLOSE | 01 January 2024 | 100 | 7.0 | DECLINING_BALANCE | DAILY | EQUAL_INSTALLMENTS | 6 | MONTHS | 1 | MONTHS | 6 | 0 | 0 | 0 | ADVANCED_PAYMENT_ALLOCATION | And Admin successfully approves the loan on "1 January 2024" with "100" amount and expected disbursement date on "1 January 2024" When Admin successfully disburse the loan on "1 January 2024" with "100" EUR transaction amount When Admin sets the business date to "1 February 2024" @@ -5736,7 +5736,7 @@ Feature: Loan | LoanProduct | submitted on date | with Principal | ANNUAL interest rate % | interest type | interest calculation period | amortization type | loanTermFrequency | loanTermFrequencyType | repaymentEvery | repaymentFrequencyType | numberOfRepayments | graceOnPrincipalPayment | graceOnInterestPayment | interest free period | Payment strategy | | LP1_INTEREST_DECLINING_BALANCE_SAR_RECALCULATION_SAME_AS_REPAYMENT_COMPOUNDING_NONE_MULTIDISB | 01 January 2023 | 10000 | 12 | DECLINING_BALANCE | SAME_AS_REPAYMENT_PERIOD | EQUAL_INSTALLMENTS | 6 | MONTHS | 1 | MONTHS | 6 | 0 | 0 | 0 | PENALTIES_FEES_INTEREST_PRINCIPAL_ORDER | And Admin successfully approves the loan on "1 January 2023" with "100" amount and expected disbursement date on "1 January 2023" - When Admin successfully disburse the loan on "1 January 2023" with "100" EUR transaction amount and "50" fixed emi amount + And Admin successfully disburse the loan on "1 January 2023" with "100" EUR transaction amount and "50" fixed emi amount Then Loan emi amount variations has 1 variation, with the following data: | Term Type Id | Term Type Code | Term Type Value | Applicable From | Decimal Value | Date Value | Is Specific To Installment | Is Processed | | 1 | loanTermType.emiAmount | emiAmount | 01 January 2023 | 50.0 | | false | | @@ -5746,11 +5746,11 @@ Feature: Loan Given Global configuration "enable-business-date" is enabled When Admin sets the business date to "1 January 2023" When Admin creates a client with random data - When Admin creates a fully customized loan with emi and the following data: + When Admin creates a fully customized loan with the following data: | LoanProduct | submitted on date | with Principal | ANNUAL interest rate % | interest type | interest calculation period | amortization type | loanTermFrequency | loanTermFrequencyType | repaymentEvery | repaymentFrequencyType | numberOfRepayments | graceOnPrincipalPayment | graceOnInterestPayment | interest free period | Payment strategy | | LP1_INTEREST_DECLINING_BALANCE_SAR_RECALCULATION_SAME_AS_REPAYMENT_COMPOUNDING_NONE_MULTIDISB | 01 January 2023 | 10000 | 12 | DECLINING_BALANCE | SAME_AS_REPAYMENT_PERIOD | EQUAL_INSTALLMENTS | 6 | MONTHS | 1 | MONTHS | 6 | 0 | 0 | 0 | PENALTIES_FEES_INTEREST_PRINCIPAL_ORDER | And Admin successfully approves the loan on "1 January 2023" with "100" amount and expected disbursement date on "1 January 2023" - When Admin successfully disburse the loan on "1 January 2023" with "100" EUR transaction amount, "50" EUR fixed emi amount and adjust repayment date on "15 January 2023" + And Admin successfully disburse the loan on "1 January 2023" with "100" EUR transaction amount, "50" EUR fixed emi amount and adjust repayment date on "15 January 2023" Then Loan term variations has 2 variation, with the following data: | Term Type Id | Term Type Code | Term Type Value | Applicable From | Decimal Value | Date Value | Is Specific To Installment | Is Processed | | 1 | loanTermType.emiAmount | emiAmount | 01 January 2023 | 50.0 | | false | | @@ -5838,4 +5838,4 @@ Feature: Loan | 15 January 2024 | Repayment | 1.5 | 1.5 | 0.0 | 0.0 | 0.0 | 83.5 | | 15 January 2024 | Repayment | 83.76 | 83.5 | 0.26 | 0.0 | 0.0 | 0.0 | | 15 January 2024 | Accrual | 0.26 | 0.0 | 0.26 | 0.0 | 0.0 | 0.0 | - Then Loan status will be "CLOSED_OBLIGATIONS_MET" \ No newline at end of file + Then Loan status will be "CLOSED_OBLIGATIONS_MET" diff --git a/fineract-e2e-tests-runner/src/test/resources/features/LoanCharge.feature b/fineract-e2e-tests-runner/src/test/resources/features/LoanCharge.feature index b3b86e03078..e7387f64ace 100644 --- a/fineract-e2e-tests-runner/src/test/resources/features/LoanCharge.feature +++ b/fineract-e2e-tests-runner/src/test/resources/features/LoanCharge.feature @@ -173,8 +173,7 @@ Feature: LoanCharge | NSF fee | true | Specified due date | 23 October 2022 | Flat | 10.0 | 10.0 | 0.0 | 0.0 | # ## charge adjustment with 8 will fail - When Admin makes a charge adjustment for the last "LOAN_NSF_FEE" type charge which is due on "23 October 2022" with transaction amount higher than the available charge amount - + When Charge adjustment for the last "LOAN_NSF_FEE" type charge which is due on "23 October 2022" with transaction amount 8 which is higher than the available charge amount results an ERROR ## revert last charge adjustment (was amount 3) When Admin reverts the charge adjustment which was raised on "04 November 2022" with 3 EUR transaction amount Then Loan has 1002 outstanding amount @@ -1678,7 +1677,7 @@ Feature: LoanCharge When Admin creates a client with random data When Admin creates a fully customized loan with the following data: | LoanProduct | submitted on date | with Principal | ANNUAL interest rate % | interest type | interest calculation period | amortization type | loanTermFrequency | loanTermFrequencyType | repaymentEvery | repaymentFrequencyType | numberOfRepayments | graceOnPrincipalPayment | graceOnInterestPayment | interest free period | Payment strategy | - | LP2_ADV_CUST_PMT_ALLOC_PROGRESSIVE_LOAN_SCHEDULE_HORIZONTAL | 27 Sep 2024 | 100 | 9.99 | DECLINING_BALANCE | DAILY | EQUAL_INSTALLMENTS | 1 | MONTHS | 1 | MONTHS | 1 | 0 | 0 | 0 | ADVANCED_PAYMENT_ALLOCATION | + | LP2_ADV_CUSTOM_PMT_ALLOC_PROGRESSIVE_LOAN_SCHEDULE_HORIZONTAL | 27 Sep 2024 | 100 | 9.99 | DECLINING_BALANCE | DAILY | EQUAL_INSTALLMENTS | 1 | MONTHS | 1 | MONTHS | 1 | 0 | 0 | 0 | ADVANCED_PAYMENT_ALLOCATION | And Admin successfully approves the loan on "27 September 2024" with "40" amount and expected disbursement date on "27 September 2024" When Admin successfully disburse the loan on "27 September 2024" with "40" EUR transaction amount Then Loan Repayment schedule has 1 periods, with the following data for periods: @@ -1707,4 +1706,4 @@ Feature: LoanCharge | 27 September 2024 | Disbursement | 40.0 | 0.0 | 0.0 | 0.0 | 0.0 | 40.0 | | 27 September 2024 | Accrual | 0.33 | 0.0 | 0.33 | 0.0 | 0.0 | 0.0 | | 27 September 2024 | Accrual | 1.0 | 0.0 | 0.0 | 0.0 | 1.0 | 0.0 | - | 27 September 2024 | Charge Adjustment | 1.0 | 1.0 | 0.0 | 0.0 | 0.0 | 39.0 | \ No newline at end of file + | 27 September 2024 | Charge Adjustment | 1.0 | 1.0 | 0.0 | 0.0 | 0.0 | 39.0 | diff --git a/fineract-e2e-tests-runner/src/test/resources/features/LoanRepayment.feature b/fineract-e2e-tests-runner/src/test/resources/features/LoanRepayment.feature index 722bf3f82f2..e4f439412db 100644 --- a/fineract-e2e-tests-runner/src/test/resources/features/LoanRepayment.feature +++ b/fineract-e2e-tests-runner/src/test/resources/features/LoanRepayment.feature @@ -3250,7 +3250,7 @@ Feature: LoanRepayment When Admin creates a client with random data When Admin creates a fully customized loan with the following data: | LoanProduct | submitted on date | with Principal | ANNUAL interest rate % | interest type | interest calculation period | amortization type | loanTermFrequency | loanTermFrequencyType | repaymentEvery | repaymentFrequencyType | numberOfRepayments | graceOnPrincipalPayment | graceOnInterestPayment | interest free period | Payment strategy | - | LP2_ADV_PMT_ALLOC_PROGRESSIVE_LOAN_SCHEDULE_HORIZONTAL | 23 July 2024 | 150 | 0 | FLAT | SAME_AS_REPAYMENT_PERIOD | EQUAL_INSTALLMENTS | 1 | MONTHS | 1 | MONTHS | 1 | 0 | 0 | 0 | ADVANCED_PAYMENT_ALLOCATION | + | LP1_ADV_PMT_ALLOC_PROGRESSIVE_LOAN_SCHEDULE_HORIZONTAL | 23 July 2024 | 150 | 0 | FLAT | SAME_AS_REPAYMENT_PERIOD | EQUAL_INSTALLMENTS | 1 | MONTHS | 1 | MONTHS | 1 | 0 | 0 | 0 | ADVANCED_PAYMENT_ALLOCATION | # --- 7/23 - Disbursement for 111.92 EUR --- And Admin successfully approves the loan on "23 July 2024" with "111.92" amount and expected disbursement date on "23 July 2024" When Admin successfully disburse the loan on "23 July 2024" with "111.92" EUR transaction amount @@ -3386,8 +3386,8 @@ Feature: LoanRepayment When Admin sets the business date to "23 June 2024" When Admin creates a client with random data When Admin creates a fully customized loan with the following data: - | LoanProduct | submitted on date | with Principal | ANNUAL interest rate % | interest type | interest calculation period | amortization type | loanTermFrequency | loanTermFrequencyType | repaymentEvery | repaymentFrequencyType | numberOfRepayments | graceOnPrincipalPayment | graceOnInterestPayment | interest free period | Payment strategy | - | LP2_ADV_PYMNT_INTEREST_DAILY_EMI_360_30_INTEREST_RECALCULATION_TILL_PRECLOSE | 23 June 2024 | 400 | 7.0 | DECLINING_BALANCE | DAILY | EQUAL_INSTALLMENTS | 6 | MONTHS | 1 | MONTHS | 6 | 0 | 0 | 0 | ADVANCED_PAYMENT_ALLOCATION | + | LoanProduct | submitted on date | with Principal | ANNUAL interest rate % | interest type | interest calculation period | amortization type | loanTermFrequency | loanTermFrequencyType | repaymentEvery | repaymentFrequencyType | numberOfRepayments | graceOnPrincipalPayment | graceOnInterestPayment | interest free period | Payment strategy | + | LP2_ADV_PYMNT_INTEREST_DAILY_EMI_360_30_INTEREST_RECALCULATION_DAILY_TILL_PRECLOSE | 23 June 2024 | 400 | 7.0 | DECLINING_BALANCE | DAILY | EQUAL_INSTALLMENTS | 6 | MONTHS | 1 | MONTHS | 6 | 0 | 0 | 0 | ADVANCED_PAYMENT_ALLOCATION | And Admin successfully approves the loan on "23 June 2024" with "400" amount and expected disbursement date on "23 June 2024" When Admin successfully disburse the loan on "23 June 2024" with "400" EUR transaction amount When Admin sets the business date to "24 June 2024"