Fix inconsistenant Date and Date time handling
This commit is contained in:
committed by
Arnold Gálovics
parent
7fb61d028e
commit
65c6b18ed1
+2
-2
@@ -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<ApiParameterError> dataValidationErrors = new ArrayList<>();
|
||||
final DataValidatorBuilder baseDataValidator = new DataValidatorBuilder(dataValidationErrors)
|
||||
|
||||
+12
@@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
+5
-1
@@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
+15
-6
@@ -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;
|
||||
|
||||
+26
-23
@@ -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<ClientChargePaidBy> 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;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
+6
-13
@@ -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) {
|
||||
|
||||
|
||||
+3
-3
@@ -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
|
||||
}
|
||||
|
||||
|
||||
+7
-7
@@ -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<FloatingRateData>, 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<FloatingRatePeriodData> ratePeriods;
|
||||
@SuppressWarnings("unused")
|
||||
private final List<EnumOptionData> interestRateFrequencyTypeOptions;
|
||||
|
||||
public FloatingRateData(Long id, String name, boolean isBaseLendingRate, boolean isActive, String createdBy, LocalDate createdOn,
|
||||
String modifiedBy, LocalDate modifiedOn, List<FloatingRatePeriodData> ratePeriods,
|
||||
public FloatingRateData(Long id, String name, boolean isBaseLendingRate, boolean isActive, String createdBy, OffsetDateTime createdOn,
|
||||
String modifiedBy, OffsetDateTime modifiedOn, List<FloatingRatePeriodData> ratePeriods,
|
||||
List<EnumOptionData> interestRateFrequencyTypeOptions) {
|
||||
this.id = id;
|
||||
this.name = name;
|
||||
@@ -75,7 +75,7 @@ public class FloatingRateData implements Comparable<FloatingRateData>, Serializa
|
||||
return this.createdBy;
|
||||
}
|
||||
|
||||
public LocalDate getCreatedOn() {
|
||||
public OffsetDateTime getCreatedOn() {
|
||||
return this.createdOn;
|
||||
}
|
||||
|
||||
@@ -83,7 +83,7 @@ public class FloatingRateData implements Comparable<FloatingRateData>, Serializa
|
||||
return this.modifiedBy;
|
||||
}
|
||||
|
||||
public LocalDate getModifiedOn() {
|
||||
public OffsetDateTime getModifiedOn() {
|
||||
return this.modifiedOn;
|
||||
}
|
||||
|
||||
|
||||
+15
-6
@@ -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<FloatingRatePeriodData
|
||||
private boolean isDifferentialToBaseLendingRate;
|
||||
private boolean isActive;
|
||||
private String createdBy;
|
||||
private LocalDateTime createdOn;
|
||||
private OffsetDateTime createdOn;
|
||||
private String modifiedBy;
|
||||
private LocalDateTime modifiedOn;
|
||||
private OffsetDateTime modifiedOn;
|
||||
|
||||
public FloatingRatePeriodData(Long id, LocalDate fromDate, BigDecimal interestRate, boolean isDifferentialToBaseLendingRate,
|
||||
boolean isActive, String createdBy, LocalDateTime createdOn, String modifiedBy, LocalDateTime modifiedOn) {
|
||||
boolean isActive, String createdBy, OffsetDateTime createdOn, String modifiedBy, OffsetDateTime modifiedOn) {
|
||||
this.id = id;
|
||||
this.fromDate = fromDate;
|
||||
this.interestRate = interestRate;
|
||||
@@ -51,6 +51,15 @@ public class FloatingRatePeriodData implements Comparable<FloatingRatePeriodData
|
||||
this.modifiedOn = modifiedOn;
|
||||
}
|
||||
|
||||
public FloatingRatePeriodData(Long id, LocalDate fromDate, BigDecimal interestRate, boolean isDifferentialToBaseLendingRate,
|
||||
boolean isActive) {
|
||||
this.id = id;
|
||||
this.fromDate = fromDate;
|
||||
this.interestRate = interestRate;
|
||||
this.isDifferentialToBaseLendingRate = isDifferentialToBaseLendingRate;
|
||||
this.isActive = isActive;
|
||||
}
|
||||
|
||||
public Long getId() {
|
||||
return this.id;
|
||||
}
|
||||
@@ -79,7 +88,7 @@ public class FloatingRatePeriodData implements Comparable<FloatingRatePeriodData
|
||||
return this.createdBy;
|
||||
}
|
||||
|
||||
public LocalDateTime getCreatedOn() {
|
||||
public OffsetDateTime getCreatedOn() {
|
||||
return this.createdOn;
|
||||
}
|
||||
|
||||
@@ -87,7 +96,7 @@ public class FloatingRatePeriodData implements Comparable<FloatingRatePeriodData
|
||||
return this.modifiedBy;
|
||||
}
|
||||
|
||||
public LocalDateTime getModifiedOn() {
|
||||
public OffsetDateTime getModifiedOn() {
|
||||
return this.modifiedOn;
|
||||
}
|
||||
|
||||
|
||||
+19
-56
@@ -23,7 +23,6 @@ import com.google.gson.JsonElement;
|
||||
import com.google.gson.JsonObject;
|
||||
import java.math.BigDecimal;
|
||||
import java.time.LocalDate;
|
||||
import java.time.LocalDateTime;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.HashSet;
|
||||
@@ -34,24 +33,20 @@ import javax.persistence.CascadeType;
|
||||
import javax.persistence.Column;
|
||||
import javax.persistence.Entity;
|
||||
import javax.persistence.FetchType;
|
||||
import javax.persistence.JoinColumn;
|
||||
import javax.persistence.ManyToOne;
|
||||
import javax.persistence.OneToMany;
|
||||
import javax.persistence.OrderBy;
|
||||
import javax.persistence.Table;
|
||||
import javax.persistence.UniqueConstraint;
|
||||
import org.apache.fineract.infrastructure.core.api.JsonCommand;
|
||||
import org.apache.fineract.infrastructure.core.domain.AbstractPersistableCustom;
|
||||
import org.apache.fineract.infrastructure.core.domain.AbstractAuditableWithUTCDateTimeCustom;
|
||||
import org.apache.fineract.infrastructure.core.serialization.JsonParserHelper;
|
||||
import org.apache.fineract.infrastructure.core.service.DateUtils;
|
||||
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", uniqueConstraints = { @UniqueConstraint(columnNames = { "name" }, name = "unq_name") })
|
||||
public class FloatingRate extends AbstractPersistableCustom {
|
||||
public class FloatingRate extends AbstractAuditableWithUTCDateTimeCustom {
|
||||
|
||||
@Column(name = "name", length = 200, unique = true, nullable = false)
|
||||
private String name;
|
||||
@@ -66,34 +61,23 @@ public class FloatingRate extends AbstractPersistableCustom {
|
||||
@OneToMany(cascade = CascadeType.ALL, mappedBy = "floatingRate", orphanRemoval = true, fetch = FetchType.EAGER)
|
||||
private List<FloatingRatePeriod> 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<FloatingRatePeriod> floatingRatePeriods,
|
||||
AppUser createdBy, AppUser modifiedBy, LocalDateTime createdOn, LocalDateTime modifiedOn) {
|
||||
public FloatingRate(String name, boolean isBaseLendingRate, boolean isActive, List<FloatingRatePeriod> 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<FloatingRatePeriod> floatingRatePeriods = getRatePeriods(currentUser, command);
|
||||
final LocalDateTime currentDate = DateUtils.getLocalDateTimeOfSystem();
|
||||
final List<FloatingRatePeriod> floatingRatePeriods = getRatePeriods(command);
|
||||
|
||||
return new FloatingRate(name, isBaseLendingRate, isActive, floatingRatePeriods, currentUser, currentUser, currentDate, currentDate);
|
||||
return new FloatingRate(name, isBaseLendingRate, isActive, floatingRatePeriods);
|
||||
}
|
||||
|
||||
private static List<FloatingRatePeriod> getRatePeriods(final AppUser currentUser, final JsonCommand command) {
|
||||
private static List<FloatingRatePeriod> 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<String, Object> update(final JsonCommand command, final AppUser appUser) {
|
||||
public Map<String, Object> update(final JsonCommand command) {
|
||||
|
||||
final Map<String, Object> actualChanges = new LinkedHashMap<>(9);
|
||||
|
||||
@@ -191,24 +156,22 @@ public class FloatingRate extends AbstractPersistableCustom {
|
||||
this.isActive = newValue;
|
||||
}
|
||||
|
||||
final List<FloatingRatePeriod> newRatePeriods = getRatePeriods(appUser, command);
|
||||
final List<FloatingRatePeriod> 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<FloatingRatePeriod> newRatePeriods, final AppUser appUser) {
|
||||
private void updateRatePeriods(final List<FloatingRatePeriod> 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());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+14
-59
@@ -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());
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
+4
-10
@@ -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<String, Object> changes = floatingRateForUpdate.update(command, currentUser);
|
||||
final Map<String, Object> changes = floatingRateForUpdate.update(command);
|
||||
|
||||
if (!changes.isEmpty()) {
|
||||
this.floatingRateRepository.save(floatingRateForUpdate);
|
||||
|
||||
+23
-7
@@ -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<FloatingRatePeriodData> 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);
|
||||
}
|
||||
|
||||
+6
-6
@@ -45,15 +45,15 @@ public class AddAccrualEntriesTasklet implements Tasklet {
|
||||
|
||||
@Override
|
||||
public RepeatStatus execute(StepContribution contribution, ChunkContext chunkContext) throws Exception {
|
||||
Collection<LoanScheduleAccrualData> loanScheduleAccrualDatas = loanReadPlatformService.retriveScheduleAccrualData();
|
||||
Collection<LoanScheduleAccrualData> loanScheduleAccrualDataList = loanReadPlatformService.retriveScheduleAccrualData();
|
||||
Map<Long, Collection<LoanScheduleAccrualData>> 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<LoanScheduleAccrualData> accrualDatas = new ArrayList<>();
|
||||
accrualDatas.add(accrualData);
|
||||
loanDataMap.put(accrualData.getLoanId(), accrualDatas);
|
||||
Collection<LoanScheduleAccrualData> 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);
|
||||
}
|
||||
}
|
||||
|
||||
+10
-10
@@ -39,31 +39,31 @@ public class LoanAccrualPlatformServiceImpl implements LoanAccrualPlatformServic
|
||||
private final LoanAccrualWritePlatformService loanAccrualWritePlatformService;
|
||||
|
||||
@Override
|
||||
public void addPeriodicAccruals(final LocalDate tilldate) throws JobExecutionException {
|
||||
Collection<LoanScheduleAccrualData> loanScheduleAccrualDatas = this.loanReadPlatformService.retrivePeriodicAccrualData(tilldate);
|
||||
addPeriodicAccruals(tilldate, loanScheduleAccrualDatas);
|
||||
public void addPeriodicAccruals(final LocalDate tillDate) throws JobExecutionException {
|
||||
Collection<LoanScheduleAccrualData> loanScheduleAccrualDataList = this.loanReadPlatformService.retrivePeriodicAccrualData(tillDate);
|
||||
addPeriodicAccruals(tillDate, loanScheduleAccrualDataList);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void addPeriodicAccruals(final LocalDate tilldate, Collection<LoanScheduleAccrualData> loanScheduleAccrualDatas)
|
||||
public void addPeriodicAccruals(final LocalDate tillDate, Collection<LoanScheduleAccrualData> loanScheduleAccrualDataList)
|
||||
throws JobExecutionException {
|
||||
Map<Long, Collection<LoanScheduleAccrualData>> 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<LoanScheduleAccrualData> accrualDatas = new ArrayList<>();
|
||||
accrualDatas.add(accrualData);
|
||||
loanDataMap.put(accrualData.getLoanId(), accrualDatas);
|
||||
Collection<LoanScheduleAccrualData> accrualDataList = new ArrayList<>();
|
||||
accrualDataList.add(accrualData);
|
||||
loanDataMap.put(accrualData.getLoanId(), accrualDataList);
|
||||
}
|
||||
}
|
||||
|
||||
List<Throwable> errors = new ArrayList<>();
|
||||
for (Map.Entry<Long, Collection<LoanScheduleAccrualData>> 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);
|
||||
}
|
||||
}
|
||||
|
||||
+106
-105
@@ -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<LoanScheduleAccrualData> loanScheduleAccrualDatas)
|
||||
throws Exception {
|
||||
public void addAccrualAccounting(final Long loanId, final Collection<LoanScheduleAccrualData> loanScheduleAccrualData) {
|
||||
Collection<LoanChargeData> chargeData = this.loanChargeReadPlatformService.retrieveLoanChargesForAccural(loanId);
|
||||
Collection<LoanSchedulePeriodData> loanWaiverScheduleData = new ArrayList<>(1);
|
||||
Collection<LoanTransactionData> loanWaiverTansactionData = new ArrayList<>(1);
|
||||
Collection<LoanTransactionData> 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<LoanScheduleAccrualData> loanScheduleAccrualDatas)
|
||||
throws Exception {
|
||||
public void addPeriodicAccruals(final LocalDate tillDate, Long loanId, Collection<LoanScheduleAccrualData> loanScheduleAccrualData) {
|
||||
boolean firstTime = true;
|
||||
LocalDate accruredTill = null;
|
||||
LocalDate accruedTill = null;
|
||||
Collection<LoanChargeData> chargeData = this.loanChargeReadPlatformService.retrieveLoanChargesForAccural(loanId);
|
||||
Collection<LoanSchedulePeriodData> loanWaiverScheduleData = new ArrayList<>(1);
|
||||
Collection<LoanTransactionData> loanWaiverTansactionData = new ArrayList<>(1);
|
||||
for (final LoanScheduleAccrualData accrualData : loanScheduleAccrualDatas) {
|
||||
Collection<LoanTransactionData> 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<LoanChargeData, BigDecimal> 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<LoanChargeData, BigDecimal> 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<String, Object> transactionMap = toMapData(transactonId, amount, interestportion, feeportion, penaltyportion,
|
||||
Map<String, Object> 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<String, Object> accountingBridgeData = deriveAccountingBridgeData(scheduleAccrualData, transactionMap);
|
||||
this.journalEntryWritePlatformService.createJournalEntriesForLoan(accountingBridgeData);
|
||||
}
|
||||
@@ -301,9 +302,9 @@ public class LoanAccrualWritePlatformServiceImpl implements LoanAccrualWritePlat
|
||||
return accountingBridgeData;
|
||||
}
|
||||
|
||||
public Map<String, Object> toMapData(final Long id, final BigDecimal amount, final BigDecimal interestportion,
|
||||
final BigDecimal feeportion, final BigDecimal penaltyportion, final LoanScheduleAccrualData loanScheduleAccrualData,
|
||||
final LocalDate accruredTill) {
|
||||
public Map<String, Object> toMapData(final Long id, final BigDecimal amount, final BigDecimal interestPortion,
|
||||
final BigDecimal feePortion, final BigDecimal penaltyPortion, final LoanScheduleAccrualData loanScheduleAccrualData,
|
||||
final LocalDate accruedTill) {
|
||||
final Map<String, Object> 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<LoanChargeData, BigDecimal> applicableCharges = loanScheduleAccrualData.getApplicableCharges();
|
||||
@@ -411,8 +412,8 @@ public class LoanAccrualWritePlatformServiceImpl implements LoanAccrualWritePlat
|
||||
}
|
||||
|
||||
private void updateInterestIncome(final LoanScheduleAccrualData accrualData,
|
||||
final Collection<LoanTransactionData> loanWaiverTansactions, final Collection<LoanSchedulePeriodData> loanSchedulePeriodDatas,
|
||||
final LocalDate tilldate) {
|
||||
final Collection<LoanTransactionData> loanWaiverTransactions,
|
||||
final Collection<LoanSchedulePeriodData> 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<LoanTransactionData> 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<LoanTransactionData> 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());
|
||||
|
||||
@@ -42,4 +42,6 @@
|
||||
<include file="parts/0020_add_audit_entries.xml" relativeToChangelogFile="true"/>
|
||||
<include file="parts/0021_add_spring_batch_db_structure.xml" relativeToChangelogFile="true"/>
|
||||
<include file="parts/0022_add_batch_business_step_configuration_table.xml" relativeToChangelogFile="true"/>
|
||||
<include file="parts/0023_use_the_proper_date_or_datetime_type.xml" relativeToChangelogFile="true"/>
|
||||
<include file="parts/0024_add_audit_entries.xml" relativeToChangelogFile="true"/>
|
||||
</databaseChangeLog>
|
||||
|
||||
+41
@@ -0,0 +1,41 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!--
|
||||
|
||||
Licensed to the Apache Software Foundation (ASF) under one
|
||||
or more contributor license agreements. See the NOTICE file
|
||||
distributed with this work for additional information
|
||||
regarding copyright ownership. The ASF licenses this file
|
||||
to you under the Apache License, Version 2.0 (the
|
||||
"License"); you may not use this file except in compliance
|
||||
with the License. You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing,
|
||||
software distributed under the License is distributed on an
|
||||
"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
KIND, either express or implied. See the License for the
|
||||
specific language governing permissions and limitations
|
||||
under the License.
|
||||
|
||||
-->
|
||||
<databaseChangeLog xmlns="http://www.liquibase.org/xml/ns/dbchangelog"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://www.liquibase.org/xml/ns/dbchangelog http://www.liquibase.org/xml/ns/dbchangelog/dbchangelog-4.1.xsd">
|
||||
|
||||
<changeSet author="fineract" id="1">
|
||||
<modifyDataType tableName="m_client_non_person" columnName="incorp_validity_till" newDataType="date"/>
|
||||
<modifyDataType tableName="m_floating_rates_periods" columnName="from_date" newDataType="date"/>
|
||||
<modifyDataType tableName="m_holiday" columnName="from_date" newDataType="date"/>
|
||||
<modifyDataType tableName="m_holiday" columnName="to_date" newDataType="date"/>
|
||||
<modifyDataType tableName="m_holiday" columnName="repayments_rescheduled_to" newDataType="date"/>
|
||||
<modifyDataType tableName="m_loan_disbursement_detail" columnName="expected_disburse_date" newDataType="date"/>
|
||||
<modifyDataType tableName="m_loan_disbursement_detail" columnName="disbursedon_date" newDataType="date"/>
|
||||
<modifyDataType tableName="m_share_product" columnName="start_date" newDataType="date"/>
|
||||
<modifyDataType tableName="m_share_product" columnName="end_date" newDataType="date"/>
|
||||
<modifyDataType tableName="m_surveys" columnName="valid_from" newDataType="date"/>
|
||||
<modifyDataType tableName="m_surveys" columnName="valid_to" newDataType="date"/>
|
||||
</changeSet>
|
||||
|
||||
|
||||
</databaseChangeLog>
|
||||
+241
@@ -0,0 +1,241 @@
|
||||
<?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.1.xsd">
|
||||
<!--Client-->
|
||||
<changeSet id="client-4" author="fineract" context="mysql">
|
||||
<preConditions onFail="MARK_RAN">
|
||||
<sqlCheck expectedResult="0">select count(*) from m_client</sqlCheck>
|
||||
</preConditions>
|
||||
<addNotNullConstraint tableName="m_client" columnName="created_on_utc" columnDataType="DATETIME"/>
|
||||
<addNotNullConstraint tableName="m_client" columnName="created_by" columnDataType="BIGINT"/>
|
||||
<addNotNullConstraint tableName="m_client" columnName="last_modified_on_utc" columnDataType="DATETIME"/>
|
||||
<addNotNullConstraint tableName="m_client" columnName="last_modified_by" columnDataType="BIGINT"/>
|
||||
</changeSet>
|
||||
<changeSet id="client-4" author="fineract" context="postgresql">
|
||||
<preConditions onFail="MARK_RAN">
|
||||
<sqlCheck expectedResult="0">select count(*) from m_client</sqlCheck>
|
||||
</preConditions>
|
||||
<addNotNullConstraint tableName="m_client" columnName="created_on_utc" columnDataType="TIMESTAMP WITH TIME ZONE"/>
|
||||
<addNotNullConstraint tableName="m_client" columnName="created_by" columnDataType="BIGINT"/>
|
||||
<addNotNullConstraint tableName="m_client" columnName="last_modified_on_utc" columnDataType="TIMESTAMP WITH TIME ZONE"/>
|
||||
<addNotNullConstraint tableName="m_client" columnName="last_modified_by" columnDataType="BIGINT"/>
|
||||
</changeSet>
|
||||
<!--Loan-->
|
||||
<changeSet id="loan-7" author="fineract" context="mysql">
|
||||
<preConditions onFail="MARK_RAN">
|
||||
<sqlCheck expectedResult="0">select count(*) from m_loan</sqlCheck>
|
||||
</preConditions>
|
||||
<addNotNullConstraint tableName="m_loan" columnName="created_on_utc" columnDataType="DATETIME"/>
|
||||
<addNotNullConstraint tableName="m_loan" columnName="created_by" columnDataType="BIGINT"/>
|
||||
<addNotNullConstraint tableName="m_loan" columnName="last_modified_on_utc" columnDataType="DATETIME"/>
|
||||
<addNotNullConstraint tableName="m_loan" columnName="last_modified_by" columnDataType="BIGINT"/>
|
||||
</changeSet>
|
||||
<changeSet id="loan-7" author="fineract" context="postgresql">
|
||||
<preConditions onFail="MARK_RAN">
|
||||
<sqlCheck expectedResult="0">select count(*) from m_loan</sqlCheck>
|
||||
</preConditions>
|
||||
<addNotNullConstraint tableName="m_loan" columnName="created_on_utc" columnDataType="TIMESTAMP WITH TIME ZONE"/>
|
||||
<addNotNullConstraint tableName="m_loan" columnName="created_by" columnDataType="BIGINT"/>
|
||||
<addNotNullConstraint tableName="m_loan" columnName="last_modified_on_utc" columnDataType="TIMESTAMP WITH TIME ZONE"/>
|
||||
<addNotNullConstraint tableName="m_loan" columnName="last_modified_by" columnDataType="BIGINT"/>
|
||||
</changeSet>
|
||||
<!-- Loan transactions -->
|
||||
<changeSet id="loan-transaction-13" author="fineract" context="mysql">
|
||||
<preConditions onFail="MARK_RAN">
|
||||
<sqlCheck expectedResult="0">select count(*) from m_loan_transaction</sqlCheck>
|
||||
</preConditions>
|
||||
<addNotNullConstraint tableName="m_loan_transaction" columnName="created_on_utc" columnDataType="DATETIME"/>
|
||||
<addNotNullConstraint tableName="m_loan_transaction" columnName="created_by" columnDataType="BIGINT"/>
|
||||
<addNotNullConstraint tableName="m_loan_transaction" columnName="last_modified_on_utc" columnDataType="DATETIME"/>
|
||||
<addNotNullConstraint tableName="m_loan_transaction" columnName="last_modified_by" columnDataType="BIGINT"/>
|
||||
</changeSet>
|
||||
<changeSet id="loan-transaction-13" author="fineract" context="postgresql">
|
||||
<preConditions onFail="MARK_RAN">
|
||||
<sqlCheck expectedResult="0">select count(*) from m_loan_transaction</sqlCheck>
|
||||
</preConditions>
|
||||
<addNotNullConstraint tableName="m_loan_transaction" columnName="created_on_utc" columnDataType="TIMESTAMP WITH TIME ZONE"/>
|
||||
<addNotNullConstraint tableName="m_loan_transaction" columnName="created_by" columnDataType="BIGINT"/>
|
||||
<addNotNullConstraint tableName="m_loan_transaction" columnName="last_modified_on_utc" columnDataType="TIMESTAMP WITH TIME ZONE"/>
|
||||
<addNotNullConstraint tableName="m_loan_transaction" columnName="last_modified_by" columnDataType="BIGINT"/>
|
||||
</changeSet>
|
||||
<!-- Client transaction -->
|
||||
<changeSet author="fineract" id="client-transaction-1" context="mysql">
|
||||
<addColumn tableName="m_client_transaction">
|
||||
<column name="created_on_utc" type="DATETIME"/>
|
||||
<column name="created_by" type="BIGINT" valueComputed="appuser_id"/>
|
||||
<column name="last_modified_by" type="BIGINT"/>
|
||||
<column name="last_modified_on_utc" type="DATETIME"/>
|
||||
</addColumn>
|
||||
</changeSet>
|
||||
<changeSet author="fineract" id="client-transaction-1" context="postgresql">
|
||||
<addColumn tableName="m_client_transaction">
|
||||
<column name="created_on_utc" type="TIMESTAMP WITH TIME ZONE"/>
|
||||
<column name="created_by" type="BIGINT" valueComputed="appuser_id"/>
|
||||
<column name="last_modified_by" type="BIGINT"/>
|
||||
<column name="last_modified_on_utc" type="TIMESTAMP WITH TIME ZONE"/>
|
||||
</addColumn>
|
||||
</changeSet>
|
||||
<changeSet id="client-transaction-2" author="fineract">
|
||||
<addColumn tableName="m_client_transaction">
|
||||
<column name="submitted_on_date" type="DATE" valueComputed="created_date">
|
||||
<constraints nullable="false"/>
|
||||
</column>
|
||||
</addColumn>
|
||||
</changeSet>
|
||||
<changeSet author="fineract" id="client-transaction-3">
|
||||
<addForeignKeyConstraint baseColumnNames="created_by" baseTableName="m_client_transaction"
|
||||
constraintName="FK_client_transaction_created_by" deferrable="false" initiallyDeferred="false"
|
||||
onDelete="RESTRICT" onUpdate="RESTRICT" referencedColumnNames="id"
|
||||
referencedTableName="m_appuser" validate="true"/>
|
||||
<addForeignKeyConstraint baseColumnNames="last_modified_by" baseTableName="m_client_transaction"
|
||||
constraintName="FK_client_transaction_last_modified_by" deferrable="false" initiallyDeferred="false"
|
||||
onDelete="RESTRICT" onUpdate="RESTRICT" referencedColumnNames="id"
|
||||
referencedTableName="m_appuser" validate="true"/>
|
||||
</changeSet>
|
||||
<changeSet id="client-transaction-4" author="fineract">
|
||||
<dropForeignKeyConstraint baseTableName="m_client_transaction" constraintName="FK_m_client_transaction_m_appuser"/>
|
||||
<dropColumn tableName="m_client_transaction">
|
||||
<column name="appuser_id"/>
|
||||
</dropColumn>
|
||||
</changeSet>
|
||||
<changeSet id="client-transaction-5" author="fineract" context="mysql">
|
||||
<preConditions onFail="MARK_RAN">
|
||||
<sqlCheck expectedResult="0">select count(*) from m_client_transaction</sqlCheck>
|
||||
</preConditions>
|
||||
<addNotNullConstraint tableName="m_client_transaction" columnName="created_on_utc" columnDataType="DATETIME"/>
|
||||
<addNotNullConstraint tableName="m_client_transaction" columnName="created_by" columnDataType="BIGINT"/>
|
||||
<addNotNullConstraint tableName="m_client_transaction" columnName="last_modified_on_utc" columnDataType="DATETIME"/>
|
||||
<addNotNullConstraint tableName="m_client_transaction" columnName="last_modified_by" columnDataType="BIGINT"/>
|
||||
</changeSet>
|
||||
<changeSet id="client-transaction-5" author="fineract" context="postgresql">
|
||||
<preConditions onFail="MARK_RAN">
|
||||
<sqlCheck expectedResult="0">select count(*) from m_client_transaction</sqlCheck>
|
||||
</preConditions>
|
||||
<addNotNullConstraint tableName="m_client_transaction" columnName="created_on_utc" columnDataType="TIMESTAMP WITH TIME ZONE"/>
|
||||
<addNotNullConstraint tableName="m_client_transaction" columnName="created_by" columnDataType="BIGINT"/>
|
||||
<addNotNullConstraint tableName="m_client_transaction" columnName="last_modified_on_utc" columnDataType="TIMESTAMP WITH TIME ZONE"/>
|
||||
<addNotNullConstraint tableName="m_client_transaction" columnName="last_modified_by" columnDataType="BIGINT"/>
|
||||
</changeSet>
|
||||
<changeSet id="client-transaction-6" author="fineract">
|
||||
<dropNotNullConstraint tableName="m_client_transaction" columnName="created_date" columnDataType="datetime"/>
|
||||
</changeSet>
|
||||
<!-- Floating rate -->
|
||||
<changeSet author="fineract" id="floating-rate-1" context="mysql">
|
||||
<addColumn tableName="m_floating_rates">
|
||||
<column name="created_on_utc" type="DATETIME"/>
|
||||
<column name="last_modified_on_utc" type="DATETIME"/>
|
||||
</addColumn>
|
||||
</changeSet>
|
||||
<changeSet author="fineract" id="floating-rate-1" context="postgresql">
|
||||
<addColumn tableName="m_floating_rates">
|
||||
<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="floating-rate-2" author="fineract">
|
||||
<renameColumn tableName="m_floating_rates" oldColumnName="createdby_id" newColumnName="created_by" columnDataType="BIGINT"/>
|
||||
<renameColumn tableName="m_floating_rates" oldColumnName="lastmodifiedby_id" newColumnName="last_modified_by" columnDataType="BIGINT"/>
|
||||
</changeSet>
|
||||
<changeSet author="fineract" id="floating-rate-3">
|
||||
<addForeignKeyConstraint baseColumnNames="created_by" baseTableName="m_floating_rates"
|
||||
constraintName="FK_floating_rates_created_by" deferrable="false" initiallyDeferred="false"
|
||||
onDelete="RESTRICT" onUpdate="RESTRICT" referencedColumnNames="id"
|
||||
referencedTableName="m_appuser" validate="true"/>
|
||||
<addForeignKeyConstraint baseColumnNames="last_modified_by" baseTableName="m_floating_rates"
|
||||
constraintName="FK_floating_rates_last_modified_by" deferrable="false" initiallyDeferred="false"
|
||||
onDelete="RESTRICT" onUpdate="RESTRICT" referencedColumnNames="id"
|
||||
referencedTableName="m_appuser" validate="true"/>
|
||||
</changeSet>
|
||||
<changeSet id="floating-rate-4" author="fineract" context="mysql">
|
||||
<preConditions onFail="MARK_RAN">
|
||||
<sqlCheck expectedResult="0">select count(*) from m_floating_rates</sqlCheck>
|
||||
</preConditions>
|
||||
<addNotNullConstraint tableName="m_floating_rates" columnName="created_on_utc" columnDataType="DATETIME"/>
|
||||
<addNotNullConstraint tableName="m_floating_rates" columnName="created_by" columnDataType="BIGINT"/>
|
||||
<addNotNullConstraint tableName="m_floating_rates" columnName="last_modified_on_utc" columnDataType="DATETIME"/>
|
||||
<addNotNullConstraint tableName="m_floating_rates" columnName="last_modified_by" columnDataType="BIGINT"/>
|
||||
</changeSet>
|
||||
<changeSet id="floating-rate-4" author="fineract" context="postgresql">
|
||||
<preConditions onFail="MARK_RAN">
|
||||
<sqlCheck expectedResult="0">select count(*) from m_client_transaction</sqlCheck>
|
||||
</preConditions>
|
||||
<addNotNullConstraint tableName="m_floating_rates" columnName="created_on_utc" columnDataType="TIMESTAMP WITH TIME ZONE"/>
|
||||
<addNotNullConstraint tableName="m_floating_rates" columnName="created_by" columnDataType="BIGINT"/>
|
||||
<addNotNullConstraint tableName="m_floating_rates" columnName="last_modified_on_utc" columnDataType="TIMESTAMP WITH TIME ZONE"/>
|
||||
<addNotNullConstraint tableName="m_floating_rates" columnName="last_modified_by" columnDataType="BIGINT"/>
|
||||
</changeSet>
|
||||
<changeSet id="floating-rate-5" author="fineract">
|
||||
<dropNotNullConstraint tableName="m_floating_rates" columnName="created_date" columnDataType="datetime"/>
|
||||
<dropNotNullConstraint tableName="m_floating_rates" columnName="lastmodified_date" columnDataType="datetime"/>
|
||||
</changeSet>
|
||||
<!-- Floating rates period -->
|
||||
<changeSet author="fineract" id="floating-rate-period-1" context="mysql">
|
||||
<addColumn tableName="m_floating_rates_periods">
|
||||
<column name="created_on_utc" type="DATETIME"/>
|
||||
<column name="last_modified_on_utc" type="DATETIME"/>
|
||||
</addColumn>
|
||||
</changeSet>
|
||||
<changeSet author="fineract" id="floating-rate-period-1" context="postgresql">
|
||||
<addColumn tableName="m_floating_rates_periods">
|
||||
<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="floating-rate-period-2" author="fineract">
|
||||
<renameColumn tableName="m_floating_rates_periods" oldColumnName="createdby_id" newColumnName="created_by" columnDataType="BIGINT"/>
|
||||
<renameColumn tableName="m_floating_rates_periods" oldColumnName="lastmodifiedby_id" newColumnName="last_modified_by" columnDataType="BIGINT"/>
|
||||
</changeSet>
|
||||
<changeSet author="fineract" id="floating-rate-period-3">
|
||||
<addForeignKeyConstraint baseColumnNames="created_by" baseTableName="m_floating_rates_periods"
|
||||
constraintName="FK_floating_rates_period_created_by" deferrable="false" initiallyDeferred="false"
|
||||
onDelete="RESTRICT" onUpdate="RESTRICT" referencedColumnNames="id"
|
||||
referencedTableName="m_appuser" validate="true"/>
|
||||
<addForeignKeyConstraint baseColumnNames="last_modified_by" baseTableName="m_floating_rates_periods"
|
||||
constraintName="FK_floating_rates_period_last_modified_by" deferrable="false" initiallyDeferred="false"
|
||||
onDelete="RESTRICT" onUpdate="RESTRICT" referencedColumnNames="id"
|
||||
referencedTableName="m_appuser" validate="true"/>
|
||||
</changeSet>
|
||||
<changeSet id="floating-rate-period-4" author="fineract" context="mysql">
|
||||
<preConditions onFail="MARK_RAN">
|
||||
<sqlCheck expectedResult="0">select count(*) from m_floating_rates_periods</sqlCheck>
|
||||
</preConditions>
|
||||
<addNotNullConstraint tableName="m_floating_rates_periods" columnName="created_on_utc" columnDataType="DATETIME"/>
|
||||
<addNotNullConstraint tableName="m_floating_rates_periods" columnName="created_by" columnDataType="BIGINT"/>
|
||||
<addNotNullConstraint tableName="m_floating_rates_periods" columnName="last_modified_on_utc" columnDataType="DATETIME"/>
|
||||
<addNotNullConstraint tableName="m_floating_rates_periods" columnName="last_modified_by" columnDataType="BIGINT"/>
|
||||
</changeSet>
|
||||
<changeSet id="floating-rate-period-4" author="fineract" context="postgresql">
|
||||
<preConditions onFail="MARK_RAN">
|
||||
<sqlCheck expectedResult="0">select count(*) from m_floating_rates_periods</sqlCheck>
|
||||
</preConditions>
|
||||
<addNotNullConstraint tableName="m_floating_rates_periods" columnName="created_on_utc" columnDataType="TIMESTAMP WITH TIME ZONE"/>
|
||||
<addNotNullConstraint tableName="m_floating_rates_periods" columnName="created_by" columnDataType="BIGINT"/>
|
||||
<addNotNullConstraint tableName="m_floating_rates_periods" columnName="last_modified_on_utc" columnDataType="TIMESTAMP WITH TIME ZONE"/>
|
||||
<addNotNullConstraint tableName="m_floating_rates_periods" columnName="last_modified_by" columnDataType="BIGINT"/>
|
||||
</changeSet>
|
||||
<changeSet id="floating-rate-period-5" author="fineract">
|
||||
<dropNotNullConstraint tableName="m_floating_rates_periods" columnName="created_date" columnDataType="datetime"/>
|
||||
<dropNotNullConstraint tableName="m_floating_rates_periods" columnName="lastmodified_date" columnDataType="datetime"/>
|
||||
</changeSet>
|
||||
</databaseChangeLog>
|
||||
+38
-50
@@ -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);
|
||||
|
||||
Reference in New Issue
Block a user