diff --git a/fineract-provider/src/main/java/org/apache/fineract/accounting/accrual/service/AccrualAccountingWritePlatformServiceImpl.java b/fineract-provider/src/main/java/org/apache/fineract/accounting/accrual/service/AccrualAccountingWritePlatformServiceImpl.java index 3ce56a237..7856cf65e 100644 --- a/fineract-provider/src/main/java/org/apache/fineract/accounting/accrual/service/AccrualAccountingWritePlatformServiceImpl.java +++ b/fineract-provider/src/main/java/org/apache/fineract/accounting/accrual/service/AccrualAccountingWritePlatformServiceImpl.java @@ -46,9 +46,9 @@ public class AccrualAccountingWritePlatformServiceImpl implements AccrualAccount @Override public CommandProcessingResult executeLoansPeriodicAccrual(JsonCommand command) { this.accountingDataValidator.validateLoanPeriodicAccrualData(command.json()); - LocalDate tilldate = command.localDateValueOfParameterNamed(accrueTillParamName); + LocalDate tillDate = command.localDateValueOfParameterNamed(accrueTillParamName); try { - this.loanAccrualPlatformService.addPeriodicAccruals(tilldate); + this.loanAccrualPlatformService.addPeriodicAccruals(tillDate); } catch (MultiException e) { final List dataValidationErrors = new ArrayList<>(); final DataValidatorBuilder baseDataValidator = new DataValidatorBuilder(dataValidationErrors) diff --git a/fineract-provider/src/main/java/org/apache/fineract/infrastructure/core/domain/JdbcSupport.java b/fineract-provider/src/main/java/org/apache/fineract/infrastructure/core/domain/JdbcSupport.java index 74728c2c3..2be81ae87 100644 --- a/fineract-provider/src/main/java/org/apache/fineract/infrastructure/core/domain/JdbcSupport.java +++ b/fineract-provider/src/main/java/org/apache/fineract/infrastructure/core/domain/JdbcSupport.java @@ -26,6 +26,8 @@ import java.sql.Timestamp; import java.time.LocalDate; import java.time.LocalDateTime; import java.time.LocalTime; +import java.time.OffsetDateTime; +import java.time.ZoneOffset; import java.time.ZonedDateTime; import org.apache.fineract.infrastructure.core.service.DateUtils; import org.springframework.jdbc.support.JdbcUtils; @@ -133,4 +135,14 @@ public final class JdbcSupport { } return result; } + + public static OffsetDateTime getOffsetDateTime(ResultSet rs, String columnName) throws SQLException { + final Timestamp timestamp = rs.getTimestamp(columnName); + if (timestamp != null) { + OffsetDateTime offsetDateTimeAtUTC = OffsetDateTime.of(timestamp.toLocalDateTime(), ZoneOffset.UTC); + return offsetDateTimeAtUTC + .withOffsetSameInstant(DateUtils.getDateTimeZoneOfTenant().getRules().getOffset(offsetDateTimeAtUTC.toInstant())); + } + return null; + } } diff --git a/fineract-provider/src/main/java/org/apache/fineract/infrastructure/jobs/service/updatenpa/UpdateNpaConfig.java b/fineract-provider/src/main/java/org/apache/fineract/infrastructure/jobs/service/updatenpa/UpdateNpaConfig.java index 861537566..b0c72d164 100644 --- a/fineract-provider/src/main/java/org/apache/fineract/infrastructure/jobs/service/updatenpa/UpdateNpaConfig.java +++ b/fineract-provider/src/main/java/org/apache/fineract/infrastructure/jobs/service/updatenpa/UpdateNpaConfig.java @@ -22,6 +22,7 @@ import org.apache.fineract.infrastructure.core.service.RoutingDataSourceServiceF import org.apache.fineract.infrastructure.core.service.database.DatabaseSpecificSQLGenerator; import org.apache.fineract.infrastructure.core.service.database.DatabaseTypeResolver; import org.apache.fineract.infrastructure.jobs.service.JobName; +import org.apache.fineract.infrastructure.security.service.PlatformSecurityContext; import org.springframework.batch.core.Job; import org.springframework.batch.core.Step; import org.springframework.batch.core.configuration.annotation.JobBuilderFactory; @@ -46,6 +47,9 @@ public class UpdateNpaConfig { @Autowired private DatabaseSpecificSQLGenerator sqlGenerator; + @Autowired + private PlatformSecurityContext platformSecurityContext; + @Bean protected Step updateNpaStep() { return steps.get(JobName.UPDATE_NPA.name()).tasklet(updateNpaTasklet()).build(); @@ -58,6 +62,6 @@ public class UpdateNpaConfig { @Bean public UpdateNpaTasklet updateNpaTasklet() { - return new UpdateNpaTasklet(dataSourceServiceFactory, databaseTypeResolver, sqlGenerator); + return new UpdateNpaTasklet(dataSourceServiceFactory, databaseTypeResolver, sqlGenerator, platformSecurityContext); } } diff --git a/fineract-provider/src/main/java/org/apache/fineract/infrastructure/jobs/service/updatenpa/UpdateNpaTasklet.java b/fineract-provider/src/main/java/org/apache/fineract/infrastructure/jobs/service/updatenpa/UpdateNpaTasklet.java index 60836514e..d2de9abae 100644 --- a/fineract-provider/src/main/java/org/apache/fineract/infrastructure/jobs/service/updatenpa/UpdateNpaTasklet.java +++ b/fineract-provider/src/main/java/org/apache/fineract/infrastructure/jobs/service/updatenpa/UpdateNpaTasklet.java @@ -20,10 +20,13 @@ package org.apache.fineract.infrastructure.jobs.service.updatenpa; import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; +import org.apache.fineract.infrastructure.core.service.DateUtils; import org.apache.fineract.infrastructure.core.service.RoutingDataSourceServiceFactory; import org.apache.fineract.infrastructure.core.service.ThreadLocalContextUtil; import org.apache.fineract.infrastructure.core.service.database.DatabaseSpecificSQLGenerator; import org.apache.fineract.infrastructure.core.service.database.DatabaseTypeResolver; +import org.apache.fineract.infrastructure.security.service.PlatformSecurityContext; +import org.apache.fineract.useradministration.domain.AppUser; import org.springframework.batch.core.StepContribution; import org.springframework.batch.core.scope.context.ChunkContext; import org.springframework.batch.core.step.tasklet.Tasklet; @@ -37,9 +40,11 @@ public class UpdateNpaTasklet implements Tasklet { private final RoutingDataSourceServiceFactory dataSourceServiceFactory; private final DatabaseTypeResolver databaseTypeResolver; private final DatabaseSpecificSQLGenerator sqlGenerator; + private final PlatformSecurityContext context; @Override public RepeatStatus execute(StepContribution contribution, ChunkContext chunkContext) throws Exception { + AppUser user = context.getAuthenticatedUserIfPresent(); final JdbcTemplate jdbcTemplate = new JdbcTemplate(dataSourceServiceFactory.determineDataSourceService().retrieveDataSource()); final StringBuilder resetNPASqlBuilder = new StringBuilder(); @@ -52,11 +57,13 @@ public class UpdateNpaTasklet implements Tasklet { String wherePart = " where loan.id = sl.id "; if (databaseTypeResolver.isMySQL()) { - resetNPASqlBuilder.append(", ").append(fromPart).append(" set loan.is_npa = false").append(wherePart); + resetNPASqlBuilder.append(", ").append(fromPart).append(" set loan.is_npa = false") + .append(", loan.last_modified_by = ?, loan.last_modified_on_utc = ? ").append(wherePart); } else { - resetNPASqlBuilder.append("set is_npa = false").append(" FROM ").append(fromPart).append(wherePart); + resetNPASqlBuilder.append("set is_npa = false").append(", last_modified_by = ?, last_modified_on_utc = ? ").append(" FROM ") + .append(fromPart).append(wherePart); } - jdbcTemplate.update(resetNPASqlBuilder.toString()); + jdbcTemplate.update(resetNPASqlBuilder.toString(), user.getId(), DateUtils.getOffsetDateTimeOfTenant()); final StringBuilder updateSqlBuilder = new StringBuilder(900); @@ -68,12 +75,14 @@ public class UpdateNpaTasklet implements Tasklet { wherePart = " where ml.id=sl.id "; updateSqlBuilder.append("UPDATE m_loan as ml "); if (databaseTypeResolver.isMySQL()) { - updateSqlBuilder.append(", ").append(fromPart).append(" SET ml.is_npa = true").append(wherePart); + updateSqlBuilder.append(", ").append(fromPart).append(" SET ml.is_npa = true") + .append(", ml.last_modified_by = ?, ml.last_modified_on_utc = ? ").append(wherePart); } else { - updateSqlBuilder.append(" SET is_npa = true").append(" FROM ").append(fromPart).append(wherePart); + updateSqlBuilder.append(" SET is_npa = true").append(", last_modified_by = ?, last_modified_on_utc = ? ").append(" FROM ") + .append(fromPart).append(wherePart); } - final int result = jdbcTemplate.update(updateSqlBuilder.toString()); + final int result = jdbcTemplate.update(updateSqlBuilder.toString(), user.getId(), DateUtils.getOffsetDateTimeOfTenant()); log.info("{}: Records affected by updateNPA: {}", ThreadLocalContextUtil.getTenant().getName(), result); return RepeatStatus.FINISHED; diff --git a/fineract-provider/src/main/java/org/apache/fineract/portfolio/client/domain/ClientTransaction.java b/fineract-provider/src/main/java/org/apache/fineract/portfolio/client/domain/ClientTransaction.java index 0023d9025..b292b521f 100644 --- a/fineract-provider/src/main/java/org/apache/fineract/portfolio/client/domain/ClientTransaction.java +++ b/fineract-provider/src/main/java/org/apache/fineract/portfolio/client/domain/ClientTransaction.java @@ -20,7 +20,6 @@ package org.apache.fineract.portfolio.client.domain; import java.math.BigDecimal; import java.time.LocalDate; -import java.time.LocalDateTime; import java.util.ArrayList; import java.util.HashSet; import java.util.LinkedHashMap; @@ -39,18 +38,17 @@ import javax.persistence.Transient; import javax.persistence.UniqueConstraint; import org.apache.fineract.accounting.glaccount.domain.GLAccount; import org.apache.fineract.infrastructure.core.data.EnumOptionData; -import org.apache.fineract.infrastructure.core.domain.AbstractPersistableCustom; +import org.apache.fineract.infrastructure.core.domain.AbstractAuditableWithUTCDateTimeCustom; import org.apache.fineract.infrastructure.core.service.DateUtils; import org.apache.fineract.organisation.monetary.domain.MonetaryCurrency; import org.apache.fineract.organisation.monetary.domain.Money; import org.apache.fineract.organisation.office.domain.Office; import org.apache.fineract.organisation.office.domain.OrganisationCurrency; import org.apache.fineract.portfolio.paymentdetail.domain.PaymentDetail; -import org.apache.fineract.useradministration.domain.AppUser; @Entity @Table(name = "m_client_transaction", uniqueConstraints = { @UniqueConstraint(columnNames = { "external_id" }, name = "external_id") }) -public class ClientTransaction extends AbstractPersistableCustom { +public class ClientTransaction extends AbstractAuditableWithUTCDateTimeCustom { @ManyToOne(optional = false) @JoinColumn(name = "client_id", nullable = false) @@ -73,6 +71,9 @@ public class ClientTransaction extends AbstractPersistableCustom { @Column(name = "transaction_date", nullable = false) private LocalDate dateOf; + @Column(name = "submitted_on_date", nullable = false) + private LocalDate submittedOnDate; + @Column(name = "amount", scale = 6, precision = 19, nullable = false) private BigDecimal amount; @@ -82,12 +83,11 @@ public class ClientTransaction extends AbstractPersistableCustom { @Column(name = "external_id", length = 100, nullable = true, unique = true) private String externalId; - @Column(name = "created_date", nullable = false) - private LocalDateTime createdDate; - - @ManyToOne - @JoinColumn(name = "appuser_id", nullable = true) - private AppUser appUser; + /* + * Deprecated since common Auditable fields were introduced. Columns and data left untouched to help migration. + * + * @Column(name = "created_date", nullable = false) private LocalDateTime createdDate; + */ @OneToMany(cascade = CascadeType.ALL, mappedBy = "clientTransaction", orphanRemoval = true, fetch = FetchType.EAGER) private Set clientChargePaidByCollection = new HashSet<>(); @@ -97,37 +97,36 @@ public class ClientTransaction extends AbstractPersistableCustom { protected ClientTransaction() {} - public static ClientTransaction payCharge(final Client client, final Office office, PaymentDetail paymentDetail, final LocalDate date, - final Money amount, final String currencyCode, final AppUser appUser) { + public static ClientTransaction payCharge(final Client client, final Office office, PaymentDetail paymentDetail, + final LocalDate transactionDate, final Money amount, final String currencyCode) { final boolean isReversed = false; final String externalId = null; - return new ClientTransaction(client, office, paymentDetail, ClientTransactionType.PAY_CHARGE.getValue(), date, amount, isReversed, - externalId, DateUtils.getLocalDateTimeOfTenant(), currencyCode, appUser); + return new ClientTransaction(client, office, paymentDetail, ClientTransactionType.PAY_CHARGE.getValue(), transactionDate, amount, + isReversed, externalId, currencyCode); } - public static ClientTransaction waiver(final Client client, final Office office, final LocalDate date, final Money amount, - final String currencyCode, final AppUser appUser) { + public static ClientTransaction waiver(final Client client, final Office office, final LocalDate transactionDate, final Money amount, + final String currencyCode) { final boolean isReversed = false; final String externalId = null; final PaymentDetail paymentDetail = null; - return new ClientTransaction(client, office, paymentDetail, ClientTransactionType.WAIVE_CHARGE.getValue(), date, amount, isReversed, - externalId, DateUtils.getLocalDateTimeOfTenant(), currencyCode, appUser); + return new ClientTransaction(client, office, paymentDetail, ClientTransactionType.WAIVE_CHARGE.getValue(), transactionDate, amount, + isReversed, externalId, currencyCode); } - public ClientTransaction(Client client, Office office, PaymentDetail paymentDetail, Integer typeOf, LocalDate transactionLocalDate, - Money amount, boolean reversed, String externalId, LocalDateTime createdDate, String currencyCode, AppUser appUser) { + public ClientTransaction(Client client, Office office, PaymentDetail paymentDetail, Integer typeOf, LocalDate transactionDate, + Money amount, boolean reversed, String externalId, String currencyCode) { this.client = client; this.office = office; this.paymentDetail = paymentDetail; this.typeOf = typeOf; - this.dateOf = transactionLocalDate; + this.dateOf = transactionDate; this.amount = amount.getAmount(); this.reversed = reversed; this.externalId = externalId; - this.createdDate = createdDate; this.currencyCode = currencyCode; - this.appUser = appUser; + this.submittedOnDate = DateUtils.getBusinessLocalDate(); } public void reverse() { @@ -226,4 +225,8 @@ public class ClientTransaction extends AbstractPersistableCustom { return this.dateOf; } + public LocalDate getSubmittedOnDate() { + return this.submittedOnDate; + } + } diff --git a/fineract-provider/src/main/java/org/apache/fineract/portfolio/client/service/ClientChargeWritePlatformServiceJpaRepositoryImpl.java b/fineract-provider/src/main/java/org/apache/fineract/portfolio/client/service/ClientChargeWritePlatformServiceJpaRepositoryImpl.java index 8b3a65e17..f0133d0bc 100644 --- a/fineract-provider/src/main/java/org/apache/fineract/portfolio/client/service/ClientChargeWritePlatformServiceJpaRepositoryImpl.java +++ b/fineract-provider/src/main/java/org/apache/fineract/portfolio/client/service/ClientChargeWritePlatformServiceJpaRepositoryImpl.java @@ -54,7 +54,6 @@ import org.apache.fineract.portfolio.client.domain.ClientTransaction; import org.apache.fineract.portfolio.client.domain.ClientTransactionRepository; import org.apache.fineract.portfolio.paymentdetail.domain.PaymentDetail; import org.apache.fineract.portfolio.paymentdetail.service.PaymentDetailWritePlatformService; -import org.apache.fineract.useradministration.domain.AppUser; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.beans.factory.annotation.Autowired; @@ -174,7 +173,7 @@ public class ClientChargeWritePlatformServiceJpaRepositoryImpl implements Client final PaymentDetail paymentDetail = this.paymentDetailWritePlatformService.createAndPersistPaymentDetail(command, changes); ClientTransaction clientTransaction = ClientTransaction.payCharge(client, client.getOffice(), paymentDetail, transactionDate, - chargePaid, clientCharge.getCurrency().getCode(), getAppUserIfPresent()); + chargePaid, clientCharge.getCurrency().getCode()); this.clientTransactionRepository.saveAndFlush(clientTransaction); // update charge paid by associations @@ -217,7 +216,7 @@ public class ClientChargeWritePlatformServiceJpaRepositoryImpl implements Client // create Waiver Transaction ClientTransaction clientTransaction = ClientTransaction.waiver(client, client.getOffice(), transactionDate, waivedAmount, - clientCharge.getCurrency().getCode(), getAppUserIfPresent()); + clientCharge.getCurrency().getCode()); this.clientTransactionRepository.saveAndFlush(clientTransaction); // update charge paid by associations @@ -392,7 +391,8 @@ public class ClientChargeWritePlatformServiceJpaRepositoryImpl implements Client /** * Ensures that the charge transaction date (for payments) is not on a holiday or a non working day * - * @param savingsAccountCharge + * @param transactionDate + * @param clientCharge * @param fmt */ private void validateTransactionDateOnWorkingDay(final LocalDate transactionDate, final ClientCharge clientCharge, @@ -406,7 +406,8 @@ public class ClientChargeWritePlatformServiceJpaRepositoryImpl implements Client * @param date * @param officeId * @param jsonPropertyName - * @param errorMessageFragment + * @param errorMessageFragmentForActivityOnHoliday + * @param errorMessageFragmentForActivityOnNonWorkingDay * @param fmt */ private void validateActivityDateFallOnAWorkingDay(final LocalDate date, final Long officeId, final String jsonPropertyName, @@ -436,14 +437,6 @@ public class ClientChargeWritePlatformServiceJpaRepositoryImpl implements Client } } - private AppUser getAppUserIfPresent() { - AppUser user = null; - if (this.context != null) { - user = this.context.getAuthenticatedUserIfPresent(); - } - return user; - } - private void handleDataIntegrityIssues(@SuppressWarnings("unused") final Long clientId, final Long clientChargeId, final Throwable realCause, final NonTransientDataAccessException dve) { diff --git a/fineract-provider/src/main/java/org/apache/fineract/portfolio/client/service/ClientTransactionReadPlatformServiceImpl.java b/fineract-provider/src/main/java/org/apache/fineract/portfolio/client/service/ClientTransactionReadPlatformServiceImpl.java index 5f9194de9..476c6aad9 100644 --- a/fineract-provider/src/main/java/org/apache/fineract/portfolio/client/service/ClientTransactionReadPlatformServiceImpl.java +++ b/fineract-provider/src/main/java/org/apache/fineract/portfolio/client/service/ClientTransactionReadPlatformServiceImpl.java @@ -68,7 +68,7 @@ public class ClientTransactionReadPlatformServiceImpl implements ClientTransacti final StringBuilder sqlBuilder = new StringBuilder(400); sqlBuilder.append("tr.id as transactionId, tr.transaction_type_enum as transactionType, "); sqlBuilder.append("tr.transaction_date as transactionDate, tr.amount as transactionAmount, "); - sqlBuilder.append("tr.created_date as submittedOnDate, tr.is_reversed as reversed, "); + sqlBuilder.append("tr.submitted_on_date as submittedOnDate, tr.is_reversed as reversed, "); sqlBuilder.append("tr.external_id as externalId, o.name as officeName, o.id as officeId, "); sqlBuilder.append("c.id as clientId, c.account_no as accountNo, ccpb.client_charge_id as clientChargeId, "); sqlBuilder.append("pd.payment_type_id as paymentType,pd.account_number as accountNumber,pd.check_number as checkNumber, "); @@ -143,7 +143,7 @@ public class ClientTransactionReadPlatformServiceImpl implements ClientTransacti sqlBuilder.append("select " + sqlGenerator.calcFoundRows() + " ").append(this.clientTransactionMapper.schema()) .append(" where c.id = ? "); parameters[0] = clientId; - sqlBuilder.append(" order by tr.transaction_date DESC, tr.created_date DESC, tr.id DESC "); + sqlBuilder.append(" order by tr.transaction_date DESC, tr.submitted_on_date DESC, tr.id DESC "); // apply limit and offsets @@ -169,7 +169,7 @@ public class ClientTransactionReadPlatformServiceImpl implements ClientTransacti sql = sql + " and ccpb.client_charge_id = ?"; } parameters[0] = clientId; - sql = sql + " order by tr.transaction_date DESC, tr.created_date DESC, tr.id DESC"; + sql = sql + " order by tr.transaction_date DESC, tr.submitted_on_date DESC, tr.id DESC"; return this.jdbcTemplate.query(sql, this.clientTransactionMapper, parameters); // NOSONAR } diff --git a/fineract-provider/src/main/java/org/apache/fineract/portfolio/floatingrates/data/FloatingRateData.java b/fineract-provider/src/main/java/org/apache/fineract/portfolio/floatingrates/data/FloatingRateData.java index 5d88d25f7..f443a9d93 100644 --- a/fineract-provider/src/main/java/org/apache/fineract/portfolio/floatingrates/data/FloatingRateData.java +++ b/fineract-provider/src/main/java/org/apache/fineract/portfolio/floatingrates/data/FloatingRateData.java @@ -19,7 +19,7 @@ package org.apache.fineract.portfolio.floatingrates.data; import java.io.Serializable; -import java.time.LocalDate; +import java.time.OffsetDateTime; import java.util.List; import org.apache.commons.lang3.builder.CompareToBuilder; import org.apache.commons.lang3.builder.EqualsBuilder; @@ -33,15 +33,15 @@ public class FloatingRateData implements Comparable, Serializa private final boolean isBaseLendingRate; private final boolean isActive; private final String createdBy; - private final LocalDate createdOn; + private final OffsetDateTime createdOn; private final String modifiedBy; - private final LocalDate modifiedOn; + private final OffsetDateTime modifiedOn; private final List ratePeriods; @SuppressWarnings("unused") private final List interestRateFrequencyTypeOptions; - public FloatingRateData(Long id, String name, boolean isBaseLendingRate, boolean isActive, String createdBy, LocalDate createdOn, - String modifiedBy, LocalDate modifiedOn, List ratePeriods, + public FloatingRateData(Long id, String name, boolean isBaseLendingRate, boolean isActive, String createdBy, OffsetDateTime createdOn, + String modifiedBy, OffsetDateTime modifiedOn, List ratePeriods, List interestRateFrequencyTypeOptions) { this.id = id; this.name = name; @@ -75,7 +75,7 @@ public class FloatingRateData implements Comparable, Serializa return this.createdBy; } - public LocalDate getCreatedOn() { + public OffsetDateTime getCreatedOn() { return this.createdOn; } @@ -83,7 +83,7 @@ public class FloatingRateData implements Comparable, Serializa return this.modifiedBy; } - public LocalDate getModifiedOn() { + public OffsetDateTime getModifiedOn() { return this.modifiedOn; } diff --git a/fineract-provider/src/main/java/org/apache/fineract/portfolio/floatingrates/data/FloatingRatePeriodData.java b/fineract-provider/src/main/java/org/apache/fineract/portfolio/floatingrates/data/FloatingRatePeriodData.java index fd2c14d78..93516f1a9 100644 --- a/fineract-provider/src/main/java/org/apache/fineract/portfolio/floatingrates/data/FloatingRatePeriodData.java +++ b/fineract-provider/src/main/java/org/apache/fineract/portfolio/floatingrates/data/FloatingRatePeriodData.java @@ -21,7 +21,7 @@ package org.apache.fineract.portfolio.floatingrates.data; import java.io.Serializable; import java.math.BigDecimal; import java.time.LocalDate; -import java.time.LocalDateTime; +import java.time.OffsetDateTime; import org.apache.commons.lang3.builder.CompareToBuilder; import org.apache.commons.lang3.builder.EqualsBuilder; import org.apache.commons.lang3.builder.HashCodeBuilder; @@ -34,12 +34,12 @@ public class FloatingRatePeriodData implements Comparable floatingRatePeriods; - @ManyToOne(optional = true, fetch = FetchType.LAZY) - @JoinColumn(name = "createdby_id", nullable = false) - private AppUser createdBy; - - @ManyToOne(optional = true, fetch = FetchType.LAZY) - @JoinColumn(name = "lastmodifiedby_id", nullable = false) - private AppUser modifiedBy; - - @Column(name = "created_date", nullable = false) - private LocalDateTime createdOn; - - @Column(name = "lastmodified_date", nullable = false) - private LocalDateTime modifiedOn; + /* + * Deprecated since common Auditable fields were introduced. Columns and data left untouched to help migration. + * + * @Column(name = "created_date", nullable = false) private LocalDateTime createdOn; + * + * @Column(name = "lastmodified_date", nullable = false) private LocalDateTime modifiedOn; + */ public FloatingRate() { } - public FloatingRate(String name, boolean isBaseLendingRate, boolean isActive, List floatingRatePeriods, - AppUser createdBy, AppUser modifiedBy, LocalDateTime createdOn, LocalDateTime modifiedOn) { + public FloatingRate(String name, boolean isBaseLendingRate, boolean isActive, List floatingRatePeriods) { this.name = name; this.isBaseLendingRate = isBaseLendingRate; this.isActive = isActive; this.floatingRatePeriods = floatingRatePeriods; - this.createdBy = createdBy; - this.createdOn = createdOn; - this.modifiedBy = modifiedBy; - this.modifiedOn = modifiedOn; if (floatingRatePeriods != null) { for (FloatingRatePeriod ratePeriod : floatingRatePeriods) { ratePeriod.updateFloatingRate(this); @@ -101,20 +85,19 @@ public class FloatingRate extends AbstractPersistableCustom { } } - public static FloatingRate createNew(AppUser currentUser, JsonCommand command) { + public static FloatingRate createNew(JsonCommand command) { final String name = command.stringValueOfParameterNamed("name"); final boolean isBaseLendingRate = command.parameterExists("isBaseLendingRate") ? command.booleanPrimitiveValueOfParameterNamed("isBaseLendingRate") : false; final boolean isActive = command.parameterExists("isActive") ? command.booleanPrimitiveValueOfParameterNamed("isActive") : true; - final List floatingRatePeriods = getRatePeriods(currentUser, command); - final LocalDateTime currentDate = DateUtils.getLocalDateTimeOfSystem(); + final List floatingRatePeriods = getRatePeriods(command); - return new FloatingRate(name, isBaseLendingRate, isActive, floatingRatePeriods, currentUser, currentUser, currentDate, currentDate); + return new FloatingRate(name, isBaseLendingRate, isActive, floatingRatePeriods); } - private static List getRatePeriods(final AppUser currentUser, final JsonCommand command) { + private static List getRatePeriods(final JsonCommand command) { if (!command.parameterExists("ratePeriods")) { return null; } @@ -129,9 +112,7 @@ public class FloatingRate extends AbstractPersistableCustom { ? ratePeriodObject.get("isDifferentialToBaseLendingRate").getAsBoolean() : false; final boolean isActive = true; - final LocalDateTime currentDate = DateUtils.getLocalDateTimeOfSystem(); - ratePeriods.add(new FloatingRatePeriod(fromDate, interestRate, isDifferentialToBaseLendingRate, isActive, currentUser, - currentUser, currentDate, currentDate)); + ratePeriods.add(new FloatingRatePeriod(fromDate, interestRate, isDifferentialToBaseLendingRate, isActive)); } return ratePeriods; @@ -153,23 +134,7 @@ public class FloatingRate extends AbstractPersistableCustom { return this.floatingRatePeriods; } - public AppUser getCreatedBy() { - return this.createdBy; - } - - public AppUser getModifiedBy() { - return this.modifiedBy; - } - - public LocalDateTime getCreatedOn() { - return this.createdOn; - } - - public LocalDateTime getModifiedOn() { - return this.modifiedOn; - } - - public Map update(final JsonCommand command, final AppUser appUser) { + public Map update(final JsonCommand command) { final Map actualChanges = new LinkedHashMap<>(9); @@ -191,24 +156,22 @@ public class FloatingRate extends AbstractPersistableCustom { this.isActive = newValue; } - final List newRatePeriods = getRatePeriods(appUser, command); + final List newRatePeriods = getRatePeriods(command); if (newRatePeriods != null && !newRatePeriods.isEmpty()) { - updateRatePeriods(newRatePeriods, appUser); + updateRatePeriods(newRatePeriods); actualChanges.put("ratePeriods", command.jsonFragment("ratePeriods")); } return actualChanges; } - private void updateRatePeriods(final List newRatePeriods, final AppUser appUser) { + private void updateRatePeriods(final List newRatePeriods) { final LocalDate today = DateUtils.getBusinessLocalDate(); if (this.floatingRatePeriods != null) { for (FloatingRatePeriod ratePeriod : this.floatingRatePeriods) { LocalDate fromDate = ratePeriod.getFromDate(); if (fromDate.isAfter(today)) { ratePeriod.setActive(false); - ratePeriod.setModifiedBy(appUser); - ratePeriod.setModifiedOn(DateUtils.getLocalDateTimeOfSystem()); } } } diff --git a/fineract-provider/src/main/java/org/apache/fineract/portfolio/floatingrates/domain/FloatingRatePeriod.java b/fineract-provider/src/main/java/org/apache/fineract/portfolio/floatingrates/domain/FloatingRatePeriod.java index f85bd8be5..0e244f81f 100644 --- a/fineract-provider/src/main/java/org/apache/fineract/portfolio/floatingrates/domain/FloatingRatePeriod.java +++ b/fineract-provider/src/main/java/org/apache/fineract/portfolio/floatingrates/domain/FloatingRatePeriod.java @@ -20,22 +20,18 @@ package org.apache.fineract.portfolio.floatingrates.domain; import java.math.BigDecimal; import java.time.LocalDate; -import java.time.LocalDateTime; import javax.persistence.Column; import javax.persistence.Entity; -import javax.persistence.FetchType; import javax.persistence.JoinColumn; import javax.persistence.ManyToOne; import javax.persistence.Table; -import org.apache.fineract.infrastructure.core.domain.AbstractPersistableCustom; +import org.apache.fineract.infrastructure.core.domain.AbstractAuditableWithUTCDateTimeCustom; import org.apache.fineract.portfolio.floatingrates.data.FloatingRateDTO; import org.apache.fineract.portfolio.floatingrates.data.FloatingRatePeriodData; -import org.apache.fineract.useradministration.domain.AppUser; -//TODO: refactor to use AbstractAuditableCustom! @Entity @Table(name = "m_floating_rates_periods") -public class FloatingRatePeriod extends AbstractPersistableCustom { +public class FloatingRatePeriod extends AbstractAuditableWithUTCDateTimeCustom { @ManyToOne @JoinColumn(name = "floating_rates_id", nullable = false) @@ -53,41 +49,30 @@ public class FloatingRatePeriod extends AbstractPersistableCustom { @Column(name = "is_active", nullable = false) private boolean isActive; - @ManyToOne(optional = true, fetch = FetchType.LAZY) - @JoinColumn(name = "createdby_id", nullable = false) - private AppUser createdBy; - - @ManyToOne(optional = true, fetch = FetchType.LAZY) - @JoinColumn(name = "lastmodifiedby_id", nullable = false) - private AppUser modifiedBy; - - @Column(name = "created_date", nullable = false) - private LocalDateTime createdOn; - - @Column(name = "lastmodified_date", nullable = false) - private LocalDateTime modifiedOn; + /* + * Deprecated since common Auditable fields were introduced. Columns and data left untouched to help migration. + * + * @Column(name = "created_date", nullable = false) private LocalDateTime createdOn; + * + * @Column(name = "lastmodified_date", nullable = false) private LocalDateTime modifiedOn; + */ public FloatingRatePeriod() { } - public FloatingRatePeriod(LocalDate fromDate, BigDecimal interestRate, boolean isDifferentialToBaseLendingRate, boolean isActive, - AppUser createdBy, AppUser modifiedBy, LocalDateTime createdOn, LocalDateTime modifiedOn) { + public FloatingRatePeriod(LocalDate fromDate, BigDecimal interestRate, boolean isDifferentialToBaseLendingRate, boolean isActive) { this.fromDate = fromDate; this.interestRate = interestRate; this.isDifferentialToBaseLendingRate = isDifferentialToBaseLendingRate; this.isActive = isActive; - this.createdBy = createdBy; - this.modifiedBy = modifiedBy; - this.createdOn = createdOn; - this.modifiedOn = modifiedOn; } public void updateFloatingRate(FloatingRate floatingRate) { this.floatingRate = floatingRate; } - public FloatingRate getFloatingRatesId() { + public FloatingRate getFloatingRate() { return this.floatingRate; } @@ -107,32 +92,8 @@ public class FloatingRatePeriod extends AbstractPersistableCustom { return this.isActive; } - public AppUser getCreatedBy() { - return this.createdBy; - } - - public AppUser getModifiedBy() { - return this.modifiedBy; - } - - public LocalDateTime getCreatedOn() { - return this.createdOn; - } - - public LocalDateTime getModifiedOn() { - return this.modifiedOn; - } - - public void setModifiedBy(AppUser modifiedBy) { - this.modifiedBy = modifiedBy; - } - - public void setModifiedOn(LocalDateTime modifiedOn) { - this.modifiedOn = modifiedOn; - } - - public void setActive(boolean b) { - this.isActive = b; + public void setActive(boolean isActive) { + this.isActive = isActive; } public LocalDate fetchFromDate() { @@ -147,13 +108,7 @@ public class FloatingRatePeriod extends AbstractPersistableCustom { } final LocalDate fromDate = getFromDate(); - final LocalDateTime createdOn = getCreatedOn(); - final LocalDateTime modifiedOn = getModifiedOn(); - - String createdBy = getCreatedBy() != null ? getCreatedBy().getUsername() : null; - String modifiedBy = getModifiedBy() != null ? getModifiedBy().getUsername() : null; - return new FloatingRatePeriodData(getId(), fromDate, interest, isDifferentialToBaseLendingRate(), isActive(), createdBy, createdOn, - modifiedBy, modifiedOn); + return new FloatingRatePeriodData(getId(), fromDate, interest, isDifferentialToBaseLendingRate(), isActive()); } } diff --git a/fineract-provider/src/main/java/org/apache/fineract/portfolio/floatingrates/service/FloatingRateWritePlatformServiceImpl.java b/fineract-provider/src/main/java/org/apache/fineract/portfolio/floatingrates/service/FloatingRateWritePlatformServiceImpl.java index fabba549c..730b27b07 100644 --- a/fineract-provider/src/main/java/org/apache/fineract/portfolio/floatingrates/service/FloatingRateWritePlatformServiceImpl.java +++ b/fineract-provider/src/main/java/org/apache/fineract/portfolio/floatingrates/service/FloatingRateWritePlatformServiceImpl.java @@ -25,11 +25,9 @@ import org.apache.fineract.infrastructure.core.api.JsonCommand; import org.apache.fineract.infrastructure.core.data.CommandProcessingResult; import org.apache.fineract.infrastructure.core.data.CommandProcessingResultBuilder; import org.apache.fineract.infrastructure.core.exception.PlatformDataIntegrityException; -import org.apache.fineract.infrastructure.security.service.PlatformSecurityContext; import org.apache.fineract.portfolio.floatingrates.domain.FloatingRate; import org.apache.fineract.portfolio.floatingrates.domain.FloatingRateRepositoryWrapper; import org.apache.fineract.portfolio.floatingrates.serialization.FloatingRateDataValidator; -import org.apache.fineract.useradministration.domain.AppUser; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.beans.factory.annotation.Autowired; @@ -42,14 +40,12 @@ import org.springframework.transaction.annotation.Transactional; public class FloatingRateWritePlatformServiceImpl implements FloatingRateWritePlatformService { private static final Logger LOG = LoggerFactory.getLogger(FloatingRateWritePlatformServiceImpl.class); - private final PlatformSecurityContext context; private final FloatingRateDataValidator fromApiJsonDeserializer; private final FloatingRateRepositoryWrapper floatingRateRepository; @Autowired - public FloatingRateWritePlatformServiceImpl(final PlatformSecurityContext context, - final FloatingRateDataValidator fromApiJsonDeserializer, final FloatingRateRepositoryWrapper floatingRateRepository) { - this.context = context; + public FloatingRateWritePlatformServiceImpl(final FloatingRateDataValidator fromApiJsonDeserializer, + final FloatingRateRepositoryWrapper floatingRateRepository) { this.fromApiJsonDeserializer = fromApiJsonDeserializer; this.floatingRateRepository = floatingRateRepository; } @@ -59,8 +55,7 @@ public class FloatingRateWritePlatformServiceImpl implements FloatingRateWritePl public CommandProcessingResult createFloatingRate(final JsonCommand command) { try { this.fromApiJsonDeserializer.validateForCreate(command.json()); - final AppUser currentUser = this.context.authenticatedUser(); - final FloatingRate newFloatingRate = FloatingRate.createNew(currentUser, command); + final FloatingRate newFloatingRate = FloatingRate.createNew(command); this.floatingRateRepository.saveAndFlush(newFloatingRate); return new CommandProcessingResultBuilder() // .withCommandId(command.commandId()) // @@ -82,8 +77,7 @@ public class FloatingRateWritePlatformServiceImpl implements FloatingRateWritePl try { final FloatingRate floatingRateForUpdate = this.floatingRateRepository.findOneWithNotFoundDetection(command.entityId()); this.fromApiJsonDeserializer.validateForUpdate(command.json(), floatingRateForUpdate); - final AppUser currentUser = this.context.authenticatedUser(); - final Map changes = floatingRateForUpdate.update(command, currentUser); + final Map changes = floatingRateForUpdate.update(command); if (!changes.isEmpty()) { this.floatingRateRepository.save(floatingRateForUpdate); diff --git a/fineract-provider/src/main/java/org/apache/fineract/portfolio/floatingrates/service/FloatingRatesReadPlatformServiceImpl.java b/fineract-provider/src/main/java/org/apache/fineract/portfolio/floatingrates/service/FloatingRatesReadPlatformServiceImpl.java index 7439a93c0..9d8bcea3a 100644 --- a/fineract-provider/src/main/java/org/apache/fineract/portfolio/floatingrates/service/FloatingRatesReadPlatformServiceImpl.java +++ b/fineract-provider/src/main/java/org/apache/fineract/portfolio/floatingrates/service/FloatingRatesReadPlatformServiceImpl.java @@ -24,8 +24,10 @@ import java.sql.ResultSet; import java.sql.SQLException; import java.time.LocalDate; import java.time.LocalDateTime; +import java.time.OffsetDateTime; import java.util.List; import org.apache.fineract.infrastructure.core.domain.JdbcSupport; +import org.apache.fineract.infrastructure.core.service.DateUtils; import org.apache.fineract.portfolio.floatingrates.data.FloatingRateData; import org.apache.fineract.portfolio.floatingrates.data.FloatingRatePeriodData; import org.apache.fineract.portfolio.floatingrates.data.InterestRatePeriodData; @@ -106,7 +108,8 @@ public class FloatingRatesReadPlatformServiceImpl implements FloatingRatesReadPl private final StringBuilder sqlQuery = new StringBuilder().append("rate.id as id, ").append("rate.name as name, ") .append("rate.is_base_lending_rate as isBaseLendingRate, ").append("rate.is_active as isActive, ") .append("crappu.username as createdBy, ").append("rate.created_date as createdOn, ") - .append("moappu.username as modifiedBy, ").append("rate.lastmodified_date as modifiedOn ") + .append("rate.created_on_utc as createdOnUTC, ").append("moappu.username as modifiedBy, ") + .append("rate.lastmodified_date as modifiedOn, ").append("rate.last_modified_on_utc as modifiedOnUTC ") .append("FROM m_floating_rates as rate ").append("LEFT JOIN m_appuser as crappu on rate.createdby_id = crappu.id ") .append("LEFT JOIN m_appuser as moappu on rate.lastmodifiedby_id = moappu.id "); @@ -121,10 +124,16 @@ public class FloatingRatesReadPlatformServiceImpl implements FloatingRatesReadPl final boolean isBaseLendingRate = rs.getBoolean("isBaseLendingRate"); final boolean isActive = rs.getBoolean("isActive"); final String createdBy = rs.getString("createdBy"); - final LocalDate createdOn = JdbcSupport.getLocalDate(rs, "createdOn"); + final LocalDateTime createdOnLocal = JdbcSupport.getLocalDateTime(rs, "createdOn"); + final OffsetDateTime createdOnUtc = JdbcSupport.getOffsetDateTime(rs, "createdOnUTC"); final String modifiedBy = rs.getString("modifiedBy"); - final LocalDate modifiedOn = JdbcSupport.getLocalDate(rs, "modifiedOn"); + final LocalDateTime modifiedOnLocal = JdbcSupport.getLocalDateTime(rs, "modifiedOn"); + final OffsetDateTime modifiedOnUtc = JdbcSupport.getOffsetDateTime(rs, "modifiedOnUTC"); List ratePeriods = null; + final OffsetDateTime createdOn = createdOnUtc != null ? createdOnUtc + : OffsetDateTime.of(createdOnLocal, DateUtils.getDateTimeZoneOfTenant().getRules().getOffset(createdOnLocal)); + final OffsetDateTime modifiedOn = modifiedOnUtc != null ? modifiedOnUtc + : OffsetDateTime.of(modifiedOnLocal, DateUtils.getDateTimeZoneOfTenant().getRules().getOffset(modifiedOnLocal)); if (addRatePeriods) { FloatingRatePeriodRowMapper ratePeriodMapper = new FloatingRatePeriodRowMapper(); final String sql = "select " + ratePeriodMapper.schema() @@ -146,8 +155,9 @@ public class FloatingRatesReadPlatformServiceImpl implements FloatingRatesReadPl .append("period.interest_rate as interestRate, ") .append("period.is_differential_to_base_lending_rate as isDifferentialToBaseLendingRate, ") .append("period.is_active as isActive, ").append("crappu.username as createdBy, ") - .append("period.created_date as createdOn, ").append("moappu.username as modifiedBy, ") - .append("period.lastmodified_date as modifiedOn ").append("FROM m_floating_rates_periods as period ") + .append("period.created_date as createdOn, ").append("rate.created_on_utc as createdOnUTC, ") + .append("moappu.username as modifiedBy, ").append("period.lastmodified_date as modifiedOn, ") + .append("rate.last_modified_on_utc as modifiedOnUTC ").append("FROM m_floating_rates_periods as period ") .append("LEFT JOIN m_appuser as crappu on period.createdby_id = crappu.id ") .append("LEFT JOIN m_appuser as moappu on period.lastmodifiedby_id = moappu.id "); @@ -159,9 +169,15 @@ public class FloatingRatesReadPlatformServiceImpl implements FloatingRatesReadPl final boolean isDifferentialToBaseLendingRate = rs.getBoolean("isDifferentialToBaseLendingRate"); final boolean isActive = rs.getBoolean("isActive"); final String createdBy = rs.getString("createdBy"); - final LocalDateTime createdOn = JdbcSupport.getLocalDateTime(rs, "createdOn"); + final LocalDateTime createdOnLocal = JdbcSupport.getLocalDateTime(rs, "createdOn"); + final OffsetDateTime createdOnUtc = JdbcSupport.getOffsetDateTime(rs, "createdOnUTC"); final String modifiedBy = rs.getString("modifiedBy"); - final LocalDateTime modifiedOn = JdbcSupport.getLocalDateTime(rs, "modifiedOn"); + final LocalDateTime modifiedOnLocal = JdbcSupport.getLocalDateTime(rs, "modifiedOn"); + final OffsetDateTime modifiedOnUtc = JdbcSupport.getOffsetDateTime(rs, "modifiedOnUTC"); + final OffsetDateTime createdOn = createdOnUtc != null ? createdOnUtc + : OffsetDateTime.of(createdOnLocal, DateUtils.getDateTimeZoneOfTenant().getRules().getOffset(createdOnLocal)); + final OffsetDateTime modifiedOn = modifiedOnUtc != null ? modifiedOnUtc + : OffsetDateTime.of(modifiedOnLocal, DateUtils.getDateTimeZoneOfTenant().getRules().getOffset(modifiedOnLocal)); return new FloatingRatePeriodData(id, fromDate, interestRate, isDifferentialToBaseLendingRate, isActive, createdBy, createdOn, modifiedBy, modifiedOn); } diff --git a/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/jobs/addaccrualentries/AddAccrualEntriesTasklet.java b/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/jobs/addaccrualentries/AddAccrualEntriesTasklet.java index d5777093c..12be78e39 100644 --- a/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/jobs/addaccrualentries/AddAccrualEntriesTasklet.java +++ b/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/jobs/addaccrualentries/AddAccrualEntriesTasklet.java @@ -45,15 +45,15 @@ public class AddAccrualEntriesTasklet implements Tasklet { @Override public RepeatStatus execute(StepContribution contribution, ChunkContext chunkContext) throws Exception { - Collection loanScheduleAccrualDatas = loanReadPlatformService.retriveScheduleAccrualData(); + Collection loanScheduleAccrualDataList = loanReadPlatformService.retriveScheduleAccrualData(); Map> loanDataMap = new HashMap<>(); - for (final LoanScheduleAccrualData accrualData : loanScheduleAccrualDatas) { + for (final LoanScheduleAccrualData accrualData : loanScheduleAccrualDataList) { if (loanDataMap.containsKey(accrualData.getLoanId())) { loanDataMap.get(accrualData.getLoanId()).add(accrualData); } else { - Collection accrualDatas = new ArrayList<>(); - accrualDatas.add(accrualData); - loanDataMap.put(accrualData.getLoanId(), accrualDatas); + Collection accrualDataList = new ArrayList<>(); + accrualDataList.add(accrualData); + loanDataMap.put(accrualData.getLoanId(), accrualDataList); } } @@ -62,7 +62,7 @@ public class AddAccrualEntriesTasklet implements Tasklet { try { loanAccrualWritePlatformService.addAccrualAccounting(mapEntry.getKey(), mapEntry.getValue()); } catch (Exception e) { - log.error("Failed to add accural transaction for loan {}", mapEntry.getKey(), e); + log.error("Failed to add accrual transaction for loan {}", mapEntry.getKey(), e); errors.add(e); } } diff --git a/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/service/LoanAccrualPlatformServiceImpl.java b/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/service/LoanAccrualPlatformServiceImpl.java index bdaf03a10..f181bd81f 100644 --- a/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/service/LoanAccrualPlatformServiceImpl.java +++ b/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/service/LoanAccrualPlatformServiceImpl.java @@ -39,31 +39,31 @@ public class LoanAccrualPlatformServiceImpl implements LoanAccrualPlatformServic private final LoanAccrualWritePlatformService loanAccrualWritePlatformService; @Override - public void addPeriodicAccruals(final LocalDate tilldate) throws JobExecutionException { - Collection loanScheduleAccrualDatas = this.loanReadPlatformService.retrivePeriodicAccrualData(tilldate); - addPeriodicAccruals(tilldate, loanScheduleAccrualDatas); + public void addPeriodicAccruals(final LocalDate tillDate) throws JobExecutionException { + Collection loanScheduleAccrualDataList = this.loanReadPlatformService.retrivePeriodicAccrualData(tillDate); + addPeriodicAccruals(tillDate, loanScheduleAccrualDataList); } @Override - public void addPeriodicAccruals(final LocalDate tilldate, Collection loanScheduleAccrualDatas) + public void addPeriodicAccruals(final LocalDate tillDate, Collection loanScheduleAccrualDataList) throws JobExecutionException { Map> loanDataMap = new HashMap<>(); - for (final LoanScheduleAccrualData accrualData : loanScheduleAccrualDatas) { + for (final LoanScheduleAccrualData accrualData : loanScheduleAccrualDataList) { if (loanDataMap.containsKey(accrualData.getLoanId())) { loanDataMap.get(accrualData.getLoanId()).add(accrualData); } else { - Collection accrualDatas = new ArrayList<>(); - accrualDatas.add(accrualData); - loanDataMap.put(accrualData.getLoanId(), accrualDatas); + Collection accrualDataList = new ArrayList<>(); + accrualDataList.add(accrualData); + loanDataMap.put(accrualData.getLoanId(), accrualDataList); } } List errors = new ArrayList<>(); for (Map.Entry> mapEntry : loanDataMap.entrySet()) { try { - this.loanAccrualWritePlatformService.addPeriodicAccruals(tilldate, mapEntry.getKey(), mapEntry.getValue()); + this.loanAccrualWritePlatformService.addPeriodicAccruals(tillDate, mapEntry.getKey(), mapEntry.getValue()); } catch (Exception e) { - log.error("Failed to add accural transaction for loan {}", mapEntry.getKey(), e); + log.error("Failed to add accrual transaction for loan {}", mapEntry.getKey(), e); errors.add(e); } } diff --git a/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/service/LoanAccrualWritePlatformServiceImpl.java b/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/service/LoanAccrualWritePlatformServiceImpl.java index 2042b7cc2..2f21fffdc 100644 --- a/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/service/LoanAccrualWritePlatformServiceImpl.java +++ b/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/service/LoanAccrualWritePlatformServiceImpl.java @@ -32,6 +32,7 @@ import lombok.RequiredArgsConstructor; import org.apache.fineract.accounting.journalentry.service.JournalEntryWritePlatformService; import org.apache.fineract.infrastructure.core.service.DateUtils; import org.apache.fineract.infrastructure.core.service.database.DatabaseSpecificSQLGenerator; +import org.apache.fineract.infrastructure.security.service.PlatformSecurityContext; import org.apache.fineract.organisation.monetary.domain.ApplicationCurrency; import org.apache.fineract.organisation.monetary.domain.ApplicationCurrencyRepositoryWrapper; import org.apache.fineract.organisation.monetary.domain.MonetaryCurrency; @@ -47,6 +48,7 @@ import org.apache.fineract.portfolio.loanaccount.domain.LoanTransactionType; import org.apache.fineract.portfolio.loanaccount.exception.LoanNotFoundException; import org.apache.fineract.portfolio.loanaccount.loanschedule.data.LoanSchedulePeriodData; import org.apache.fineract.portfolio.loanproduct.service.LoanEnumerations; +import org.apache.fineract.useradministration.domain.AppUser; import org.apache.fineract.useradministration.domain.AppUserRepositoryWrapper; import org.springframework.dao.DataAccessException; import org.springframework.jdbc.core.JdbcTemplate; @@ -63,63 +65,62 @@ public class LoanAccrualWritePlatformServiceImpl implements LoanAccrualWritePlat private final DatabaseSpecificSQLGenerator sqlGenerator; private final JournalEntryWritePlatformService journalEntryWritePlatformService; private final AppUserRepositoryWrapper userRepository; + private final PlatformSecurityContext context; private final LoanRepositoryWrapper loanRepositoryWrapper; private final ApplicationCurrencyRepositoryWrapper applicationCurrencyRepository; @Override @Transactional - public void addAccrualAccounting(final Long loanId, final Collection loanScheduleAccrualDatas) - throws Exception { + public void addAccrualAccounting(final Long loanId, final Collection loanScheduleAccrualData) { Collection chargeData = this.loanChargeReadPlatformService.retrieveLoanChargesForAccural(loanId); Collection loanWaiverScheduleData = new ArrayList<>(1); - Collection loanWaiverTansactionData = new ArrayList<>(1); + Collection loanWaiverTransactionData = new ArrayList<>(1); - for (final LoanScheduleAccrualData accrualData : loanScheduleAccrualDatas) { + for (final LoanScheduleAccrualData accrualData : loanScheduleAccrualData) { if (accrualData.getWaivedInterestIncome() != null && loanWaiverScheduleData.isEmpty()) { loanWaiverScheduleData = this.loanReadPlatformService.fetchWaiverInterestRepaymentData(accrualData.getLoanId()); - loanWaiverTansactionData = this.loanReadPlatformService.retrieveWaiverLoanTransactions(accrualData.getLoanId()); + loanWaiverTransactionData = this.loanReadPlatformService.retrieveWaiverLoanTransactions(accrualData.getLoanId()); } updateCharges(chargeData, accrualData, accrualData.getFromDateAsLocaldate(), accrualData.getDueDateAsLocaldate()); - updateInterestIncome(accrualData, loanWaiverTansactionData, loanWaiverScheduleData, accrualData.getDueDateAsLocaldate()); + updateInterestIncome(accrualData, loanWaiverTransactionData, loanWaiverScheduleData, accrualData.getDueDateAsLocaldate()); addAccrualAccounting(accrualData); } } @Override @Transactional - public void addPeriodicAccruals(final LocalDate tilldate, Long loanId, Collection loanScheduleAccrualDatas) - throws Exception { + public void addPeriodicAccruals(final LocalDate tillDate, Long loanId, Collection loanScheduleAccrualData) { boolean firstTime = true; - LocalDate accruredTill = null; + LocalDate accruedTill = null; Collection chargeData = this.loanChargeReadPlatformService.retrieveLoanChargesForAccural(loanId); Collection loanWaiverScheduleData = new ArrayList<>(1); - Collection loanWaiverTansactionData = new ArrayList<>(1); - for (final LoanScheduleAccrualData accrualData : loanScheduleAccrualDatas) { + Collection loanWaiverTransactionData = new ArrayList<>(1); + for (final LoanScheduleAccrualData accrualData : loanScheduleAccrualData) { if (accrualData.getWaivedInterestIncome() != null && loanWaiverScheduleData.isEmpty()) { loanWaiverScheduleData = this.loanReadPlatformService.fetchWaiverInterestRepaymentData(accrualData.getLoanId()); - loanWaiverTansactionData = this.loanReadPlatformService.retrieveWaiverLoanTransactions(accrualData.getLoanId()); + loanWaiverTransactionData = this.loanReadPlatformService.retrieveWaiverLoanTransactions(accrualData.getLoanId()); } - if (accrualData.getDueDateAsLocaldate().isAfter(tilldate)) { - if (accruredTill == null || firstTime) { - accruredTill = accrualData.getAccruedTill(); + if (accrualData.getDueDateAsLocaldate().isAfter(tillDate)) { + if (accruedTill == null || firstTime) { + accruedTill = accrualData.getAccruedTill(); firstTime = false; } - if (accruredTill == null || accruredTill.isBefore(tilldate)) { - updateCharges(chargeData, accrualData, accrualData.getFromDateAsLocaldate(), tilldate); - updateInterestIncome(accrualData, loanWaiverTansactionData, loanWaiverScheduleData, tilldate); - addAccrualTillSpecificDate(tilldate, accrualData); + if (accruedTill == null || accruedTill.isBefore(tillDate)) { + updateCharges(chargeData, accrualData, accrualData.getFromDateAsLocaldate(), tillDate); + updateInterestIncome(accrualData, loanWaiverTransactionData, loanWaiverScheduleData, tillDate); + addAccrualTillSpecificDate(tillDate, accrualData); } } else { updateCharges(chargeData, accrualData, accrualData.getFromDateAsLocaldate(), accrualData.getDueDateAsLocaldate()); - updateInterestIncome(accrualData, loanWaiverTansactionData, loanWaiverScheduleData, tilldate); + updateInterestIncome(accrualData, loanWaiverTransactionData, loanWaiverScheduleData, tillDate); addAccrualAccounting(accrualData); - accruredTill = accrualData.getDueDateAsLocaldate(); + accruedTill = accrualData.getDueDateAsLocaldate(); } } } - private void addAccrualTillSpecificDate(final LocalDate tilldate, final LoanScheduleAccrualData accrualData) throws Exception { + private void addAccrualTillSpecificDate(final LocalDate tillDate, final LoanScheduleAccrualData accrualData) { LocalDate interestStartDate = accrualData.getFromDateAsLocaldate(); if (accrualData.getInterestCalculatedFrom() != null && accrualData.getFromDateAsLocaldate().isBefore(accrualData.getInterestCalculatedFrom())) { @@ -133,150 +134,150 @@ public class LoanAccrualWritePlatformServiceImpl implements LoanAccrualWritePlat int totalNumberOfDays = Math.toIntExact(ChronoUnit.DAYS.between(interestStartDate, accrualData.getDueDateAsLocaldate())); LocalDate startDate = accrualData.getFromDateAsLocaldate(); if (accrualData.getInterestCalculatedFrom() != null && startDate.isBefore(accrualData.getInterestCalculatedFrom())) { - if (accrualData.getInterestCalculatedFrom().isBefore(tilldate)) { + if (accrualData.getInterestCalculatedFrom().isBefore(tillDate)) { startDate = accrualData.getInterestCalculatedFrom(); } else { - startDate = tilldate; + startDate = tillDate; } } - int daysToBeAccrued = Math.toIntExact(ChronoUnit.DAYS.between(startDate, tilldate)); + int daysToBeAccrued = Math.toIntExact(ChronoUnit.DAYS.between(startDate, tillDate)); double interestPerDay = accrualData.getAccruableIncome().doubleValue() / totalNumberOfDays; BigDecimal amount = BigDecimal.ZERO; - BigDecimal interestportion = null; - BigDecimal feeportion = accrualData.getDueDateFeeIncome(); - BigDecimal penaltyportion = accrualData.getDueDatePenaltyIncome(); + BigDecimal interestPortion; + BigDecimal feePortion = accrualData.getDueDateFeeIncome(); + BigDecimal penaltyPortion = accrualData.getDueDatePenaltyIncome(); if (daysToBeAccrued >= totalNumberOfDays) { - interestportion = accrualData.getAccruableIncome(); + interestPortion = accrualData.getAccruableIncome(); } else { - double iterest = interestPerDay * daysToBeAccrued; - interestportion = BigDecimal.valueOf(iterest); + interestPortion = BigDecimal.valueOf(interestPerDay * daysToBeAccrued); } - interestportion = interestportion.setScale(accrualData.getCurrencyData().decimalPlaces(), MoneyHelper.getRoundingMode()); + interestPortion = interestPortion.setScale(accrualData.getCurrencyData().decimalPlaces(), MoneyHelper.getRoundingMode()); BigDecimal totalAccInterest = accrualData.getAccruedInterestIncome(); BigDecimal totalAccPenalty = accrualData.getAccruedPenaltyIncome(); BigDecimal totalAccFee = accrualData.getAccruedFeeIncome(); - if (interestportion != null) { - if (totalAccInterest == null) { - totalAccInterest = BigDecimal.ZERO; - } - interestportion = interestportion.subtract(totalAccInterest); - amount = amount.add(interestportion); - totalAccInterest = totalAccInterest.add(interestportion); - if (interestportion.compareTo(BigDecimal.ZERO) == 0) { - interestportion = null; - } + if (totalAccInterest == null) { + totalAccInterest = BigDecimal.ZERO; } - if (feeportion != null) { + interestPortion = interestPortion.subtract(totalAccInterest); + amount = amount.add(interestPortion); + totalAccInterest = totalAccInterest.add(interestPortion); + if (interestPortion.compareTo(BigDecimal.ZERO) == 0) { + interestPortion = null; + } + if (feePortion != null) { if (totalAccFee == null) { totalAccFee = BigDecimal.ZERO; } - feeportion = feeportion.subtract(totalAccFee); - amount = amount.add(feeportion); - totalAccFee = totalAccFee.add(feeportion); - if (feeportion.compareTo(BigDecimal.ZERO) == 0) { - feeportion = null; + feePortion = feePortion.subtract(totalAccFee); + amount = amount.add(feePortion); + totalAccFee = totalAccFee.add(feePortion); + if (feePortion.compareTo(BigDecimal.ZERO) == 0) { + feePortion = null; } } - if (penaltyportion != null) { + if (penaltyPortion != null) { if (totalAccPenalty == null) { totalAccPenalty = BigDecimal.ZERO; } - penaltyportion = penaltyportion.subtract(totalAccPenalty); - amount = amount.add(penaltyportion); - totalAccPenalty = totalAccPenalty.add(penaltyportion); - if (penaltyportion.compareTo(BigDecimal.ZERO) == 0) { - penaltyportion = null; + penaltyPortion = penaltyPortion.subtract(totalAccPenalty); + amount = amount.add(penaltyPortion); + totalAccPenalty = totalAccPenalty.add(penaltyPortion); + if (penaltyPortion.compareTo(BigDecimal.ZERO) == 0) { + penaltyPortion = null; } } if (amount.compareTo(BigDecimal.ZERO) > 0) { - addAccrualAccounting(accrualData, amount, interestportion, totalAccInterest, feeportion, totalAccFee, penaltyportion, - totalAccPenalty, tilldate); + addAccrualAccounting(accrualData, amount, interestPortion, totalAccInterest, feePortion, totalAccFee, penaltyPortion, + totalAccPenalty, tillDate); } } @Transactional - public void addAccrualAccounting(LoanScheduleAccrualData scheduleAccrualData) throws Exception { + public void addAccrualAccounting(LoanScheduleAccrualData scheduleAccrualData) { BigDecimal amount = BigDecimal.ZERO; - BigDecimal interestportion = null; + BigDecimal interestPortion = null; BigDecimal totalAccInterest = null; if (scheduleAccrualData.getAccruableIncome() != null) { - interestportion = scheduleAccrualData.getAccruableIncome(); - totalAccInterest = interestportion; + interestPortion = scheduleAccrualData.getAccruableIncome(); + totalAccInterest = interestPortion; if (scheduleAccrualData.getAccruedInterestIncome() != null) { - interestportion = interestportion.subtract(scheduleAccrualData.getAccruedInterestIncome()); + interestPortion = interestPortion.subtract(scheduleAccrualData.getAccruedInterestIncome()); } - amount = amount.add(interestportion); - if (interestportion.compareTo(BigDecimal.ZERO) == 0) { - interestportion = null; + amount = amount.add(interestPortion); + if (interestPortion.compareTo(BigDecimal.ZERO) == 0) { + interestPortion = null; } } - BigDecimal feeportion = null; + BigDecimal feePortion = null; BigDecimal totalAccFee = null; if (scheduleAccrualData.getDueDateFeeIncome() != null) { - feeportion = scheduleAccrualData.getDueDateFeeIncome(); - totalAccFee = feeportion; + feePortion = scheduleAccrualData.getDueDateFeeIncome(); + totalAccFee = feePortion; if (scheduleAccrualData.getAccruedFeeIncome() != null) { - feeportion = feeportion.subtract(scheduleAccrualData.getAccruedFeeIncome()); + feePortion = feePortion.subtract(scheduleAccrualData.getAccruedFeeIncome()); } - amount = amount.add(feeportion); - if (feeportion.compareTo(BigDecimal.ZERO) == 0) { - feeportion = null; + amount = amount.add(feePortion); + if (feePortion.compareTo(BigDecimal.ZERO) == 0) { + feePortion = null; } } - BigDecimal penaltyportion = null; + BigDecimal penaltyPortion = null; BigDecimal totalAccPenalty = null; if (scheduleAccrualData.getDueDatePenaltyIncome() != null) { - penaltyportion = scheduleAccrualData.getDueDatePenaltyIncome(); - totalAccPenalty = penaltyportion; + penaltyPortion = scheduleAccrualData.getDueDatePenaltyIncome(); + totalAccPenalty = penaltyPortion; if (scheduleAccrualData.getAccruedPenaltyIncome() != null) { - penaltyportion = penaltyportion.subtract(scheduleAccrualData.getAccruedPenaltyIncome()); + penaltyPortion = penaltyPortion.subtract(scheduleAccrualData.getAccruedPenaltyIncome()); } - amount = amount.add(penaltyportion); - if (penaltyportion.compareTo(BigDecimal.ZERO) == 0) { - penaltyportion = null; + amount = amount.add(penaltyPortion); + if (penaltyPortion.compareTo(BigDecimal.ZERO) == 0) { + penaltyPortion = null; } } if (amount.compareTo(BigDecimal.ZERO) > 0) { - addAccrualAccounting(scheduleAccrualData, amount, interestportion, totalAccInterest, feeportion, totalAccFee, penaltyportion, + addAccrualAccounting(scheduleAccrualData, amount, interestPortion, totalAccInterest, feePortion, totalAccFee, penaltyPortion, totalAccPenalty, scheduleAccrualData.getDueDateAsLocaldate()); } } - private void addAccrualAccounting(LoanScheduleAccrualData scheduleAccrualData, BigDecimal amount, BigDecimal interestportion, - BigDecimal totalAccInterest, BigDecimal feeportion, BigDecimal totalAccFee, BigDecimal penaltyportion, + private void addAccrualAccounting(LoanScheduleAccrualData scheduleAccrualData, BigDecimal amount, BigDecimal interestPortion, + BigDecimal totalAccInterest, BigDecimal feePortion, BigDecimal totalAccFee, BigDecimal penaltyPortion, BigDecimal totalAccPenalty, final LocalDate accruedTill) throws DataAccessException { + AppUser user = context.authenticatedUser(); String transactionSql = "INSERT INTO m_loan_transaction (loan_id,office_id,is_reversed,transaction_type_enum,transaction_date,amount,interest_portion_derived," - + "fee_charges_portion_derived,penalty_charges_portion_derived, submitted_on_date) VALUES (?, ?, false, ?, ?, ?, ?, ?, ?, ?)"; + + "fee_charges_portion_derived,penalty_charges_portion_derived, submitted_on_date, created_by, last_modified_by, created_on_utc, last_modified_on_utc) " + + "VALUES (?, ?, false, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)"; this.jdbcTemplate.update(transactionSql, scheduleAccrualData.getLoanId(), scheduleAccrualData.getOfficeId(), - LoanTransactionType.ACCRUAL.getValue(), accruedTill, amount, interestportion, feeportion, penaltyportion, - DateUtils.getBusinessLocalDate()); - @SuppressWarnings("deprecation") - final Long transactonId = this.jdbcTemplate.queryForObject("SELECT " + sqlGenerator.lastInsertId(), Long.class); // NOSONAR + LoanTransactionType.ACCRUAL.getValue(), accruedTill, amount, interestPortion, feePortion, penaltyPortion, + DateUtils.getBusinessLocalDate(), user.getId(), user.getId(), DateUtils.getOffsetDateTimeOfTenant(), + DateUtils.getOffsetDateTimeOfTenant()); + final Long transactionId = this.jdbcTemplate.queryForObject("SELECT " + sqlGenerator.lastInsertId(), Long.class); // NOSONAR Map applicableCharges = scheduleAccrualData.getApplicableCharges(); - String chargespaidSql = "INSERT INTO m_loan_charge_paid_by (loan_transaction_id, loan_charge_id, amount,installment_number) VALUES (?,?,?,?)"; + String chargesPaidSql = "INSERT INTO m_loan_charge_paid_by (loan_transaction_id, loan_charge_id, amount,installment_number) VALUES (?,?,?,?)"; for (Map.Entry entry : applicableCharges.entrySet()) { LoanChargeData chargeData = entry.getKey(); - this.jdbcTemplate.update(chargespaidSql, transactonId, chargeData.getId(), entry.getValue(), + this.jdbcTemplate.update(chargesPaidSql, transactionId, chargeData.getId(), entry.getValue(), scheduleAccrualData.getInstallmentNumber()); } - Map transactionMap = toMapData(transactonId, amount, interestportion, feeportion, penaltyportion, + Map transactionMap = toMapData(transactionId, amount, interestPortion, feePortion, penaltyPortion, scheduleAccrualData, accruedTill); - String repaymetUpdatesql = "UPDATE m_loan_repayment_schedule SET accrual_interest_derived=?, accrual_fee_charges_derived=?, " + String repaymentUpdateSql = "UPDATE m_loan_repayment_schedule SET accrual_interest_derived=?, accrual_fee_charges_derived=?, " + "accrual_penalty_charges_derived=? WHERE id=?"; - this.jdbcTemplate.update(repaymetUpdatesql, totalAccInterest, totalAccFee, totalAccPenalty, + this.jdbcTemplate.update(repaymentUpdateSql, totalAccInterest, totalAccFee, totalAccPenalty, scheduleAccrualData.getRepaymentScheduleId()); - String updateLoan = "UPDATE m_loan SET accrued_till=? WHERE id=?"; - this.jdbcTemplate.update(updateLoan, accruedTill, scheduleAccrualData.getLoanId()); + String updateLoan = "UPDATE m_loan SET accrued_till=?, last_modified_by=?, last_modified_on_utc=? WHERE id=?"; + this.jdbcTemplate.update(updateLoan, accruedTill, user.getId(), DateUtils.getOffsetDateTimeOfTenant(), + scheduleAccrualData.getLoanId()); final Map accountingBridgeData = deriveAccountingBridgeData(scheduleAccrualData, transactionMap); this.journalEntryWritePlatformService.createJournalEntriesForLoan(accountingBridgeData); } @@ -301,9 +302,9 @@ public class LoanAccrualWritePlatformServiceImpl implements LoanAccrualWritePlat return accountingBridgeData; } - public Map toMapData(final Long id, final BigDecimal amount, final BigDecimal interestportion, - final BigDecimal feeportion, final BigDecimal penaltyportion, final LoanScheduleAccrualData loanScheduleAccrualData, - final LocalDate accruredTill) { + public Map toMapData(final Long id, final BigDecimal amount, final BigDecimal interestPortion, + final BigDecimal feePortion, final BigDecimal penaltyPortion, final LoanScheduleAccrualData loanScheduleAccrualData, + final LocalDate accruedTill) { final Map thisTransactionData = new LinkedHashMap<>(); final LoanTransactionEnumData transactionType = LoanEnumerations.transactionType(LoanTransactionType.ACCRUAL); @@ -312,13 +313,13 @@ public class LoanAccrualWritePlatformServiceImpl implements LoanAccrualWritePlat thisTransactionData.put("officeId", loanScheduleAccrualData.getOfficeId()); thisTransactionData.put("type", transactionType); thisTransactionData.put("reversed", false); - thisTransactionData.put("date", accruredTill); + thisTransactionData.put("date", accruedTill); thisTransactionData.put("currency", loanScheduleAccrualData.getCurrencyData()); thisTransactionData.put("amount", amount); thisTransactionData.put("principalPortion", null); - thisTransactionData.put("interestPortion", interestportion); - thisTransactionData.put("feeChargesPortion", feeportion); - thisTransactionData.put("penaltyChargesPortion", penaltyportion); + thisTransactionData.put("interestPortion", interestPortion); + thisTransactionData.put("feeChargesPortion", feePortion); + thisTransactionData.put("penaltyChargesPortion", penaltyPortion); thisTransactionData.put("overPaymentPortion", null); Map applicableCharges = loanScheduleAccrualData.getApplicableCharges(); @@ -411,8 +412,8 @@ public class LoanAccrualWritePlatformServiceImpl implements LoanAccrualWritePlat } private void updateInterestIncome(final LoanScheduleAccrualData accrualData, - final Collection loanWaiverTansactions, final Collection loanSchedulePeriodDatas, - final LocalDate tilldate) { + final Collection loanWaiverTransactions, + final Collection loanSchedulePeriodDataList, final LocalDate tillDate) { BigDecimal interestIncome = BigDecimal.ZERO; if (accrualData.getInterestIncome() != null) { @@ -424,17 +425,17 @@ public class LoanAccrualWritePlatformServiceImpl implements LoanAccrualWritePlat BigDecimal remainingAmt = BigDecimal.ZERO; Collection loanTransactionDatas = new ArrayList<>(); - for (LoanTransactionData loanTransactionData : loanWaiverTansactions) { + for (LoanTransactionData loanTransactionData : loanWaiverTransactions) { if (!loanTransactionData.dateOf().isAfter(accrualData.getFromDateAsLocaldate()) || (loanTransactionData.dateOf().isAfter(accrualData.getFromDateAsLocaldate()) && !loanTransactionData.dateOf().isAfter(accrualData.getDueDateAsLocaldate()) - && !loanTransactionData.dateOf().isAfter(tilldate))) { + && !loanTransactionData.dateOf().isAfter(tillDate))) { loanTransactionDatas.add(loanTransactionData); } } Iterator iterator = loanTransactionDatas.iterator(); - for (LoanSchedulePeriodData loanSchedulePeriodData : loanSchedulePeriodDatas) { + for (LoanSchedulePeriodData loanSchedulePeriodData : loanSchedulePeriodDataList) { if (recognized.compareTo(BigDecimal.ZERO) <= 0 && unrecognized.compareTo(BigDecimal.ZERO) <= 0 && iterator.hasNext()) { LoanTransactionData loanTransactionData = iterator.next(); recognized = recognized.add(loanTransactionData.getInterestPortion()); diff --git a/fineract-provider/src/main/resources/db/changelog/tenant/changelog-tenant.xml b/fineract-provider/src/main/resources/db/changelog/tenant/changelog-tenant.xml index 7f3d90b79..cb283230e 100644 --- a/fineract-provider/src/main/resources/db/changelog/tenant/changelog-tenant.xml +++ b/fineract-provider/src/main/resources/db/changelog/tenant/changelog-tenant.xml @@ -42,4 +42,6 @@ + + diff --git a/fineract-provider/src/main/resources/db/changelog/tenant/parts/0023_use_the_proper_date_or_datetime_type.xml b/fineract-provider/src/main/resources/db/changelog/tenant/parts/0023_use_the_proper_date_or_datetime_type.xml new file mode 100644 index 000000000..2a2ea0562 --- /dev/null +++ b/fineract-provider/src/main/resources/db/changelog/tenant/parts/0023_use_the_proper_date_or_datetime_type.xml @@ -0,0 +1,41 @@ + + + + + + + + + + + + + + + + + + + + diff --git a/fineract-provider/src/main/resources/db/changelog/tenant/parts/0024_add_audit_entries.xml b/fineract-provider/src/main/resources/db/changelog/tenant/parts/0024_add_audit_entries.xml new file mode 100644 index 000000000..739751d04 --- /dev/null +++ b/fineract-provider/src/main/resources/db/changelog/tenant/parts/0024_add_audit_entries.xml @@ -0,0 +1,241 @@ + + + + + + + select count(*) from m_client + + + + + + + + + select count(*) from m_client + + + + + + + + + + select count(*) from m_loan + + + + + + + + + select count(*) from m_loan + + + + + + + + + + select count(*) from m_loan_transaction + + + + + + + + + select count(*) from m_loan_transaction + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + select count(*) from m_client_transaction + + + + + + + + + select count(*) from m_client_transaction + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + select count(*) from m_floating_rates + + + + + + + + + select count(*) from m_client_transaction + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + select count(*) from m_floating_rates_periods + + + + + + + + + select count(*) from m_floating_rates_periods + + + + + + + + + + + diff --git a/integration-tests/src/test/java/org/apache/fineract/integrationtests/FixedDepositTest.java b/integration-tests/src/test/java/org/apache/fineract/integrationtests/FixedDepositTest.java index 63e5a5f69..fd4bc8036 100644 --- a/integration-tests/src/test/java/org/apache/fineract/integrationtests/FixedDepositTest.java +++ b/integration-tests/src/test/java/org/apache/fineract/integrationtests/FixedDepositTest.java @@ -30,7 +30,10 @@ import java.math.BigDecimal; import java.math.RoundingMode; import java.text.DateFormat; import java.text.SimpleDateFormat; +import java.time.LocalDate; import java.time.ZonedDateTime; +import java.time.format.DateTimeFormatter; +import java.time.format.DateTimeFormatterBuilder; import java.time.temporal.ChronoUnit; import java.util.ArrayList; import java.util.Arrays; @@ -442,7 +445,7 @@ public class FixedDepositTest { } @Test - public void testFixedDepositAccountClosureTypeWithdrawal_WITH_HOLD_TAX() throws InterruptedException { + public void testFixedDepositAccountClosureTypeWithdrawal_WITH_HOLD_TAX() { this.fixedDepositProductHelper = new FixedDepositProductHelper(this.requestSpec, this.responseSpec); this.accountHelper = new AccountHelper(this.requestSpec, this.responseSpec); this.savingsAccountHelper = new SavingsAccountHelper(this.requestSpec, this.responseSpec); @@ -457,30 +460,23 @@ public class FixedDepositTest { final Account liabilityAccount = this.accountHelper.createLiabilityAccount(); final Account liabilityAccountForTax = this.accountHelper.createLiabilityAccount(); - DateFormat dateFormat = new SimpleDateFormat("dd MMMM yyyy", Locale.US); - DateFormat monthDayFormat = new SimpleDateFormat("dd MMM", Locale.US); - DateFormat currentDateFormat = new SimpleDateFormat("dd"); + DateTimeFormatter monthDayFormat = new DateTimeFormatterBuilder().appendPattern("dd MMM").toFormatter(); + DateTimeFormatter currentDateFormat = new DateTimeFormatterBuilder().appendPattern("dd").toFormatter(); - Calendar todaysDate = Calendar.getInstance(); - todaysDate.add(Calendar.MONTH, -20); - final String VALID_FROM = dateFormat.format(todaysDate.getTime()); - todaysDate.add(Calendar.YEAR, 10); - final String VALID_TO = dateFormat.format(todaysDate.getTime()); + LocalDate todaysDate = Utils.getLocalDateOfTenant(); + todaysDate = todaysDate.minusMonths(20); + final String VALID_FROM = Utils.dateFormatter.format(todaysDate); + todaysDate = todaysDate.plusYears(10); + final String VALID_TO = Utils.dateFormatter.format(todaysDate); - todaysDate = Calendar.getInstance(); - todaysDate.add(Calendar.MONTH, -20); - final String SUBMITTED_ON_DATE = dateFormat.format(todaysDate.getTime()); - final String APPROVED_ON_DATE = dateFormat.format(todaysDate.getTime()); - final String ACTIVATION_DATE = dateFormat.format(todaysDate.getTime()); - monthDayFormat.format(todaysDate.getTime()); + todaysDate = Utils.getLocalDateOfTenant(); + todaysDate = todaysDate.minusMonths(20); + final String SUBMITTED_ON_DATE = Utils.dateFormatter.format(todaysDate); + final String APPROVED_ON_DATE = Utils.dateFormatter.format(todaysDate); + final String ACTIVATION_DATE = Utils.dateFormatter.format(todaysDate); - Integer currentDate = Integer.valueOf(currentDateFormat.format(todaysDate.getTime())); - Integer daysInMonth = todaysDate.getActualMaximum(Calendar.DATE); - int numberOfDaysLeft = daysInMonth - currentDate + 1; - todaysDate.add(Calendar.DATE, numberOfDaysLeft); - Calendar closedOn = Calendar.getInstance(); - closedOn.add(Calendar.MONTH, -6); - final String CLOSED_ON_DATE = dateFormat.format(closedOn.getTime()); + LocalDate closedOn = todaysDate.plusMonths(14); + final String CLOSED_ON_DATE = Utils.dateFormatter.format(closedOn); Integer clientId = ClientHelper.createClient(requestSpec, responseSpec); Assertions.assertNotNull(clientId); @@ -1282,26 +1278,23 @@ public class FixedDepositTest { this.savingsAccountHelper = new SavingsAccountHelper(this.requestSpec, this.responseSpec); this.fixedDepositAccountHelper = new FixedDepositAccountHelper(this.requestSpec, this.responseSpec); - DateFormat dateFormat = new SimpleDateFormat("dd MMMM yyyy", Locale.US); - DateFormat monthDayFormat = new SimpleDateFormat("dd MMM", Locale.US); - DateFormat currentDateFormat = new SimpleDateFormat("dd"); + DateTimeFormatter dateFormat = Utils.dateFormatter; - Calendar todaysDate = Calendar.getInstance(); - todaysDate.add(Calendar.MONTH, -3); - final String VALID_FROM = dateFormat.format(todaysDate.getTime()); - todaysDate.add(Calendar.YEAR, 10); - final String VALID_TO = dateFormat.format(todaysDate.getTime()); + LocalDate todaysDate = Utils.getLocalDateOfTenant(); + todaysDate = todaysDate.minusMonths(3); + final String VALID_FROM = dateFormat.format(todaysDate); + todaysDate = todaysDate.plusYears(10); + final String VALID_TO = dateFormat.format(todaysDate); - todaysDate = Calendar.getInstance(); - todaysDate.add(Calendar.MONTH, -1); - todaysDate.add(Calendar.DAY_OF_MONTH, -1); - final String SUBMITTED_ON_DATE = dateFormat.format(todaysDate.getTime()); - final String APPROVED_ON_DATE = dateFormat.format(todaysDate.getTime()); - final String ACTIVATION_DATE = dateFormat.format(todaysDate.getTime()); - monthDayFormat.format(todaysDate.getTime()); - todaysDate.add(Calendar.MONTH, 1); - todaysDate.add(Calendar.DAY_OF_MONTH, 1); - final String CLOSED_ON_DATE = dateFormat.format(todaysDate.getTime()); + todaysDate = Utils.getLocalDateOfTenant(); + todaysDate = todaysDate.minusMonths(1); + todaysDate = todaysDate.minusDays(1); + final String SUBMITTED_ON_DATE = dateFormat.format(todaysDate); + final String APPROVED_ON_DATE = dateFormat.format(todaysDate); + final String ACTIVATION_DATE = dateFormat.format(todaysDate); + + todaysDate = Utils.getLocalDateOfTenant(); + final String CLOSED_ON_DATE = dateFormat.format(todaysDate); Integer clientId = ClientHelper.createClient(this.requestSpec, this.responseSpec); Assertions.assertNotNull(clientId); @@ -1345,18 +1338,13 @@ public class FixedDepositTest { log.info("per day = {}", perDay); double interestPerDay = interestRateInFraction * perDay; - todaysDate.add(Calendar.MONTH, -1); - todaysDate.add(Calendar.DAY_OF_MONTH, -1); - Integer currentDate = Integer.valueOf(currentDateFormat.format(todaysDate.getTime())); - Integer daysInMonth = todaysDate.getActualMaximum(Calendar.DATE); - daysInMonth = daysInMonth - currentDate + 1; - Float interestPerMonth = (float) (interestPerDay * principal * daysInMonth); + todaysDate = todaysDate.minusMonths(1); + todaysDate = todaysDate.minusDays(1); + + Float interestPerMonth = (float) (interestPerDay * principal * ChronoUnit.DAYS.between(todaysDate, Utils.getLocalDateOfTenant())); principal += interestPerMonth; - todaysDate.add(Calendar.DATE, daysInMonth); - log.info("{}", monthDayFormat.format(todaysDate.getTime())); - interestPerMonth = (float) (interestPerDay * principal * currentDate); + log.info("{}", Utils.dateFormatter.format(todaysDate)); log.info("IPM = {}", interestPerMonth); - principal += interestPerMonth; log.info("principal = {}", principal); Integer transactionIdForPostInterest = this.fixedDepositAccountHelper.postInterestForFixedDeposit(fixedDepositAccountId);