FINERACT-1670: Add auditable fields to Loan Repayment Schedule installment and history
diff --git a/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/domain/LoanRepaymentScheduleInstallment.java b/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/domain/LoanRepaymentScheduleInstallment.java
index 5430c4b..078e051 100644
--- a/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/domain/LoanRepaymentScheduleInstallment.java
+++ b/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/domain/LoanRepaymentScheduleInstallment.java
@@ -31,14 +31,14 @@
 import javax.persistence.ManyToOne;
 import javax.persistence.OneToMany;
 import javax.persistence.Table;
-import org.apache.fineract.infrastructure.core.domain.AbstractAuditableCustom;
+import org.apache.fineract.infrastructure.core.domain.AbstractAuditableWithUTCDateTimeCustom;
 import org.apache.fineract.organisation.monetary.domain.MonetaryCurrency;
 import org.apache.fineract.organisation.monetary.domain.Money;
 import org.apache.fineract.portfolio.repaymentwithpostdatedchecks.domain.PostDatedChecks;
 
 @Entity
 @Table(name = "m_loan_repayment_schedule")
-public final class LoanRepaymentScheduleInstallment extends AbstractAuditableCustom
+public class LoanRepaymentScheduleInstallment extends AbstractAuditableWithUTCDateTimeCustom
         implements Comparable<LoanRepaymentScheduleInstallment> {
 
     @ManyToOne(optional = false)
@@ -135,7 +135,7 @@
     @OneToMany(cascade = CascadeType.ALL, orphanRemoval = true, fetch = FetchType.LAZY, mappedBy = "installment")
     private Set<LoanInstallmentCharge> installmentCharges = new HashSet<>();
 
-    LoanRepaymentScheduleInstallment() {
+    public LoanRepaymentScheduleInstallment() {
         this.installmentNumber = null;
         this.fromDate = null;
         this.dueDate = null;
diff --git a/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/loanschedule/domain/LoanRepaymentScheduleHistory.java b/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/loanschedule/domain/LoanRepaymentScheduleHistory.java
index 7b2acca..36147cc 100644
--- a/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/loanschedule/domain/LoanRepaymentScheduleHistory.java
+++ b/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/loanschedule/domain/LoanRepaymentScheduleHistory.java
@@ -21,6 +21,7 @@
 import java.math.BigDecimal;
 import java.time.LocalDate;
 import java.time.LocalDateTime;
+import java.time.OffsetDateTime;
 import javax.persistence.Column;
 import javax.persistence.Entity;
 import javax.persistence.JoinColumn;
@@ -28,6 +29,8 @@
 import javax.persistence.OneToOne;
 import javax.persistence.Table;
 import org.apache.fineract.infrastructure.core.domain.AbstractPersistableCustom;
+import static org.apache.fineract.infrastructure.core.domain.AuditableFieldsConstants.CREATED_DATE_DB_FIELD;
+import static org.apache.fineract.infrastructure.core.domain.AuditableFieldsConstants.LAST_MODIFIED_DATE_DB_FIELD;
 import org.apache.fineract.portfolio.loanaccount.domain.Loan;
 import org.apache.fineract.portfolio.loanaccount.rescheduleloan.domain.LoanRescheduleRequest;
 
@@ -65,7 +68,7 @@
     private BigDecimal penaltyCharges;
 
     @Column(name = "created_date")
-    private LocalDateTime createdOnDate;
+    private LocalDateTime oldCreatedOnDate;
 
     @Column(name = "createdby_id")
     private Long createdByUser;
@@ -74,7 +77,13 @@
     private Long lastModifiedByUser;
 
     @Column(name = "lastmodified_date")
-    private LocalDateTime lastModifiedOnDate;
+    private LocalDateTime oldLastModifiedOnDate;
+
+    @Column(name = CREATED_DATE_DB_FIELD)
+    private OffsetDateTime createdDate;
+
+    @Column(name = LAST_MODIFIED_DATE_DB_FIELD)
+    private OffsetDateTime  lastModifiedDate;
 
     @Column(name = "version")
     private Integer version;
@@ -90,8 +99,8 @@
     private LoanRepaymentScheduleHistory(final Loan loan, final LoanRescheduleRequest loanRescheduleRequest,
             final Integer installmentNumber, final LocalDate fromDate, final LocalDate dueDate, final BigDecimal principal,
             final BigDecimal interestCharged, final BigDecimal feeChargesCharged, final BigDecimal penaltyCharges,
-            final LocalDateTime createdOnDate, final Long createdByUser, final Long lastModifiedByUser,
-            final LocalDateTime lastModifiedOnDate, final Integer version) {
+            final LocalDateTime oldCreatedOnDate, final Long createdByUser, final Long lastModifiedByUser,
+            final LocalDateTime oldLastModifiedOnDate, final Integer version, final OffsetDateTime createdDate, final OffsetDateTime lastModifiedDate) {
 
         this.loan = loan;
         this.loanRescheduleRequest = loanRescheduleRequest;
@@ -102,11 +111,13 @@
         this.interestCharged = interestCharged;
         this.feeChargesCharged = feeChargesCharged;
         this.penaltyCharges = penaltyCharges;
-        this.createdOnDate = createdOnDate;
+        this.oldCreatedOnDate = oldCreatedOnDate;
         this.createdByUser = createdByUser;
         this.lastModifiedByUser = lastModifiedByUser;
-        this.lastModifiedOnDate = lastModifiedOnDate;
+        this.oldLastModifiedOnDate = oldLastModifiedOnDate;
         this.version = version;
+        this.createdDate = createdDate;
+        this.lastModifiedDate = lastModifiedDate;
     }
 
     /**
@@ -115,12 +126,12 @@
     public static LoanRepaymentScheduleHistory instance(final Loan loan, final LoanRescheduleRequest loanRescheduleRequest,
             final Integer installmentNumber, final LocalDate fromDate, final LocalDate dueDate, final BigDecimal principal,
             final BigDecimal interestCharged, final BigDecimal feeChargesCharged, final BigDecimal penaltyCharges,
-            final LocalDateTime createdOnDate, final Long createdByUser, final Long lastModifiedByUser,
-            final LocalDateTime lastModifiedOnDate, final Integer version) {
+            final LocalDateTime oldCreatedOnDate, final Long createdByUser, final Long lastModifiedByUser,
+            final LocalDateTime oldLastModifiedOnDate, final Integer version, final OffsetDateTime createdDate, final OffsetDateTime lastModifiedDate) {
 
         return new LoanRepaymentScheduleHistory(loan, loanRescheduleRequest, installmentNumber, fromDate, dueDate, principal,
-                interestCharged, feeChargesCharged, penaltyCharges, createdOnDate, createdByUser, lastModifiedByUser, lastModifiedOnDate,
-                version);
+                interestCharged, feeChargesCharged, penaltyCharges, oldCreatedOnDate, createdByUser, lastModifiedByUser, oldLastModifiedOnDate,
+                version, createdDate, lastModifiedDate);
 
     }
 
diff --git a/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/loanschedule/service/LoanScheduleHistoryReadPlatformService.java b/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/loanschedule/service/LoanScheduleHistoryReadPlatformService.java
index cd2bf3e..22270a1 100755
--- a/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/loanschedule/service/LoanScheduleHistoryReadPlatformService.java
+++ b/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/loanschedule/service/LoanScheduleHistoryReadPlatformService.java
@@ -19,6 +19,7 @@
 package org.apache.fineract.portfolio.loanaccount.loanschedule.service;
 
 import java.util.Collection;
+import java.util.Map;
 import org.apache.fineract.portfolio.loanaccount.data.DisbursementData;
 import org.apache.fineract.portfolio.loanaccount.data.RepaymentScheduleRelatedLoanData;
 import org.apache.fineract.portfolio.loanaccount.loanschedule.data.LoanScheduleData;
@@ -29,4 +30,6 @@
 
     LoanScheduleData retrieveRepaymentArchiveSchedule(Long loanId, RepaymentScheduleRelatedLoanData repaymentScheduleRelatedLoanData,
             Collection<DisbursementData> disbursementData);
+
+    Map<String, Object> fetchOldAuditDates(Long id);
 }
diff --git a/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/loanschedule/service/LoanScheduleHistoryReadPlatformServiceImpl.java b/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/loanschedule/service/LoanScheduleHistoryReadPlatformServiceImpl.java
index ebf4876..4ab2750 100644
--- a/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/loanschedule/service/LoanScheduleHistoryReadPlatformServiceImpl.java
+++ b/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/loanschedule/service/LoanScheduleHistoryReadPlatformServiceImpl.java
@@ -25,6 +25,7 @@
 import java.time.temporal.ChronoUnit;
 import java.util.ArrayList;
 import java.util.Collection;
+import java.util.Map;
 import org.apache.commons.lang3.ObjectUtils;
 import org.apache.fineract.infrastructure.core.domain.JdbcSupport;
 import org.apache.fineract.infrastructure.security.service.PlatformSecurityContext;
@@ -86,6 +87,12 @@
         }
     }
 
+    @Override
+    public Map<String, Object> fetchOldAuditDates(Long id) {
+        final String sql = "select lrs.created_date, lrs.lastmodified_date from m_loan_repayment_schedule lrs where lrs.id = ?";
+        return this.jdbcTemplate.queryForMap(sql, id);
+    }
+
     private static final class LoanScheduleArchiveResultSetExtractor implements ResultSetExtractor<LoanScheduleData> {
 
         private final CurrencyData currency;
diff --git a/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/loanschedule/service/LoanScheduleHistoryWritePlatformServiceImpl.java b/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/loanschedule/service/LoanScheduleHistoryWritePlatformServiceImpl.java
index 12f5d2f..91f4681 100644
--- a/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/loanschedule/service/LoanScheduleHistoryWritePlatformServiceImpl.java
+++ b/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/loanschedule/service/LoanScheduleHistoryWritePlatformServiceImpl.java
@@ -21,32 +21,31 @@
 import java.math.BigDecimal;
 import java.time.LocalDate;
 import java.time.LocalDateTime;
+import java.time.OffsetDateTime;
 import java.util.ArrayList;
 import java.util.List;
+import java.util.Map;
+import lombok.RequiredArgsConstructor;
+import org.apache.fineract.infrastructure.core.service.DateUtils;
+import org.apache.fineract.infrastructure.security.service.PlatformSecurityContext;
 import org.apache.fineract.organisation.monetary.domain.MonetaryCurrency;
 import org.apache.fineract.portfolio.loanaccount.domain.Loan;
 import org.apache.fineract.portfolio.loanaccount.domain.LoanRepaymentScheduleInstallment;
 import org.apache.fineract.portfolio.loanaccount.loanschedule.domain.LoanRepaymentScheduleHistory;
 import org.apache.fineract.portfolio.loanaccount.loanschedule.domain.LoanRepaymentScheduleHistoryRepository;
 import org.apache.fineract.portfolio.loanaccount.rescheduleloan.domain.LoanRescheduleRequest;
-import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.stereotype.Service;
 import org.springframework.transaction.annotation.Transactional;
 
 @Service
 @Transactional
+@RequiredArgsConstructor
 public class LoanScheduleHistoryWritePlatformServiceImpl implements LoanScheduleHistoryWritePlatformService {
 
     private final LoanScheduleHistoryReadPlatformService loanScheduleHistoryReadPlatformService;
     private final LoanRepaymentScheduleHistoryRepository loanRepaymentScheduleHistoryRepository;
 
-    @Autowired
-    public LoanScheduleHistoryWritePlatformServiceImpl(final LoanScheduleHistoryReadPlatformService loanScheduleHistoryReadPlatformService,
-            final LoanRepaymentScheduleHistoryRepository loanRepaymentScheduleHistoryRepository) {
-        this.loanScheduleHistoryReadPlatformService = loanScheduleHistoryReadPlatformService;
-        this.loanRepaymentScheduleHistoryRepository = loanRepaymentScheduleHistoryRepository;
-
-    }
+    private final PlatformSecurityContext platformSecurityContext;
 
     @Override
     public List<LoanRepaymentScheduleHistory> createLoanScheduleArchive(
@@ -73,23 +72,33 @@
             final BigDecimal feeChargesCharged = repaymentScheduleInstallment.getFeeChargesCharged(currency).getAmount();
             final BigDecimal penaltyCharges = repaymentScheduleInstallment.getPenaltyChargesCharged(currency).getAmount();
 
-            LocalDateTime createdOnDate = null;
+            Map<String, Object> oldDates = null;
+            OffsetDateTime createdOnDate = DateUtils.getOffsetDateTimeOfTenant();
+            LocalDateTime oldCreatedOnDate = null;
+            LocalDateTime oldLastModifiedOnDate = null;
             if (repaymentScheduleInstallment.getCreatedDate().isPresent()) {
-                createdOnDate = repaymentScheduleInstallment.getCreatedDate().get(); // NOSONAR
+                createdOnDate = repaymentScheduleInstallment.getCreatedDate().get();
+            } else if (repaymentScheduleInstallment.getId() != null) {
+                oldDates = loanScheduleHistoryReadPlatformService.fetchOldAuditDates(repaymentScheduleInstallment.getId());
+                oldCreatedOnDate = (LocalDateTime) oldDates.get("created_date");
+                oldLastModifiedOnDate = (LocalDateTime) oldDates.get("lastmodified_date");
             }
 
-            final Long createdByUser = repaymentScheduleInstallment.getCreatedBy().orElse(null);
-            final Long lastModifiedByUser = repaymentScheduleInstallment.getLastModifiedBy().orElse(null);
+            final Long createdByUser = repaymentScheduleInstallment.getCreatedBy().orElse(platformSecurityContext.authenticatedUser().getId());
+            final Long lastModifiedByUser = repaymentScheduleInstallment.getLastModifiedBy().orElse(platformSecurityContext.authenticatedUser().getId());
 
-            LocalDateTime lastModifiedOnDate = null;
-
+            OffsetDateTime lastModifiedOnDate = DateUtils.getOffsetDateTimeOfTenant();
             if (repaymentScheduleInstallment.getLastModifiedDate().isPresent()) {
-                lastModifiedOnDate = repaymentScheduleInstallment.getLastModifiedDate().get(); // NOSONAR
+                lastModifiedOnDate = repaymentScheduleInstallment.getLastModifiedDate().get();
+            } else if (repaymentScheduleInstallment.getId() != null && oldDates == null) {
+                oldDates = loanScheduleHistoryReadPlatformService.fetchOldAuditDates(repaymentScheduleInstallment.getId());
+                oldCreatedOnDate = (LocalDateTime) oldDates.get("created_date");
+                oldLastModifiedOnDate = (LocalDateTime) oldDates.get("lastmodified_date");
             }
 
             LoanRepaymentScheduleHistory loanRepaymentScheduleHistory = LoanRepaymentScheduleHistory.instance(loan, loanRescheduleRequest,
-                    installmentNumber, fromDate, dueDate, principal, interestCharged, feeChargesCharged, penaltyCharges, createdOnDate,
-                    createdByUser, lastModifiedByUser, lastModifiedOnDate, version);
+                    installmentNumber, fromDate, dueDate, principal, interestCharged, feeChargesCharged, penaltyCharges, oldCreatedOnDate,
+                    createdByUser, lastModifiedByUser, oldLastModifiedOnDate, version, createdOnDate, lastModifiedOnDate);
 
             loanRepaymentScheduleHistoryList.add(loanRepaymentScheduleHistory);
         }
diff --git a/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/rescheduleloan/service/LoanRescheduleRequestWritePlatformServiceImpl.java b/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/rescheduleloan/service/LoanRescheduleRequestWritePlatformServiceImpl.java
index 976b19a..6f7e37d 100644
--- a/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/rescheduleloan/service/LoanRescheduleRequestWritePlatformServiceImpl.java
+++ b/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/rescheduleloan/service/LoanRescheduleRequestWritePlatformServiceImpl.java
@@ -475,9 +475,8 @@
             loan.recalculateAllCharges();
             ChangedTransactionDetail changedTransactionDetail = loan.processTransactions();
 
-            for (LoanRepaymentScheduleHistory loanRepaymentScheduleHistory : loanRepaymentScheduleHistoryList) {
-                this.loanRepaymentScheduleHistoryRepository.save(loanRepaymentScheduleHistory);
-            }
+
+            this.loanRepaymentScheduleHistoryRepository.saveAll(loanRepaymentScheduleHistoryList);
 
             loan.updateRescheduledByUser(appUser);
             loan.updateRescheduledOnDate(DateUtils.getBusinessLocalDate());
diff --git a/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/service/LoanWritePlatformServiceJpaRepositoryImpl.java b/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/service/LoanWritePlatformServiceJpaRepositoryImpl.java
index 936c376..029ca66 100644
--- a/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/service/LoanWritePlatformServiceJpaRepositoryImpl.java
+++ b/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/service/LoanWritePlatformServiceJpaRepositoryImpl.java
@@ -1943,9 +1943,6 @@
                 // Subtract the amount waived from the existing fee charges waived amount.
                 chargePerInstallment.getInstallment().setFeeChargesWaived(feeChargesWaivedAmount.subtract(amountWaived));
 
-                // Set the last modification date.
-                chargePerInstallment.getInstallment().setLastModifiedDate(DateUtils.getLocalDateTimeOfSystem());
-
                 // Update loan charge.
                 loanCharge.setInstallmentLoanCharge(chargePerInstallment, chargePerInstallment.getInstallment().getInstallmentNumber());
 
diff --git a/fineract-provider/src/main/resources/db/changelog/tenant/parts/0032_add_audit_entries_to_loan_repayment_schedule_installment.xml b/fineract-provider/src/main/resources/db/changelog/tenant/parts/0032_add_audit_entries_to_loan_repayment_schedule_installment.xml
new file mode 100644
index 0000000..9144fea
--- /dev/null
+++ b/fineract-provider/src/main/resources/db/changelog/tenant/parts/0032_add_audit_entries_to_loan_repayment_schedule_installment.xml
@@ -0,0 +1,103 @@
+<?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="loan_repayment_schedule-1" context="mysql">
+        <addColumn tableName="m_loan_repayment_schedule">
+            <column name="created_on_utc" type="DATETIME"/>
+            <column name="last_modified_on_utc" type="DATETIME"/>
+        </addColumn>
+    </changeSet>
+    <changeSet author="fineract" id="loan_repayment_schedule-1" context="postgresql">
+        <addColumn tableName="m_loan_repayment_schedule">
+            <column name="created_on_utc" type="TIMESTAMP WITH TIME ZONE"/>
+            <column name="last_modified_on_utc" type="TIMESTAMP WITH TIME ZONE"/>
+        </addColumn>
+    </changeSet>
+
+    <changeSet id="loan_repayment_schedule-2" author="fineract">
+        <dropNotNullConstraint tableName="m_loan_repayment_schedule" columnName="created_date" columnDataType="datetime"/>
+        <dropNotNullConstraint tableName="m_loan_repayment_schedule" columnName="lastmodified_date" columnDataType="datetime"/>
+    </changeSet>
+    <changeSet id="loan_repayment_schedule-3" author="fineract">
+        <renameColumn tableName="m_loan_repayment_schedule" oldColumnName="createdby_id" newColumnName="created_by" columnDataType="BIGINT"/>
+        <renameColumn tableName="m_loan_repayment_schedule" oldColumnName="lastmodifiedby_id" newColumnName="last_modified_by" columnDataType="BIGINT"/>
+    </changeSet>
+    <changeSet author="fineract" id="loan_repayment_schedule-4">
+        <addForeignKeyConstraint baseColumnNames="created_by" baseTableName="m_loan_repayment_schedule"
+                                 constraintName="FK_loan_repayment_schedule_created_by" deferrable="false" initiallyDeferred="false"
+                                 onDelete="RESTRICT" onUpdate="RESTRICT" referencedColumnNames="id"
+                                 referencedTableName="m_appuser" validate="true"/>
+        <addForeignKeyConstraint baseColumnNames="last_modified_by" baseTableName="m_loan_repayment_schedule"
+                                 constraintName="FK_loan_repayment_schedule_last_modified_by" deferrable="false" initiallyDeferred="false"
+                                 onDelete="RESTRICT" onUpdate="RESTRICT" referencedColumnNames="id"
+                                 referencedTableName="m_appuser" validate="true"/>
+    </changeSet>
+    <changeSet id="loan_repayment_schedule-5" author="fineract" context="mysql">
+        <preConditions onFail="MARK_RAN">
+            <sqlCheck expectedResult="0">select count(*) from m_loan_repayment_schedule</sqlCheck>
+        </preConditions>
+        <addNotNullConstraint tableName="m_loan_repayment_schedule" columnName="created_on_utc" columnDataType="DATETIME"/>
+        <addNotNullConstraint tableName="m_loan_repayment_schedule" columnName="last_modified_on_utc" columnDataType="DATETIME"/>
+    </changeSet>
+    <changeSet id="loan_repayment_schedule-5" author="fineract" context="postgresql">
+        <preConditions onFail="MARK_RAN">
+            <sqlCheck expectedResult="0">select count(*) from m_loan_repayment_schedule</sqlCheck>
+        </preConditions>
+        <addNotNullConstraint tableName="m_loan_repayment_schedule" columnName="created_on_utc" columnDataType="TIMESTAMP WITH TIME ZONE"/>
+        <addNotNullConstraint tableName="m_loan_repayment_schedule" columnName="last_modified_on_utc" columnDataType="TIMESTAMP WITH TIME ZONE"/>
+    </changeSet>
+    <changeSet id="loan_repayment_schedule-6" author="fineract">
+        <preConditions onFail="MARK_RAN">
+            <sqlCheck expectedResult="0">select count(*) from m_loan_repayment_schedule where created_by is null or last_modified_by is null</sqlCheck>
+        </preConditions>
+        <addNotNullConstraint tableName="m_loan_repayment_schedule" columnName="created_by" columnDataType="BIGINT"/>
+        <addNotNullConstraint tableName="m_loan_repayment_schedule" columnName="last_modified_by" columnDataType="BIGINT"/>
+    </changeSet>
+    <changeSet author="fineract" id="loan_repayment_schedule_history-1" context="mysql">
+        <addColumn tableName="m_loan_repayment_schedule_history">
+            <column name="created_on_utc" type="DATETIME"/>
+            <column name="last_modified_on_utc" type="DATETIME"/>
+        </addColumn>
+    </changeSet>
+    <changeSet author="fineract" id="loan_repayment_schedule_history-1" context="postgresql">
+        <addColumn tableName="m_loan_repayment_schedule_history">
+            <column name="created_on_utc" type="TIMESTAMP WITH TIME ZONE"/>
+            <column name="last_modified_on_utc" type="TIMESTAMP WITH TIME ZONE"/>
+        </addColumn>
+    </changeSet>
+    <changeSet id="loan_repayment_schedule_history-2" author="fineract" context="mysql">
+        <preConditions onFail="MARK_RAN">
+            <sqlCheck expectedResult="0">select count(*) from m_loan_repayment_schedule_history</sqlCheck>
+        </preConditions>
+        <addNotNullConstraint tableName="m_loan_repayment_schedule_history" columnName="created_on_utc" columnDataType="DATETIME"/>
+        <addNotNullConstraint tableName="m_loan_repayment_schedule_history" columnName="last_modified_on_utc" columnDataType="DATETIME"/>
+    </changeSet>
+    <changeSet id="loan_repayment_schedule_history-2" author="fineract" context="postgresql">
+        <preConditions onFail="MARK_RAN">
+            <sqlCheck expectedResult="0">select count(*) from m_loan_repayment_schedule_history</sqlCheck>
+        </preConditions>
+        <addNotNullConstraint tableName="m_loan_repayment_schedule_history" columnName="created_on_utc" columnDataType="TIMESTAMP WITH TIME ZONE"/>
+        <addNotNullConstraint tableName="m_loan_repayment_schedule_history" columnName="last_modified_on_utc" columnDataType="TIMESTAMP WITH TIME ZONE"/>
+    </changeSet>
+</databaseChangeLog>