FINERACT-2312: Accruals added for savings accounts (#4885)
This commit is contained in:
+45
@@ -0,0 +1,45 @@
|
||||
/**
|
||||
* Licensed to the Apache Software Foundation (ASF) under one
|
||||
* or more contributor license agreements. See the NOTICE file
|
||||
* distributed with this work for additional information
|
||||
* regarding copyright ownership. The ASF licenses this file
|
||||
* to you under the Apache License, Version 2.0 (the
|
||||
* "License"); you may not use this file except in compliance
|
||||
* with the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing,
|
||||
* software distributed under the License is distributed on an
|
||||
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
* KIND, either express or implied. See the License for the
|
||||
* specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*/
|
||||
package org.apache.fineract.portfolio.savings.data;
|
||||
|
||||
import java.time.LocalDate;
|
||||
import lombok.Data;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import org.apache.fineract.infrastructure.core.data.EnumOptionData;
|
||||
import org.apache.fineract.portfolio.savings.DepositAccountType;
|
||||
import org.apache.fineract.portfolio.savings.service.SavingsEnumerations;
|
||||
|
||||
@Data
|
||||
@RequiredArgsConstructor
|
||||
public class SavingsAccrualData {
|
||||
|
||||
private final Long id;
|
||||
private final String accountNo;
|
||||
private final LocalDate accruedTill;
|
||||
private final Boolean isTypeInterestReceivable;
|
||||
private final Boolean isAllowOverdraft;
|
||||
private final Integer depositType;
|
||||
|
||||
public DepositAccountType getDepositType() {
|
||||
final EnumOptionData depositType = SavingsEnumerations.depositType(this.depositType);
|
||||
DepositAccountType depositAccountType = DepositAccountType.fromInt(depositType.getId().intValue());
|
||||
return depositAccountType;
|
||||
}
|
||||
|
||||
}
|
||||
+24
@@ -71,6 +71,7 @@ import java.util.Locale;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import java.util.UUID;
|
||||
import java.util.stream.Collectors;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
import org.apache.fineract.infrastructure.configuration.domain.ConfigurationDomainService;
|
||||
import org.apache.fineract.infrastructure.configuration.service.TemporaryConfigurationServiceContainer;
|
||||
@@ -337,6 +338,9 @@ public class SavingsAccount extends AbstractAuditableWithUTCDateTimeCustom<Long>
|
||||
@JoinColumn(name = "tax_group_id")
|
||||
private TaxGroup taxGroup;
|
||||
|
||||
@Column(name = "accrued_till_date")
|
||||
private LocalDate accruedTillDate;
|
||||
|
||||
@Column(name = "total_savings_amount_on_hold", scale = 6, precision = 19, nullable = true)
|
||||
private BigDecimal savingsOnHoldAmount;
|
||||
@OneToMany(cascade = CascadeType.ALL, mappedBy = "account", orphanRemoval = true, fetch = FetchType.LAZY)
|
||||
@@ -926,6 +930,10 @@ public class SavingsAccount extends AbstractAuditableWithUTCDateTimeCustom<Long>
|
||||
return this.nominalAnnualInterestRateOverdraft.divide(BigDecimal.valueOf(100L), mc);
|
||||
}
|
||||
|
||||
public BigDecimal getEffectiveInterestRateAsFractionAccrual(final MathContext mc, final LocalDate upToInterestCalculationDate) {
|
||||
return this.nominalAnnualInterestRate.divide(BigDecimal.valueOf(100L), mc);
|
||||
}
|
||||
|
||||
@SuppressWarnings("unused")
|
||||
protected BigDecimal getEffectiveInterestRateAsFraction(final MathContext mc, final LocalDate upToInterestCalculationDate) {
|
||||
return this.nominalAnnualInterestRate.divide(BigDecimal.valueOf(100L), mc);
|
||||
@@ -939,6 +947,11 @@ public class SavingsAccount extends AbstractAuditableWithUTCDateTimeCustom<Long>
|
||||
return isAllowOverdraft() && !MathUtil.isEmpty(getOverdraftLimit()) && !MathUtil.isEmpty(nominalAnnualInterestRateOverdraft);
|
||||
}
|
||||
|
||||
public List<SavingsAccountTransaction> retrieveOrderedAccrualTransactions() {
|
||||
return retrieveListOfTransactions().stream().filter(SavingsAccountTransaction::isAccrual)
|
||||
.sorted(new SavingsAccountTransactionComparator()).collect(Collectors.toList());
|
||||
}
|
||||
|
||||
protected List<SavingsAccountTransaction> retreiveOrderedNonInterestPostingTransactions() {
|
||||
final List<SavingsAccountTransaction> listOfTransactionsSorted = retrieveListOfTransactions();
|
||||
|
||||
@@ -3841,10 +3854,21 @@ public class SavingsAccount extends AbstractAuditableWithUTCDateTimeCustom<Long>
|
||||
return this.withHoldTax;
|
||||
}
|
||||
|
||||
public void setAccruedTillDate(LocalDate accruedTillDate) {
|
||||
this.accruedTillDate = accruedTillDate;
|
||||
}
|
||||
|
||||
public List<SavingsAccountTransactionDetailsForPostingPeriod> toSavingsAccountTransactionDetailsForPostingPeriodList(
|
||||
List<SavingsAccountTransaction> transactions) {
|
||||
return transactions.stream()
|
||||
.map(transaction -> transaction.toSavingsAccountTransactionDetailsForPostingPeriod(this.currency, this.allowOverdraft))
|
||||
.toList();
|
||||
}
|
||||
|
||||
public List<SavingsAccountTransactionDetailsForPostingPeriod> toSavingsAccountTransactionDetailsForPostingPeriodList() {
|
||||
return retreiveOrderedNonInterestPostingTransactions().stream()
|
||||
.map(transaction -> transaction.toSavingsAccountTransactionDetailsForPostingPeriod(this.currency, this.allowOverdraft))
|
||||
.toList();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
+24
@@ -19,8 +19,10 @@
|
||||
package org.apache.fineract.portfolio.savings.domain;
|
||||
|
||||
import jakarta.persistence.LockModeType;
|
||||
import java.time.LocalDate;
|
||||
import java.util.List;
|
||||
import org.apache.fineract.infrastructure.core.domain.ExternalId;
|
||||
import org.apache.fineract.portfolio.savings.data.SavingsAccrualData;
|
||||
import org.springframework.data.domain.Page;
|
||||
import org.springframework.data.domain.Pageable;
|
||||
import org.springframework.data.jpa.repository.JpaRepository;
|
||||
@@ -70,4 +72,26 @@ public interface SavingsAccountRepository extends JpaRepository<SavingsAccount,
|
||||
|
||||
@Query("SELECT sa.id FROM SavingsAccount sa WHERE sa.externalId = :externalId")
|
||||
Long findIdByExternalId(@Param("externalId") ExternalId externalId);
|
||||
|
||||
@Query("""
|
||||
SELECT new org.apache.fineract.portfolio.savings.data.SavingsAccrualData(
|
||||
savings.id,
|
||||
savings.accountNumber,
|
||||
savings.accruedTillDate,
|
||||
CASE WHEN apm.financialAccountType = 18 THEN TRUE ELSE FALSE END,
|
||||
msp.allowOverdraft,
|
||||
savings.depositType
|
||||
)
|
||||
FROM SavingsAccount savings
|
||||
LEFT JOIN SavingsProduct msp ON msp = savings.product
|
||||
LEFT JOIN ProductToGLAccountMapping apm ON apm.productId = msp.id and (apm.financialAccountType = 18 or apm.financialAccountType IS NULL)
|
||||
WHERE savings.status = :status
|
||||
AND (savings.nominalAnnualInterestRate IS NOT NULL AND savings.nominalAnnualInterestRate > 0)
|
||||
AND msp.accountingRule = :accountingRule
|
||||
AND ( savings.closedOnDate <= :tillDate OR savings.closedOnDate IS NULL)
|
||||
AND ( savings.accruedTillDate <= :tillDate OR savings.accruedTillDate IS NULL )
|
||||
ORDER BY savings.id
|
||||
""")
|
||||
List<SavingsAccrualData> findAccrualData(@Param("tillDate") LocalDate tillDate, @Param("savingsId") Long savingsId,
|
||||
@Param("status") Integer status, @Param("accountingRule") Integer accountingRule);
|
||||
}
|
||||
|
||||
+7
@@ -22,6 +22,7 @@ import java.time.LocalDate;
|
||||
import java.util.List;
|
||||
import org.apache.fineract.infrastructure.core.domain.ExternalId;
|
||||
import org.apache.fineract.portfolio.savings.DepositAccountType;
|
||||
import org.apache.fineract.portfolio.savings.data.SavingsAccrualData;
|
||||
import org.apache.fineract.portfolio.savings.exception.SavingsAccountNotFoundException;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.data.domain.Page;
|
||||
@@ -179,4 +180,10 @@ public class SavingsAccountRepositoryWrapper {
|
||||
public Long findIdByExternalId(final ExternalId externalId) {
|
||||
return this.repository.findIdByExternalId(externalId);
|
||||
}
|
||||
|
||||
@Transactional(readOnly = true)
|
||||
public List<SavingsAccrualData> findAccrualData(final LocalDate tillDate, final Long savingsId, final Integer status,
|
||||
final Integer accountingRule) {
|
||||
return this.repository.findAccrualData(tillDate, savingsId, status, accountingRule);
|
||||
}
|
||||
}
|
||||
|
||||
+13
-1
@@ -198,6 +198,14 @@ public final class SavingsAccountTransaction extends AbstractAuditableWithUTCDat
|
||||
date, amount, isReversed, isManualTransaction, lienTransaction, refNo);
|
||||
}
|
||||
|
||||
public static SavingsAccountTransaction accrual(final SavingsAccount savingsAccount, final Office office, final LocalDate date,
|
||||
final Money amount, final boolean isManualTransaction, final String refNo) {
|
||||
final boolean isReversed = false;
|
||||
final Boolean lienTransaction = false;
|
||||
return new SavingsAccountTransaction(savingsAccount, office, SavingsAccountTransactionType.ACCRUAL.getValue(), date, amount,
|
||||
isReversed, isManualTransaction, lienTransaction, refNo);
|
||||
}
|
||||
|
||||
public static SavingsAccountTransaction interestPosting(final SavingsAccount savingsAccount, final Office office, final LocalDate date,
|
||||
final Money amount, final boolean isManualTransaction) {
|
||||
final boolean isReversed = false;
|
||||
@@ -415,7 +423,7 @@ public final class SavingsAccountTransaction extends AbstractAuditableWithUTCDat
|
||||
return Money.of(currency, this.overdraftAmount);
|
||||
}
|
||||
|
||||
void setOverdraftAmount(Money overdraftAmount) {
|
||||
public void setOverdraftAmount(Money overdraftAmount) {
|
||||
this.overdraftAmount = overdraftAmount == null ? null : overdraftAmount.getAmount();
|
||||
}
|
||||
|
||||
@@ -511,6 +519,10 @@ public final class SavingsAccountTransaction extends AbstractAuditableWithUTCDat
|
||||
return this.isDeposit() || this.isWithdrawal() || this.isChargeTransaction() || this.isDividendPayout() || this.isInterestPosting();
|
||||
}
|
||||
|
||||
public boolean isAccrual() {
|
||||
return getTransactionType().isAccrual();
|
||||
}
|
||||
|
||||
public boolean isInterestPostingAndNotReversed() {
|
||||
return getTransactionType().isInterestPosting() && isNotReversed();
|
||||
}
|
||||
|
||||
+4
@@ -27,6 +27,8 @@ import org.apache.fineract.infrastructure.core.service.SearchParameters;
|
||||
import org.apache.fineract.portfolio.savings.DepositAccountType;
|
||||
import org.apache.fineract.portfolio.savings.data.SavingsAccountData;
|
||||
import org.apache.fineract.portfolio.savings.data.SavingsAccountTransactionData;
|
||||
import org.apache.fineract.portfolio.savings.data.SavingsAccrualData;
|
||||
import org.apache.fineract.portfolio.savings.domain.SavingsAccount;
|
||||
|
||||
public interface SavingsAccountReadPlatformService {
|
||||
|
||||
@@ -69,4 +71,6 @@ public interface SavingsAccountReadPlatformService {
|
||||
List<SavingsAccountTransactionData> retrieveAllTransactionData(List<String> refNo);
|
||||
|
||||
Long retrieveAccountIdByExternalId(ExternalId externalId);
|
||||
|
||||
List<SavingsAccrualData> retrievePeriodicAccrualData(LocalDate tillDate, SavingsAccount savings);
|
||||
}
|
||||
|
||||
+3
@@ -23,4 +23,7 @@
|
||||
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">
|
||||
<!-- Sequence is starting from 2000 to make it easier to move existing liquibase changesets here -->
|
||||
<include file="parts/2001_add_savings_accrual_job.xml" relativeToChangelogFile="true" />
|
||||
<include file="parts/2002_add_savings_accrual_permission.xml" relativeToChangelogFile="true" />
|
||||
<include file="parts/2003_add_accrued_till_date_to_savings_account.xml" relativeToChangelogFile="true" />
|
||||
</databaseChangeLog>
|
||||
|
||||
+46
@@ -0,0 +1,46 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!--
|
||||
|
||||
Licensed to the Apache Software Foundation (ASF) under one
|
||||
or more contributor license agreements. See the NOTICE file
|
||||
distributed with this work for additional information
|
||||
regarding copyright ownership. The ASF licenses this file
|
||||
to you under the Apache License, Version 2.0 (the
|
||||
"License"); you may not use this file except in compliance
|
||||
with the License. You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing,
|
||||
software distributed under the License is distributed on an
|
||||
"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
KIND, either express or implied. See the License for the
|
||||
specific language governing permissions and limitations
|
||||
under the License.
|
||||
|
||||
-->
|
||||
<databaseChangeLog xmlns="http://www.liquibase.org/xml/ns/dbchangelog"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://www.liquibase.org/xml/ns/dbchangelog http://www.liquibase.org/xml/ns/dbchangelog/dbchangelog-4.3.xsd">
|
||||
<changeSet author="fineract" id="1">
|
||||
<insert tableName="job">
|
||||
<column name="name" value="Add Accrual Transactions For Savings"/>
|
||||
<column name="display_name" value="Add Accrual Transactions For Savings"/>
|
||||
<column name="cron_expression" value="0 1 0 1/1 * ? *"/>
|
||||
<column name="create_time" valueDate="${current_datetime}"/>
|
||||
<column name="task_priority" valueNumeric="5"/>
|
||||
<column name="group_name"/>
|
||||
<column name="previous_run_start_time"/>
|
||||
<column name="job_key" value="Add Accrual Transactions For Savings _ DEFAULT"/>
|
||||
<column name="initializing_errorlog"/>
|
||||
<column name="is_active" valueBoolean="false"/>
|
||||
<column name="currently_running" valueBoolean="false"/>
|
||||
<column name="updates_allowed" valueBoolean="true"/>
|
||||
<column name="scheduler_group" valueNumeric="0"/>
|
||||
<column name="is_misfired" valueBoolean="false"/>
|
||||
<column name="node_id" valueNumeric="1"/>
|
||||
<column name="is_mismatched_job" valueBoolean="true"/>
|
||||
<column name="short_name" value="ADD_ATFS"/>
|
||||
</insert>
|
||||
</changeSet>
|
||||
</databaseChangeLog>
|
||||
+34
@@ -0,0 +1,34 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!--
|
||||
|
||||
Licensed to the Apache Software Foundation (ASF) under one
|
||||
or more contributor license agreements. See the NOTICE file
|
||||
distributed with this work for additional information
|
||||
regarding copyright ownership. The ASF licenses this file
|
||||
to you under the Apache License, Version 2.0 (the
|
||||
"License"); you may not use this file except in compliance
|
||||
with the License. You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing,
|
||||
software distributed under the License is distributed on an
|
||||
"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
KIND, either express or implied. See the License for the
|
||||
specific language governing permissions and limitations
|
||||
under the License.
|
||||
|
||||
-->
|
||||
<databaseChangeLog xmlns="http://www.liquibase.org/xml/ns/dbchangelog"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://www.liquibase.org/xml/ns/dbchangelog http://www.liquibase.org/xml/ns/dbchangelog/dbchangelog-4.3.xsd">
|
||||
<changeSet author="fineract" id="1">
|
||||
<insert tableName="m_permission">
|
||||
<column name="grouping" value="accounting"/>
|
||||
<column name="code" value="EXECUTEFORSAVINGS"/>
|
||||
<column name="entity_name" value="PERIODICACCRUALACCOUNTINGFORSAVINGS"/>
|
||||
<column name="action_name" value="EXECUTE"/>
|
||||
<column name="can_maker_checker" valueBoolean="false"/>
|
||||
</insert>
|
||||
</changeSet>
|
||||
</databaseChangeLog>
|
||||
+31
@@ -0,0 +1,31 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!--
|
||||
|
||||
Licensed to the Apache Software Foundation (ASF) under one
|
||||
or more contributor license agreements. See the NOTICE file
|
||||
distributed with this work for additional information
|
||||
regarding copyright ownership. The ASF licenses this file
|
||||
to you under the Apache License, Version 2.0 (the
|
||||
"License"); you may not use this file except in compliance
|
||||
with the License. You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing,
|
||||
software distributed under the License is distributed on an
|
||||
"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
KIND, either express or implied. See the License for the
|
||||
specific language governing permissions and limitations
|
||||
under the License.
|
||||
|
||||
-->
|
||||
<databaseChangeLog xmlns="http://www.liquibase.org/xml/ns/dbchangelog"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://www.liquibase.org/xml/ns/dbchangelog http://www.liquibase.org/xml/ns/dbchangelog/dbchangelog-4.3.xsd">
|
||||
<changeSet author="fineract" id="1">
|
||||
<addColumn tableName="m_savings_account">
|
||||
<column name="accrued_till_date" type="DATE" defaultValueComputed="NULL" />
|
||||
</addColumn>
|
||||
</changeSet>
|
||||
|
||||
</databaseChangeLog>
|
||||
Reference in New Issue
Block a user