This is an automated email from the ASF dual-hosted git repository.

arnold pushed a commit to branch develop
in repository https://gitbox.apache.org/repos/asf/fineract.git

commit 176c5700d09d5955de7204a60f416b7575b92199
Author: Adam Saghy <[email protected]>
AuthorDate: Sun Jul 24 23:14:56 2022 +0200

    Refactor Loan to support auditable fields
---
 ...etailsReadPlatformServiceJpaRepositoryImpl.java |   2 +-
 .../api/InternalLoanInformationApiResource.java    | 110 ++++++++++++
 .../portfolio/loanaccount/domain/Loan.java         |  19 +-
 ...ationWritePlatformServiceJpaRepositoryImpl.java |   3 +-
 .../loanaccount/service/LoanAssembler.java         |   9 +-
 .../LoanAuditingIntegrationTest.java               | 200 +++++++++++++++++++++
 6 files changed, 325 insertions(+), 18 deletions(-)

diff --git 
a/fineract-provider/src/main/java/org/apache/fineract/portfolio/accountdetails/service/AccountDetailsReadPlatformServiceJpaRepositoryImpl.java
 
b/fineract-provider/src/main/java/org/apache/fineract/portfolio/accountdetails/service/AccountDetailsReadPlatformServiceJpaRepositoryImpl.java
index 158ef8021..e783e7bfb 100644
--- 
a/fineract-provider/src/main/java/org/apache/fineract/portfolio/accountdetails/service/AccountDetailsReadPlatformServiceJpaRepositoryImpl.java
+++ 
b/fineract-provider/src/main/java/org/apache/fineract/portfolio/accountdetails/service/AccountDetailsReadPlatformServiceJpaRepositoryImpl.java
@@ -482,7 +482,7 @@ public class 
AccountDetailsReadPlatformServiceJpaRepositoryImpl implements Accou
                     .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(" 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 wbu on wbu.id = 
l.withdrawnon_userid")
                     .append(" left join m_appuser abu on abu.id = 
l.approvedon_userid")
diff --git 
a/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/api/InternalLoanInformationApiResource.java
 
b/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/api/InternalLoanInformationApiResource.java
new file mode 100644
index 000000000..20cf85559
--- /dev/null
+++ 
b/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/api/InternalLoanInformationApiResource.java
@@ -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);
+    }
+}
diff --git 
a/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/domain/Loan.java
 
b/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/domain/Loan.java
index d74d844ad..05d265c77 100644
--- 
a/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/domain/Loan.java
+++ 
b/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/domain/Loan.java
@@ -64,7 +64,7 @@ import org.apache.commons.lang3.StringUtils;
 import org.apache.fineract.infrastructure.codes.domain.CodeValue;
 import org.apache.fineract.infrastructure.core.api.JsonCommand;
 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.serialization.JsonParserHelper;
 import org.apache.fineract.infrastructure.core.service.DateUtils;
