Refactor Loan to support auditable fields

This commit is contained in:
Adam Saghy
2022-07-26 09:56:30 +02:00
committed by Arnold Gálovics
parent d8f483ab45
commit 176c5700d0
6 changed files with 325 additions and 18 deletions
@@ -482,7 +482,7 @@ public class AccountDetailsReadPlatformServiceJpaRepositoryImpl implements Accou
.append(" l.writtenoffon_date as writtenOffOnDate, l.expected_maturedon_date as expectedMaturityDate") .append(" l.writtenoffon_date as writtenOffOnDate, l.expected_maturedon_date as expectedMaturityDate")
.append(" from m_loan l ").append("LEFT JOIN m_product_loan AS lp ON lp.id = l.product_id") .append(" from m_loan l ").append("LEFT JOIN m_product_loan AS lp ON lp.id = l.product_id")
.append(" left join m_appuser sbu on sbu.id = l.submittedon_userid") .append(" left join m_appuser sbu on sbu.id = l.created_by")
.append(" left join m_appuser rbu on rbu.id = l.rejectedon_userid") .append(" left join m_appuser rbu on rbu.id = l.rejectedon_userid")
.append(" left join m_appuser wbu on wbu.id = l.withdrawnon_userid") .append(" left join m_appuser wbu on wbu.id = l.withdrawnon_userid")
.append(" left join m_appuser abu on abu.id = l.approvedon_userid") .append(" left join m_appuser abu on abu.id = l.approvedon_userid")
@@ -0,0 +1,110 @@
/**
* 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.portfolio.loanaccount.api;
import static org.apache.fineract.infrastructure.core.domain.AuditableFieldsConstants.CREATED_BY;
import static org.apache.fineract.infrastructure.core.domain.AuditableFieldsConstants.CREATED_DATE;
import static org.apache.fineract.infrastructure.core.domain.AuditableFieldsConstants.LAST_MODIFIED_BY;
import static org.apache.fineract.infrastructure.core.domain.AuditableFieldsConstants.LAST_MODIFIED_DATE;
import java.util.HashMap;
import java.util.Map;
import javax.ws.rs.Consumes;
import javax.ws.rs.GET;
import javax.ws.rs.Path;
import javax.ws.rs.PathParam;
import javax.ws.rs.Produces;
import javax.ws.rs.core.Context;
import javax.ws.rs.core.MediaType;
import javax.ws.rs.core.UriInfo;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.apache.fineract.infrastructure.core.api.ApiRequestParameterHelper;
import org.apache.fineract.infrastructure.core.serialization.ApiRequestJsonSerializationSettings;
import org.apache.fineract.infrastructure.core.serialization.ToApiJsonSerializer;
import org.apache.fineract.portfolio.loanaccount.domain.Loan;
import org.apache.fineract.portfolio.loanaccount.domain.LoanRepositoryWrapper;
import org.apache.fineract.portfolio.loanaccount.domain.LoanTransaction;
import org.apache.fineract.portfolio.loanaccount.domain.LoanTransactionRepository;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.stereotype.Component;
//@Profile("test")
@Component
@Path("/internal/loan")
@RequiredArgsConstructor
@Slf4j
public class InternalLoanInformationApiResource implements InitializingBean {
private final LoanRepositoryWrapper loanRepositoryWrapper;
private final LoanTransactionRepository loanTransactionRepository;
private final ToApiJsonSerializer<Map> toApiJsonSerializer;
private final ApiRequestParameterHelper apiRequestParameterHelper;
@Override
public void afterPropertiesSet() {
log.warn("------------------------------------------------------------");
log.warn(" ");
log.warn("DO NOT USE THIS IN PRODUCTION!");
log.warn("Internal loan services mode is enabled");
log.warn("DO NOT USE THIS IN PRODUCTION!");
log.warn(" ");
log.warn("------------------------------------------------------------");
}
@GET
@Path("{loanId}/audit")
@Consumes({ MediaType.APPLICATION_JSON })
@Produces({ MediaType.APPLICATION_JSON })
public String getLoanAuditFields(@Context final UriInfo uriInfo, @PathParam("loanId") Long loanId) {
log.warn("------------------------------------------------------------");
log.warn(" ");
log.warn("Fetching loan with {}", loanId);
log.warn(" ");
log.warn("------------------------------------------------------------");
final Loan loan = loanRepositoryWrapper.findOneWithNotFoundDetection(loanId);
Map<String, Object> auditFields = new HashMap<>(
Map.of(CREATED_BY, loan.getCreatedBy().orElse(null), CREATED_DATE, loan.getCreatedDate().orElse(null), LAST_MODIFIED_BY,
loan.getLastModifiedBy().orElse(null), LAST_MODIFIED_DATE, loan.getLastModifiedDate().orElse(null)));
final ApiRequestJsonSerializationSettings settings = this.apiRequestParameterHelper.process(uriInfo.getQueryParameters());
return this.toApiJsonSerializer.serialize(settings, auditFields);
}
@GET
@Path("{loanId}/transaction/{transactionId}/audit")
@Consumes({ MediaType.APPLICATION_JSON })
@Produces({ MediaType.APPLICATION_JSON })
public String getLoanTransactionAuditFields(@Context final UriInfo uriInfo, @PathParam("loanId") Long loanId,
@PathParam("transactionId") Long transactionId) {
log.warn("------------------------------------------------------------");
log.warn(" ");
log.warn("Fetching loan transaction with loanId {}, transactionId {}", loanId, transactionId);
log.warn(" ");
log.warn("------------------------------------------------------------");
final LoanTransaction transaction = loanTransactionRepository.findById(transactionId).orElseThrow();
Map<String, Object> auditFields = new HashMap<>(Map.of(CREATED_BY, transaction.getCreatedBy().orElse(null), CREATED_DATE,
transaction.getCreatedDate().orElse(null), LAST_MODIFIED_BY, transaction.getLastModifiedBy().orElse(null),
LAST_MODIFIED_DATE, transaction.getLastModifiedDate().orElse(null)));
final ApiRequestJsonSerializationSettings settings = this.apiRequestParameterHelper.process(uriInfo.getQueryParameters());
return this.toApiJsonSerializer.serialize(settings, auditFields);
}
}
@@ -64,7 +64,7 @@ import org.apache.commons.lang3.StringUtils;
import org.apache.fineract.infrastructure.codes.domain.CodeValue; import org.apache.fineract.infrastructure.codes.domain.CodeValue;
import org.apache.fineract.infrastructure.core.api.JsonCommand; import org.apache.fineract.infrastructure.core.api.JsonCommand;
import org.apache.fineract.infrastructure.core.data.ApiParameterError; import org.apache.fineract.infrastructure.core.data.ApiParameterError;
import org.apache.fineract.infrastructure.core.domain.AbstractPersistableCustom; import org.apache.fineract.infrastructure.core.domain.AbstractAuditableWithUTCDateTimeCustom;
import org.apache.fineract.infrastructure.core.exception.PlatformApiDataValidationException; import org.apache.fineract.infrastructure.core.exception.PlatformApiDataValidationException;
import org.apache.fineract.infrastructure.core.serialization.JsonParserHelper; import org.apache.fineract.infrastructure.core.serialization.JsonParserHelper;
import org.apache.fineract.infrastructure.core.service.DateUtils; import org.apache.fineract.infrastructure.core.service.DateUtils;
@@ -151,7 +151,7 @@ import org.springframework.stereotype.Component;
@Component @Component
@Table(name = "m_loan", uniqueConstraints = { @UniqueConstraint(columnNames = { "account_no" }, name = "loan_account_no_UNIQUE"), @Table(name = "m_loan", uniqueConstraints = { @UniqueConstraint(columnNames = { "account_no" }, name = "loan_account_no_UNIQUE"),
@UniqueConstraint(columnNames = { "external_id" }, name = "loan_externalid_UNIQUE") }) @UniqueConstraint(columnNames = { "external_id" }, name = "loan_externalid_UNIQUE") })
public class Loan extends AbstractPersistableCustom { public class Loan extends AbstractAuditableWithUTCDateTimeCustom {
private static final Logger LOG = LoggerFactory.getLogger(Loan.class); private static final Logger LOG = LoggerFactory.getLogger(Loan.class);
@@ -219,9 +219,9 @@ public class Loan extends AbstractPersistableCustom {
@Column(name = "submittedon_date") @Column(name = "submittedon_date")
private LocalDate submittedOnDate; private LocalDate submittedOnDate;
@ManyToOne(optional = true, fetch = FetchType.LAZY) // @ManyToOne(optional = true, fetch = FetchType.LAZY)
@JoinColumn(name = "submittedon_userid", nullable = true) // @JoinColumn(name = "submittedon_userid", nullable = true)
private AppUser submittedBy; // private AppUser submittedBy;
@Column(name = "rejectedon_date") @Column(name = "rejectedon_date")
private LocalDate rejectedOnDate; private LocalDate rejectedOnDate;
@@ -2029,10 +2029,10 @@ public class Loan extends AbstractPersistableCustom {
} }
} }
public void loanApplicationSubmittal(final AppUser currentUser, final LoanScheduleModel loanSchedule, public void loanApplicationSubmittal(final LoanScheduleModel loanSchedule, final LoanApplicationTerms loanApplicationTerms,
final LoanApplicationTerms loanApplicationTerms, final LoanLifecycleStateMachine lifecycleStateMachine, final LoanLifecycleStateMachine lifecycleStateMachine, final LocalDate submittedOn, final String externalId,
final LocalDate submittedOn, final String externalId, final boolean allowTransactionsOnHoliday, final List<Holiday> holidays, final boolean allowTransactionsOnHoliday, final List<Holiday> holidays, final WorkingDays workingDays,
final WorkingDays workingDays, final boolean allowTransactionsOnNonWorkingDay) { final boolean allowTransactionsOnNonWorkingDay) {
updateLoanSchedule(loanSchedule); updateLoanSchedule(loanSchedule);
@@ -2048,7 +2048,6 @@ public class Loan extends AbstractPersistableCustom {
this.termFrequency = loanApplicationTerms.getLoanTermFrequency(); this.termFrequency = loanApplicationTerms.getLoanTermFrequency();
this.termPeriodFrequencyType = loanApplicationTerms.getLoanTermPeriodFrequencyType().getValue(); this.termPeriodFrequencyType = loanApplicationTerms.getLoanTermPeriodFrequencyType().getValue();
this.submittedOnDate = submittedOn; this.submittedOnDate = submittedOn;
this.submittedBy = currentUser;
this.expectedDisbursementDate = loanApplicationTerms.getExpectedDisbursementDate(); this.expectedDisbursementDate = loanApplicationTerms.getExpectedDisbursementDate();
this.expectedFirstRepaymentOnDate = loanApplicationTerms.getRepaymentStartFromDate(); this.expectedFirstRepaymentOnDate = loanApplicationTerms.getRepaymentStartFromDate();
this.interestChargedFromDate = loanApplicationTerms.getInterestChargedFromDate(); this.interestChargedFromDate = loanApplicationTerms.getInterestChargedFromDate();
@@ -284,7 +284,6 @@ public class LoanApplicationWritePlatformServiceJpaRepositoryImpl implements Loa
public CommandProcessingResult submitApplication(final JsonCommand command) { public CommandProcessingResult submitApplication(final JsonCommand command) {
try { try {
final AppUser currentUser = getAppUserIfPresent();
boolean isMeetingMandatoryForJLGLoans = configurationDomainService.isMeetingMandatoryForJLGLoans(); boolean isMeetingMandatoryForJLGLoans = configurationDomainService.isMeetingMandatoryForJLGLoans();
final Long productId = this.fromJsonHelper.extractLongNamed("productId", command.parsedJson()); final Long productId = this.fromJsonHelper.extractLongNamed("productId", command.parsedJson());
final LoanProduct loanProduct = this.loanProductRepository.findById(productId) final LoanProduct loanProduct = this.loanProductRepository.findById(productId)
@@ -334,7 +333,7 @@ public class LoanApplicationWritePlatformServiceJpaRepositoryImpl implements Loa
throw new PlatformApiDataValidationException(dataValidationErrors); throw new PlatformApiDataValidationException(dataValidationErrors);
} }
final Loan newLoanApplication = this.loanAssembler.assembleFrom(command, currentUser); final Loan newLoanApplication = this.loanAssembler.assembleFrom(command);
checkForProductMixRestrictions(newLoanApplication); checkForProductMixRestrictions(newLoanApplication);
@@ -87,7 +87,6 @@ import org.apache.fineract.portfolio.loanproduct.exception.LinkedAccountRequired
import org.apache.fineract.portfolio.loanproduct.exception.LoanProductNotFoundException; import org.apache.fineract.portfolio.loanproduct.exception.LoanProductNotFoundException;
import org.apache.fineract.portfolio.rate.domain.Rate; import org.apache.fineract.portfolio.rate.domain.Rate;
import org.apache.fineract.portfolio.rate.service.RateAssembler; import org.apache.fineract.portfolio.rate.service.RateAssembler;
import org.apache.fineract.useradministration.domain.AppUser;
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service; import org.springframework.stereotype.Service;
@@ -159,16 +158,16 @@ public class LoanAssembler {
this.loanRepaymentScheduleTransactionProcessorFactory); this.loanRepaymentScheduleTransactionProcessorFactory);
} }
public Loan assembleFrom(final JsonCommand command, final AppUser currentUser) { public Loan assembleFrom(final JsonCommand command) {
final JsonElement element = command.parsedJson(); final JsonElement element = command.parsedJson();
final Long clientId = this.fromApiJsonHelper.extractLongNamed("clientId", element); final Long clientId = this.fromApiJsonHelper.extractLongNamed("clientId", element);
final Long groupId = this.fromApiJsonHelper.extractLongNamed("groupId", element); final Long groupId = this.fromApiJsonHelper.extractLongNamed("groupId", element);
return assembleApplication(element, clientId, groupId, currentUser); return assembleApplication(element, clientId, groupId);
} }
private Loan assembleApplication(final JsonElement element, final Long clientId, final Long groupId, final AppUser currentUser) { private Loan assembleApplication(final JsonElement element, final Long clientId, final Long groupId) {
final String accountNo = this.fromApiJsonHelper.extractStringNamed("accountNo", element); final String accountNo = this.fromApiJsonHelper.extractStringNamed("accountNo", element);
final Long productId = this.fromApiJsonHelper.extractLongNamed("productId", element); final Long productId = this.fromApiJsonHelper.extractLongNamed("productId", element);
@@ -348,7 +347,7 @@ public class LoanAssembler {
final boolean allowTransactionsOnHoliday = this.configurationDomainService.allowTransactionsOnHolidayEnabled(); final boolean allowTransactionsOnHoliday = this.configurationDomainService.allowTransactionsOnHolidayEnabled();
final LoanScheduleModel loanScheduleModel = this.loanScheduleAssembler.assembleLoanScheduleFrom(loanApplicationTerms, final LoanScheduleModel loanScheduleModel = this.loanScheduleAssembler.assembleLoanScheduleFrom(loanApplicationTerms,
isHolidayEnabled, holidays, workingDays, element, disbursementDetails); isHolidayEnabled, holidays, workingDays, element, disbursementDetails);
loanApplication.loanApplicationSubmittal(currentUser, loanScheduleModel, loanApplicationTerms, defaultLoanLifecycleStateMachine(), loanApplication.loanApplicationSubmittal(loanScheduleModel, loanApplicationTerms, defaultLoanLifecycleStateMachine(),
submittedOnDate, externalId, allowTransactionsOnHoliday, holidays, workingDays, allowTransactionsOnNonWorkingDay); submittedOnDate, externalId, allowTransactionsOnHoliday, holidays, workingDays, allowTransactionsOnNonWorkingDay);
return loanApplication; return loanApplication;
@@ -0,0 +1,200 @@
/**
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
package org.apache.fineract.integrationtests;
import static org.apache.fineract.infrastructure.core.domain.AuditableFieldsConstants.CREATED_BY;
import static org.apache.fineract.infrastructure.core.domain.AuditableFieldsConstants.CREATED_DATE;
import static org.apache.fineract.infrastructure.core.domain.AuditableFieldsConstants.LAST_MODIFIED_BY;
import static org.apache.fineract.infrastructure.core.domain.AuditableFieldsConstants.LAST_MODIFIED_DATE;
import static org.junit.jupiter.api.Assertions.assertEquals;
import io.restassured.builder.RequestSpecBuilder;
import io.restassured.builder.ResponseSpecBuilder;
import io.restassured.http.ContentType;
import io.restassured.specification.RequestSpecification;
import io.restassured.specification.ResponseSpecification;
import java.time.OffsetDateTime;
import java.time.ZoneId;
import java.time.format.DateTimeFormatter;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import org.apache.fineract.integrationtests.common.ClientHelper;
import org.apache.fineract.integrationtests.common.Utils;
import org.apache.fineract.integrationtests.common.accounting.Account;
import org.apache.fineract.integrationtests.common.accounting.AccountHelper;
import org.apache.fineract.integrationtests.common.loans.LoanApplicationTestBuilder;
import org.apache.fineract.integrationtests.common.loans.LoanProductTestBuilder;
import org.apache.fineract.integrationtests.common.loans.LoanStatusChecker;
import org.apache.fineract.integrationtests.common.loans.LoanTransactionHelper;
import org.apache.fineract.integrationtests.common.organisation.StaffHelper;
import org.apache.fineract.integrationtests.useradministration.users.UserHelper;
import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
public class LoanAuditingIntegrationTest {
private static final Logger LOG = LoggerFactory.getLogger(LoanAuditingIntegrationTest.class);
private ResponseSpecification responseSpec;
private RequestSpecification requestSpec;
private LoanTransactionHelper loanTransactionHelper;
private AccountHelper accountHelper;
@BeforeEach
public void setup() {
Utils.initializeRESTAssured();
this.requestSpec = new RequestSpecBuilder().setContentType(ContentType.JSON).build();
this.requestSpec.header("Authorization", "Basic " + Utils.loginIntoServerAndGetBase64EncodedAuthenticationKey());
this.responseSpec = new ResponseSpecBuilder().expectStatusCode(200).build();
this.loanTransactionHelper = new LoanTransactionHelper(this.requestSpec, this.responseSpec);
this.accountHelper = new AccountHelper(this.requestSpec, this.responseSpec);
}
@Test
public void checkAuditDates() throws InterruptedException {
final Integer staffId = StaffHelper.createStaff(this.requestSpec, this.responseSpec);
String username = Utils.randomNameGenerator("user", 8);
final Integer userId = (Integer) UserHelper.createUser(this.requestSpec, this.responseSpec, 1, staffId, username, "resourceId");
LOG.info("-------------------------Creating Client---------------------------");
final Integer clientID = ClientHelper.createClient(requestSpec, responseSpec);
ClientHelper.verifyClientCreatedOnServer(requestSpec, responseSpec, clientID);
LOG.info("-------------------------Creating Loan---------------------------");
final Account assetAccount = this.accountHelper.createAssetAccount();
final Account incomeAccount = this.accountHelper.createIncomeAccount();
final Account expenseAccount = this.accountHelper.createExpenseAccount();
final Account overpaymentAccount = this.accountHelper.createLiabilityAccount();
final Integer loanProductID = createLoanProduct("0", "0", LoanProductTestBuilder.DEFAULT_STRATEGY, "2", assetAccount, incomeAccount,
expenseAccount, overpaymentAccount);
OffsetDateTime now = OffsetDateTime.now(ZoneId.of("Asia/Kolkata"));
// Testing in minutes precision, but still need to take care around the end of the actual minute
if (now.getSecond() > 56) {
Thread.sleep(5000);
now = OffsetDateTime.now(ZoneId.of("Asia/Kolkata"));
}
final Integer loanID = applyForLoanApplicationWithPaymentStrategyAndPastMonth(clientID, loanProductID, Collections.emptyList(),
null, "10000", LoanApplicationTestBuilder.DEFAULT_STRATEGY, "10 July 2022");
Assertions.assertNotNull(loanID);
HashMap loanStatusHashMap = LoanStatusChecker.getStatusOfLoan(this.requestSpec, this.responseSpec, loanID);
LoanStatusChecker.verifyLoanIsPending(loanStatusHashMap);
Map<String, Object> auditFieldsResponse = LoanTransactionHelper.getLoanAuditFields(requestSpec, responseSpec, loanID, "");
OffsetDateTime createdDate = OffsetDateTime.parse((String) auditFieldsResponse.get(CREATED_DATE),
DateTimeFormatter.ISO_OFFSET_DATE_TIME);
OffsetDateTime lastModifiedDate = OffsetDateTime.parse((String) auditFieldsResponse.get(LAST_MODIFIED_DATE),
DateTimeFormatter.ISO_OFFSET_DATE_TIME);
LOG.info("-------------------------Check Audit dates---------------------------");
assertEquals(1, auditFieldsResponse.get(CREATED_BY));
assertEquals(1, auditFieldsResponse.get(LAST_MODIFIED_BY));
assertEquals(now.getYear(), createdDate.getYear());
assertEquals(now.getMonth(), createdDate.getMonth());
assertEquals(now.getDayOfMonth(), createdDate.getDayOfMonth());
assertEquals(now.getHour(), createdDate.getHour());
assertEquals(now.getMinute(), createdDate.getMinute());
assertEquals(now.getYear(), lastModifiedDate.getYear());
assertEquals(now.getMonth(), lastModifiedDate.getMonth());
assertEquals(now.getDayOfMonth(), lastModifiedDate.getDayOfMonth());
assertEquals(now.getHour(), lastModifiedDate.getHour());
assertEquals(now.getMinute(), lastModifiedDate.getMinute());
LOG.info("-----------------------------------APPROVE LOAN-----------------------------------------");
this.requestSpec = new RequestSpecBuilder().setContentType(ContentType.JSON).build();
this.requestSpec.header("Authorization",
"Basic " + Utils.loginIntoServerAndGetBase64EncodedAuthenticationKey(username, "password"));
this.loanTransactionHelper = new LoanTransactionHelper(this.requestSpec, this.responseSpec);
loanStatusHashMap = this.loanTransactionHelper.approveLoan("11 July 2022", loanID);
LoanStatusChecker.verifyLoanIsApproved(loanStatusHashMap);
auditFieldsResponse = LoanTransactionHelper.getLoanAuditFields(requestSpec, responseSpec, loanID, "");
createdDate = OffsetDateTime.parse((String) auditFieldsResponse.get(CREATED_DATE), DateTimeFormatter.ISO_OFFSET_DATE_TIME);
lastModifiedDate = OffsetDateTime.parse((String) auditFieldsResponse.get(LAST_MODIFIED_DATE),
DateTimeFormatter.ISO_OFFSET_DATE_TIME);
LOG.info("-------------------------Check Audit dates---------------------------");
assertEquals(1, auditFieldsResponse.get(CREATED_BY));
assertEquals(now.getYear(), createdDate.getYear());
assertEquals(now.getMonth(), createdDate.getMonth());
assertEquals(now.getDayOfMonth(), createdDate.getDayOfMonth());
assertEquals(now.getHour(), createdDate.getHour());
assertEquals(now.getMinute(), createdDate.getMinute());
now = OffsetDateTime.now(ZoneId.of("Asia/Kolkata"));
assertEquals(userId, auditFieldsResponse.get(LAST_MODIFIED_BY));
assertEquals(now.getYear(), lastModifiedDate.getYear());
assertEquals(now.getMonth(), lastModifiedDate.getMonth());
assertEquals(now.getDayOfMonth(), lastModifiedDate.getDayOfMonth());
assertEquals(now.getHour(), lastModifiedDate.getHour());
assertEquals(now.getMinute(), lastModifiedDate.getMinute());
}
private Integer applyForLoanApplicationWithPaymentStrategyAndPastMonth(final Integer clientID, final Integer loanProductID,
List<HashMap> charges, final String savingsId, String principal, final String repaymentStrategy, final String submittedOnDate) {
LOG.info("--------------------------------APPLYING FOR LOAN APPLICATION--------------------------------");
final String loanApplicationJSON = new LoanApplicationTestBuilder() //
.withPrincipal(principal) //
.withLoanTermFrequency("6") //
.withLoanTermFrequencyAsMonths() //
.withNumberOfRepayments("6") //
.withRepaymentEveryAfter("1") //
.withRepaymentFrequencyTypeAsMonths() //
.withInterestRatePerPeriod("2") //
.withAmortizationTypeAsEqualInstallments() //
.withInterestTypeAsFlatBalance() //
.withInterestCalculationPeriodTypeSameAsRepaymentPeriod() //
.withExpectedDisbursementDate(submittedOnDate) //
.withSubmittedOnDate(submittedOnDate) //
.withwithRepaymentStrategy(repaymentStrategy) //
.withCharges(charges).build(clientID.toString(), loanProductID.toString(), savingsId);
return this.loanTransactionHelper.getLoanId(loanApplicationJSON);
}
private Integer createLoanProduct(final String inMultiplesOf, final String digitsAfterDecimal, final String repaymentStrategy,
final String accountingRule, final Account... accounts) {
LOG.info("------------------------------CREATING NEW LOAN PRODUCT ---------------------------------------");
final String loanProductJSON = new LoanProductTestBuilder() //
.withPrincipal("10000000.00") //
.withNumberOfRepayments("24") //
.withRepaymentAfterEvery("1") //
.withRepaymentTypeAsMonth() //
.withinterestRatePerPeriod("2") //
.withInterestRateFrequencyTypeAsMonths() //
.withRepaymentStrategy(repaymentStrategy) //
.withAmortizationTypeAsEqualPrincipalPayment() //
.withInterestTypeAsDecliningBalance() //
.currencyDetails(digitsAfterDecimal, inMultiplesOf).withAccounting(accountingRule, accounts).build(null);
return this.loanTransactionHelper.getLoanProductId(loanProductJSON);
}
}