FINERACT-2347: Introduce classification field on loan transactions
This commit is contained in:
committed by
Adam Saghy
parent
9ba17bf79a
commit
65538495aa
@@ -263,6 +263,14 @@
|
||||
"null",
|
||||
"boolean"
|
||||
]
|
||||
},
|
||||
{
|
||||
"default": null,
|
||||
"name": "classification",
|
||||
"type": [
|
||||
"null",
|
||||
"org.apache.fineract.avro.generic.v1.CodeValueDataV1"
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
|
||||
@@ -60,4 +60,8 @@ public class CodeHelper {
|
||||
return codesApi.retrieveCodes().execute().body().stream().filter(r -> name.equals(r.getName())).findAny()
|
||||
.orElseThrow(() -> new IllegalArgumentException("Code with name " + name + " has not been found"));
|
||||
}
|
||||
|
||||
public Response<PostCodeValueDataResponse> createCodeValue(Long codeId, PostCodeValuesDataRequest request) throws IOException {
|
||||
return codeValuesApi.createCodeValue(codeId, request).execute();
|
||||
}
|
||||
}
|
||||
|
||||
+112
@@ -67,6 +67,8 @@ import org.apache.fineract.client.models.BuyDownFeeAmortizationDetails;
|
||||
import org.apache.fineract.client.models.CapitalizedIncomeDetails;
|
||||
import org.apache.fineract.client.models.DeleteLoansLoanIdResponse;
|
||||
import org.apache.fineract.client.models.DisbursementDetail;
|
||||
import org.apache.fineract.client.models.GetCodeValuesDataResponse;
|
||||
import org.apache.fineract.client.models.GetCodesResponse;
|
||||
import org.apache.fineract.client.models.GetLoanProductsChargeOffReasonOptions;
|
||||
import org.apache.fineract.client.models.GetLoanProductsProductIdResponse;
|
||||
import org.apache.fineract.client.models.GetLoanProductsResponse;
|
||||
@@ -90,6 +92,8 @@ import org.apache.fineract.client.models.OldestCOBProcessedLoanDTO;
|
||||
import org.apache.fineract.client.models.PaymentAllocationOrder;
|
||||
import org.apache.fineract.client.models.PostAddAndDeleteDisbursementDetailRequest;
|
||||
import org.apache.fineract.client.models.PostClientsResponse;
|
||||
import org.apache.fineract.client.models.PostCodeValueDataResponse;
|
||||
import org.apache.fineract.client.models.PostCodeValuesDataRequest;
|
||||
import org.apache.fineract.client.models.PostLoansDisbursementData;
|
||||
import org.apache.fineract.client.models.PostLoansLoanIdRequest;
|
||||
import org.apache.fineract.client.models.PostLoansLoanIdResponse;
|
||||
@@ -108,6 +112,7 @@ import org.apache.fineract.client.models.PutLoansAvailableDisbursementAmountResp
|
||||
import org.apache.fineract.client.models.PutLoansLoanIdRequest;
|
||||
import org.apache.fineract.client.models.PutLoansLoanIdResponse;
|
||||
import org.apache.fineract.client.services.BusinessDateManagementApi;
|
||||
import org.apache.fineract.client.services.CodeValuesApi;
|
||||
import org.apache.fineract.client.services.LoanBuyDownFeesApi;
|
||||
import org.apache.fineract.client.services.LoanCapitalizedIncomeApi;
|
||||
import org.apache.fineract.client.services.LoanCobCatchUpApi;
|
||||
@@ -236,6 +241,9 @@ public class LoanStepDef extends AbstractStepDef {
|
||||
@Autowired
|
||||
private CodeHelper codeHelper;
|
||||
|
||||
@Autowired
|
||||
private CodeValuesApi codeValuesApi;
|
||||
|
||||
@Autowired
|
||||
private LoanInterestPauseApi loanInterestPauseApi;
|
||||
|
||||
@@ -4771,6 +4779,35 @@ public class LoanStepDef extends AbstractStepDef {
|
||||
ErrorHelper.checkSuccessfulApiCall(capitalizedIncomeResponse);
|
||||
}
|
||||
|
||||
@And("Admin adds capitalized income with {string} payment type to the loan on {string} with {string} EUR transaction amount and {string} classification")
|
||||
public void adminAddsCapitalizedIncomeWithClassification(final String transactionPaymentType, final String transactionDate,
|
||||
final String amount, final String classificationCodeName) throws IOException {
|
||||
final Response<PostLoansLoanIdTransactionsResponse> capitalizedIncomeResponse = addCapitalizedIncomeWithClassification(
|
||||
transactionPaymentType, transactionDate, amount, classificationCodeName);
|
||||
testContext().set(TestContextKey.LOAN_CAPITALIZED_INCOME_RESPONSE, capitalizedIncomeResponse);
|
||||
ErrorHelper.checkSuccessfulApiCall(capitalizedIncomeResponse);
|
||||
}
|
||||
|
||||
public Response<PostLoansLoanIdTransactionsResponse> addCapitalizedIncomeWithClassification(final String transactionPaymentType,
|
||||
final String transactionDate, final String amount, final String classificationCodeName) throws IOException {
|
||||
final Response<PostLoansResponse> loanResponse = testContext().get(TestContextKey.LOAN_CREATE_RESPONSE);
|
||||
final long loanId = loanResponse.body().getLoanId();
|
||||
|
||||
final DefaultPaymentType paymentType = DefaultPaymentType.valueOf(transactionPaymentType);
|
||||
final Long paymentTypeValue = paymentTypeResolver.resolve(paymentType);
|
||||
|
||||
// Get classification code value
|
||||
final Long classificationId = getClassificationCodeValueId(classificationCodeName);
|
||||
|
||||
final PostLoansLoanIdTransactionsRequest capitalizedIncomeRequest = LoanRequestFactory.defaultCapitalizedIncomeRequest()
|
||||
.transactionDate(transactionDate).transactionAmount(Double.valueOf(amount)).paymentTypeId(paymentTypeValue)
|
||||
.externalId("EXT-CAP-INC-" + UUID.randomUUID()).classificationId(classificationId);
|
||||
|
||||
final Response<PostLoansLoanIdTransactionsResponse> capitalizedIncomeResponse = loanTransactionsApi
|
||||
.executeLoanTransaction(loanId, capitalizedIncomeRequest, "capitalizedIncome").execute();
|
||||
return capitalizedIncomeResponse;
|
||||
}
|
||||
|
||||
public Response<PostLoansLoanIdTransactionsResponse> adjustCapitalizedIncome(final String transactionPaymentType,
|
||||
final String transactionDate, final String amount, final Long transactionId) throws IOException {
|
||||
|
||||
@@ -5167,6 +5204,35 @@ public class LoanStepDef extends AbstractStepDef {
|
||||
ErrorHelper.checkSuccessfulApiCall(buyDownFeesIncomeResponse);
|
||||
}
|
||||
|
||||
@When("Admin adds buy down fee with {string} payment type to the loan on {string} with {string} EUR transaction amount and {string} classification")
|
||||
public void adminAddsBuyDownFeeWithClassification(final String transactionPaymentType, final String transactionDate,
|
||||
final String amount, final String classificationCodeName) throws IOException {
|
||||
final Response<PostLoansLoanIdTransactionsResponse> buyDownFeesIncomeResponse = addBuyDownFeeWithClassification(
|
||||
transactionPaymentType, transactionDate, amount, classificationCodeName);
|
||||
testContext().set(TestContextKey.LOAN_BUY_DOWN_FEE_RESPONSE, buyDownFeesIncomeResponse);
|
||||
ErrorHelper.checkSuccessfulApiCall(buyDownFeesIncomeResponse);
|
||||
}
|
||||
|
||||
public Response<PostLoansLoanIdTransactionsResponse> addBuyDownFeeWithClassification(final String transactionPaymentType,
|
||||
final String transactionDate, final String amount, final String classificationCodeName) throws IOException {
|
||||
final Response<PostLoansResponse> loanResponse = testContext().get(TestContextKey.LOAN_CREATE_RESPONSE);
|
||||
final long loanId = loanResponse.body().getLoanId();
|
||||
|
||||
final DefaultPaymentType paymentType = DefaultPaymentType.valueOf(transactionPaymentType);
|
||||
final Long paymentTypeValue = paymentTypeResolver.resolve(paymentType);
|
||||
|
||||
// Get classification code value
|
||||
final Long classificationId = getClassificationCodeValueId(classificationCodeName);
|
||||
|
||||
final PostLoansLoanIdTransactionsRequest buyDownFeeRequest = LoanRequestFactory.defaultBuyDownFeeIncomeRequest()
|
||||
.transactionDate(transactionDate).transactionAmount(Double.valueOf(amount)).paymentTypeId(paymentTypeValue)
|
||||
.externalId("EXT-BUY-DOWN-FEE" + UUID.randomUUID()).classificationId(classificationId);
|
||||
|
||||
final Response<PostLoansLoanIdTransactionsResponse> buyDownFeeResponse = loanTransactionsApi
|
||||
.executeLoanTransaction(loanId, buyDownFeeRequest, "buyDownFee").execute();
|
||||
return buyDownFeeResponse;
|
||||
}
|
||||
|
||||
@And("Admin adds buy down fee adjustment with {string} payment type to the loan on {string} with {string} EUR transaction amount")
|
||||
public void adminAddsBuyDownFeesAdjustmentToTheLoan(final String transactionPaymentType, final String transactionDate,
|
||||
final String amount) throws IOException {
|
||||
@@ -5553,4 +5619,50 @@ public class LoanStepDef extends AbstractStepDef {
|
||||
eventAssertion.assertEventRaised(LoanBuyDownFeeAmortizationAdjustmentTransactionCreatedBusinessEvent.class,
|
||||
buyDownFeeAmortizationAdjustmentTransactionId);
|
||||
}
|
||||
|
||||
@And("Loan Transactions tab has a {string} transaction with date {string} which has classification code value {string}")
|
||||
public void loanTransactionHasClassification(String transactionType, String expectedDate, String expectedClassification)
|
||||
throws IOException {
|
||||
Response<PostLoansResponse> loanCreateResponse = testContext().get(TestContextKey.LOAN_CREATE_RESPONSE);
|
||||
long loanId = loanCreateResponse.body().getLoanId();
|
||||
|
||||
Response<GetLoansLoanIdResponse> loanDetailsResponse = loansApi.retrieveLoan(loanId, false, "transactions", "", "").execute();
|
||||
ErrorHelper.checkSuccessfulApiCall(loanDetailsResponse);
|
||||
|
||||
List<GetLoansLoanIdTransactions> transactions = loanDetailsResponse.body().getTransactions();
|
||||
GetLoansLoanIdTransactions transaction = transactions.stream()
|
||||
.filter(t -> transactionType.equals(t.getType().getValue()) && expectedDate.equals(FORMATTER.format(t.getDate())))
|
||||
.findFirst().orElseThrow(
|
||||
() -> new IllegalStateException(String.format("No %s transaction found on %s", transactionType, expectedDate)));
|
||||
|
||||
// Get detailed transaction information including classification
|
||||
Response<GetLoansLoanIdTransactionsTransactionIdResponse> transactionDetailsResponse = loanTransactionsApi
|
||||
.retrieveTransaction(loanId, transaction.getId(), null).execute();
|
||||
ErrorHelper.checkSuccessfulApiCall(transactionDetailsResponse);
|
||||
|
||||
GetLoansLoanIdTransactionsTransactionIdResponse transactionDetails = transactionDetailsResponse.body();
|
||||
assertThat(transactionDetails.getClassification()).as(String.format("%s transaction should have classification", transactionType))
|
||||
.isNotNull();
|
||||
assertThat(transactionDetails.getClassification().getName()).as("Classification name should match expected value")
|
||||
.isEqualTo(expectedClassification);
|
||||
}
|
||||
|
||||
private Long getClassificationCodeValueId(String classificationName) throws IOException {
|
||||
final GetCodesResponse code = codeHelper.retrieveCodeByName(classificationName);
|
||||
|
||||
// Delete all existing code values for this classification
|
||||
List<GetCodeValuesDataResponse> existingCodeValues = codeValuesApi.retrieveAllCodeValues(code.getId()).execute().body();
|
||||
for (GetCodeValuesDataResponse codeValue : existingCodeValues) {
|
||||
codeValuesApi.deleteCodeValue(code.getId(), codeValue.getId()).execute();
|
||||
}
|
||||
|
||||
// Create a new code value under the classification code
|
||||
PostCodeValuesDataRequest codeValueRequest = new PostCodeValuesDataRequest().name(classificationName + "_value").isActive(true)
|
||||
.position(1);
|
||||
|
||||
Response<PostCodeValueDataResponse> response = codeHelper.createCodeValue(code.getId(), codeValueRequest);
|
||||
ErrorHelper.checkSuccessfulApiCall(response);
|
||||
|
||||
return response.body().getSubResourceId();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3204,3 +3204,39 @@ Feature:Feature: Buy Down Fees
|
||||
| Date | Fee Amount | Amortized Amount | Not Yet Amortized Amount | Adjusted Amount | Charged Off Amount |
|
||||
| 01 January 2024 | 50.0 | 50.0 | 0.0 | 0.0 | 0.0 |
|
||||
And LoanBuyDownFeeAmortizationTransactionCreatedBusinessEvent is created on "01 April 2024"
|
||||
|
||||
@TestRailId:C4004
|
||||
Scenario: Verify buy down fee transaction creation with classification field set
|
||||
When Admin sets the business date to "01 January 2024"
|
||||
And Admin creates a client with random data
|
||||
And 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_PROGRESSIVE_ADVANCED_PAYMENT_ALLOCATION_BUYDOWN_FEES | 01 January 2024 | 100 | 7 | DECLINING_BALANCE | DAILY | EQUAL_INSTALLMENTS | 3 | MONTHS | 1 | MONTHS | 3 | 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"
|
||||
And Admin successfully disburse the loan on "01 January 2024" with "100" EUR transaction amount
|
||||
Then Loan status will be "ACTIVE"
|
||||
When Admin adds buy down fee with "AUTOPAY" payment type to the loan on "01 January 2024" with "50" EUR transaction amount and "buydown_fee_transaction_classification" classification
|
||||
Then Loan Repayment schedule has 3 periods, with the following data for periods:
|
||||
| Nr | Days | Date | Paid date | Balance of loan | Principal due | Interest | Fees | Penalties | Due | Paid | In advance | Late | Outstanding |
|
||||
| | | 01 January 2024 | | 100.0 | | | 0.0 | | 0.0 | 0.0 | | | |
|
||||
| 1 | 31 | 01 February 2024 | | 66.86 | 33.14 | 0.58 | 0.0 | 0.0 | 33.72 | 0.0 | 0.0 | 0.0 | 33.72 |
|
||||
| 2 | 29 | 01 March 2024 | | 33.53 | 33.33 | 0.39 | 0.0 | 0.0 | 33.72 | 0.0 | 0.0 | 0.0 | 33.72 |
|
||||
| 3 | 31 | 01 April 2024 | | 0.0 | 33.53 | 0.2 | 0.0 | 0.0 | 33.73 | 0.0 | 0.0 | 0.0 | 33.73 |
|
||||
And Loan Repayment schedule has the following data in Total row:
|
||||
| Principal due | Interest | Fees | Penalties | Due | Paid | In advance | Late | Outstanding |
|
||||
| 100.0 | 1.17 | 0.0 | 0.0 | 101.17 | 0.0 | 0.0 | 0.0 | 101.17 |
|
||||
And Loan Transactions tab has the following data:
|
||||
| Transaction date | Transaction Type | Amount | Principal | Interest | Fees | Penalties | Loan Balance | Reverted |
|
||||
| 01 January 2024 | Disbursement | 100.0 | 0.0 | 0.0 | 0.0 | 0.0 | 100.0 | false |
|
||||
| 01 January 2024 | Buy Down Fee | 50.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | false |
|
||||
And Loan Transactions tab has a "BUY_DOWN_FEE" transaction with date "01 January 2024" which has the following Journal entries:
|
||||
| Type | Account code | Account name | Debit | Credit |
|
||||
| EXPENSE | 450280 | Buy Down Expense | 50.0 | |
|
||||
| LIABILITY | 145024 | Deferred Capitalized Income | | 50.0 |
|
||||
And Loan Transactions tab has a "Buy Down Fee" transaction with date "01 January 2024" which has classification code value "buydown_fee_transaction_classification_value"
|
||||
And Buy down fee contains the following data:
|
||||
| Date | Fee Amount | Amortized Amount | Not Yet Amortized Amount | Adjusted Amount | Charged Off Amount |
|
||||
| 01 January 2024 | 50.0 | 0.0 | 50.0 | 0.0 | 0.0 |
|
||||
And LoanBuyDownFeeTransactionCreatedBusinessEvent is created on "01 January 2024"
|
||||
And Admin adds buy down fee adjustment with "AUTOPAY" payment type to the loan on "01 January 2024" with "25" EUR transaction amount
|
||||
And Loan Transactions tab has a "Buy Down Fee Adjustment" transaction with date "01 January 2024" which has classification code value "buydown_fee_transaction_classification_value"
|
||||
|
||||
@@ -7529,3 +7529,40 @@ Feature: Capitalized Income
|
||||
When Admin successfully disburse the loan on "2 January 2024" with "300" EUR transaction amount
|
||||
# Available amount = 1200 - 900 - 300 - 0 = 0
|
||||
Then Loan's available disbursement amount is "0.0"
|
||||
|
||||
@TestRailId:C4005
|
||||
Scenario: Verify capitalized income transaction creation with classification field set
|
||||
When Admin sets the business date to "1 January 2024"
|
||||
And Admin creates a client with random data
|
||||
And 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_PROGRESSIVE_ADVANCED_PAYMENT_ALLOCATION_CAPITALIZED_INCOME | 1 January 2024 | 1000.0 | 0 | FLAT | SAME_AS_REPAYMENT_PERIOD | EQUAL_INSTALLMENTS | 30 | DAYS | 30 | DAYS | 1 | 0 | 0 | 0 | ADVANCED_PAYMENT_ALLOCATION |
|
||||
And Admin successfully approves the loan on "1 January 2024" with "1000" amount and expected disbursement date on "1 January 2024"
|
||||
And Admin successfully disburse the loan on "1 January 2024" with "900" EUR transaction amount
|
||||
Then Loan status will be "ACTIVE"
|
||||
When Admin sets the business date to "2 January 2024"
|
||||
And Admin adds capitalized income with "AUTOPAY" payment type to the loan on "2 January 2024" with "100" EUR transaction amount and "capitalized_income_transaction_classification" classification
|
||||
Then Loan Repayment schedule has 2 periods, with the following data for periods:
|
||||
| Nr | Days | Date | Paid date | Balance of loan | Principal due | Interest | Fees | Penalties | Due | Paid | In advance | Late | Outstanding |
|
||||
| | | 01 January 2024 | | 900.0 | | | 0.0 | | 0.0 | 0.0 | | | |
|
||||
| 1 | 0 | 01 January 2024 | 01 January 2024 | 675.0 | 225.0 | 0.0 | 0.0 | 0.0 | 225.0 | 225.0 | 0.0 | 0.0 | 0.0 |
|
||||
| | | 02 January 2024 | | 100.0 | | | 0.0 | | 0.0 | 0.0 | | | |
|
||||
| 2 | 30 | 31 January 2024 | | 0.0 | 775.0 | 0.0 | 0.0 | 0.0 | 775.0 | 0.0 | 0.0 | 0.0 | 775.0 |
|
||||
And Loan Repayment schedule has the following data in Total row:
|
||||
| Principal due | Interest | Fees | Penalties | Due | Paid | In advance | Late | Outstanding |
|
||||
| 1000.0 | 0.0 | 0.0 | 0.0 | 1000.0 | 225.0 | 0.0 | 0.0 | 775.0 |
|
||||
And Loan Transactions tab has the following data:
|
||||
| Transaction date | Transaction Type | Amount | Principal | Interest | Fees | Penalties | Loan Balance | Reverted |
|
||||
| 01 January 2024 | Disbursement | 900.0 | 0.0 | 0.0 | 0.0 | 0.0 | 900.0 | false |
|
||||
| 01 January 2024 | Down Payment | 225.0 | 225.0 | 0.0 | 0.0 | 0.0 | 675.0 | false |
|
||||
| 02 January 2024 | Capitalized Income | 100.0 | 100.0 | 0.0 | 0.0 | 0.0 | 775.0 | false |
|
||||
And Loan Transactions tab has a "CAPITALIZED_INCOME" transaction with date "02 January 2024" which has the following Journal entries:
|
||||
| Type | Account code | Account name | Debit | Credit |
|
||||
| ASSET | 112601 | Loans Receivable | 100.0 | |
|
||||
| LIABILITY | 145024 | Deferred Capitalized Income | | 100.0 |
|
||||
And Loan Transactions tab has a "Capitalized Income" transaction with date "02 January 2024" which has classification code value "capitalized_income_transaction_classification_value"
|
||||
And Deferred Capitalized Income contains the following data:
|
||||
| Amount | Amortized Amount | Unrecognized Amount | Adjusted Amount | Charged Off Amount |
|
||||
| 100.0 | 0.0 | 100.0 | 0.0 | 0.0 |
|
||||
And Admin adds capitalized income adjustment with "AUTOPAY" payment type to the loan on "02 January 2024" with "50" EUR transaction amount
|
||||
And Loan Transactions tab has a "Capitalized Income Adjustment" transaction with date "02 January 2024" which has classification code value "capitalized_income_transaction_classification_value"
|
||||
|
||||
+4
@@ -60,4 +60,8 @@ public interface LoanTransactionApiConstants {
|
||||
buyDownFeeAmortization, //
|
||||
buyDownFeeAmortizationAdjustment, //
|
||||
}
|
||||
|
||||
String TRANSACTION_CLASSIFICATIONID_PARAMNAME = "classificationId";
|
||||
String CAPITALIZED_INCOME_CLASSIFICATION_CODE = "capitalized_income_transaction_classification";
|
||||
String BUY_DOWN_FEE_CLASSIFICATION_CODE = "buydown_fee_transaction_classification";
|
||||
}
|
||||
|
||||
+19
@@ -32,6 +32,20 @@ final class LoanTransactionsApiResourceSwagger {
|
||||
|
||||
private LoanTransactionsApiResourceSwagger() {}
|
||||
|
||||
static final class GetCodeValuesDataResponse {
|
||||
|
||||
private GetCodeValuesDataResponse() {}
|
||||
|
||||
@Schema(example = "1")
|
||||
public Long id;
|
||||
@Schema(example = "Passport")
|
||||
public String name;
|
||||
@Schema(example = "Passport information")
|
||||
public String description;
|
||||
@Schema(example = "0")
|
||||
public Integer position;
|
||||
}
|
||||
|
||||
@Schema(description = "GetLoansLoanIdTransactionsTemplateResponse")
|
||||
public static final class GetLoansLoanIdTransactionsTemplateResponse {
|
||||
|
||||
@@ -110,6 +124,8 @@ final class LoanTransactionsApiResourceSwagger {
|
||||
public List<GetPaymentTypeOptions> paymentTypeOptions;
|
||||
@Schema(example = "200.000000")
|
||||
public Double netDisbursalAmount;
|
||||
|
||||
public List<GetCodeValuesDataResponse> classificationOptions;
|
||||
}
|
||||
|
||||
public static final class GetLoanCurrency {
|
||||
@@ -263,6 +279,7 @@ final class LoanTransactionsApiResourceSwagger {
|
||||
public Set<GetLoanTransactionRelation> transactionRelations;
|
||||
public Set<GetLoansLoanIdLoanChargePaidByData> loanChargePaidByList;
|
||||
public PaymentDetailData paymentDetailData;
|
||||
public GetCodeValuesDataResponse classification;
|
||||
|
||||
static final class PaymentDetailData {
|
||||
|
||||
@@ -354,6 +371,8 @@ final class LoanTransactionsApiResourceSwagger {
|
||||
// command=reAge END
|
||||
@Schema(description = "Optional. Controls whether Interest Refund transaction should be created for this refund. If not provided, loan product config is used.", example = "false")
|
||||
public Boolean interestRefundCalculation;
|
||||
@Schema(example = "1")
|
||||
public Long classificationId;
|
||||
}
|
||||
|
||||
@Schema(description = "PostLoansLoanIdTransactionsResponse")
|
||||
|
||||
+4
-2
@@ -113,6 +113,8 @@ public class LoanTransactionData implements Serializable {
|
||||
private List<LoanTransactionRelationData> transactionRelations;
|
||||
|
||||
private Collection<CodeValueData> chargeOffReasonOptions = null;
|
||||
private Collection<CodeValueData> classificationOptions = null;
|
||||
private CodeValueData classification;
|
||||
|
||||
public static LoanTransactionData importInstance(BigDecimal repaymentAmount, LocalDate lastRepaymentDate, Long repaymentTypeId,
|
||||
Integer rowIndex, String locale, String dateFormat) {
|
||||
@@ -162,10 +164,10 @@ public class LoanTransactionData implements Serializable {
|
||||
|
||||
public static LoanTransactionData loanTransactionDataForCreditTemplate(final LoanTransactionEnumData transactionType,
|
||||
final LocalDate transactionDate, final BigDecimal transactionAmount, final Collection<PaymentTypeData> paymentOptions,
|
||||
final CurrencyData currency) {
|
||||
final CurrencyData currency, List<CodeValueData> classificationOptions) {
|
||||
return builder().type(transactionType).date(transactionDate).amount(transactionAmount).paymentTypeOptions(paymentOptions)
|
||||
.currency(currency).externalLoanId(ExternalId.empty()).externalId(ExternalId.empty()).reversalExternalId(ExternalId.empty())
|
||||
.manuallyReversed(false).build();
|
||||
.manuallyReversed(false).classificationOptions(classificationOptions).build();
|
||||
}
|
||||
|
||||
public static LoanTransactionData loanTransactionDataForDisbursalTemplate(final LoanTransactionEnumData transactionType,
|
||||
|
||||
+7
@@ -39,6 +39,7 @@ import java.util.Set;
|
||||
import java.util.function.Predicate;
|
||||
import lombok.Getter;
|
||||
import lombok.Setter;
|
||||
import org.apache.fineract.infrastructure.codes.domain.CodeValue;
|
||||
import org.apache.fineract.infrastructure.core.domain.AbstractAuditableWithUTCDateTimeCustom;
|
||||
import org.apache.fineract.infrastructure.core.domain.ExternalId;
|
||||
import org.apache.fineract.infrastructure.core.service.DateUtils;
|
||||
@@ -144,6 +145,11 @@ public class LoanTransaction extends AbstractAuditableWithUTCDateTimeCustom<Long
|
||||
@OneToOne(cascade = CascadeType.ALL, orphanRemoval = true, fetch = FetchType.LAZY, mappedBy = "loanTransaction")
|
||||
private LoanReAgeParameter loanReAgeParameter;
|
||||
|
||||
@Setter
|
||||
@ManyToOne(fetch = FetchType.LAZY)
|
||||
@JoinColumn(name = "classification_cv_id")
|
||||
private CodeValue classification;
|
||||
|
||||
protected LoanTransaction() {}
|
||||
|
||||
public static LoanTransaction incomePosting(final Loan loan, final Office office, final LocalDate dateOf, final BigDecimal amount,
|
||||
@@ -312,6 +318,7 @@ public class LoanTransaction extends AbstractAuditableWithUTCDateTimeCustom<Long
|
||||
if (LoanTransactionType.REAGE.equals(loanTransaction.getTypeOf())) {
|
||||
newTransaction.setLoanReAgeParameter(loanTransaction.getLoanReAgeParameter().getCopy(newTransaction));
|
||||
}
|
||||
newTransaction.setClassification(loanTransaction.getClassification());
|
||||
return newTransaction;
|
||||
}
|
||||
|
||||
|
||||
+2
@@ -33,6 +33,7 @@ public interface LoanTransactionMapper {
|
||||
@Mapping(target = "loanRepaymentScheduleInstallments", ignore = true)
|
||||
@Mapping(target = "writeOffReasonOptions", ignore = true)
|
||||
@Mapping(target = "chargeOffReasonOptions", ignore = true)
|
||||
@Mapping(target = "classificationOptions", ignore = true)
|
||||
@Mapping(target = "paymentTypeOptions", ignore = true)
|
||||
@Mapping(target = "overpaymentPortion", ignore = true)
|
||||
@Mapping(target = "transfer", ignore = true)
|
||||
@@ -63,5 +64,6 @@ public interface LoanTransactionMapper {
|
||||
@Mapping(target = "bankNumber", ignore = true)
|
||||
@Mapping(target = "accountId", ignore = true)
|
||||
@Mapping(target = "transactionAmount", ignore = true)
|
||||
@Mapping(target = "classification", expression = "java(loanTransaction.getClassification() != null ? loanTransaction.getClassification().toData() : null)")
|
||||
LoanTransactionData mapLoanTransaction(LoanTransaction loanTransaction);
|
||||
}
|
||||
|
||||
+2
@@ -96,4 +96,6 @@ public interface LoanTransactionValidator {
|
||||
void validateReversalExternalId(DataValidatorBuilder baseDataValidator, JsonElement element);
|
||||
|
||||
void validateManualInterestRefundTransaction(String json);
|
||||
|
||||
void validateClassificationCodeValue(String codeName, Long transactionClassificationId, DataValidatorBuilder baseDataValidator);
|
||||
}
|
||||
|
||||
+1
@@ -54,4 +54,5 @@
|
||||
<include relativeToChangelogFile="true" file="parts/1029_add_installment_amount_in_multiples_of_to_loan.xml"/>
|
||||
<include relativeToChangelogFile="true" file="parts/1030_add_loan_undo_contract_termination_event.xml"/>
|
||||
<include relativeToChangelogFile="true" file="parts/1031_loan_merchant_buy_down_fee.xml"/>
|
||||
<include relativeToChangelogFile="true" file="parts/1032_add_classification_to_loan_transaction.xml"/>
|
||||
</databaseChangeLog>
|
||||
|
||||
+41
@@ -0,0 +1,41 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!--
|
||||
|
||||
Licensed to the Apache Software Foundation (ASF) under one
|
||||
or more contributor license agreements. See the NOTICE file
|
||||
distributed with this work for additional information
|
||||
regarding copyright ownership. The ASF licenses this file
|
||||
to you under the Apache License, Version 2.0 (the
|
||||
"License"); you may not use this file except in compliance
|
||||
with the License. You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing,
|
||||
software distributed under the License is distributed on an
|
||||
"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
KIND, either express or implied. See the License for the
|
||||
specific language governing permissions and limitations
|
||||
under the License.
|
||||
|
||||
-->
|
||||
<databaseChangeLog xmlns="http://www.liquibase.org/xml/ns/dbchangelog"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://www.liquibase.org/xml/ns/dbchangelog http://www.liquibase.org/xml/ns/dbchangelog/dbchangelog-4.3.xsd">
|
||||
|
||||
<changeSet author="fineract" id="1">
|
||||
<addColumn tableName="m_loan_transaction">
|
||||
<column defaultValueComputed="NULL" name="classification_cv_id" type="BIGINT"/>
|
||||
</addColumn>
|
||||
</changeSet>
|
||||
<changeSet author="fineract" id="2">
|
||||
<insert tableName="m_code">
|
||||
<column name="code_name" value="capitalized_income_transaction_classification"/>
|
||||
<column name="is_system_defined" valueBoolean="true"/>
|
||||
</insert>
|
||||
<insert tableName="m_code">
|
||||
<column name="code_name" value="buydown_fee_transaction_classification"/>
|
||||
<column name="is_system_defined" valueBoolean="true"/>
|
||||
</insert>
|
||||
</changeSet>
|
||||
</databaseChangeLog>
|
||||
+3
-1
@@ -280,10 +280,11 @@ public class LoanTransactionDataTest {
|
||||
BigDecimal transactionAmount = new BigDecimal("3000.00");
|
||||
Collection<PaymentTypeData> paymentOptions = mock(Collection.class);
|
||||
CurrencyData currency = new CurrencyData("USD", "US Dollar", 2, 0, "$", "USD");
|
||||
List<CodeValueData> classificationOptions = mock(List.class);
|
||||
|
||||
// When
|
||||
LoanTransactionData result = LoanTransactionData.loanTransactionDataForCreditTemplate(transactionType, transactionDate,
|
||||
transactionAmount, paymentOptions, currency);
|
||||
transactionAmount, paymentOptions, currency, classificationOptions);
|
||||
|
||||
// Then
|
||||
assertEquals(transactionType, result.getType());
|
||||
@@ -295,6 +296,7 @@ public class LoanTransactionDataTest {
|
||||
assertEquals(ExternalId.empty(), result.getExternalId());
|
||||
assertEquals(ExternalId.empty(), result.getExternalLoanId());
|
||||
assertEquals(ExternalId.empty(), result.getReversalExternalId());
|
||||
assertEquals(classificationOptions, result.getClassificationOptions());
|
||||
}
|
||||
|
||||
@Test
|
||||
|
||||
+16
@@ -26,6 +26,7 @@ import java.util.Optional;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
import org.apache.fineract.infrastructure.codes.domain.CodeValueRepository;
|
||||
import org.apache.fineract.infrastructure.core.api.JsonCommand;
|
||||
import org.apache.fineract.infrastructure.core.data.CommandProcessingResult;
|
||||
import org.apache.fineract.infrastructure.core.data.CommandProcessingResultBuilder;
|
||||
@@ -40,6 +41,7 @@ import org.apache.fineract.portfolio.client.domain.Client;
|
||||
import org.apache.fineract.portfolio.client.exception.ClientNotActiveException;
|
||||
import org.apache.fineract.portfolio.group.domain.Group;
|
||||
import org.apache.fineract.portfolio.group.exception.GroupNotActiveException;
|
||||
import org.apache.fineract.portfolio.loanaccount.api.LoanTransactionApiConstants;
|
||||
import org.apache.fineract.portfolio.loanaccount.domain.Loan;
|
||||
import org.apache.fineract.portfolio.loanaccount.domain.LoanBuyDownFeeBalance;
|
||||
import org.apache.fineract.portfolio.loanaccount.domain.LoanTransaction;
|
||||
@@ -65,6 +67,7 @@ public class BuyDownFeeWritePlatformServiceImpl implements BuyDownFeePlatformSer
|
||||
private final ExternalIdFactory externalIdFactory;
|
||||
private final LoanBuyDownFeeBalanceRepository loanBuyDownFeeBalanceRepository;
|
||||
private final BusinessEventNotifierService businessEventNotifierService;
|
||||
private final CodeValueRepository codeValueRepository;
|
||||
|
||||
@Transactional
|
||||
@Override
|
||||
@@ -93,6 +96,9 @@ public class BuyDownFeeWritePlatformServiceImpl implements BuyDownFeePlatformSer
|
||||
// Add to loan (NO schedule recalculation as per requirements)
|
||||
loan.addLoanTransaction(buyDownFeeTransaction);
|
||||
|
||||
// Add Loan Transaction classification
|
||||
addClassificationCodeToTransaction(command, LoanTransactionApiConstants.BUY_DOWN_FEE_CLASSIFICATION_CODE, buyDownFeeTransaction);
|
||||
|
||||
// Save transaction
|
||||
loanTransactionRepository.saveAndFlush(buyDownFeeTransaction);
|
||||
|
||||
@@ -150,6 +156,8 @@ public class BuyDownFeeWritePlatformServiceImpl implements BuyDownFeePlatformSer
|
||||
buyDownFeeAdjustment.getLoanTransactionRelations().add(LoanTransactionRelation.linkToTransaction(buyDownFeeAdjustment,
|
||||
originalBuyDownFee.get(), LoanTransactionRelationTypeEnum.ADJUSTMENT));
|
||||
|
||||
// Inherit from the target transaction the classification
|
||||
buyDownFeeAdjustment.setClassification(originalBuyDownFee.get().getClassification());
|
||||
// Add transaction to loan
|
||||
loan.addLoanTransaction(buyDownFeeAdjustment);
|
||||
|
||||
@@ -203,4 +211,12 @@ public class BuyDownFeeWritePlatformServiceImpl implements BuyDownFeePlatformSer
|
||||
buyDownFeeBalance.setUnrecognizedAmount(buyDownFeeTransaction.getAmount());
|
||||
loanBuyDownFeeBalanceRepository.saveAndFlush(buyDownFeeBalance);
|
||||
}
|
||||
|
||||
private void addClassificationCodeToTransaction(final JsonCommand command, final String codeName, LoanTransaction loanTransaction) {
|
||||
final Long transactionClassificationId = command
|
||||
.longValueOfParameterNamed(LoanTransactionApiConstants.TRANSACTION_CLASSIFICATIONID_PARAMNAME);
|
||||
if (transactionClassificationId != null) {
|
||||
loanTransaction.setClassification(codeValueRepository.findByCodeNameAndId(codeName, transactionClassificationId));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+14
@@ -25,6 +25,7 @@ import java.util.Map;
|
||||
import java.util.Optional;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.apache.fineract.infrastructure.codes.domain.CodeValueRepository;
|
||||
import org.apache.fineract.infrastructure.core.api.JsonCommand;
|
||||
import org.apache.fineract.infrastructure.core.data.CommandProcessingResult;
|
||||
import org.apache.fineract.infrastructure.core.data.CommandProcessingResultBuilder;
|
||||
@@ -37,6 +38,7 @@ import org.apache.fineract.infrastructure.event.business.domain.loan.transaction
|
||||
import org.apache.fineract.infrastructure.event.business.domain.loan.transaction.LoanCapitalizedIncomeTransactionCreatedBusinessEvent;
|
||||
import org.apache.fineract.infrastructure.event.business.service.BusinessEventNotifierService;
|
||||
import org.apache.fineract.organisation.monetary.domain.Money;
|
||||
import org.apache.fineract.portfolio.loanaccount.api.LoanTransactionApiConstants;
|
||||
import org.apache.fineract.portfolio.loanaccount.domain.Loan;
|
||||
import org.apache.fineract.portfolio.loanaccount.domain.LoanCapitalizedIncomeBalance;
|
||||
import org.apache.fineract.portfolio.loanaccount.domain.LoanLifecycleStateMachine;
|
||||
@@ -66,6 +68,7 @@ public class CapitalizedIncomeWritePlatformServiceImpl implements CapitalizedInc
|
||||
private final LoanBalanceService loanBalanceService;
|
||||
private final LoanLifecycleStateMachine loanLifecycleStateMachine;
|
||||
private final BusinessEventNotifierService businessEventNotifierService;
|
||||
private final CodeValueRepository codeValueRepository;
|
||||
|
||||
@Transactional
|
||||
@Override
|
||||
@@ -86,6 +89,9 @@ public class CapitalizedIncomeWritePlatformServiceImpl implements CapitalizedInc
|
||||
transactionDate, txnExternalId);
|
||||
// Update loan with capitalized income
|
||||
loan.addLoanTransaction(capitalizedIncomeTransaction);
|
||||
// Add Loan Transaction classification
|
||||
addClassificationCodeToTransaction(command, LoanTransactionApiConstants.CAPITALIZED_INCOME_CLASSIFICATION_CODE,
|
||||
capitalizedIncomeTransaction);
|
||||
// Recalculate loan transactions
|
||||
recalculateLoanTransactions(loan, transactionDate, capitalizedIncomeTransaction);
|
||||
// Save and flush (PK is set)
|
||||
@@ -137,6 +143,7 @@ public class CapitalizedIncomeWritePlatformServiceImpl implements CapitalizedInc
|
||||
Money.of(loan.getCurrency(), transactionAmount), paymentDetail, transactionDate, txnExternalId);
|
||||
capitalizedIncomeAdjustment.getLoanTransactionRelations().add(LoanTransactionRelation.linkToTransaction(capitalizedIncomeAdjustment,
|
||||
capitalizedIncome.get(), LoanTransactionRelationTypeEnum.ADJUSTMENT));
|
||||
capitalizedIncomeAdjustment.setClassification(capitalizedIncome.get().getClassification());
|
||||
loan.addLoanTransaction(capitalizedIncomeAdjustment);
|
||||
recalculateLoanTransactions(loan, transactionDate, capitalizedIncomeAdjustment);
|
||||
LoanTransaction savedCapitalizedIncomeAdjustment = loanTransactionRepository.saveAndFlush(capitalizedIncomeAdjustment);
|
||||
@@ -205,4 +212,11 @@ public class CapitalizedIncomeWritePlatformServiceImpl implements CapitalizedInc
|
||||
capitalizedIncomeBalanceRepository.saveAndFlush(capitalizedIncomeBalance);
|
||||
}
|
||||
|
||||
private void addClassificationCodeToTransaction(final JsonCommand command, final String codeName, LoanTransaction loanTransaction) {
|
||||
final Long transactionClassificationId = command
|
||||
.longValueOfParameterNamed(LoanTransactionApiConstants.TRANSACTION_CLASSIFICATIONID_PARAMNAME);
|
||||
if (transactionClassificationId != null) {
|
||||
loanTransaction.setClassification(codeValueRepository.findByCodeNameAndId(codeName, transactionClassificationId));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+21
-3
@@ -45,6 +45,7 @@ import org.apache.fineract.infrastructure.core.service.MathUtil;
|
||||
import org.apache.fineract.organisation.holiday.domain.Holiday;
|
||||
import org.apache.fineract.organisation.workingdays.domain.WorkingDays;
|
||||
import org.apache.fineract.portfolio.common.service.Validator;
|
||||
import org.apache.fineract.portfolio.loanaccount.api.LoanTransactionApiConstants;
|
||||
import org.apache.fineract.portfolio.loanaccount.data.ScheduleGeneratorDTO;
|
||||
import org.apache.fineract.portfolio.loanaccount.domain.Loan;
|
||||
import org.apache.fineract.portfolio.loanaccount.domain.LoanBuyDownFeeBalance;
|
||||
@@ -149,6 +150,11 @@ public class ProgressiveLoanTransactionValidatorImpl implements ProgressiveLoanT
|
||||
}
|
||||
}
|
||||
|
||||
final Long transactionClassificationId = fromApiJsonHelper
|
||||
.extractLongNamed(LoanTransactionApiConstants.TRANSACTION_CLASSIFICATIONID_PARAMNAME, element);
|
||||
loanTransactionValidator.validateClassificationCodeValue(LoanTransactionApiConstants.CAPITALIZED_INCOME_CLASSIFICATION_CODE,
|
||||
transactionClassificationId, baseDataValidator);
|
||||
|
||||
validatePaymentDetails(baseDataValidator, element);
|
||||
validateNote(baseDataValidator, element);
|
||||
validateExternalId(baseDataValidator, element);
|
||||
@@ -276,7 +282,8 @@ public class ProgressiveLoanTransactionValidatorImpl implements ProgressiveLoanT
|
||||
}
|
||||
|
||||
private static final List<String> BUY_DOWN_FEE_TRANSACTION_SUPPORTED_PARAMETERS = List
|
||||
.of(new String[] { "transactionDate", "dateFormat", "locale", "transactionAmount", "paymentTypeId", "note", "externalId" });
|
||||
.of(new String[] { "transactionDate", "dateFormat", "locale", "transactionAmount", "paymentTypeId", "note", "externalId",
|
||||
LoanTransactionApiConstants.TRANSACTION_CLASSIFICATIONID_PARAMNAME });
|
||||
|
||||
@Override
|
||||
public void validateBuyDownFee(JsonCommand command, Long loanId) {
|
||||
@@ -313,6 +320,11 @@ public class ProgressiveLoanTransactionValidatorImpl implements ProgressiveLoanT
|
||||
final BigDecimal transactionAmount = this.fromApiJsonHelper.extractBigDecimalWithLocaleNamed("transactionAmount", element);
|
||||
baseDataValidator.reset().parameter("transactionAmount").value(transactionAmount).notNull().positiveAmount();
|
||||
|
||||
final Long transactionClassificationId = fromApiJsonHelper
|
||||
.extractLongNamed(LoanTransactionApiConstants.TRANSACTION_CLASSIFICATIONID_PARAMNAME, element);
|
||||
loanTransactionValidator.validateClassificationCodeValue(LoanTransactionApiConstants.BUY_DOWN_FEE_CLASSIFICATION_CODE,
|
||||
transactionClassificationId, baseDataValidator);
|
||||
|
||||
throwExceptionIfValidationWarningsExist(dataValidationErrors);
|
||||
}
|
||||
|
||||
@@ -576,9 +588,15 @@ public class ProgressiveLoanTransactionValidatorImpl implements ProgressiveLoanT
|
||||
loanTransactionValidator.validateManualInterestRefundTransaction(json);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void validateClassificationCodeValue(final String codeName, final Long transactionClassificationId,
|
||||
DataValidatorBuilder baseDataValidator) {
|
||||
loanTransactionValidator.validateClassificationCodeValue(codeName, transactionClassificationId, baseDataValidator);
|
||||
}
|
||||
|
||||
private Set<String> getCapitalizedIncomeParameters() {
|
||||
return new HashSet<>(
|
||||
Arrays.asList("transactionDate", "dateFormat", "locale", "transactionAmount", "paymentTypeId", "note", "externalId"));
|
||||
return new HashSet<>(Arrays.asList("transactionDate", "dateFormat", "locale", "transactionAmount", "paymentTypeId", "note",
|
||||
"externalId", LoanTransactionApiConstants.TRANSACTION_CLASSIFICATIONID_PARAMNAME));
|
||||
}
|
||||
|
||||
private Set<String> getCapitalizedIncomeAdjustmentParameters() {
|
||||
|
||||
+5
-2
@@ -18,6 +18,7 @@
|
||||
*/
|
||||
package org.apache.fineract.portfolio.loanaccount.starter;
|
||||
|
||||
import org.apache.fineract.infrastructure.codes.domain.CodeValueRepository;
|
||||
import org.apache.fineract.infrastructure.core.serialization.FromJsonHelper;
|
||||
import org.apache.fineract.infrastructure.core.service.ExternalIdFactory;
|
||||
import org.apache.fineract.infrastructure.event.business.service.BusinessEventNotifierService;
|
||||
@@ -57,11 +58,12 @@ public class ProgressiveLoanAccountConfiguration {
|
||||
NoteWritePlatformService noteWritePlatformService, ExternalIdFactory externalIdFactory,
|
||||
LoanCapitalizedIncomeBalanceRepository capitalizedIncomeBalanceRepository,
|
||||
ReprocessLoanTransactionsService reprocessLoanTransactionsService, LoanBalanceService loanBalanceService,
|
||||
LoanLifecycleStateMachine loanLifecycleStateMachine, BusinessEventNotifierService businessEventNotifierService) {
|
||||
LoanLifecycleStateMachine loanLifecycleStateMachine, BusinessEventNotifierService businessEventNotifierService,
|
||||
CodeValueRepository codeValueRepository) {
|
||||
return new CapitalizedIncomeWritePlatformServiceImpl(loanTransactionValidator, loanAssembler, loanTransactionRepository,
|
||||
paymentDetailWritePlatformService, journalEntryPoster, noteWritePlatformService, externalIdFactory,
|
||||
capitalizedIncomeBalanceRepository, reprocessLoanTransactionsService, loanBalanceService, loanLifecycleStateMachine,
|
||||
businessEventNotifierService);
|
||||
businessEventNotifierService, codeValueRepository);
|
||||
}
|
||||
|
||||
@Bean
|
||||
@@ -89,4 +91,5 @@ public class ProgressiveLoanAccountConfiguration {
|
||||
LoanCapitalizedIncomeBalanceRepository loanCapitalizedIncomeBalanceRepository) {
|
||||
return new CapitalizedIncomeBalanceReadServiceImpl(loanRepository, loanCapitalizedIncomeBalanceRepository);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
+17
@@ -123,6 +123,23 @@ public class CodesApiResource {
|
||||
return this.toApiJsonSerializer.serialize(settings, code, RESPONSE_DATA_PARAMETERS);
|
||||
}
|
||||
|
||||
@GET
|
||||
@Path("name/{codeName}")
|
||||
@Consumes({ MediaType.APPLICATION_JSON })
|
||||
@Produces({ MediaType.APPLICATION_JSON })
|
||||
@Operation(summary = "Retrieve a Code", description = "Returns the details of a Code.\n" + "\n" + "Example Requests:\n" + "\n"
|
||||
+ "codes/1")
|
||||
@ApiResponses({
|
||||
@ApiResponse(responseCode = "200", description = "OK", content = @Content(schema = @Schema(implementation = CodesApiResourceSwagger.GetCodesResponse.class))) })
|
||||
public String retrieveCodeByName(@PathParam("codeName") @Parameter(description = "codeName") final String codeName,
|
||||
@Context final UriInfo uriInfo) {
|
||||
|
||||
final CodeData code = this.readPlatformService.retriveCode(codeName);
|
||||
|
||||
final ApiRequestJsonSerializationSettings settings = this.apiRequestParameterHelper.process(uriInfo.getQueryParameters());
|
||||
return this.toApiJsonSerializer.serialize(settings, code, RESPONSE_DATA_PARAMETERS);
|
||||
}
|
||||
|
||||
@PUT
|
||||
@Path("{codeId}")
|
||||
@Consumes({ MediaType.APPLICATION_JSON })
|
||||
|
||||
+1
-1
@@ -93,7 +93,7 @@ public class LoanTransactionsApiResource {
|
||||
public static final String CAPITALIZED_INCOME = "capitalizedIncome";
|
||||
public static final String INTEREST_REFUND_COMMAND_VALUE = "interest-refund";
|
||||
private final Set<String> responseDataParameters = new HashSet<>(Arrays.asList("id", "type", "date", "currency", "amount", "externalId",
|
||||
LoanApiConstants.REVERSAL_EXTERNAL_ID_PARAMNAME, LoanApiConstants.REVERSED_ON_DATE_PARAMNAME));
|
||||
LoanApiConstants.REVERSAL_EXTERNAL_ID_PARAMNAME, LoanApiConstants.REVERSED_ON_DATE_PARAMNAME, "classification"));
|
||||
|
||||
private static final String RESOURCE_NAME_FOR_PERMISSIONS = "LOAN";
|
||||
|
||||
|
||||
+18
@@ -35,6 +35,8 @@ import java.util.Set;
|
||||
import java.util.stream.Collectors;
|
||||
import lombok.AllArgsConstructor;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
import org.apache.fineract.infrastructure.codes.domain.CodeValue;
|
||||
import org.apache.fineract.infrastructure.codes.domain.CodeValueRepository;
|
||||
import org.apache.fineract.infrastructure.core.api.JsonCommand;
|
||||
import org.apache.fineract.infrastructure.core.data.ApiParameterError;
|
||||
import org.apache.fineract.infrastructure.core.data.DataValidatorBuilder;
|
||||
@@ -67,6 +69,7 @@ import org.apache.fineract.portfolio.common.service.Validator;
|
||||
import org.apache.fineract.portfolio.group.domain.Group;
|
||||
import org.apache.fineract.portfolio.group.exception.GroupNotActiveException;
|
||||
import org.apache.fineract.portfolio.loanaccount.api.LoanApiConstants;
|
||||
import org.apache.fineract.portfolio.loanaccount.api.LoanTransactionApiConstants;
|
||||
import org.apache.fineract.portfolio.loanaccount.data.HolidayDetailDTO;
|
||||
import org.apache.fineract.portfolio.loanaccount.data.ScheduleGeneratorDTO;
|
||||
import org.apache.fineract.portfolio.loanaccount.domain.Loan;
|
||||
@@ -107,6 +110,7 @@ public final class LoanTransactionValidatorImpl implements LoanTransactionValida
|
||||
private final CalendarInstanceRepository calendarInstanceRepository;
|
||||
private final LoanDownPaymentTransactionValidator loanDownPaymentTransactionValidator;
|
||||
private final LoanDisbursementValidator loanDisbursementValidator;
|
||||
private final CodeValueRepository codeValueRepository;
|
||||
|
||||
private void throwExceptionIfValidationWarningsExist(final List<ApiParameterError> dataValidationErrors) {
|
||||
if (!dataValidationErrors.isEmpty()) {
|
||||
@@ -1120,4 +1124,18 @@ public final class LoanTransactionValidatorImpl implements LoanTransactionValida
|
||||
validatePaymentDetails(baseDataValidator, element);
|
||||
throwExceptionIfValidationWarningsExist(dataValidationErrors);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void validateClassificationCodeValue(final String codeName, final Long transactionClassificationId,
|
||||
DataValidatorBuilder baseDataValidator) {
|
||||
baseDataValidator.reset().parameter(LoanTransactionApiConstants.TRANSACTION_CLASSIFICATIONID_PARAMNAME)
|
||||
.value(transactionClassificationId).ignoreIfNull().positiveAmount();
|
||||
if (transactionClassificationId != null) {
|
||||
final CodeValue codeValue = codeValueRepository.findByCodeNameAndId(codeName, transactionClassificationId);
|
||||
if (codeValue == null) {
|
||||
baseDataValidator.reset().parameter(LoanTransactionApiConstants.TRANSACTION_CLASSIFICATIONID_PARAMNAME)
|
||||
.failWithCode("code.value.classification.not.exists", "Code value does not exists in the code " + codeName);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+20
-9
@@ -94,6 +94,7 @@ import org.apache.fineract.portfolio.group.data.GroupGeneralData;
|
||||
import org.apache.fineract.portfolio.group.data.GroupRoleData;
|
||||
import org.apache.fineract.portfolio.group.service.GroupReadPlatformService;
|
||||
import org.apache.fineract.portfolio.loanaccount.api.LoanApiConstants;
|
||||
import org.apache.fineract.portfolio.loanaccount.api.LoanTransactionApiConstants;
|
||||
import org.apache.fineract.portfolio.loanaccount.data.DisbursementData;
|
||||
import org.apache.fineract.portfolio.loanaccount.data.LoanAccountData;
|
||||
import org.apache.fineract.portfolio.loanaccount.data.LoanApplicationTimelineData;
|
||||
@@ -485,6 +486,7 @@ public class LoanReadPlatformServiceImpl implements LoanReadPlatformService, Loa
|
||||
|
||||
LoanTransactionData loanTransactionData = null;
|
||||
Collection<PaymentTypeData> paymentOptions = null;
|
||||
List<CodeValueData> classificationOptions = null;
|
||||
BigDecimal transactionAmount = BigDecimal.ZERO;
|
||||
switch (transactionType) {
|
||||
case CAPITALIZED_INCOME:
|
||||
@@ -499,15 +501,19 @@ public class LoanReadPlatformServiceImpl implements LoanReadPlatformService, Loa
|
||||
: loan.getApprovedPrincipal();
|
||||
transactionAmount = transactionAmount.subtract(loan.getDisbursedAmount()).subtract(capitalizedIncomeBalance);
|
||||
paymentOptions = this.paymentTypeReadPlatformService.retrieveAllPaymentTypes();
|
||||
classificationOptions = this.codeValueReadPlatformService
|
||||
.retrieveCodeValuesByCode(LoanTransactionApiConstants.CAPITALIZED_INCOME_CLASSIFICATION_CODE);
|
||||
loanTransactionData = LoanTransactionData.loanTransactionDataForCreditTemplate(
|
||||
LoanEnumerations.transactionType(transactionType), DateUtils.getBusinessLocalDate(), transactionAmount,
|
||||
paymentOptions, retriveLoanCurrencyData(loanId));
|
||||
paymentOptions, retriveLoanCurrencyData(loanId), classificationOptions);
|
||||
break;
|
||||
case BUY_DOWN_FEE:
|
||||
paymentOptions = this.paymentTypeReadPlatformService.retrieveAllPaymentTypes();
|
||||
classificationOptions = this.codeValueReadPlatformService
|
||||
.retrieveCodeValuesByCode(LoanTransactionApiConstants.BUY_DOWN_FEE_CLASSIFICATION_CODE);
|
||||
loanTransactionData = LoanTransactionData.loanTransactionDataForCreditTemplate(
|
||||
LoanEnumerations.transactionType(transactionType), DateUtils.getBusinessLocalDate(), transactionAmount,
|
||||
paymentOptions, retriveLoanCurrencyData(loanId));
|
||||
paymentOptions, retriveLoanCurrencyData(loanId), classificationOptions);
|
||||
break;
|
||||
case CAPITALIZED_INCOME_ADJUSTMENT:
|
||||
final LoanCapitalizedIncomeBalance loanCapitalizedIncomeBalance = loanCapitalizedIncomeBalanceRepository
|
||||
@@ -518,7 +524,7 @@ public class LoanReadPlatformServiceImpl implements LoanReadPlatformService, Loa
|
||||
.subtract(MathUtil.nullToZero(loanCapitalizedIncomeBalance.getAmountAdjustment()));
|
||||
loanTransactionData = LoanTransactionData.loanTransactionDataForCreditTemplate(
|
||||
LoanEnumerations.transactionType(transactionType), DateUtils.getBusinessLocalDate(), transactionAmount,
|
||||
paymentOptions, retriveLoanCurrencyData(loanId));
|
||||
paymentOptions, retriveLoanCurrencyData(loanId), classificationOptions);
|
||||
break;
|
||||
case BUY_DOWN_FEE_ADJUSTMENT:
|
||||
final LoanBuyDownFeeBalance loanBuyDownFeeBalance = loanBuyDownFeeBalanceRepository.findByLoanIdAndLoanTransactionId(loanId,
|
||||
@@ -528,7 +534,7 @@ public class LoanReadPlatformServiceImpl implements LoanReadPlatformService, Loa
|
||||
: loanBuyDownFeeBalance.getAmount().subtract(MathUtil.nullToZero(loanBuyDownFeeBalance.getAmountAdjustment()));
|
||||
loanTransactionData = LoanTransactionData.loanTransactionDataForCreditTemplate(
|
||||
LoanEnumerations.transactionType(transactionType), DateUtils.getBusinessLocalDate(), transactionAmount,
|
||||
paymentOptions, retriveLoanCurrencyData(loanId));
|
||||
paymentOptions, retriveLoanCurrencyData(loanId), classificationOptions);
|
||||
break;
|
||||
default:
|
||||
loanTransactionData = LoanTransactionData.templateOnTop(retrieveLoanTransactionTemplate(loanId),
|
||||
@@ -1667,13 +1673,15 @@ public class LoanReadPlatformServiceImpl implements LoanReadPlatformService, Loa
|
||||
+ " fromtran.transaction_date as fromTransferDate, fromtran.amount as fromTransferAmount,"
|
||||
+ " fromtran.description as fromTransferDescription, "
|
||||
+ " totran.id as toTransferId, totran.is_reversed as toTransferReversed, "
|
||||
+ " totran.transaction_date as toTransferDate, totran.amount as toTransferAmount,"
|
||||
+ " totran.transaction_date as toTransferDate, totran.amount as toTransferAmount, "
|
||||
+ " clcv.id as classCodeId, clcv.code_value as classCodeValue, "
|
||||
+ " totran.description as toTransferDescription from m_loan l join m_loan_transaction tr on tr.loan_id = l.id "
|
||||
+ " join m_currency rc on rc." + sqlGenerator.escape("code") + " = l.currency_code "
|
||||
+ " left JOIN m_payment_detail pd ON tr.payment_detail_id = pd.id"
|
||||
+ " left join m_payment_type pt on pd.payment_type_id = pt.id left join m_office office on office.id=tr.office_id"
|
||||
+ " left join m_account_transfer_transaction fromtran on fromtran.from_loan_transaction_id = tr.id "
|
||||
+ " left join m_account_transfer_transaction totran on totran.to_loan_transaction_id = tr.id ";
|
||||
+ " left join m_account_transfer_transaction totran on totran.to_loan_transaction_id = tr.id "
|
||||
+ " left join m_code_value clcv on clcv.id = tr.classification_cv_id ";
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -1700,6 +1708,8 @@ public class LoanReadPlatformServiceImpl implements LoanReadPlatformService, Loa
|
||||
|
||||
PaymentDetailData paymentDetailData = null;
|
||||
|
||||
final CodeValueData classificationData = CodeValueData.instance(rs.getLong("classCodeId"), rs.getString("classCodeValue"));
|
||||
|
||||
final Long paymentTypeId = JdbcSupport.getLong(rs, "paymentType");
|
||||
if (paymentTypeId != null) {
|
||||
final String typeName = rs.getString("paymentTypeName");
|
||||
@@ -1759,7 +1769,7 @@ public class LoanReadPlatformServiceImpl implements LoanReadPlatformService, Loa
|
||||
.overpaymentPortion(overPaymentPortion).unrecognizedIncomePortion(unrecognizedIncomePortion).externalId(externalId)
|
||||
.transfer(transfer).outstandingLoanBalance(outstandingLoanBalance).submittedOnDate(submittedOnDate)
|
||||
.manuallyReversed(manuallyReversed).reversalExternalId(reversalExternalId).reversedOnDate(reversedOnDate).loanId(loanId)
|
||||
.externalLoanId(externalLoanId).build();
|
||||
.externalLoanId(externalLoanId).classification(classificationData).build();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2491,8 +2501,9 @@ public class LoanReadPlatformServiceImpl implements LoanReadPlatformService, Loa
|
||||
final Collection<PaymentTypeData> paymentTypeOptions = paymentTypeReadPlatformService.retrieveAllPaymentTypes();
|
||||
final LoanTransactionEnumData transactionType = LoanEnumerations.transactionType(LoanTransactionType.INTEREST_REFUND);
|
||||
|
||||
return LoanTransactionData.loanTransactionDataForCreditTemplate(transactionType, targetTxn.getTransactionDate(),
|
||||
interestRefundAmount, paymentTypeOptions, loan.getCurrency().toData());
|
||||
return LoanTransactionData.builder().transactionType(LoanTransactionType.INTEREST_REFUND.name()).type(transactionType)
|
||||
.date(targetTxn.getTransactionDate()).amount(interestRefundAmount).paymentTypeOptions(paymentTypeOptions)
|
||||
.currency(loan.getCurrency().toData()).build();
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
+4
-2
@@ -20,6 +20,7 @@ package org.apache.fineract.portfolio.loanaccount.starter;
|
||||
|
||||
import org.apache.fineract.cob.service.LoanAccountLockService;
|
||||
import org.apache.fineract.infrastructure.accountnumberformat.domain.AccountNumberFormatRepositoryWrapper;
|
||||
import org.apache.fineract.infrastructure.codes.domain.CodeValueRepository;
|
||||
import org.apache.fineract.infrastructure.codes.domain.CodeValueRepositoryWrapper;
|
||||
import org.apache.fineract.infrastructure.codes.service.CodeValueReadPlatformService;
|
||||
import org.apache.fineract.infrastructure.configuration.domain.ConfigurationDomainService;
|
||||
@@ -391,10 +392,11 @@ public class LoanAccountConfiguration {
|
||||
LoanAssembler loanAssembler, LoanTransactionRepository loanTransactionRepository,
|
||||
PaymentDetailWritePlatformService paymentDetailWritePlatformService, LoanJournalEntryPoster loanJournalEntryPoster,
|
||||
NoteWritePlatformService noteWritePlatformService, ExternalIdFactory externalIdFactory,
|
||||
LoanBuyDownFeeBalanceRepository loanBuyDownFeeBalanceRepository, BusinessEventNotifierService businessEventNotifierService) {
|
||||
LoanBuyDownFeeBalanceRepository loanBuyDownFeeBalanceRepository, BusinessEventNotifierService businessEventNotifierService,
|
||||
CodeValueRepository codeValueRepository) {
|
||||
return new BuyDownFeeWritePlatformServiceImpl(loanTransactionValidator, loanAssembler, loanTransactionRepository,
|
||||
paymentDetailWritePlatformService, loanJournalEntryPoster, noteWritePlatformService, externalIdFactory,
|
||||
loanBuyDownFeeBalanceRepository, businessEventNotifierService);
|
||||
loanBuyDownFeeBalanceRepository, businessEventNotifierService, codeValueRepository);
|
||||
}
|
||||
|
||||
@Bean
|
||||
|
||||
+23
-1
@@ -29,10 +29,14 @@ import java.util.List;
|
||||
import java.util.Optional;
|
||||
import java.util.concurrent.atomic.AtomicReference;
|
||||
import org.apache.fineract.client.models.CapitalizedIncomeDetails;
|
||||
import org.apache.fineract.client.models.GetCodesResponse;
|
||||
import org.apache.fineract.client.models.GetLoansLoanIdResponse;
|
||||
import org.apache.fineract.client.models.GetLoansLoanIdTransactions;
|
||||
import org.apache.fineract.client.models.GetLoansLoanIdTransactionsTransactionIdResponse;
|
||||
import org.apache.fineract.client.models.LoanCapitalizedIncomeData;
|
||||
import org.apache.fineract.client.models.PostClientsResponse;
|
||||
import org.apache.fineract.client.models.PostCodeValueDataResponse;
|
||||
import org.apache.fineract.client.models.PostCodeValuesDataRequest;
|
||||
import org.apache.fineract.client.models.PostLoanProductsRequest;
|
||||
import org.apache.fineract.client.models.PostLoanProductsResponse;
|
||||
import org.apache.fineract.client.models.PostLoansLoanIdTransactionsRequest;
|
||||
@@ -45,6 +49,7 @@ import org.apache.fineract.integrationtests.common.Utils;
|
||||
import org.apache.fineract.integrationtests.common.externalevents.LoanAdjustTransactionBusinessEvent;
|
||||
import org.apache.fineract.integrationtests.common.externalevents.LoanBusinessEvent;
|
||||
import org.apache.fineract.integrationtests.common.externalevents.LoanTransactionBusinessEvent;
|
||||
import org.apache.fineract.portfolio.loanaccount.api.LoanTransactionApiConstants;
|
||||
import org.junit.jupiter.api.Assertions;
|
||||
import org.junit.jupiter.api.BeforeAll;
|
||||
import org.junit.jupiter.api.Test;
|
||||
@@ -185,6 +190,11 @@ public class LoanCapitalizedIncomeTest extends BaseLoanIntegrationTest {
|
||||
.incomeFromCapitalizationAccountId(feeIncomeAccount.getAccountID().longValue())
|
||||
.capitalizedIncomeType(PostLoanProductsRequest.CapitalizedIncomeTypeEnum.FEE));
|
||||
|
||||
final GetCodesResponse code = codeHelper.retrieveCodeByName(LoanTransactionApiConstants.CAPITALIZED_INCOME_CLASSIFICATION_CODE);
|
||||
final PostCodeValueDataResponse classificationCode = codeHelper.createCodeValue(code.getId(),
|
||||
new PostCodeValuesDataRequest().name(Utils.uniqueRandomStringGenerator("CLASS_", 6)).isActive(true).position(10));
|
||||
final Long classificationId = classificationCode.getSubResourceId();
|
||||
|
||||
runAt("1 April 2024", () -> {
|
||||
Long loanId = applyAndApproveProgressiveLoan(client.getClientId(), loanProductsResponse.getResourceId(), "1 January 2024",
|
||||
500.0, 7.0, 3, null);
|
||||
@@ -192,9 +202,15 @@ public class LoanCapitalizedIncomeTest extends BaseLoanIntegrationTest {
|
||||
|
||||
disburseLoan(loanId, BigDecimal.valueOf(100), "1 January 2024");
|
||||
PostLoansLoanIdTransactionsResponse capitalizedIncomeResponse = loanTransactionHelper.addCapitalizedIncome(loanId,
|
||||
"1 January 2024", 50.0);
|
||||
"1 January 2024", 50.0, classificationId);
|
||||
capitalizedIncomeIdRef.set(capitalizedIncomeResponse.getResourceId());
|
||||
|
||||
// Validate Loan Transaction classification set value
|
||||
GetLoansLoanIdTransactionsTransactionIdResponse transactionDetails = loanTransactionHelper.getLoanTransactionDetails(loanId,
|
||||
capitalizedIncomeIdRef.get());
|
||||
assertNotNull(transactionDetails.getClassification());
|
||||
assertEquals(classificationId, transactionDetails.getClassification().getId());
|
||||
|
||||
PostLoansLoanIdTransactionsResponse capitalizedIncomeAdjustmentResponse = loanTransactionHelper
|
||||
.capitalizedIncomeAdjustment(loanId, capitalizedIncomeIdRef.get(), "1 April 2024", 50.0);
|
||||
assertNotNull(capitalizedIncomeAdjustmentResponse.getLoanId());
|
||||
@@ -222,6 +238,12 @@ public class LoanCapitalizedIncomeTest extends BaseLoanIntegrationTest {
|
||||
journalEntry(49.71, loansReceivableAccount, "CREDIT"), //
|
||||
journalEntry(0.29, interestReceivableAccount, "CREDIT") //
|
||||
);
|
||||
|
||||
// Validate Loan Transaction classification Inherit
|
||||
transactionDetails = loanTransactionHelper.getLoanTransactionDetails(loanId,
|
||||
capitalizedIncomeAdjustmentResponse.getResourceId());
|
||||
assertNotNull(transactionDetails.getClassification());
|
||||
assertEquals(classificationId, transactionDetails.getClassification().getId());
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
+13
@@ -26,15 +26,20 @@ import java.util.List;
|
||||
import java.util.UUID;
|
||||
import java.util.concurrent.atomic.AtomicReference;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.apache.fineract.client.models.GetCodesResponse;
|
||||
import org.apache.fineract.client.models.GetLoansLoanIdTransactionsResponse;
|
||||
import org.apache.fineract.client.models.GetLoansLoanIdTransactionsTemplateResponse;
|
||||
import org.apache.fineract.client.models.PostClientsResponse;
|
||||
import org.apache.fineract.client.models.PostCodeValueDataResponse;
|
||||
import org.apache.fineract.client.models.PostCodeValuesDataRequest;
|
||||
import org.apache.fineract.client.models.PostLoanProductsRequest;
|
||||
import org.apache.fineract.client.models.PostLoanProductsResponse;
|
||||
import org.apache.fineract.client.models.PostLoansLoanIdTransactionsRequest;
|
||||
import org.apache.fineract.client.models.PostLoansLoanIdTransactionsResponse;
|
||||
import org.apache.fineract.client.models.TransactionType;
|
||||
import org.apache.fineract.integrationtests.common.ClientHelper;
|
||||
import org.apache.fineract.integrationtests.common.Utils;
|
||||
import org.apache.fineract.portfolio.loanaccount.api.LoanTransactionApiConstants;
|
||||
import org.junit.jupiter.api.Assertions;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
@@ -103,6 +108,9 @@ public class LoanTransactionTest extends BaseLoanIntegrationTest {
|
||||
@Test
|
||||
public void testGetLoanTransactionTemplateForCapitalizedIncomeWithOverAppliedAmount() {
|
||||
final PostClientsResponse client = clientHelper.createClient(ClientHelper.defaultClientCreationRequest());
|
||||
final GetCodesResponse code = codeHelper.retrieveCodeByName(LoanTransactionApiConstants.CAPITALIZED_INCOME_CLASSIFICATION_CODE);
|
||||
final PostCodeValueDataResponse classificationCode = codeHelper.createCodeValue(code.getId(),
|
||||
new PostCodeValuesDataRequest().name(Utils.uniqueRandomStringGenerator("CLASS_", 6)).isActive(true).position(10));
|
||||
|
||||
final PostLoanProductsResponse loanProductsResponse = loanProductHelper
|
||||
.createLoanProduct(create4IProgressive().enableIncomeCapitalization(true)
|
||||
@@ -127,6 +135,7 @@ public class LoanTransactionTest extends BaseLoanIntegrationTest {
|
||||
assertEquals("loanTransactionType." + capitalizedIncomeCommand, transactionTemplate.getType().getCode());
|
||||
assertEquals(transactionTemplate.getAmount(), 415);
|
||||
assertThat(transactionTemplate.getPaymentTypeOptions().size() > 0);
|
||||
assertThat(transactionTemplate.getClassificationOptions().size() > 0);
|
||||
});
|
||||
}
|
||||
|
||||
@@ -242,6 +251,9 @@ public class LoanTransactionTest extends BaseLoanIntegrationTest {
|
||||
@Test
|
||||
public void testGetLoanTransactionTemplateForBuyDownFee() {
|
||||
final PostClientsResponse client = clientHelper.createClient(ClientHelper.defaultClientCreationRequest());
|
||||
final GetCodesResponse code = codeHelper.retrieveCodeByName(LoanTransactionApiConstants.BUY_DOWN_FEE_CLASSIFICATION_CODE);
|
||||
final PostCodeValueDataResponse classificationCode = codeHelper.createCodeValue(code.getId(),
|
||||
new PostCodeValuesDataRequest().name(Utils.uniqueRandomStringGenerator("CLASS_", 6)).isActive(true).position(10));
|
||||
|
||||
final PostLoanProductsResponse loanProductsResponse = loanProductHelper
|
||||
.createLoanProduct(create4IProgressive().enableIncomeCapitalization(true)
|
||||
@@ -266,6 +278,7 @@ public class LoanTransactionTest extends BaseLoanIntegrationTest {
|
||||
assertEquals("loanTransactionType." + buyDownFeeCommand, transactionTemplate.getType().getCode());
|
||||
assertEquals(transactionTemplate.getAmount(), 0);
|
||||
assertThat(transactionTemplate.getPaymentTypeOptions().size() > 0);
|
||||
assertThat(transactionTemplate.getClassificationOptions().size() > 0);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
+6
@@ -930,6 +930,12 @@ public class LoanTransactionHelper {
|
||||
.transactionDate(transactionDate).dateFormat("dd MMMM yyyy").locale("en"));
|
||||
}
|
||||
|
||||
public PostLoansLoanIdTransactionsResponse addCapitalizedIncome(final Long loanId, final String transactionDate, final double amount,
|
||||
final Long classificationId) {
|
||||
return addCapitalizedIncome(loanId, new PostLoansLoanIdTransactionsRequest().transactionAmount(amount)
|
||||
.transactionDate(transactionDate).dateFormat("dd MMMM yyyy").locale("en").classificationId(classificationId));
|
||||
}
|
||||
|
||||
public Response<CommandProcessingResult> createInterestPause(Long loanId, String startDate, String endDate) {
|
||||
log.info("Creating interest pause for Loan {} from {} to {}", loanId, startDate, endDate);
|
||||
return Calls.executeU(FineractClientHelper.getFineractClient().loanInterestPauseApi.createInterestPause(loanId,
|
||||
|
||||
+4
@@ -388,4 +388,8 @@ public final class CodeHelper {
|
||||
public List<GetCodesResponse> retrieveCodes() {
|
||||
return Calls.ok(FineractClientHelper.getFineractClient().codes.retrieveCodes());
|
||||
}
|
||||
|
||||
public GetCodesResponse retrieveCodeByName(final String codeName) {
|
||||
return Calls.ok(FineractClientHelper.getFineractClient().codes.retrieveCodeByName(codeName));
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user