@@ -151,7 +151,7 @@ import org.springframework.stereotype.Component;
 @Component
 @Table(name = "m_loan", uniqueConstraints = { @UniqueConstraint(columnNames = 
{ "account_no" }, name = "loan_account_no_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);
 
@@ -219,9 +219,9 @@ public class Loan extends AbstractPersistableCustom {
     @Column(name = "submittedon_date")
     private LocalDate submittedOnDate;
 
-    @ManyToOne(optional = true, fetch = FetchType.LAZY)
-    @JoinColumn(name = "submittedon_userid", nullable = true)
-    private AppUser submittedBy;
+    // @ManyToOne(optional = true, fetch = FetchType.LAZY)
+    // @JoinColumn(name = "submittedon_userid", nullable = true)
+    // private AppUser submittedBy;
 
     @Column(name = "rejectedon_date")
     private LocalDate rejectedOnDate;
@@ -2029,10 +2029,10 @@ public class Loan extends AbstractPersistableCustom {
         }
     }
 
-    public void loanApplicationSubmittal(final AppUser currentUser, final 
LoanScheduleModel loanSchedule,
-            final LoanApplicationTerms loanApplicationTerms, final 
LoanLifecycleStateMachine lifecycleStateMachine,
-            final LocalDate submittedOn, final String externalId, final 
boolean allowTransactionsOnHoliday, final List<Holiday> holidays,
-            final WorkingDays workingDays, final boolean 
allowTransactionsOnNonWorkingDay) {
+    public void loanApplicationSubmittal(final LoanScheduleModel loanSchedule, 
final LoanApplicationTerms loanApplicationTerms,
+            final LoanLifecycleStateMachine lifecycleStateMachine, final 
LocalDate submittedOn, final String externalId,
+            final boolean allowTransactionsOnHoliday, final List<Holiday> 
holidays, final WorkingDays workingDays,
+            final boolean allowTransactionsOnNonWorkingDay) {
 
         updateLoanSchedule(loanSchedule);
 
@@ -2048,7 +2048,6 @@ public class Loan extends AbstractPersistableCustom {
         this.termFrequency = loanApplicationTerms.getLoanTermFrequency();
         this.termPeriodFrequencyType = 
loanApplicationTerms.getLoanTermPeriodFrequencyType().getValue();
         this.submittedOnDate = submittedOn;
-        this.submittedBy = currentUser;
         this.expectedDisbursementDate = 
loanApplicationTerms.getExpectedDisbursementDate();
         this.expectedFirstRepaymentOnDate = 
loanApplicationTerms.getRepaymentStartFromDate();
         this.interestChargedFromDate = 
loanApplicationTerms.getInterestChargedFromDate();
diff --git 
a/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/service/LoanApplicationWritePlatformServiceJpaRepositoryImpl.java
 
b/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/service/LoanApplicationWritePlatformServiceJpaRepositoryImpl.java
index fa7dcc040..817cde37e 100644
--- 
a/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/service/LoanApplicationWritePlatformServiceJpaRepositoryImpl.java
+++ 
b/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/service/LoanApplicationWritePlatformServiceJpaRepositoryImpl.java
@@ -284,7 +284,6 @@ public class 
LoanApplicationWritePlatformServiceJpaRepositoryImpl implements Loa
     public CommandProcessingResult submitApplication(final JsonCommand 
command) {
 
         try {
-            final AppUser currentUser = getAppUserIfPresent();
             boolean isMeetingMandatoryForJLGLoans = 
configurationDomainService.isMeetingMandatoryForJLGLoans();
             final Long productId = 
this.fromJsonHelper.extractLongNamed("productId", command.parsedJson());
             final LoanProduct loanProduct = 
this.loanProductRepository.findById(productId)
@@ -334,7 +333,7 @@ public class 
LoanApplicationWritePlatformServiceJpaRepositoryImpl implements Loa
                 throw new 
PlatformApiDataValidationException(dataValidationErrors);
             }
 
-            final Loan newLoanApplication = 
this.loanAssembler.assembleFrom(command, currentUser);
+            final Loan newLoanApplication = 
this.loanAssembler.assembleFrom(command);
 
             checkForProductMixRestrictions(newLoanApplication);
 
diff --git 
a/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/service/LoanAssembler.java
 
b/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/service/LoanAssembler.java
index 41b49b026..c57433d22 100644
--- 
a/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/service/LoanAssembler.java
+++ 
b/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/service/LoanAssembler.java
@@ -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.rate.domain.Rate;
 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.stereotype.Service;
 
@@ -159,16 +158,16 @@ public class LoanAssembler {
                 this.loanRepaymentScheduleTransactionProcessorFactory);
     }
 
-    public Loan assembleFrom(final JsonCommand command, final AppUser 
currentUser) {
+    public Loan assembleFrom(final JsonCommand command) {
         final JsonElement element = command.parsedJson();
 
         final Long clientId = 
this.fromApiJsonHelper.extractLongNamed("clientId", 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 Long productId = 
this.fromApiJsonHelper.extractLongNamed("productId", element);
@@ -348,7 +347,7 @@ public class LoanAssembler {
         final boolean allowTransactionsOnHoliday = 
this.configurationDomainService.allowTransactionsOnHolidayEnabled();
         final LoanScheduleModel loanScheduleModel = 
this.loanScheduleAssembler.assembleLoanScheduleFrom(loanApplicationTerms,
                 isHolidayEnabled, holidays, workingDays, element, 
disbursementDetails);
-        loanApplication.loanApplicationSubmittal(currentUser, 
loanScheduleModel, loanApplicationTerms, defaultLoanLifecycleStateMachine(),
+        loanApplication.loanApplicationSubmittal(loanScheduleModel, 
loanApplicationTerms, defaultLoanLifecycleStateMachine(),
                 submittedOnDate, externalId, allowTransactionsOnHoliday, 
holidays, workingDays, allowTransactionsOnNonWorkingDay);
 
         return loanApplication;
diff --git 
a/integration-tests/src/test/java/org/apache/fineract/integrationtests/LoanAuditingIntegrationTest.java
 
b/integration-tests/src/test/java/org/apache/fineract/integrationtests/LoanAuditingIntegrationTest.java
new file mode 100644
index 000000000..1649d26db
--- /dev/null
+++ 
b/integration-tests/src/test/java/org/apache/fineract/integrationtests/LoanAuditingIntegrationTest.java
@@ -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);
+    }
+
+}

Reply via email to