feat: FD/RD GL transaction prefixes + savingsAccountNo in journal entry API
- Use FD/RD transaction ID prefixes for Fixed/Recurring Deposit GL entries via ThreadLocal context set in Cash/AccrualBasedAccountingProcessorForSavings - Add depositAccountType to SavingsDTO and pass from SavingsAccount bridge data - Add savingsAccountNo field to JournalEntryData; populate via LEFT JOIN on m_savings_account (SB/FD/RD) and m_current_account (CA prefix) in read query - Fix JournalEntryMapper MapStruct: ignore savingsAccountNo (SQL-populated) - Fix JournalEntryRunningBalanceUpdateServiceImpl constructor call (27 params) Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Sonnet 4.6
parent
be26ba16c9
commit
b25d5a30d2
+109
-108
@@ -1,108 +1,109 @@
|
||||
/**
|
||||
* 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.accounting.journalentry;
|
||||
|
||||
import java.time.OffsetDateTime;
|
||||
import org.apache.fineract.accounting.glaccount.domain.GLAccountType;
|
||||
import org.apache.fineract.accounting.journalentry.data.JournalEntryData;
|
||||
import org.apache.fineract.accounting.journalentry.domain.JournalEntry;
|
||||
import org.apache.fineract.accounting.journalentry.domain.JournalEntryType;
|
||||
import org.apache.fineract.infrastructure.core.config.MapstructMapperConfig;
|
||||
import org.apache.fineract.infrastructure.core.data.EnumOptionData;
|
||||
import org.apache.fineract.organisation.monetary.data.CurrencyData;
|
||||
import org.apache.fineract.portfolio.PortfolioProductType;
|
||||
import org.mapstruct.Mapper;
|
||||
import org.mapstruct.Mapping;
|
||||
import org.mapstruct.Named;
|
||||
|
||||
@Mapper(config = MapstructMapperConfig.class)
|
||||
public interface JournalEntryMapper {
|
||||
|
||||
@Mapping(target = "id", source = "id")
|
||||
@Mapping(target = "officeId", source = "office.id")
|
||||
@Mapping(target = "officeName", source = "office.name")
|
||||
@Mapping(target = "glAccountId", source = "glAccount.id")
|
||||
@Mapping(target = "glAccountCode", source = "glAccount.glCode")
|
||||
@Mapping(target = "glAccountName", source = "glAccount.name")
|
||||
@Mapping(target = "glAccountType", source = "glAccount.type", qualifiedByName = "glAccountType")
|
||||
@Mapping(target = "transactionDate", source = "transactionDate")
|
||||
@Mapping(target = "entryType", source = "type", qualifiedByName = "journalEntryType")
|
||||
@Mapping(target = "amount", source = "amount")
|
||||
@Mapping(target = "entityType", source = "entityType", qualifiedByName = "entityType")
|
||||
@Mapping(target = "entityId", source = "entityId")
|
||||
@Mapping(target = "submittedOnDate", expression = "java(journalEntry.getCreatedDate().orElse(null))")
|
||||
@Mapping(target = "transactionId", source = "transactionId")
|
||||
@Mapping(target = "currency", source = "currencyCode")
|
||||
@Mapping(target = "manualEntry", source = "manualEntry")
|
||||
@Mapping(target = "reversed", source = "reversed")
|
||||
@Mapping(target = "referenceNumber", source = "referenceNumber")
|
||||
@Mapping(target = "paymentTypeId", source = "paymentDetail.paymentType.id")
|
||||
@Mapping(target = "accountNumber", source = "paymentDetail.accountNumber")
|
||||
@Mapping(target = "checkNumber", source = "paymentDetail.checkNumber")
|
||||
@Mapping(target = "routingCode", source = "paymentDetail.routingCode")
|
||||
@Mapping(target = "receiptNumber", source = "paymentDetail.receiptNumber")
|
||||
@Mapping(target = "bankNumber", source = "paymentDetail.bankNumber")
|
||||
@Mapping(target = "createdDate", ignore = true)
|
||||
@Mapping(target = "createdByUserId", ignore = true)
|
||||
@Mapping(target = "createdByUserName", ignore = true)
|
||||
@Mapping(target = "comments", ignore = true)
|
||||
@Mapping(target = "officeRunningBalance", ignore = true)
|
||||
@Mapping(target = "organizationRunningBalance", ignore = true)
|
||||
@Mapping(target = "runningBalanceComputed", ignore = true)
|
||||
@Mapping(target = "rowIndex", ignore = true)
|
||||
@Mapping(target = "dateFormat", ignore = true)
|
||||
@Mapping(target = "locale", ignore = true)
|
||||
@Mapping(target = "credits", ignore = true)
|
||||
@Mapping(target = "debits", ignore = true)
|
||||
@Mapping(target = "transactionDetails", ignore = true)
|
||||
@Mapping(target = "savingTransactionId", ignore = true)
|
||||
@Mapping(target = "externalAssetOwner", ignore = true)
|
||||
JournalEntryData map(JournalEntry journalEntry);
|
||||
|
||||
@Named("entityType")
|
||||
default PortfolioProductType mapEntityType(Integer entityTypeId) {
|
||||
return PortfolioProductType.fromInt(entityTypeId);
|
||||
}
|
||||
|
||||
@Named("glAccountType")
|
||||
default GLAccountType mapGlAccountType(Integer typeId) {
|
||||
return GLAccountType.fromInt(typeId);
|
||||
}
|
||||
|
||||
@Named("journalEntryType")
|
||||
default JournalEntryType mapJournalEntryType(Integer typeId) {
|
||||
return JournalEntryType.fromInt(typeId);
|
||||
}
|
||||
|
||||
default EnumOptionData mapGlAccountType(GLAccountType accountType) {
|
||||
return new EnumOptionData((long) accountType.getValue(), accountType.getCode(), accountType.name());
|
||||
}
|
||||
|
||||
default EnumOptionData mapJournalEntryType(JournalEntryType journalEntryType) {
|
||||
return new EnumOptionData((long) journalEntryType.getValue(), journalEntryType.getCode(), journalEntryType.name());
|
||||
}
|
||||
|
||||
default EnumOptionData mapEntityType(PortfolioProductType entityType) {
|
||||
return new EnumOptionData((long) entityType.getValue(), entityType.getCode(), entityType.name());
|
||||
}
|
||||
|
||||
default CurrencyData mapCurrency(String currencyCode) {
|
||||
return new CurrencyData(currencyCode);
|
||||
}
|
||||
}
|
||||
/**
|
||||
* 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.accounting.journalentry;
|
||||
|
||||
import java.time.OffsetDateTime;
|
||||
import org.apache.fineract.accounting.glaccount.domain.GLAccountType;
|
||||
import org.apache.fineract.accounting.journalentry.data.JournalEntryData;
|
||||
import org.apache.fineract.accounting.journalentry.domain.JournalEntry;
|
||||
import org.apache.fineract.accounting.journalentry.domain.JournalEntryType;
|
||||
import org.apache.fineract.infrastructure.core.config.MapstructMapperConfig;
|
||||
import org.apache.fineract.infrastructure.core.data.EnumOptionData;
|
||||
import org.apache.fineract.organisation.monetary.data.CurrencyData;
|
||||
import org.apache.fineract.portfolio.PortfolioProductType;
|
||||
import org.mapstruct.Mapper;
|
||||
import org.mapstruct.Mapping;
|
||||
import org.mapstruct.Named;
|
||||
|
||||
@Mapper(config = MapstructMapperConfig.class)
|
||||
public interface JournalEntryMapper {
|
||||
|
||||
@Mapping(target = "id", source = "id")
|
||||
@Mapping(target = "officeId", source = "office.id")
|
||||
@Mapping(target = "officeName", source = "office.name")
|
||||
@Mapping(target = "glAccountId", source = "glAccount.id")
|
||||
@Mapping(target = "glAccountCode", source = "glAccount.glCode")
|
||||
@Mapping(target = "glAccountName", source = "glAccount.name")
|
||||
@Mapping(target = "glAccountType", source = "glAccount.type", qualifiedByName = "glAccountType")
|
||||
@Mapping(target = "transactionDate", source = "transactionDate")
|
||||
@Mapping(target = "entryType", source = "type", qualifiedByName = "journalEntryType")
|
||||
@Mapping(target = "amount", source = "amount")
|
||||
@Mapping(target = "entityType", source = "entityType", qualifiedByName = "entityType")
|
||||
@Mapping(target = "entityId", source = "entityId")
|
||||
@Mapping(target = "submittedOnDate", expression = "java(journalEntry.getCreatedDate().orElse(null))")
|
||||
@Mapping(target = "transactionId", source = "transactionId")
|
||||
@Mapping(target = "currency", source = "currencyCode")
|
||||
@Mapping(target = "manualEntry", source = "manualEntry")
|
||||
@Mapping(target = "reversed", source = "reversed")
|
||||
@Mapping(target = "referenceNumber", source = "referenceNumber")
|
||||
@Mapping(target = "paymentTypeId", source = "paymentDetail.paymentType.id")
|
||||
@Mapping(target = "accountNumber", source = "paymentDetail.accountNumber")
|
||||
@Mapping(target = "checkNumber", source = "paymentDetail.checkNumber")
|
||||
@Mapping(target = "routingCode", source = "paymentDetail.routingCode")
|
||||
@Mapping(target = "receiptNumber", source = "paymentDetail.receiptNumber")
|
||||
@Mapping(target = "bankNumber", source = "paymentDetail.bankNumber")
|
||||
@Mapping(target = "createdDate", ignore = true)
|
||||
@Mapping(target = "createdByUserId", ignore = true)
|
||||
@Mapping(target = "createdByUserName", ignore = true)
|
||||
@Mapping(target = "comments", ignore = true)
|
||||
@Mapping(target = "officeRunningBalance", ignore = true)
|
||||
@Mapping(target = "organizationRunningBalance", ignore = true)
|
||||
@Mapping(target = "runningBalanceComputed", ignore = true)
|
||||
@Mapping(target = "rowIndex", ignore = true)
|
||||
@Mapping(target = "dateFormat", ignore = true)
|
||||
@Mapping(target = "locale", ignore = true)
|
||||
@Mapping(target = "credits", ignore = true)
|
||||
@Mapping(target = "debits", ignore = true)
|
||||
@Mapping(target = "transactionDetails", ignore = true)
|
||||
@Mapping(target = "savingTransactionId", ignore = true)
|
||||
@Mapping(target = "externalAssetOwner", ignore = true)
|
||||
@Mapping(target = "savingsAccountNo", ignore = true)
|
||||
JournalEntryData map(JournalEntry journalEntry);
|
||||
|
||||
@Named("entityType")
|
||||
default PortfolioProductType mapEntityType(Integer entityTypeId) {
|
||||
return PortfolioProductType.fromInt(entityTypeId);
|
||||
}
|
||||
|
||||
@Named("glAccountType")
|
||||
default GLAccountType mapGlAccountType(Integer typeId) {
|
||||
return GLAccountType.fromInt(typeId);
|
||||
}
|
||||
|
||||
@Named("journalEntryType")
|
||||
default JournalEntryType mapJournalEntryType(Integer typeId) {
|
||||
return JournalEntryType.fromInt(typeId);
|
||||
}
|
||||
|
||||
default EnumOptionData mapGlAccountType(GLAccountType accountType) {
|
||||
return new EnumOptionData((long) accountType.getValue(), accountType.getCode(), accountType.name());
|
||||
}
|
||||
|
||||
default EnumOptionData mapJournalEntryType(JournalEntryType journalEntryType) {
|
||||
return new EnumOptionData((long) journalEntryType.getValue(), journalEntryType.getCode(), journalEntryType.name());
|
||||
}
|
||||
|
||||
default EnumOptionData mapEntityType(PortfolioProductType entityType) {
|
||||
return new EnumOptionData((long) entityType.getValue(), entityType.getCode(), entityType.name());
|
||||
}
|
||||
|
||||
default CurrencyData mapCurrency(String currencyCode) {
|
||||
return new CurrencyData(currencyCode);
|
||||
}
|
||||
}
|
||||
|
||||
+291
-287
@@ -1,287 +1,291 @@
|
||||
/**
|
||||
* 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.accounting.journalentry.data;
|
||||
|
||||
import java.math.BigDecimal;
|
||||
import java.time.LocalDate;
|
||||
import java.time.OffsetDateTime;
|
||||
import java.util.List;
|
||||
import lombok.Data;
|
||||
import org.apache.fineract.accounting.glaccount.data.GLAccountData;
|
||||
import org.apache.fineract.infrastructure.core.data.EnumOptionData;
|
||||
import org.apache.fineract.organisation.monetary.data.CurrencyData;
|
||||
|
||||
/**
|
||||
* Immutable object representing a General Ledger Account
|
||||
*
|
||||
* Note: no getter/setters required as google will produce json from fields of object.
|
||||
*/
|
||||
@Data
|
||||
public class JournalEntryData {
|
||||
|
||||
private Long id;
|
||||
private Long officeId;
|
||||
@SuppressWarnings("unused")
|
||||
private String officeName;
|
||||
@SuppressWarnings("unused")
|
||||
private String glAccountName;
|
||||
private Long glAccountId;
|
||||
@SuppressWarnings("unused")
|
||||
private String glAccountCode;
|
||||
private EnumOptionData glAccountType;
|
||||
@SuppressWarnings("unused")
|
||||
private LocalDate transactionDate;
|
||||
private EnumOptionData entryType;
|
||||
private BigDecimal amount;
|
||||
@SuppressWarnings("unused")
|
||||
private CurrencyData currency;
|
||||
private String transactionId;
|
||||
@SuppressWarnings("unused")
|
||||
private Boolean manualEntry;
|
||||
@SuppressWarnings("unused")
|
||||
private EnumOptionData entityType;
|
||||
@SuppressWarnings("unused")
|
||||
private Long entityId;
|
||||
@SuppressWarnings("unused")
|
||||
private Long createdByUserId;
|
||||
@SuppressWarnings("unused")
|
||||
private OffsetDateTime createdDate;
|
||||
@SuppressWarnings("unused")
|
||||
private String createdByUserName;
|
||||
@SuppressWarnings("unused")
|
||||
private String comments;
|
||||
@SuppressWarnings("unused")
|
||||
private Boolean reversed;
|
||||
@SuppressWarnings("unused")
|
||||
private String referenceNumber;
|
||||
@SuppressWarnings("unused")
|
||||
private BigDecimal officeRunningBalance;
|
||||
@SuppressWarnings("unused")
|
||||
private BigDecimal organizationRunningBalance;
|
||||
@SuppressWarnings("unused")
|
||||
private Boolean runningBalanceComputed;
|
||||
|
||||
@SuppressWarnings("unused")
|
||||
private TransactionDetailData transactionDetails;
|
||||
@SuppressWarnings("unused")
|
||||
private OffsetDateTime submittedOnDate;
|
||||
|
||||
// import fields
|
||||
private transient Integer rowIndex;
|
||||
private String dateFormat;
|
||||
private String locale;
|
||||
private List<CreditDebit> credits;
|
||||
private List<CreditDebit> debits;
|
||||
private Long paymentTypeId;
|
||||
private String currencyCode;
|
||||
private String accountNumber;
|
||||
private String checkNumber;
|
||||
private String routingCode;
|
||||
private String receiptNumber;
|
||||
private String bankNumber;
|
||||
private String externalAssetOwner;
|
||||
private transient Long savingTransactionId;
|
||||
|
||||
public JournalEntryData() {}
|
||||
|
||||
// for opening bal bulk import
|
||||
public JournalEntryData(Long officeId, LocalDate transactionDate, String currencyCode, List<CreditDebit> credits,
|
||||
List<CreditDebit> debits, String locale, String dateFormat) {
|
||||
this.officeId = officeId;
|
||||
this.dateFormat = dateFormat;
|
||||
this.locale = locale;
|
||||
this.transactionDate = transactionDate;
|
||||
this.currencyCode = currencyCode;
|
||||
this.credits = credits;
|
||||
this.debits = debits;
|
||||
this.rowIndex = null;
|
||||
this.paymentTypeId = null;
|
||||
this.accountNumber = null;
|
||||
this.checkNumber = null;
|
||||
this.routingCode = null;
|
||||
this.receiptNumber = null;
|
||||
this.bankNumber = null;
|
||||
this.comments = null;
|
||||
this.id = null;
|
||||
this.officeName = null;
|
||||
this.glAccountName = null;
|
||||
this.glAccountId = null;
|
||||
this.glAccountCode = null;
|
||||
this.glAccountType = null;
|
||||
this.entryType = null;
|
||||
this.amount = null;
|
||||
this.currency = null;
|
||||
this.transactionId = null;
|
||||
this.manualEntry = null;
|
||||
this.entityType = null;
|
||||
this.entityId = null;
|
||||
this.createdByUserId = null;
|
||||
this.createdDate = null;
|
||||
this.createdByUserName = null;
|
||||
this.reversed = null;
|
||||
this.referenceNumber = null;
|
||||
this.officeRunningBalance = null;
|
||||
this.organizationRunningBalance = null;
|
||||
this.runningBalanceComputed = null;
|
||||
this.transactionDetails = null;
|
||||
this.submittedOnDate = null;
|
||||
}
|
||||
|
||||
private JournalEntryData(Long officeId, LocalDate transactionDate, String currencyCode, Long paymentTypeId, Integer rowIndex,
|
||||
List<CreditDebit> credits, List<CreditDebit> debits, String accountNumber, String checkNumber, String routingCode,
|
||||
String receiptNumber, String bankNumber, String comments, String locale, String dateFormat) {
|
||||
|
||||
this.officeId = officeId;
|
||||
this.dateFormat = dateFormat;
|
||||
this.locale = locale;
|
||||
this.transactionDate = transactionDate;
|
||||
this.currencyCode = currencyCode;
|
||||
this.rowIndex = rowIndex;
|
||||
this.credits = credits;
|
||||
this.debits = debits;
|
||||
this.paymentTypeId = paymentTypeId;
|
||||
this.accountNumber = accountNumber;
|
||||
this.checkNumber = checkNumber;
|
||||
this.routingCode = routingCode;
|
||||
this.receiptNumber = receiptNumber;
|
||||
this.bankNumber = bankNumber;
|
||||
this.comments = comments;
|
||||
this.id = null;
|
||||
this.officeName = null;
|
||||
this.glAccountName = null;
|
||||
this.glAccountId = null;
|
||||
this.glAccountCode = null;
|
||||
this.glAccountType = null;
|
||||
this.entryType = null;
|
||||
this.amount = null;
|
||||
this.currency = null;
|
||||
this.transactionId = null;
|
||||
this.manualEntry = null;
|
||||
this.entityType = null;
|
||||
this.entityId = null;
|
||||
this.createdByUserId = null;
|
||||
this.submittedOnDate = null;
|
||||
this.createdDate = null;
|
||||
this.createdByUserName = null;
|
||||
this.reversed = null;
|
||||
this.referenceNumber = null;
|
||||
this.officeRunningBalance = null;
|
||||
this.organizationRunningBalance = null;
|
||||
this.runningBalanceComputed = null;
|
||||
this.transactionDetails = null;
|
||||
}
|
||||
|
||||
public JournalEntryData(final Long id, final Long officeId, final String officeName, final String glAccountName, final Long glAccountId,
|
||||
final String glAccountCode, final EnumOptionData glAccountClassification, final LocalDate transactionDate,
|
||||
final EnumOptionData entryType, final BigDecimal amount, final String transactionId, final Boolean manualEntry,
|
||||
final EnumOptionData entityType, final Long entityId, final Long createdByUserId, final OffsetDateTime submittedOnDate,
|
||||
final String createdByUserName, final String comments, final Boolean reversed, final String referenceNumber,
|
||||
final BigDecimal officeRunningBalance, final BigDecimal organizationRunningBalance, final Boolean runningBalanceComputed,
|
||||
final TransactionDetailData transactionDetailData, final CurrencyData currency, final String externalAssetOwner) {
|
||||
this.id = id;
|
||||
this.officeId = officeId;
|
||||
this.officeName = officeName;
|
||||
this.glAccountName = glAccountName;
|
||||
this.glAccountId = glAccountId;
|
||||
this.glAccountCode = glAccountCode;
|
||||
this.glAccountType = glAccountClassification;
|
||||
this.transactionDate = transactionDate;
|
||||
this.entryType = entryType;
|
||||
this.amount = amount;
|
||||
this.transactionId = transactionId;
|
||||
this.manualEntry = manualEntry;
|
||||
this.entityType = entityType;
|
||||
this.entityId = entityId;
|
||||
this.createdByUserId = createdByUserId;
|
||||
this.createdDate = submittedOnDate;
|
||||
this.submittedOnDate = submittedOnDate;
|
||||
this.createdByUserName = createdByUserName;
|
||||
this.comments = comments;
|
||||
this.reversed = reversed;
|
||||
this.referenceNumber = referenceNumber;
|
||||
this.officeRunningBalance = officeRunningBalance;
|
||||
this.organizationRunningBalance = organizationRunningBalance;
|
||||
this.runningBalanceComputed = runningBalanceComputed;
|
||||
this.transactionDetails = transactionDetailData;
|
||||
this.currency = currency;
|
||||
this.externalAssetOwner = externalAssetOwner;
|
||||
}
|
||||
|
||||
public static JournalEntryData importInstance(Long officeId, LocalDate transactionDate, String currencyCode, Long paymentTypeId,
|
||||
Integer rowIndex, List<CreditDebit> credits, List<CreditDebit> debits, String accountNumber, String checkNumber,
|
||||
String routingCode, String receiptNumber, String bankNumber, String comments, String locale, String dateFormat) {
|
||||
return new JournalEntryData(officeId, transactionDate, currencyCode, paymentTypeId, rowIndex, credits, debits, accountNumber,
|
||||
checkNumber, routingCode, receiptNumber, bankNumber, comments, locale, dateFormat);
|
||||
}
|
||||
|
||||
public static JournalEntryData importInstance1(Long officeId, LocalDate transactionDate, String currencyCode, List<CreditDebit> credits,
|
||||
List<CreditDebit> debits, String locale, String dateFormat) {
|
||||
return new JournalEntryData(officeId, transactionDate, currencyCode, credits, debits, locale, dateFormat);
|
||||
}
|
||||
|
||||
public static JournalEntryData fromGLAccountData(final GLAccountData glAccountData) {
|
||||
|
||||
final Long id = null;
|
||||
final Long officeId = null;
|
||||
final String officeName = null;
|
||||
final String glAccountName = glAccountData.getName();
|
||||
final Long glAccountId = glAccountData.getId();
|
||||
final String glAccountCode = glAccountData.getGlCode();
|
||||
final EnumOptionData glAccountClassification = glAccountData.getType();
|
||||
final LocalDate transactionDate = null;
|
||||
final EnumOptionData entryType = null;
|
||||
final BigDecimal amount = null;
|
||||
final String transactionId = null;
|
||||
final Boolean manualEntry = null;
|
||||
final EnumOptionData entityType = null;
|
||||
final Long entityId = null;
|
||||
final Long createdByUserId = null;
|
||||
final OffsetDateTime submittedOnDate = null;
|
||||
final String createdByUserName = null;
|
||||
final String comments = null;
|
||||
final Boolean reversed = null;
|
||||
final String referenceNumber = null;
|
||||
final BigDecimal officeRunningBalance = null;
|
||||
final BigDecimal organizationRunningBalance = null;
|
||||
final Boolean runningBalanceComputed = null;
|
||||
final TransactionDetailData transactionDetailData = null;
|
||||
final CurrencyData currency = null;
|
||||
final String externalAssetOwner = null;
|
||||
return new JournalEntryData(id, officeId, officeName, glAccountName, glAccountId, glAccountCode, glAccountClassification,
|
||||
transactionDate, entryType, amount, transactionId, manualEntry, entityType, entityId, createdByUserId, submittedOnDate,
|
||||
createdByUserName, comments, reversed, referenceNumber, officeRunningBalance, organizationRunningBalance,
|
||||
runningBalanceComputed, transactionDetailData, currency, externalAssetOwner);
|
||||
}
|
||||
|
||||
public Integer getRowIndex() {
|
||||
return rowIndex;
|
||||
}
|
||||
|
||||
public LocalDate getTransactionDate() {
|
||||
return transactionDate;
|
||||
}
|
||||
|
||||
public void addDebits(CreditDebit debit) {
|
||||
this.debits.add(debit);
|
||||
}
|
||||
|
||||
public void addCredits(CreditDebit credit) {
|
||||
this.credits.add(credit);
|
||||
}
|
||||
}
|
||||
/**
|
||||
* 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.accounting.journalentry.data;
|
||||
|
||||
import java.math.BigDecimal;
|
||||
import java.time.LocalDate;
|
||||
import java.time.OffsetDateTime;
|
||||
import java.util.List;
|
||||
import lombok.Data;
|
||||
import org.apache.fineract.accounting.glaccount.data.GLAccountData;
|
||||
import org.apache.fineract.infrastructure.core.data.EnumOptionData;
|
||||
import org.apache.fineract.organisation.monetary.data.CurrencyData;
|
||||
|
||||
/**
|
||||
* Immutable object representing a General Ledger Account
|
||||
*
|
||||
* Note: no getter/setters required as google will produce json from fields of object.
|
||||
*/
|
||||
@Data
|
||||
public class JournalEntryData {
|
||||
|
||||
private Long id;
|
||||
private Long officeId;
|
||||
@SuppressWarnings("unused")
|
||||
private String officeName;
|
||||
@SuppressWarnings("unused")
|
||||
private String glAccountName;
|
||||
private Long glAccountId;
|
||||
@SuppressWarnings("unused")
|
||||
private String glAccountCode;
|
||||
private EnumOptionData glAccountType;
|
||||
@SuppressWarnings("unused")
|
||||
private LocalDate transactionDate;
|
||||
private EnumOptionData entryType;
|
||||
private BigDecimal amount;
|
||||
@SuppressWarnings("unused")
|
||||
private CurrencyData currency;
|
||||
private String transactionId;
|
||||
@SuppressWarnings("unused")
|
||||
private Boolean manualEntry;
|
||||
@SuppressWarnings("unused")
|
||||
private EnumOptionData entityType;
|
||||
@SuppressWarnings("unused")
|
||||
private Long entityId;
|
||||
@SuppressWarnings("unused")
|
||||
private String savingsAccountNo;
|
||||
@SuppressWarnings("unused")
|
||||
private Long createdByUserId;
|
||||
@SuppressWarnings("unused")
|
||||
private OffsetDateTime createdDate;
|
||||
@SuppressWarnings("unused")
|
||||
private String createdByUserName;
|
||||
@SuppressWarnings("unused")
|
||||
private String comments;
|
||||
@SuppressWarnings("unused")
|
||||
private Boolean reversed;
|
||||
@SuppressWarnings("unused")
|
||||
private String referenceNumber;
|
||||
@SuppressWarnings("unused")
|
||||
private BigDecimal officeRunningBalance;
|
||||
@SuppressWarnings("unused")
|
||||
private BigDecimal organizationRunningBalance;
|
||||
@SuppressWarnings("unused")
|
||||
private Boolean runningBalanceComputed;
|
||||
|
||||
@SuppressWarnings("unused")
|
||||
private TransactionDetailData transactionDetails;
|
||||
@SuppressWarnings("unused")
|
||||
private OffsetDateTime submittedOnDate;
|
||||
|
||||
// import fields
|
||||
private transient Integer rowIndex;
|
||||
private String dateFormat;
|
||||
private String locale;
|
||||
private List<CreditDebit> credits;
|
||||
private List<CreditDebit> debits;
|
||||
private Long paymentTypeId;
|
||||
private String currencyCode;
|
||||
private String accountNumber;
|
||||
private String checkNumber;
|
||||
private String routingCode;
|
||||
private String receiptNumber;
|
||||
private String bankNumber;
|
||||
private String externalAssetOwner;
|
||||
private transient Long savingTransactionId;
|
||||
|
||||
public JournalEntryData() {}
|
||||
|
||||
// for opening bal bulk import
|
||||
public JournalEntryData(Long officeId, LocalDate transactionDate, String currencyCode, List<CreditDebit> credits,
|
||||
List<CreditDebit> debits, String locale, String dateFormat) {
|
||||
this.officeId = officeId;
|
||||
this.dateFormat = dateFormat;
|
||||
this.locale = locale;
|
||||
this.transactionDate = transactionDate;
|
||||
this.currencyCode = currencyCode;
|
||||
this.credits = credits;
|
||||
this.debits = debits;
|
||||
this.rowIndex = null;
|
||||
this.paymentTypeId = null;
|
||||
this.accountNumber = null;
|
||||
this.checkNumber = null;
|
||||
this.routingCode = null;
|
||||
this.receiptNumber = null;
|
||||
this.bankNumber = null;
|
||||
this.comments = null;
|
||||
this.id = null;
|
||||
this.officeName = null;
|
||||
this.glAccountName = null;
|
||||
this.glAccountId = null;
|
||||
this.glAccountCode = null;
|
||||
this.glAccountType = null;
|
||||
this.entryType = null;
|
||||
this.amount = null;
|
||||
this.currency = null;
|
||||
this.transactionId = null;
|
||||
this.manualEntry = null;
|
||||
this.entityType = null;
|
||||
this.entityId = null;
|
||||
this.createdByUserId = null;
|
||||
this.createdDate = null;
|
||||
this.createdByUserName = null;
|
||||
this.reversed = null;
|
||||
this.referenceNumber = null;
|
||||
this.officeRunningBalance = null;
|
||||
this.organizationRunningBalance = null;
|
||||
this.runningBalanceComputed = null;
|
||||
this.transactionDetails = null;
|
||||
this.submittedOnDate = null;
|
||||
}
|
||||
|
||||
private JournalEntryData(Long officeId, LocalDate transactionDate, String currencyCode, Long paymentTypeId, Integer rowIndex,
|
||||
List<CreditDebit> credits, List<CreditDebit> debits, String accountNumber, String checkNumber, String routingCode,
|
||||
String receiptNumber, String bankNumber, String comments, String locale, String dateFormat) {
|
||||
|
||||
this.officeId = officeId;
|
||||
this.dateFormat = dateFormat;
|
||||
this.locale = locale;
|
||||
this.transactionDate = transactionDate;
|
||||
this.currencyCode = currencyCode;
|
||||
this.rowIndex = rowIndex;
|
||||
this.credits = credits;
|
||||
this.debits = debits;
|
||||
this.paymentTypeId = paymentTypeId;
|
||||
this.accountNumber = accountNumber;
|
||||
this.checkNumber = checkNumber;
|
||||
this.routingCode = routingCode;
|
||||
this.receiptNumber = receiptNumber;
|
||||
this.bankNumber = bankNumber;
|
||||
this.comments = comments;
|
||||
this.id = null;
|
||||
this.officeName = null;
|
||||
this.glAccountName = null;
|
||||
this.glAccountId = null;
|
||||
this.glAccountCode = null;
|
||||
this.glAccountType = null;
|
||||
this.entryType = null;
|
||||
this.amount = null;
|
||||
this.currency = null;
|
||||
this.transactionId = null;
|
||||
this.manualEntry = null;
|
||||
this.entityType = null;
|
||||
this.entityId = null;
|
||||
this.createdByUserId = null;
|
||||
this.submittedOnDate = null;
|
||||
this.createdDate = null;
|
||||
this.createdByUserName = null;
|
||||
this.reversed = null;
|
||||
this.referenceNumber = null;
|
||||
this.officeRunningBalance = null;
|
||||
this.organizationRunningBalance = null;
|
||||
this.runningBalanceComputed = null;
|
||||
this.transactionDetails = null;
|
||||
}
|
||||
|
||||
public JournalEntryData(final Long id, final Long officeId, final String officeName, final String glAccountName, final Long glAccountId,
|
||||
final String glAccountCode, final EnumOptionData glAccountClassification, final LocalDate transactionDate,
|
||||
final EnumOptionData entryType, final BigDecimal amount, final String transactionId, final Boolean manualEntry,
|
||||
final EnumOptionData entityType, final Long entityId, final Long createdByUserId, final OffsetDateTime submittedOnDate,
|
||||
final String createdByUserName, final String comments, final Boolean reversed, final String referenceNumber,
|
||||
final BigDecimal officeRunningBalance, final BigDecimal organizationRunningBalance, final Boolean runningBalanceComputed,
|
||||
final TransactionDetailData transactionDetailData, final CurrencyData currency, final String externalAssetOwner,
|
||||
final String savingsAccountNo) {
|
||||
this.id = id;
|
||||
this.officeId = officeId;
|
||||
this.officeName = officeName;
|
||||
this.glAccountName = glAccountName;
|
||||
this.glAccountId = glAccountId;
|
||||
this.glAccountCode = glAccountCode;
|
||||
this.glAccountType = glAccountClassification;
|
||||
this.transactionDate = transactionDate;
|
||||
this.entryType = entryType;
|
||||
this.amount = amount;
|
||||
this.transactionId = transactionId;
|
||||
this.manualEntry = manualEntry;
|
||||
this.entityType = entityType;
|
||||
this.entityId = entityId;
|
||||
this.createdByUserId = createdByUserId;
|
||||
this.createdDate = submittedOnDate;
|
||||
this.submittedOnDate = submittedOnDate;
|
||||
this.createdByUserName = createdByUserName;
|
||||
this.comments = comments;
|
||||
this.reversed = reversed;
|
||||
this.referenceNumber = referenceNumber;
|
||||
this.officeRunningBalance = officeRunningBalance;
|
||||
this.organizationRunningBalance = organizationRunningBalance;
|
||||
this.runningBalanceComputed = runningBalanceComputed;
|
||||
this.transactionDetails = transactionDetailData;
|
||||
this.currency = currency;
|
||||
this.externalAssetOwner = externalAssetOwner;
|
||||
this.savingsAccountNo = savingsAccountNo;
|
||||
}
|
||||
|
||||
public static JournalEntryData importInstance(Long officeId, LocalDate transactionDate, String currencyCode, Long paymentTypeId,
|
||||
Integer rowIndex, List<CreditDebit> credits, List<CreditDebit> debits, String accountNumber, String checkNumber,
|
||||
String routingCode, String receiptNumber, String bankNumber, String comments, String locale, String dateFormat) {
|
||||
return new JournalEntryData(officeId, transactionDate, currencyCode, paymentTypeId, rowIndex, credits, debits, accountNumber,
|
||||
checkNumber, routingCode, receiptNumber, bankNumber, comments, locale, dateFormat);
|
||||
}
|
||||
|
||||
public static JournalEntryData importInstance1(Long officeId, LocalDate transactionDate, String currencyCode, List<CreditDebit> credits,
|
||||
List<CreditDebit> debits, String locale, String dateFormat) {
|
||||
return new JournalEntryData(officeId, transactionDate, currencyCode, credits, debits, locale, dateFormat);
|
||||
}
|
||||
|
||||
public static JournalEntryData fromGLAccountData(final GLAccountData glAccountData) {
|
||||
|
||||
final Long id = null;
|
||||
final Long officeId = null;
|
||||
final String officeName = null;
|
||||
final String glAccountName = glAccountData.getName();
|
||||
final Long glAccountId = glAccountData.getId();
|
||||
final String glAccountCode = glAccountData.getGlCode();
|
||||
final EnumOptionData glAccountClassification = glAccountData.getType();
|
||||
final LocalDate transactionDate = null;
|
||||
final EnumOptionData entryType = null;
|
||||
final BigDecimal amount = null;
|
||||
final String transactionId = null;
|
||||
final Boolean manualEntry = null;
|
||||
final EnumOptionData entityType = null;
|
||||
final Long entityId = null;
|
||||
final Long createdByUserId = null;
|
||||
final OffsetDateTime submittedOnDate = null;
|
||||
final String createdByUserName = null;
|
||||
final String comments = null;
|
||||
final Boolean reversed = null;
|
||||
final String referenceNumber = null;
|
||||
final BigDecimal officeRunningBalance = null;
|
||||
final BigDecimal organizationRunningBalance = null;
|
||||
final Boolean runningBalanceComputed = null;
|
||||
final TransactionDetailData transactionDetailData = null;
|
||||
final CurrencyData currency = null;
|
||||
final String externalAssetOwner = null;
|
||||
return new JournalEntryData(id, officeId, officeName, glAccountName, glAccountId, glAccountCode, glAccountClassification,
|
||||
transactionDate, entryType, amount, transactionId, manualEntry, entityType, entityId, createdByUserId, submittedOnDate,
|
||||
createdByUserName, comments, reversed, referenceNumber, officeRunningBalance, organizationRunningBalance,
|
||||
runningBalanceComputed, transactionDetailData, currency, externalAssetOwner, null);
|
||||
}
|
||||
|
||||
public Integer getRowIndex() {
|
||||
return rowIndex;
|
||||
}
|
||||
|
||||
public LocalDate getTransactionDate() {
|
||||
return transactionDate;
|
||||
}
|
||||
|
||||
public void addDebits(CreditDebit debit) {
|
||||
this.debits.add(debit);
|
||||
}
|
||||
|
||||
public void addCredits(CreditDebit credit) {
|
||||
this.credits.add(credit);
|
||||
}
|
||||
}
|
||||
|
||||
+39
-38
@@ -1,38 +1,39 @@
|
||||
/**
|
||||
* 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.accounting.journalentry.data;
|
||||
|
||||
import java.util.List;
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Getter;
|
||||
import lombok.Setter;
|
||||
|
||||
@AllArgsConstructor
|
||||
@Getter
|
||||
@Setter
|
||||
public class SavingsDTO {
|
||||
|
||||
private Long savingsId;
|
||||
private Long savingsProductId;
|
||||
private Long officeId;
|
||||
private String currencyCode;
|
||||
private boolean cashBasedAccountingEnabled;
|
||||
private boolean accrualBasedAccountingEnabled;
|
||||
private List<SavingsTransactionDTO> newSavingsTransactions;
|
||||
}
|
||||
/**
|
||||
* 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.accounting.journalentry.data;
|
||||
|
||||
import java.util.List;
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Getter;
|
||||
import lombok.Setter;
|
||||
|
||||
@AllArgsConstructor
|
||||
@Getter
|
||||
@Setter
|
||||
public class SavingsDTO {
|
||||
|
||||
private Long savingsId;
|
||||
private Long savingsProductId;
|
||||
private Long officeId;
|
||||
private String currencyCode;
|
||||
private boolean cashBasedAccountingEnabled;
|
||||
private boolean accrualBasedAccountingEnabled;
|
||||
private List<SavingsTransactionDTO> newSavingsTransactions;
|
||||
private int depositAccountType;
|
||||
}
|
||||
|
||||
+1409
-1386
File diff suppressed because it is too large
Load Diff
+290
-285
@@ -1,285 +1,290 @@
|
||||
/**
|
||||
* 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.accounting.journalentry.service;
|
||||
|
||||
import java.math.BigDecimal;
|
||||
import java.time.LocalDate;
|
||||
import java.util.List;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import org.apache.fineract.accounting.closure.domain.GLClosure;
|
||||
import org.apache.fineract.accounting.common.AccountingConstants.AccrualAccountsForSavings;
|
||||
import org.apache.fineract.accounting.common.AccountingConstants.FinancialActivity;
|
||||
import org.apache.fineract.accounting.journalentry.data.ChargePaymentDTO;
|
||||
import org.apache.fineract.accounting.journalentry.data.SavingsDTO;
|
||||
import org.apache.fineract.accounting.journalentry.data.SavingsTransactionDTO;
|
||||
import org.apache.fineract.infrastructure.core.service.MathUtil;
|
||||
import org.apache.fineract.organisation.office.domain.Office;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
@Component
|
||||
@RequiredArgsConstructor
|
||||
public class AccrualBasedAccountingProcessorForSavings implements AccountingProcessorForSavings {
|
||||
|
||||
private final AccountingProcessorHelper helper;
|
||||
|
||||
@Override
|
||||
public void createJournalEntriesForSavings(final SavingsDTO savingsDTO) {
|
||||
final GLClosure latestGLClosure = this.helper.getLatestClosureByBranch(savingsDTO.getOfficeId());
|
||||
final Long savingsProductId = savingsDTO.getSavingsProductId();
|
||||
final Long savingsId = savingsDTO.getSavingsId();
|
||||
final String currencyCode = savingsDTO.getCurrencyCode();
|
||||
for (final SavingsTransactionDTO savingsTransactionDTO : savingsDTO.getNewSavingsTransactions()) {
|
||||
final LocalDate transactionDate = savingsTransactionDTO.getTransactionDate();
|
||||
final String transactionId = savingsTransactionDTO.getTransactionId();
|
||||
final Office office = this.helper.getOfficeById(savingsTransactionDTO.getOfficeId());
|
||||
final Long paymentTypeId = savingsTransactionDTO.getPaymentTypeId();
|
||||
final boolean isReversal = savingsTransactionDTO.isReversed();
|
||||
final BigDecimal amount = savingsTransactionDTO.getAmount();
|
||||
final BigDecimal overdraftAmount = savingsTransactionDTO.getOverdraftAmount();
|
||||
final List<ChargePaymentDTO> feePayments = savingsTransactionDTO.getFeePayments();
|
||||
final List<ChargePaymentDTO> penaltyPayments = savingsTransactionDTO.getPenaltyPayments();
|
||||
|
||||
this.helper.checkForBranchClosures(latestGLClosure, transactionDate);
|
||||
|
||||
if (savingsTransactionDTO.getTransactionType().isWithdrawal() && savingsTransactionDTO.isOverdraftTransaction()) {
|
||||
boolean isPositive = amount.subtract(overdraftAmount).compareTo(BigDecimal.ZERO) > 0;
|
||||
if (savingsTransactionDTO.isAccountTransfer()) {
|
||||
this.helper.createCashBasedJournalEntriesAndReversalsForSavings(office, currencyCode,
|
||||
AccrualAccountsForSavings.OVERDRAFT_PORTFOLIO_CONTROL.getValue(),
|
||||
FinancialActivity.LIABILITY_TRANSFER.getValue(), savingsProductId, paymentTypeId, savingsId, transactionId,
|
||||
transactionDate, overdraftAmount, isReversal);
|
||||
if (isPositive) {
|
||||
this.helper.createCashBasedJournalEntriesAndReversalsForSavings(office, currencyCode,
|
||||
AccrualAccountsForSavings.SAVINGS_CONTROL.getValue(), FinancialActivity.LIABILITY_TRANSFER.getValue(),
|
||||
savingsProductId, paymentTypeId, savingsId, transactionId, transactionDate,
|
||||
amount.subtract(overdraftAmount), isReversal);
|
||||
}
|
||||
} else {
|
||||
this.helper.createCashBasedJournalEntriesAndReversalsForSavings(office, currencyCode,
|
||||
AccrualAccountsForSavings.OVERDRAFT_PORTFOLIO_CONTROL.getValue(),
|
||||
AccrualAccountsForSavings.SAVINGS_REFERENCE.getValue(), savingsProductId, paymentTypeId, savingsId,
|
||||
transactionId, transactionDate, overdraftAmount, isReversal);
|
||||
if (isPositive) {
|
||||
this.helper.createCashBasedJournalEntriesAndReversalsForSavings(office, currencyCode,
|
||||
AccrualAccountsForSavings.SAVINGS_CONTROL.getValue(),
|
||||
AccrualAccountsForSavings.SAVINGS_REFERENCE.getValue(), savingsProductId, paymentTypeId, savingsId,
|
||||
transactionId, transactionDate, amount.subtract(overdraftAmount), isReversal);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
else if (savingsTransactionDTO.getTransactionType().isDeposit() && savingsTransactionDTO.isOverdraftTransaction()) {
|
||||
boolean isPositive = amount.subtract(overdraftAmount).compareTo(BigDecimal.ZERO) > 0;
|
||||
if (savingsTransactionDTO.isAccountTransfer()) {
|
||||
this.helper.createCashBasedJournalEntriesAndReversalsForSavings(office, currencyCode,
|
||||
FinancialActivity.LIABILITY_TRANSFER.getValue(),
|
||||
AccrualAccountsForSavings.OVERDRAFT_PORTFOLIO_CONTROL.getValue(), savingsProductId, paymentTypeId, savingsId,
|
||||
transactionId, transactionDate, overdraftAmount, isReversal);
|
||||
if (isPositive) {
|
||||
this.helper.createCashBasedJournalEntriesAndReversalsForSavings(office, currencyCode,
|
||||
FinancialActivity.LIABILITY_TRANSFER.getValue(), AccrualAccountsForSavings.SAVINGS_CONTROL.getValue(),
|
||||
savingsProductId, paymentTypeId, savingsId, transactionId, transactionDate,
|
||||
amount.subtract(overdraftAmount), isReversal);
|
||||
}
|
||||
} else {
|
||||
this.helper.createCashBasedJournalEntriesAndReversalsForSavings(office, currencyCode,
|
||||
AccrualAccountsForSavings.SAVINGS_REFERENCE.getValue(),
|
||||
AccrualAccountsForSavings.OVERDRAFT_PORTFOLIO_CONTROL.getValue(), savingsProductId, paymentTypeId, savingsId,
|
||||
transactionId, transactionDate, overdraftAmount, isReversal);
|
||||
if (isPositive) {
|
||||
this.helper.createCashBasedJournalEntriesAndReversalsForSavings(office, currencyCode,
|
||||
AccrualAccountsForSavings.SAVINGS_REFERENCE.getValue(),
|
||||
AccrualAccountsForSavings.SAVINGS_CONTROL.getValue(), savingsProductId, paymentTypeId, savingsId,
|
||||
transactionId, transactionDate, amount.subtract(overdraftAmount), isReversal);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/** Handle Deposits and reversals of deposits **/
|
||||
else if (savingsTransactionDTO.getTransactionType().isDeposit()) {
|
||||
if (savingsTransactionDTO.isAccountTransfer()) {
|
||||
this.helper.createCashBasedJournalEntriesAndReversalsForSavings(office, currencyCode,
|
||||
FinancialActivity.LIABILITY_TRANSFER.getValue(), AccrualAccountsForSavings.SAVINGS_CONTROL.getValue(),
|
||||
savingsProductId, paymentTypeId, savingsId, transactionId, transactionDate, amount, isReversal);
|
||||
} else {
|
||||
this.helper.createCashBasedJournalEntriesAndReversalsForSavings(office, currencyCode,
|
||||
AccrualAccountsForSavings.SAVINGS_REFERENCE.getValue(), AccrualAccountsForSavings.SAVINGS_CONTROL.getValue(),
|
||||
savingsProductId, paymentTypeId, savingsId, transactionId, transactionDate, amount, isReversal);
|
||||
}
|
||||
}
|
||||
|
||||
/** Handle Deposits and reversals of Dividend pay outs **/
|
||||
else if (savingsTransactionDTO.getTransactionType().isDividendPayout()) {
|
||||
this.helper.createCashBasedJournalEntriesAndReversalsForSavings(office, currencyCode,
|
||||
FinancialActivity.PAYABLE_DIVIDENDS.getValue(), AccrualAccountsForSavings.SAVINGS_CONTROL.getValue(),
|
||||
savingsProductId, paymentTypeId, savingsId, transactionId, transactionDate, amount, isReversal);
|
||||
}
|
||||
|
||||
/** Handle withdrawals and reversals of withdrawals **/
|
||||
else if (savingsTransactionDTO.getTransactionType().isWithdrawal()) {
|
||||
if (savingsTransactionDTO.isAccountTransfer()) {
|
||||
this.helper.createCashBasedJournalEntriesAndReversalsForSavings(office, currencyCode,
|
||||
AccrualAccountsForSavings.SAVINGS_CONTROL.getValue(), FinancialActivity.LIABILITY_TRANSFER.getValue(),
|
||||
savingsProductId, paymentTypeId, savingsId, transactionId, transactionDate, amount, isReversal);
|
||||
} else {
|
||||
this.helper.createCashBasedJournalEntriesAndReversalsForSavings(office, currencyCode,
|
||||
AccrualAccountsForSavings.SAVINGS_CONTROL.getValue(), AccrualAccountsForSavings.SAVINGS_REFERENCE.getValue(),
|
||||
savingsProductId, paymentTypeId, savingsId, transactionId, transactionDate, amount, isReversal);
|
||||
}
|
||||
}
|
||||
|
||||
else if (savingsTransactionDTO.getTransactionType().isEscheat()) {
|
||||
this.helper.createCashBasedJournalEntriesAndReversalsForSavings(office, currencyCode,
|
||||
AccrualAccountsForSavings.SAVINGS_CONTROL.getValue(), AccrualAccountsForSavings.ESCHEAT_LIABILITY.getValue(),
|
||||
savingsProductId, paymentTypeId, savingsId, transactionId, transactionDate, amount, isReversal);
|
||||
}
|
||||
/**
|
||||
* Handle Interest Applications and reversals of Interest Applications
|
||||
**/
|
||||
else if (savingsTransactionDTO.getTransactionType().isInterestPosting() && savingsTransactionDTO.isOverdraftTransaction()) {
|
||||
boolean isPositive = amount.subtract(overdraftAmount).compareTo(BigDecimal.ZERO) > 0;
|
||||
// Post journal entry if earned interest amount is greater than
|
||||
// zero
|
||||
if (savingsTransactionDTO.getAmount().compareTo(BigDecimal.ZERO) > 0) {
|
||||
this.helper.createCashBasedJournalEntriesAndReversalsForSavings(office, currencyCode,
|
||||
AccrualAccountsForSavings.INTEREST_ON_SAVINGS.getValue(),
|
||||
AccrualAccountsForSavings.OVERDRAFT_PORTFOLIO_CONTROL.getValue(), savingsProductId, paymentTypeId, savingsId,
|
||||
transactionId, transactionDate, overdraftAmount, isReversal);
|
||||
if (isPositive) {
|
||||
this.helper.createCashBasedJournalEntriesAndReversalsForSavings(office, currencyCode,
|
||||
AccrualAccountsForSavings.INTEREST_ON_SAVINGS.getValue(),
|
||||
AccrualAccountsForSavings.SAVINGS_CONTROL.getValue(), savingsProductId, paymentTypeId, savingsId,
|
||||
transactionId, transactionDate, amount.subtract(overdraftAmount), isReversal);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
else if (savingsTransactionDTO.getTransactionType().isInterestPosting()) {
|
||||
// Post journal entry if earned interest amount is greater than
|
||||
// zero
|
||||
if (savingsTransactionDTO.getAmount().compareTo(BigDecimal.ZERO) > 0) {
|
||||
this.helper.createCashBasedJournalEntriesAndReversalsForSavings(office, currencyCode,
|
||||
AccrualAccountsForSavings.INTEREST_PAYABLE.getValue(), AccrualAccountsForSavings.SAVINGS_CONTROL.getValue(),
|
||||
savingsProductId, paymentTypeId, savingsId, transactionId, transactionDate, amount, isReversal);
|
||||
}
|
||||
}
|
||||
|
||||
else if (savingsTransactionDTO.getTransactionType().isAccrual()) {
|
||||
// Post journal entry for Accrual Recognition
|
||||
if (savingsTransactionDTO.getAmount().compareTo(BigDecimal.ZERO) > 0) {
|
||||
if (MathUtil.isGreaterThanZero(overdraftAmount)) {
|
||||
this.helper.createAccrualBasedDebitJournalEntriesAndReversalsForSavings(office, currencyCode,
|
||||
AccrualAccountsForSavings.INTEREST_ON_SAVINGS.getValue(), savingsProductId, paymentTypeId, savingsId,
|
||||
transactionId, transactionDate, amount, isReversal);
|
||||
this.helper.createAccrualBasedCreditJournalEntriesAndReversalsForSavings(office, currencyCode,
|
||||
AccrualAccountsForSavings.INTEREST_PAYABLE.getValue(), savingsProductId, paymentTypeId, savingsId,
|
||||
transactionId, transactionDate, amount, isReversal);
|
||||
} else {
|
||||
this.helper.createAccrualBasedDebitJournalEntriesAndReversalsForSavings(office, currencyCode,
|
||||
AccrualAccountsForSavings.INTEREST_RECEIVABLE.getValue(), savingsProductId, paymentTypeId, savingsId,
|
||||
transactionId, transactionDate, amount, isReversal);
|
||||
this.helper.createAccrualBasedCreditJournalEntriesAndReversalsForSavings(office, currencyCode,
|
||||
AccrualAccountsForSavings.INCOME_FROM_INTEREST.getValue(), savingsProductId, paymentTypeId, savingsId,
|
||||
transactionId, transactionDate, amount, isReversal);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
else if (savingsTransactionDTO.getTransactionType().isWithholdTax()) {
|
||||
this.helper.createAccrualBasedJournalEntriesAndReversalsForSavingsTax(office, currencyCode,
|
||||
AccrualAccountsForSavings.SAVINGS_CONTROL, AccrualAccountsForSavings.SAVINGS_REFERENCE, savingsProductId,
|
||||
paymentTypeId, savingsId, transactionId, transactionDate, amount, isReversal,
|
||||
savingsTransactionDTO.getTaxPayments());
|
||||
}
|
||||
|
||||
/** Handle Fees Deductions and reversals of Fees Deductions **/
|
||||
else if (savingsTransactionDTO.getTransactionType().isFeeDeduction() && savingsTransactionDTO.isOverdraftTransaction()) {
|
||||
boolean isPositive = amount.subtract(overdraftAmount).compareTo(BigDecimal.ZERO) > 0;
|
||||
// Is the Charge a penalty?
|
||||
if (penaltyPayments.size() > 0) {
|
||||
this.helper.createAccrualBasedJournalEntriesAndReversalsForSavingsCharges(office, currencyCode,
|
||||
AccrualAccountsForSavings.OVERDRAFT_PORTFOLIO_CONTROL, AccrualAccountsForSavings.INCOME_FROM_PENALTIES,
|
||||
savingsProductId, paymentTypeId, savingsId, transactionId, transactionDate, overdraftAmount, isReversal,
|
||||
penaltyPayments);
|
||||
if (isPositive) {
|
||||
this.helper.createAccrualBasedJournalEntriesAndReversalsForSavingsCharges(office, currencyCode,
|
||||
AccrualAccountsForSavings.SAVINGS_CONTROL, AccrualAccountsForSavings.INCOME_FROM_PENALTIES,
|
||||
savingsProductId, paymentTypeId, savingsId, transactionId, transactionDate,
|
||||
amount.subtract(overdraftAmount), isReversal, penaltyPayments);
|
||||
}
|
||||
} else {
|
||||
this.helper.createAccrualBasedJournalEntriesAndReversalsForSavingsCharges(office, currencyCode,
|
||||
AccrualAccountsForSavings.OVERDRAFT_PORTFOLIO_CONTROL, AccrualAccountsForSavings.INCOME_FROM_FEES,
|
||||
savingsProductId, paymentTypeId, savingsId, transactionId, transactionDate, overdraftAmount, isReversal,
|
||||
feePayments);
|
||||
if (isPositive) {
|
||||
this.helper.createAccrualBasedJournalEntriesAndReversalsForSavingsCharges(office, currencyCode,
|
||||
AccrualAccountsForSavings.SAVINGS_CONTROL, AccrualAccountsForSavings.INCOME_FROM_FEES, savingsProductId,
|
||||
paymentTypeId, savingsId, transactionId, transactionDate, amount.subtract(overdraftAmount), isReversal,
|
||||
feePayments);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
else if (savingsTransactionDTO.getTransactionType().isFeeDeduction()) {
|
||||
// Is the Charge a penalty?
|
||||
if (penaltyPayments.size() > 0) {
|
||||
this.helper.createAccrualBasedJournalEntriesAndReversalsForSavingsCharges(office, currencyCode,
|
||||
AccrualAccountsForSavings.SAVINGS_CONTROL, AccrualAccountsForSavings.INCOME_FROM_PENALTIES, savingsProductId,
|
||||
paymentTypeId, savingsId, transactionId, transactionDate, amount, isReversal, penaltyPayments);
|
||||
} else {
|
||||
this.helper.createAccrualBasedJournalEntriesAndReversalsForSavingsCharges(office, currencyCode,
|
||||
AccrualAccountsForSavings.SAVINGS_CONTROL, AccrualAccountsForSavings.INCOME_FROM_FEES, savingsProductId,
|
||||
paymentTypeId, savingsId, transactionId, transactionDate, amount, isReversal, feePayments);
|
||||
}
|
||||
}
|
||||
|
||||
/** Handle Transfers proposal **/
|
||||
else if (savingsTransactionDTO.getTransactionType().isInitiateTransfer()) {
|
||||
this.helper.createCashBasedJournalEntriesAndReversalsForSavings(office, currencyCode,
|
||||
AccrualAccountsForSavings.SAVINGS_CONTROL.getValue(), AccrualAccountsForSavings.TRANSFERS_SUSPENSE.getValue(),
|
||||
savingsProductId, paymentTypeId, savingsId, transactionId, transactionDate, amount, isReversal);
|
||||
}
|
||||
|
||||
/** Handle Transfer Withdrawal or Acceptance **/
|
||||
else if (savingsTransactionDTO.getTransactionType().isWithdrawTransfer()
|
||||
|| savingsTransactionDTO.getTransactionType().isApproveTransfer()) {
|
||||
this.helper.createCashBasedJournalEntriesAndReversalsForSavings(office, currencyCode,
|
||||
AccrualAccountsForSavings.TRANSFERS_SUSPENSE.getValue(), AccrualAccountsForSavings.SAVINGS_CONTROL.getValue(),
|
||||
savingsProductId, paymentTypeId, savingsId, transactionId, transactionDate, amount, isReversal);
|
||||
}
|
||||
|
||||
/** overdraft **/
|
||||
else if (savingsTransactionDTO.getTransactionType().isOverdraftInterest()) {
|
||||
this.helper.createCashBasedJournalEntriesAndReversalsForSavings(office, currencyCode,
|
||||
AccrualAccountsForSavings.SAVINGS_REFERENCE.getValue(), AccrualAccountsForSavings.INCOME_FROM_INTEREST.getValue(),
|
||||
savingsProductId, paymentTypeId, savingsId, transactionId, transactionDate, amount, isReversal);
|
||||
} else if (savingsTransactionDTO.getTransactionType().isWrittenoff()) {
|
||||
this.helper.createCashBasedJournalEntriesAndReversalsForSavings(office, currencyCode,
|
||||
AccrualAccountsForSavings.LOSSES_WRITTEN_OFF.getValue(),
|
||||
AccrualAccountsForSavings.OVERDRAFT_PORTFOLIO_CONTROL.getValue(), savingsProductId, paymentTypeId, savingsId,
|
||||
transactionId, transactionDate, amount, isReversal);
|
||||
} else if (savingsTransactionDTO.getTransactionType().isOverdraftFee()) {
|
||||
this.helper.createAccrualBasedJournalEntriesAndReversalsForSavingsCharges(office, currencyCode,
|
||||
AccrualAccountsForSavings.SAVINGS_REFERENCE, AccrualAccountsForSavings.INCOME_FROM_FEES, savingsProductId,
|
||||
paymentTypeId, savingsId, transactionId, transactionDate, amount, isReversal, feePayments);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
/**
|
||||
* 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.accounting.journalentry.service;
|
||||
|
||||
import java.math.BigDecimal;
|
||||
import java.time.LocalDate;
|
||||
import java.util.List;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import org.apache.fineract.accounting.closure.domain.GLClosure;
|
||||
import org.apache.fineract.accounting.common.AccountingConstants.AccrualAccountsForSavings;
|
||||
import org.apache.fineract.accounting.common.AccountingConstants.FinancialActivity;
|
||||
import org.apache.fineract.accounting.journalentry.data.ChargePaymentDTO;
|
||||
import org.apache.fineract.accounting.journalentry.data.SavingsDTO;
|
||||
import org.apache.fineract.accounting.journalentry.data.SavingsTransactionDTO;
|
||||
import org.apache.fineract.infrastructure.core.service.MathUtil;
|
||||
import org.apache.fineract.organisation.office.domain.Office;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
@Component
|
||||
@RequiredArgsConstructor
|
||||
public class AccrualBasedAccountingProcessorForSavings implements AccountingProcessorForSavings {
|
||||
|
||||
private final AccountingProcessorHelper helper;
|
||||
|
||||
@Override
|
||||
public void createJournalEntriesForSavings(final SavingsDTO savingsDTO) {
|
||||
AccountingProcessorHelper.setDepositAccountTypeContext(savingsDTO.getDepositAccountType());
|
||||
try {
|
||||
final GLClosure latestGLClosure = this.helper.getLatestClosureByBranch(savingsDTO.getOfficeId());
|
||||
final Long savingsProductId = savingsDTO.getSavingsProductId();
|
||||
final Long savingsId = savingsDTO.getSavingsId();
|
||||
final String currencyCode = savingsDTO.getCurrencyCode();
|
||||
for (final SavingsTransactionDTO savingsTransactionDTO : savingsDTO.getNewSavingsTransactions()) {
|
||||
final LocalDate transactionDate = savingsTransactionDTO.getTransactionDate();
|
||||
final String transactionId = savingsTransactionDTO.getTransactionId();
|
||||
final Office office = this.helper.getOfficeById(savingsTransactionDTO.getOfficeId());
|
||||
final Long paymentTypeId = savingsTransactionDTO.getPaymentTypeId();
|
||||
final boolean isReversal = savingsTransactionDTO.isReversed();
|
||||
final BigDecimal amount = savingsTransactionDTO.getAmount();
|
||||
final BigDecimal overdraftAmount = savingsTransactionDTO.getOverdraftAmount();
|
||||
final List<ChargePaymentDTO> feePayments = savingsTransactionDTO.getFeePayments();
|
||||
final List<ChargePaymentDTO> penaltyPayments = savingsTransactionDTO.getPenaltyPayments();
|
||||
|
||||
this.helper.checkForBranchClosures(latestGLClosure, transactionDate);
|
||||
|
||||
if (savingsTransactionDTO.getTransactionType().isWithdrawal() && savingsTransactionDTO.isOverdraftTransaction()) {
|
||||
boolean isPositive = amount.subtract(overdraftAmount).compareTo(BigDecimal.ZERO) > 0;
|
||||
if (savingsTransactionDTO.isAccountTransfer()) {
|
||||
this.helper.createCashBasedJournalEntriesAndReversalsForSavings(office, currencyCode,
|
||||
AccrualAccountsForSavings.OVERDRAFT_PORTFOLIO_CONTROL.getValue(),
|
||||
FinancialActivity.LIABILITY_TRANSFER.getValue(), savingsProductId, paymentTypeId, savingsId, transactionId,
|
||||
transactionDate, overdraftAmount, isReversal);
|
||||
if (isPositive) {
|
||||
this.helper.createCashBasedJournalEntriesAndReversalsForSavings(office, currencyCode,
|
||||
AccrualAccountsForSavings.SAVINGS_CONTROL.getValue(), FinancialActivity.LIABILITY_TRANSFER.getValue(),
|
||||
savingsProductId, paymentTypeId, savingsId, transactionId, transactionDate,
|
||||
amount.subtract(overdraftAmount), isReversal);
|
||||
}
|
||||
} else {
|
||||
this.helper.createCashBasedJournalEntriesAndReversalsForSavings(office, currencyCode,
|
||||
AccrualAccountsForSavings.OVERDRAFT_PORTFOLIO_CONTROL.getValue(),
|
||||
AccrualAccountsForSavings.SAVINGS_REFERENCE.getValue(), savingsProductId, paymentTypeId, savingsId,
|
||||
transactionId, transactionDate, overdraftAmount, isReversal);
|
||||
if (isPositive) {
|
||||
this.helper.createCashBasedJournalEntriesAndReversalsForSavings(office, currencyCode,
|
||||
AccrualAccountsForSavings.SAVINGS_CONTROL.getValue(),
|
||||
AccrualAccountsForSavings.SAVINGS_REFERENCE.getValue(), savingsProductId, paymentTypeId, savingsId,
|
||||
transactionId, transactionDate, amount.subtract(overdraftAmount), isReversal);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
else if (savingsTransactionDTO.getTransactionType().isDeposit() && savingsTransactionDTO.isOverdraftTransaction()) {
|
||||
boolean isPositive = amount.subtract(overdraftAmount).compareTo(BigDecimal.ZERO) > 0;
|
||||
if (savingsTransactionDTO.isAccountTransfer()) {
|
||||
this.helper.createCashBasedJournalEntriesAndReversalsForSavings(office, currencyCode,
|
||||
FinancialActivity.LIABILITY_TRANSFER.getValue(),
|
||||
AccrualAccountsForSavings.OVERDRAFT_PORTFOLIO_CONTROL.getValue(), savingsProductId, paymentTypeId, savingsId,
|
||||
transactionId, transactionDate, overdraftAmount, isReversal);
|
||||
if (isPositive) {
|
||||
this.helper.createCashBasedJournalEntriesAndReversalsForSavings(office, currencyCode,
|
||||
FinancialActivity.LIABILITY_TRANSFER.getValue(), AccrualAccountsForSavings.SAVINGS_CONTROL.getValue(),
|
||||
savingsProductId, paymentTypeId, savingsId, transactionId, transactionDate,
|
||||
amount.subtract(overdraftAmount), isReversal);
|
||||
}
|
||||
} else {
|
||||
this.helper.createCashBasedJournalEntriesAndReversalsForSavings(office, currencyCode,
|
||||
AccrualAccountsForSavings.SAVINGS_REFERENCE.getValue(),
|
||||
AccrualAccountsForSavings.OVERDRAFT_PORTFOLIO_CONTROL.getValue(), savingsProductId, paymentTypeId, savingsId,
|
||||
transactionId, transactionDate, overdraftAmount, isReversal);
|
||||
if (isPositive) {
|
||||
this.helper.createCashBasedJournalEntriesAndReversalsForSavings(office, currencyCode,
|
||||
AccrualAccountsForSavings.SAVINGS_REFERENCE.getValue(),
|
||||
AccrualAccountsForSavings.SAVINGS_CONTROL.getValue(), savingsProductId, paymentTypeId, savingsId,
|
||||
transactionId, transactionDate, amount.subtract(overdraftAmount), isReversal);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/** Handle Deposits and reversals of deposits **/
|
||||
else if (savingsTransactionDTO.getTransactionType().isDeposit()) {
|
||||
if (savingsTransactionDTO.isAccountTransfer()) {
|
||||
this.helper.createCashBasedJournalEntriesAndReversalsForSavings(office, currencyCode,
|
||||
FinancialActivity.LIABILITY_TRANSFER.getValue(), AccrualAccountsForSavings.SAVINGS_CONTROL.getValue(),
|
||||
savingsProductId, paymentTypeId, savingsId, transactionId, transactionDate, amount, isReversal);
|
||||
} else {
|
||||
this.helper.createCashBasedJournalEntriesAndReversalsForSavings(office, currencyCode,
|
||||
AccrualAccountsForSavings.SAVINGS_REFERENCE.getValue(), AccrualAccountsForSavings.SAVINGS_CONTROL.getValue(),
|
||||
savingsProductId, paymentTypeId, savingsId, transactionId, transactionDate, amount, isReversal);
|
||||
}
|
||||
}
|
||||
|
||||
/** Handle Deposits and reversals of Dividend pay outs **/
|
||||
else if (savingsTransactionDTO.getTransactionType().isDividendPayout()) {
|
||||
this.helper.createCashBasedJournalEntriesAndReversalsForSavings(office, currencyCode,
|
||||
FinancialActivity.PAYABLE_DIVIDENDS.getValue(), AccrualAccountsForSavings.SAVINGS_CONTROL.getValue(),
|
||||
savingsProductId, paymentTypeId, savingsId, transactionId, transactionDate, amount, isReversal);
|
||||
}
|
||||
|
||||
/** Handle withdrawals and reversals of withdrawals **/
|
||||
else if (savingsTransactionDTO.getTransactionType().isWithdrawal()) {
|
||||
if (savingsTransactionDTO.isAccountTransfer()) {
|
||||
this.helper.createCashBasedJournalEntriesAndReversalsForSavings(office, currencyCode,
|
||||
AccrualAccountsForSavings.SAVINGS_CONTROL.getValue(), FinancialActivity.LIABILITY_TRANSFER.getValue(),
|
||||
savingsProductId, paymentTypeId, savingsId, transactionId, transactionDate, amount, isReversal);
|
||||
} else {
|
||||
this.helper.createCashBasedJournalEntriesAndReversalsForSavings(office, currencyCode,
|
||||
AccrualAccountsForSavings.SAVINGS_CONTROL.getValue(), AccrualAccountsForSavings.SAVINGS_REFERENCE.getValue(),
|
||||
savingsProductId, paymentTypeId, savingsId, transactionId, transactionDate, amount, isReversal);
|
||||
}
|
||||
}
|
||||
|
||||
else if (savingsTransactionDTO.getTransactionType().isEscheat()) {
|
||||
this.helper.createCashBasedJournalEntriesAndReversalsForSavings(office, currencyCode,
|
||||
AccrualAccountsForSavings.SAVINGS_CONTROL.getValue(), AccrualAccountsForSavings.ESCHEAT_LIABILITY.getValue(),
|
||||
savingsProductId, paymentTypeId, savingsId, transactionId, transactionDate, amount, isReversal);
|
||||
}
|
||||
/**
|
||||
* Handle Interest Applications and reversals of Interest Applications
|
||||
**/
|
||||
else if (savingsTransactionDTO.getTransactionType().isInterestPosting() && savingsTransactionDTO.isOverdraftTransaction()) {
|
||||
boolean isPositive = amount.subtract(overdraftAmount).compareTo(BigDecimal.ZERO) > 0;
|
||||
// Post journal entry if earned interest amount is greater than
|
||||
// zero
|
||||
if (savingsTransactionDTO.getAmount().compareTo(BigDecimal.ZERO) > 0) {
|
||||
this.helper.createCashBasedJournalEntriesAndReversalsForSavings(office, currencyCode,
|
||||
AccrualAccountsForSavings.INTEREST_ON_SAVINGS.getValue(),
|
||||
AccrualAccountsForSavings.OVERDRAFT_PORTFOLIO_CONTROL.getValue(), savingsProductId, paymentTypeId, savingsId,
|
||||
transactionId, transactionDate, overdraftAmount, isReversal);
|
||||
if (isPositive) {
|
||||
this.helper.createCashBasedJournalEntriesAndReversalsForSavings(office, currencyCode,
|
||||
AccrualAccountsForSavings.INTEREST_ON_SAVINGS.getValue(),
|
||||
AccrualAccountsForSavings.SAVINGS_CONTROL.getValue(), savingsProductId, paymentTypeId, savingsId,
|
||||
transactionId, transactionDate, amount.subtract(overdraftAmount), isReversal);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
else if (savingsTransactionDTO.getTransactionType().isInterestPosting()) {
|
||||
// Post journal entry if earned interest amount is greater than
|
||||
// zero
|
||||
if (savingsTransactionDTO.getAmount().compareTo(BigDecimal.ZERO) > 0) {
|
||||
this.helper.createCashBasedJournalEntriesAndReversalsForSavings(office, currencyCode,
|
||||
AccrualAccountsForSavings.INTEREST_PAYABLE.getValue(), AccrualAccountsForSavings.SAVINGS_CONTROL.getValue(),
|
||||
savingsProductId, paymentTypeId, savingsId, transactionId, transactionDate, amount, isReversal);
|
||||
}
|
||||
}
|
||||
|
||||
else if (savingsTransactionDTO.getTransactionType().isAccrual()) {
|
||||
// Post journal entry for Accrual Recognition
|
||||
if (savingsTransactionDTO.getAmount().compareTo(BigDecimal.ZERO) > 0) {
|
||||
if (MathUtil.isGreaterThanZero(overdraftAmount)) {
|
||||
this.helper.createAccrualBasedDebitJournalEntriesAndReversalsForSavings(office, currencyCode,
|
||||
AccrualAccountsForSavings.INTEREST_ON_SAVINGS.getValue(), savingsProductId, paymentTypeId, savingsId,
|
||||
transactionId, transactionDate, amount, isReversal);
|
||||
this.helper.createAccrualBasedCreditJournalEntriesAndReversalsForSavings(office, currencyCode,
|
||||
AccrualAccountsForSavings.INTEREST_PAYABLE.getValue(), savingsProductId, paymentTypeId, savingsId,
|
||||
transactionId, transactionDate, amount, isReversal);
|
||||
} else {
|
||||
this.helper.createAccrualBasedDebitJournalEntriesAndReversalsForSavings(office, currencyCode,
|
||||
AccrualAccountsForSavings.INTEREST_RECEIVABLE.getValue(), savingsProductId, paymentTypeId, savingsId,
|
||||
transactionId, transactionDate, amount, isReversal);
|
||||
this.helper.createAccrualBasedCreditJournalEntriesAndReversalsForSavings(office, currencyCode,
|
||||
AccrualAccountsForSavings.INCOME_FROM_INTEREST.getValue(), savingsProductId, paymentTypeId, savingsId,
|
||||
transactionId, transactionDate, amount, isReversal);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
else if (savingsTransactionDTO.getTransactionType().isWithholdTax()) {
|
||||
this.helper.createAccrualBasedJournalEntriesAndReversalsForSavingsTax(office, currencyCode,
|
||||
AccrualAccountsForSavings.SAVINGS_CONTROL, AccrualAccountsForSavings.SAVINGS_REFERENCE, savingsProductId,
|
||||
paymentTypeId, savingsId, transactionId, transactionDate, amount, isReversal,
|
||||
savingsTransactionDTO.getTaxPayments());
|
||||
}
|
||||
|
||||
/** Handle Fees Deductions and reversals of Fees Deductions **/
|
||||
else if (savingsTransactionDTO.getTransactionType().isFeeDeduction() && savingsTransactionDTO.isOverdraftTransaction()) {
|
||||
boolean isPositive = amount.subtract(overdraftAmount).compareTo(BigDecimal.ZERO) > 0;
|
||||
// Is the Charge a penalty?
|
||||
if (penaltyPayments.size() > 0) {
|
||||
this.helper.createAccrualBasedJournalEntriesAndReversalsForSavingsCharges(office, currencyCode,
|
||||
AccrualAccountsForSavings.OVERDRAFT_PORTFOLIO_CONTROL, AccrualAccountsForSavings.INCOME_FROM_PENALTIES,
|
||||
savingsProductId, paymentTypeId, savingsId, transactionId, transactionDate, overdraftAmount, isReversal,
|
||||
penaltyPayments);
|
||||
if (isPositive) {
|
||||
this.helper.createAccrualBasedJournalEntriesAndReversalsForSavingsCharges(office, currencyCode,
|
||||
AccrualAccountsForSavings.SAVINGS_CONTROL, AccrualAccountsForSavings.INCOME_FROM_PENALTIES,
|
||||
savingsProductId, paymentTypeId, savingsId, transactionId, transactionDate,
|
||||
amount.subtract(overdraftAmount), isReversal, penaltyPayments);
|
||||
}
|
||||
} else {
|
||||
this.helper.createAccrualBasedJournalEntriesAndReversalsForSavingsCharges(office, currencyCode,
|
||||
AccrualAccountsForSavings.OVERDRAFT_PORTFOLIO_CONTROL, AccrualAccountsForSavings.INCOME_FROM_FEES,
|
||||
savingsProductId, paymentTypeId, savingsId, transactionId, transactionDate, overdraftAmount, isReversal,
|
||||
feePayments);
|
||||
if (isPositive) {
|
||||
this.helper.createAccrualBasedJournalEntriesAndReversalsForSavingsCharges(office, currencyCode,
|
||||
AccrualAccountsForSavings.SAVINGS_CONTROL, AccrualAccountsForSavings.INCOME_FROM_FEES, savingsProductId,
|
||||
paymentTypeId, savingsId, transactionId, transactionDate, amount.subtract(overdraftAmount), isReversal,
|
||||
feePayments);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
else if (savingsTransactionDTO.getTransactionType().isFeeDeduction()) {
|
||||
// Is the Charge a penalty?
|
||||
if (penaltyPayments.size() > 0) {
|
||||
this.helper.createAccrualBasedJournalEntriesAndReversalsForSavingsCharges(office, currencyCode,
|
||||
AccrualAccountsForSavings.SAVINGS_CONTROL, AccrualAccountsForSavings.INCOME_FROM_PENALTIES, savingsProductId,
|
||||
paymentTypeId, savingsId, transactionId, transactionDate, amount, isReversal, penaltyPayments);
|
||||
} else {
|
||||
this.helper.createAccrualBasedJournalEntriesAndReversalsForSavingsCharges(office, currencyCode,
|
||||
AccrualAccountsForSavings.SAVINGS_CONTROL, AccrualAccountsForSavings.INCOME_FROM_FEES, savingsProductId,
|
||||
paymentTypeId, savingsId, transactionId, transactionDate, amount, isReversal, feePayments);
|
||||
}
|
||||
}
|
||||
|
||||
/** Handle Transfers proposal **/
|
||||
else if (savingsTransactionDTO.getTransactionType().isInitiateTransfer()) {
|
||||
this.helper.createCashBasedJournalEntriesAndReversalsForSavings(office, currencyCode,
|
||||
AccrualAccountsForSavings.SAVINGS_CONTROL.getValue(), AccrualAccountsForSavings.TRANSFERS_SUSPENSE.getValue(),
|
||||
savingsProductId, paymentTypeId, savingsId, transactionId, transactionDate, amount, isReversal);
|
||||
}
|
||||
|
||||
/** Handle Transfer Withdrawal or Acceptance **/
|
||||
else if (savingsTransactionDTO.getTransactionType().isWithdrawTransfer()
|
||||
|| savingsTransactionDTO.getTransactionType().isApproveTransfer()) {
|
||||
this.helper.createCashBasedJournalEntriesAndReversalsForSavings(office, currencyCode,
|
||||
AccrualAccountsForSavings.TRANSFERS_SUSPENSE.getValue(), AccrualAccountsForSavings.SAVINGS_CONTROL.getValue(),
|
||||
savingsProductId, paymentTypeId, savingsId, transactionId, transactionDate, amount, isReversal);
|
||||
}
|
||||
|
||||
/** overdraft **/
|
||||
else if (savingsTransactionDTO.getTransactionType().isOverdraftInterest()) {
|
||||
this.helper.createCashBasedJournalEntriesAndReversalsForSavings(office, currencyCode,
|
||||
AccrualAccountsForSavings.SAVINGS_REFERENCE.getValue(), AccrualAccountsForSavings.INCOME_FROM_INTEREST.getValue(),
|
||||
savingsProductId, paymentTypeId, savingsId, transactionId, transactionDate, amount, isReversal);
|
||||
} else if (savingsTransactionDTO.getTransactionType().isWrittenoff()) {
|
||||
this.helper.createCashBasedJournalEntriesAndReversalsForSavings(office, currencyCode,
|
||||
AccrualAccountsForSavings.LOSSES_WRITTEN_OFF.getValue(),
|
||||
AccrualAccountsForSavings.OVERDRAFT_PORTFOLIO_CONTROL.getValue(), savingsProductId, paymentTypeId, savingsId,
|
||||
transactionId, transactionDate, amount, isReversal);
|
||||
} else if (savingsTransactionDTO.getTransactionType().isOverdraftFee()) {
|
||||
this.helper.createAccrualBasedJournalEntriesAndReversalsForSavingsCharges(office, currencyCode,
|
||||
AccrualAccountsForSavings.SAVINGS_REFERENCE, AccrualAccountsForSavings.INCOME_FROM_FEES, savingsProductId,
|
||||
paymentTypeId, savingsId, transactionId, transactionDate, amount, isReversal, feePayments);
|
||||
}
|
||||
}
|
||||
} finally {
|
||||
AccountingProcessorHelper.clearDepositAccountTypeContext();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+260
-255
@@ -1,255 +1,260 @@
|
||||
/**
|
||||
* 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.accounting.journalentry.service;
|
||||
|
||||
import java.math.BigDecimal;
|
||||
import java.time.LocalDate;
|
||||
import java.util.List;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import org.apache.fineract.accounting.closure.domain.GLClosure;
|
||||
import org.apache.fineract.accounting.common.AccountingConstants.CashAccountsForSavings;
|
||||
import org.apache.fineract.accounting.common.AccountingConstants.FinancialActivity;
|
||||
import org.apache.fineract.accounting.journalentry.data.ChargePaymentDTO;
|
||||
import org.apache.fineract.accounting.journalentry.data.SavingsDTO;
|
||||
import org.apache.fineract.accounting.journalentry.data.SavingsTransactionDTO;
|
||||
import org.apache.fineract.organisation.office.domain.Office;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
@Component
|
||||
@RequiredArgsConstructor
|
||||
public class CashBasedAccountingProcessorForSavings implements AccountingProcessorForSavings {
|
||||
|
||||
private final AccountingProcessorHelper helper;
|
||||
|
||||
@Override
|
||||
public void createJournalEntriesForSavings(final SavingsDTO savingsDTO) {
|
||||
final GLClosure latestGLClosure = this.helper.getLatestClosureByBranch(savingsDTO.getOfficeId());
|
||||
final Long savingsProductId = savingsDTO.getSavingsProductId();
|
||||
final Long savingsId = savingsDTO.getSavingsId();
|
||||
final String currencyCode = savingsDTO.getCurrencyCode();
|
||||
for (final SavingsTransactionDTO savingsTransactionDTO : savingsDTO.getNewSavingsTransactions()) {
|
||||
final LocalDate transactionDate = savingsTransactionDTO.getTransactionDate();
|
||||
final String transactionId = savingsTransactionDTO.getTransactionId();
|
||||
final Office office = this.helper.getOfficeById(savingsTransactionDTO.getOfficeId());
|
||||
final Long paymentTypeId = savingsTransactionDTO.getPaymentTypeId();
|
||||
final boolean isReversal = savingsTransactionDTO.isReversed();
|
||||
final BigDecimal amount = savingsTransactionDTO.getAmount();
|
||||
final BigDecimal overdraftAmount = savingsTransactionDTO.getOverdraftAmount();
|
||||
final List<ChargePaymentDTO> feePayments = savingsTransactionDTO.getFeePayments();
|
||||
final List<ChargePaymentDTO> penaltyPayments = savingsTransactionDTO.getPenaltyPayments();
|
||||
|
||||
this.helper.checkForBranchClosures(latestGLClosure, transactionDate);
|
||||
|
||||
if (savingsTransactionDTO.getTransactionType().isWithdrawal() && savingsTransactionDTO.isOverdraftTransaction()) {
|
||||
boolean isPositive = amount.subtract(overdraftAmount).compareTo(BigDecimal.ZERO) > 0;
|
||||
if (savingsTransactionDTO.isAccountTransfer()) {
|
||||
this.helper.createCashBasedJournalEntriesAndReversalsForSavings(office, currencyCode,
|
||||
CashAccountsForSavings.OVERDRAFT_PORTFOLIO_CONTROL.getValue(), FinancialActivity.LIABILITY_TRANSFER.getValue(),
|
||||
savingsProductId, paymentTypeId, savingsId, transactionId, transactionDate, overdraftAmount, isReversal);
|
||||
if (isPositive) {
|
||||
this.helper.createCashBasedJournalEntriesAndReversalsForSavings(office, currencyCode,
|
||||
CashAccountsForSavings.SAVINGS_CONTROL.getValue(), FinancialActivity.LIABILITY_TRANSFER.getValue(),
|
||||
savingsProductId, paymentTypeId, savingsId, transactionId, transactionDate,
|
||||
amount.subtract(overdraftAmount), isReversal);
|
||||
}
|
||||
} else {
|
||||
this.helper.createCashBasedJournalEntriesAndReversalsForSavings(office, currencyCode,
|
||||
CashAccountsForSavings.OVERDRAFT_PORTFOLIO_CONTROL.getValue(),
|
||||
CashAccountsForSavings.SAVINGS_REFERENCE.getValue(), savingsProductId, paymentTypeId, savingsId, transactionId,
|
||||
transactionDate, overdraftAmount, isReversal);
|
||||
if (isPositive) {
|
||||
this.helper.createCashBasedJournalEntriesAndReversalsForSavings(office, currencyCode,
|
||||
CashAccountsForSavings.SAVINGS_CONTROL.getValue(), CashAccountsForSavings.SAVINGS_REFERENCE.getValue(),
|
||||
savingsProductId, paymentTypeId, savingsId, transactionId, transactionDate,
|
||||
amount.subtract(overdraftAmount), isReversal);
|
||||
}
|
||||
}
|
||||
} else if (savingsTransactionDTO.getTransactionType().isDeposit() && savingsTransactionDTO.isOverdraftTransaction()) {
|
||||
boolean isPositive = amount.subtract(overdraftAmount).compareTo(BigDecimal.ZERO) > 0;
|
||||
if (savingsTransactionDTO.isAccountTransfer()) {
|
||||
this.helper.createCashBasedJournalEntriesAndReversalsForSavings(office, currencyCode,
|
||||
FinancialActivity.LIABILITY_TRANSFER.getValue(), CashAccountsForSavings.OVERDRAFT_PORTFOLIO_CONTROL.getValue(),
|
||||
savingsProductId, paymentTypeId, savingsId, transactionId, transactionDate, overdraftAmount, isReversal);
|
||||
if (isPositive) {
|
||||
this.helper.createCashBasedJournalEntriesAndReversalsForSavings(office, currencyCode,
|
||||
FinancialActivity.LIABILITY_TRANSFER.getValue(), CashAccountsForSavings.SAVINGS_CONTROL.getValue(),
|
||||
savingsProductId, paymentTypeId, savingsId, transactionId, transactionDate,
|
||||
amount.subtract(overdraftAmount), isReversal);
|
||||
}
|
||||
} else {
|
||||
this.helper.createCashBasedJournalEntriesAndReversalsForSavings(office, currencyCode,
|
||||
CashAccountsForSavings.SAVINGS_REFERENCE.getValue(),
|
||||
CashAccountsForSavings.OVERDRAFT_PORTFOLIO_CONTROL.getValue(), savingsProductId, paymentTypeId, savingsId,
|
||||
transactionId, transactionDate, overdraftAmount, isReversal);
|
||||
if (isPositive) {
|
||||
this.helper.createCashBasedJournalEntriesAndReversalsForSavings(office, currencyCode,
|
||||
CashAccountsForSavings.SAVINGS_REFERENCE.getValue(), CashAccountsForSavings.SAVINGS_CONTROL.getValue(),
|
||||
savingsProductId, paymentTypeId, savingsId, transactionId, transactionDate,
|
||||
amount.subtract(overdraftAmount), isReversal);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/** Handle Deposits and reversals of deposits **/
|
||||
else if (savingsTransactionDTO.getTransactionType().isDeposit()) {
|
||||
if (savingsTransactionDTO.isAccountTransfer()) {
|
||||
this.helper.createCashBasedJournalEntriesAndReversalsForSavings(office, currencyCode,
|
||||
FinancialActivity.LIABILITY_TRANSFER.getValue(), CashAccountsForSavings.SAVINGS_CONTROL.getValue(),
|
||||
savingsProductId, paymentTypeId, savingsId, transactionId, transactionDate, amount, isReversal);
|
||||
} else {
|
||||
this.helper.createCashBasedJournalEntriesAndReversalsForSavings(office, currencyCode,
|
||||
CashAccountsForSavings.SAVINGS_REFERENCE.getValue(), CashAccountsForSavings.SAVINGS_CONTROL.getValue(),
|
||||
savingsProductId, paymentTypeId, savingsId, transactionId, transactionDate, amount, isReversal);
|
||||
}
|
||||
}
|
||||
|
||||
/** Handle Deposits and reversals of Dividend pay outs **/
|
||||
else if (savingsTransactionDTO.getTransactionType().isDividendPayout()) {
|
||||
this.helper.createCashBasedJournalEntriesAndReversalsForSavings(office, currencyCode,
|
||||
FinancialActivity.PAYABLE_DIVIDENDS.getValue(), CashAccountsForSavings.SAVINGS_CONTROL.getValue(), savingsProductId,
|
||||
paymentTypeId, savingsId, transactionId, transactionDate, amount, isReversal);
|
||||
}
|
||||
/** Handle withdrawals and reversals of withdrawals **/
|
||||
else if (savingsTransactionDTO.getTransactionType().isWithdrawal()) {
|
||||
if (savingsTransactionDTO.isAccountTransfer()) {
|
||||
this.helper.createCashBasedJournalEntriesAndReversalsForSavings(office, currencyCode,
|
||||
CashAccountsForSavings.SAVINGS_CONTROL.getValue(), FinancialActivity.LIABILITY_TRANSFER.getValue(),
|
||||
savingsProductId, paymentTypeId, savingsId, transactionId, transactionDate, amount, isReversal);
|
||||
} else {
|
||||
this.helper.createCashBasedJournalEntriesAndReversalsForSavings(office, currencyCode,
|
||||
CashAccountsForSavings.SAVINGS_CONTROL.getValue(), CashAccountsForSavings.SAVINGS_REFERENCE.getValue(),
|
||||
savingsProductId, paymentTypeId, savingsId, transactionId, transactionDate, amount, isReversal);
|
||||
}
|
||||
}
|
||||
|
||||
else if (savingsTransactionDTO.getTransactionType().isEscheat()) {
|
||||
this.helper.createCashBasedJournalEntriesAndReversalsForSavings(office, currencyCode,
|
||||
CashAccountsForSavings.SAVINGS_CONTROL.getValue(), CashAccountsForSavings.ESCHEAT_LIABILITY.getValue(),
|
||||
savingsProductId, paymentTypeId, savingsId, transactionId, transactionDate, amount, isReversal);
|
||||
}
|
||||
/**
|
||||
* Handle Interest Applications and reversals of Interest Applications
|
||||
**/
|
||||
else if (savingsTransactionDTO.getTransactionType().isInterestPosting() && savingsTransactionDTO.isOverdraftTransaction()) {
|
||||
boolean isPositive = amount.subtract(overdraftAmount).compareTo(BigDecimal.ZERO) > 0;
|
||||
// Post journal entry if earned interest amount is greater than
|
||||
// zero
|
||||
if (savingsTransactionDTO.getAmount().compareTo(BigDecimal.ZERO) > 0) {
|
||||
this.helper.createCashBasedJournalEntriesAndReversalsForSavings(office, currencyCode,
|
||||
CashAccountsForSavings.INTEREST_ON_SAVINGS.getValue(),
|
||||
CashAccountsForSavings.OVERDRAFT_PORTFOLIO_CONTROL.getValue(), savingsProductId, paymentTypeId, savingsId,
|
||||
transactionId, transactionDate, overdraftAmount, isReversal);
|
||||
if (isPositive) {
|
||||
this.helper.createCashBasedJournalEntriesAndReversalsForSavings(office, currencyCode,
|
||||
CashAccountsForSavings.INTEREST_ON_SAVINGS.getValue(), CashAccountsForSavings.SAVINGS_CONTROL.getValue(),
|
||||
savingsProductId, paymentTypeId, savingsId, transactionId, transactionDate,
|
||||
amount.subtract(overdraftAmount), isReversal);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
else if (savingsTransactionDTO.getTransactionType().isInterestPosting()) {
|
||||
// Post journal entry if earned interest amount is greater than
|
||||
// zero
|
||||
if (savingsTransactionDTO.getAmount().compareTo(BigDecimal.ZERO) > 0) {
|
||||
this.helper.createCashBasedJournalEntriesAndReversalsForSavings(office, currencyCode,
|
||||
CashAccountsForSavings.INTEREST_ON_SAVINGS.getValue(), CashAccountsForSavings.SAVINGS_CONTROL.getValue(),
|
||||
savingsProductId, paymentTypeId, savingsId, transactionId, transactionDate, amount, isReversal);
|
||||
}
|
||||
}
|
||||
|
||||
else if (savingsTransactionDTO.getTransactionType().isWithholdTax()) {
|
||||
this.helper.createCashBasedJournalEntriesAndReversalsForSavingsTax(office, currencyCode,
|
||||
CashAccountsForSavings.SAVINGS_CONTROL, CashAccountsForSavings.SAVINGS_REFERENCE, savingsProductId, paymentTypeId,
|
||||
savingsId, transactionId, transactionDate, amount, isReversal, savingsTransactionDTO.getTaxPayments());
|
||||
}
|
||||
|
||||
/** Handle Fees Deductions and reversals of Fees Deductions **/
|
||||
else if (savingsTransactionDTO.getTransactionType().isFeeDeduction() && savingsTransactionDTO.isOverdraftTransaction()) {
|
||||
boolean isPositive = amount.subtract(overdraftAmount).compareTo(BigDecimal.ZERO) > 0;
|
||||
// Is the Charge a penalty?
|
||||
if (penaltyPayments.size() > 0) {
|
||||
this.helper.createCashBasedJournalEntriesAndReversalsForSavingsCharges(office, currencyCode,
|
||||
CashAccountsForSavings.OVERDRAFT_PORTFOLIO_CONTROL, CashAccountsForSavings.INCOME_FROM_PENALTIES,
|
||||
savingsProductId, paymentTypeId, savingsId, transactionId, transactionDate, overdraftAmount, isReversal,
|
||||
penaltyPayments);
|
||||
if (isPositive) {
|
||||
this.helper.createCashBasedJournalEntriesAndReversalsForSavingsCharges(office, currencyCode,
|
||||
CashAccountsForSavings.SAVINGS_CONTROL, CashAccountsForSavings.INCOME_FROM_PENALTIES, savingsProductId,
|
||||
paymentTypeId, savingsId, transactionId, transactionDate, amount.subtract(overdraftAmount), isReversal,
|
||||
penaltyPayments);
|
||||
}
|
||||
} else {
|
||||
this.helper.createCashBasedJournalEntriesAndReversalsForSavingsCharges(office, currencyCode,
|
||||
CashAccountsForSavings.OVERDRAFT_PORTFOLIO_CONTROL, CashAccountsForSavings.INCOME_FROM_FEES, savingsProductId,
|
||||
paymentTypeId, savingsId, transactionId, transactionDate, overdraftAmount, isReversal, feePayments);
|
||||
if (isPositive) {
|
||||
this.helper.createCashBasedJournalEntriesAndReversalsForSavingsCharges(office, currencyCode,
|
||||
CashAccountsForSavings.SAVINGS_CONTROL, CashAccountsForSavings.INCOME_FROM_FEES, savingsProductId,
|
||||
paymentTypeId, savingsId, transactionId, transactionDate, amount.subtract(overdraftAmount), isReversal,
|
||||
feePayments);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
else if (savingsTransactionDTO.getTransactionType().isFeeDeduction()) {
|
||||
// Is the Charge a penalty?
|
||||
if (penaltyPayments.size() > 0) {
|
||||
this.helper.createCashBasedJournalEntriesAndReversalsForSavingsCharges(office, currencyCode,
|
||||
CashAccountsForSavings.SAVINGS_CONTROL, CashAccountsForSavings.INCOME_FROM_PENALTIES, savingsProductId,
|
||||
paymentTypeId, savingsId, transactionId, transactionDate, amount, isReversal, penaltyPayments);
|
||||
} else {
|
||||
this.helper.createCashBasedJournalEntriesAndReversalsForSavingsCharges(office, currencyCode,
|
||||
CashAccountsForSavings.SAVINGS_CONTROL, CashAccountsForSavings.INCOME_FROM_FEES, savingsProductId,
|
||||
paymentTypeId, savingsId, transactionId, transactionDate, amount, isReversal, feePayments);
|
||||
}
|
||||
}
|
||||
|
||||
/** Handle Transfers proposal **/
|
||||
else if (savingsTransactionDTO.getTransactionType().isInitiateTransfer()) {
|
||||
this.helper.createCashBasedJournalEntriesAndReversalsForSavings(office, currencyCode,
|
||||
CashAccountsForSavings.SAVINGS_CONTROL.getValue(), CashAccountsForSavings.TRANSFERS_SUSPENSE.getValue(),
|
||||
savingsProductId, paymentTypeId, savingsId, transactionId, transactionDate, amount, isReversal);
|
||||
}
|
||||
|
||||
/** Handle Transfer Withdrawal or Acceptance **/
|
||||
else if (savingsTransactionDTO.getTransactionType().isWithdrawTransfer()
|
||||
|| savingsTransactionDTO.getTransactionType().isApproveTransfer()) {
|
||||
this.helper.createCashBasedJournalEntriesAndReversalsForSavings(office, currencyCode,
|
||||
CashAccountsForSavings.TRANSFERS_SUSPENSE.getValue(), CashAccountsForSavings.SAVINGS_CONTROL.getValue(),
|
||||
savingsProductId, paymentTypeId, savingsId, transactionId, transactionDate, amount, isReversal);
|
||||
}
|
||||
|
||||
/** overdraft **/
|
||||
else if (savingsTransactionDTO.getTransactionType().isOverdraftInterest()) {
|
||||
this.helper.createCashBasedJournalEntriesAndReversalsForSavings(office, currencyCode,
|
||||
CashAccountsForSavings.SAVINGS_REFERENCE.getValue(), CashAccountsForSavings.INCOME_FROM_INTEREST.getValue(),
|
||||
savingsProductId, paymentTypeId, savingsId, transactionId, transactionDate, amount, isReversal);
|
||||
} else if (savingsTransactionDTO.getTransactionType().isWrittenoff()) {
|
||||
this.helper.createCashBasedJournalEntriesAndReversalsForSavings(office, currencyCode,
|
||||
CashAccountsForSavings.LOSSES_WRITTEN_OFF.getValue(), CashAccountsForSavings.OVERDRAFT_PORTFOLIO_CONTROL.getValue(),
|
||||
savingsProductId, paymentTypeId, savingsId, transactionId, transactionDate, amount, isReversal);
|
||||
} else if (savingsTransactionDTO.getTransactionType().isOverdraftFee()) {
|
||||
this.helper.createCashBasedJournalEntriesAndReversalsForSavingsCharges(office, currencyCode,
|
||||
CashAccountsForSavings.SAVINGS_REFERENCE, CashAccountsForSavings.INCOME_FROM_FEES, savingsProductId, paymentTypeId,
|
||||
savingsId, transactionId, transactionDate, amount, isReversal, feePayments);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
/**
|
||||
* 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.accounting.journalentry.service;
|
||||
|
||||
import java.math.BigDecimal;
|
||||
import java.time.LocalDate;
|
||||
import java.util.List;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import org.apache.fineract.accounting.closure.domain.GLClosure;
|
||||
import org.apache.fineract.accounting.common.AccountingConstants.CashAccountsForSavings;
|
||||
import org.apache.fineract.accounting.common.AccountingConstants.FinancialActivity;
|
||||
import org.apache.fineract.accounting.journalentry.data.ChargePaymentDTO;
|
||||
import org.apache.fineract.accounting.journalentry.data.SavingsDTO;
|
||||
import org.apache.fineract.accounting.journalentry.data.SavingsTransactionDTO;
|
||||
import org.apache.fineract.organisation.office.domain.Office;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
@Component
|
||||
@RequiredArgsConstructor
|
||||
public class CashBasedAccountingProcessorForSavings implements AccountingProcessorForSavings {
|
||||
|
||||
private final AccountingProcessorHelper helper;
|
||||
|
||||
@Override
|
||||
public void createJournalEntriesForSavings(final SavingsDTO savingsDTO) {
|
||||
AccountingProcessorHelper.setDepositAccountTypeContext(savingsDTO.getDepositAccountType());
|
||||
try {
|
||||
final GLClosure latestGLClosure = this.helper.getLatestClosureByBranch(savingsDTO.getOfficeId());
|
||||
final Long savingsProductId = savingsDTO.getSavingsProductId();
|
||||
final Long savingsId = savingsDTO.getSavingsId();
|
||||
final String currencyCode = savingsDTO.getCurrencyCode();
|
||||
for (final SavingsTransactionDTO savingsTransactionDTO : savingsDTO.getNewSavingsTransactions()) {
|
||||
final LocalDate transactionDate = savingsTransactionDTO.getTransactionDate();
|
||||
final String transactionId = savingsTransactionDTO.getTransactionId();
|
||||
final Office office = this.helper.getOfficeById(savingsTransactionDTO.getOfficeId());
|
||||
final Long paymentTypeId = savingsTransactionDTO.getPaymentTypeId();
|
||||
final boolean isReversal = savingsTransactionDTO.isReversed();
|
||||
final BigDecimal amount = savingsTransactionDTO.getAmount();
|
||||
final BigDecimal overdraftAmount = savingsTransactionDTO.getOverdraftAmount();
|
||||
final List<ChargePaymentDTO> feePayments = savingsTransactionDTO.getFeePayments();
|
||||
final List<ChargePaymentDTO> penaltyPayments = savingsTransactionDTO.getPenaltyPayments();
|
||||
|
||||
this.helper.checkForBranchClosures(latestGLClosure, transactionDate);
|
||||
|
||||
if (savingsTransactionDTO.getTransactionType().isWithdrawal() && savingsTransactionDTO.isOverdraftTransaction()) {
|
||||
boolean isPositive = amount.subtract(overdraftAmount).compareTo(BigDecimal.ZERO) > 0;
|
||||
if (savingsTransactionDTO.isAccountTransfer()) {
|
||||
this.helper.createCashBasedJournalEntriesAndReversalsForSavings(office, currencyCode,
|
||||
CashAccountsForSavings.OVERDRAFT_PORTFOLIO_CONTROL.getValue(), FinancialActivity.LIABILITY_TRANSFER.getValue(),
|
||||
savingsProductId, paymentTypeId, savingsId, transactionId, transactionDate, overdraftAmount, isReversal);
|
||||
if (isPositive) {
|
||||
this.helper.createCashBasedJournalEntriesAndReversalsForSavings(office, currencyCode,
|
||||
CashAccountsForSavings.SAVINGS_CONTROL.getValue(), FinancialActivity.LIABILITY_TRANSFER.getValue(),
|
||||
savingsProductId, paymentTypeId, savingsId, transactionId, transactionDate,
|
||||
amount.subtract(overdraftAmount), isReversal);
|
||||
}
|
||||
} else {
|
||||
this.helper.createCashBasedJournalEntriesAndReversalsForSavings(office, currencyCode,
|
||||
CashAccountsForSavings.OVERDRAFT_PORTFOLIO_CONTROL.getValue(),
|
||||
CashAccountsForSavings.SAVINGS_REFERENCE.getValue(), savingsProductId, paymentTypeId, savingsId, transactionId,
|
||||
transactionDate, overdraftAmount, isReversal);
|
||||
if (isPositive) {
|
||||
this.helper.createCashBasedJournalEntriesAndReversalsForSavings(office, currencyCode,
|
||||
CashAccountsForSavings.SAVINGS_CONTROL.getValue(), CashAccountsForSavings.SAVINGS_REFERENCE.getValue(),
|
||||
savingsProductId, paymentTypeId, savingsId, transactionId, transactionDate,
|
||||
amount.subtract(overdraftAmount), isReversal);
|
||||
}
|
||||
}
|
||||
} else if (savingsTransactionDTO.getTransactionType().isDeposit() && savingsTransactionDTO.isOverdraftTransaction()) {
|
||||
boolean isPositive = amount.subtract(overdraftAmount).compareTo(BigDecimal.ZERO) > 0;
|
||||
if (savingsTransactionDTO.isAccountTransfer()) {
|
||||
this.helper.createCashBasedJournalEntriesAndReversalsForSavings(office, currencyCode,
|
||||
FinancialActivity.LIABILITY_TRANSFER.getValue(), CashAccountsForSavings.OVERDRAFT_PORTFOLIO_CONTROL.getValue(),
|
||||
savingsProductId, paymentTypeId, savingsId, transactionId, transactionDate, overdraftAmount, isReversal);
|
||||
if (isPositive) {
|
||||
this.helper.createCashBasedJournalEntriesAndReversalsForSavings(office, currencyCode,
|
||||
FinancialActivity.LIABILITY_TRANSFER.getValue(), CashAccountsForSavings.SAVINGS_CONTROL.getValue(),
|
||||
savingsProductId, paymentTypeId, savingsId, transactionId, transactionDate,
|
||||
amount.subtract(overdraftAmount), isReversal);
|
||||
}
|
||||
} else {
|
||||
this.helper.createCashBasedJournalEntriesAndReversalsForSavings(office, currencyCode,
|
||||
CashAccountsForSavings.SAVINGS_REFERENCE.getValue(),
|
||||
CashAccountsForSavings.OVERDRAFT_PORTFOLIO_CONTROL.getValue(), savingsProductId, paymentTypeId, savingsId,
|
||||
transactionId, transactionDate, overdraftAmount, isReversal);
|
||||
if (isPositive) {
|
||||
this.helper.createCashBasedJournalEntriesAndReversalsForSavings(office, currencyCode,
|
||||
CashAccountsForSavings.SAVINGS_REFERENCE.getValue(), CashAccountsForSavings.SAVINGS_CONTROL.getValue(),
|
||||
savingsProductId, paymentTypeId, savingsId, transactionId, transactionDate,
|
||||
amount.subtract(overdraftAmount), isReversal);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/** Handle Deposits and reversals of deposits **/
|
||||
else if (savingsTransactionDTO.getTransactionType().isDeposit()) {
|
||||
if (savingsTransactionDTO.isAccountTransfer()) {
|
||||
this.helper.createCashBasedJournalEntriesAndReversalsForSavings(office, currencyCode,
|
||||
FinancialActivity.LIABILITY_TRANSFER.getValue(), CashAccountsForSavings.SAVINGS_CONTROL.getValue(),
|
||||
savingsProductId, paymentTypeId, savingsId, transactionId, transactionDate, amount, isReversal);
|
||||
} else {
|
||||
this.helper.createCashBasedJournalEntriesAndReversalsForSavings(office, currencyCode,
|
||||
CashAccountsForSavings.SAVINGS_REFERENCE.getValue(), CashAccountsForSavings.SAVINGS_CONTROL.getValue(),
|
||||
savingsProductId, paymentTypeId, savingsId, transactionId, transactionDate, amount, isReversal);
|
||||
}
|
||||
}
|
||||
|
||||
/** Handle Deposits and reversals of Dividend pay outs **/
|
||||
else if (savingsTransactionDTO.getTransactionType().isDividendPayout()) {
|
||||
this.helper.createCashBasedJournalEntriesAndReversalsForSavings(office, currencyCode,
|
||||
FinancialActivity.PAYABLE_DIVIDENDS.getValue(), CashAccountsForSavings.SAVINGS_CONTROL.getValue(), savingsProductId,
|
||||
paymentTypeId, savingsId, transactionId, transactionDate, amount, isReversal);
|
||||
}
|
||||
/** Handle withdrawals and reversals of withdrawals **/
|
||||
else if (savingsTransactionDTO.getTransactionType().isWithdrawal()) {
|
||||
if (savingsTransactionDTO.isAccountTransfer()) {
|
||||
this.helper.createCashBasedJournalEntriesAndReversalsForSavings(office, currencyCode,
|
||||
CashAccountsForSavings.SAVINGS_CONTROL.getValue(), FinancialActivity.LIABILITY_TRANSFER.getValue(),
|
||||
savingsProductId, paymentTypeId, savingsId, transactionId, transactionDate, amount, isReversal);
|
||||
} else {
|
||||
this.helper.createCashBasedJournalEntriesAndReversalsForSavings(office, currencyCode,
|
||||
CashAccountsForSavings.SAVINGS_CONTROL.getValue(), CashAccountsForSavings.SAVINGS_REFERENCE.getValue(),
|
||||
savingsProductId, paymentTypeId, savingsId, transactionId, transactionDate, amount, isReversal);
|
||||
}
|
||||
}
|
||||
|
||||
else if (savingsTransactionDTO.getTransactionType().isEscheat()) {
|
||||
this.helper.createCashBasedJournalEntriesAndReversalsForSavings(office, currencyCode,
|
||||
CashAccountsForSavings.SAVINGS_CONTROL.getValue(), CashAccountsForSavings.ESCHEAT_LIABILITY.getValue(),
|
||||
savingsProductId, paymentTypeId, savingsId, transactionId, transactionDate, amount, isReversal);
|
||||
}
|
||||
/**
|
||||
* Handle Interest Applications and reversals of Interest Applications
|
||||
**/
|
||||
else if (savingsTransactionDTO.getTransactionType().isInterestPosting() && savingsTransactionDTO.isOverdraftTransaction()) {
|
||||
boolean isPositive = amount.subtract(overdraftAmount).compareTo(BigDecimal.ZERO) > 0;
|
||||
// Post journal entry if earned interest amount is greater than
|
||||
// zero
|
||||
if (savingsTransactionDTO.getAmount().compareTo(BigDecimal.ZERO) > 0) {
|
||||
this.helper.createCashBasedJournalEntriesAndReversalsForSavings(office, currencyCode,
|
||||
CashAccountsForSavings.INTEREST_ON_SAVINGS.getValue(),
|
||||
CashAccountsForSavings.OVERDRAFT_PORTFOLIO_CONTROL.getValue(), savingsProductId, paymentTypeId, savingsId,
|
||||
transactionId, transactionDate, overdraftAmount, isReversal);
|
||||
if (isPositive) {
|
||||
this.helper.createCashBasedJournalEntriesAndReversalsForSavings(office, currencyCode,
|
||||
CashAccountsForSavings.INTEREST_ON_SAVINGS.getValue(), CashAccountsForSavings.SAVINGS_CONTROL.getValue(),
|
||||
savingsProductId, paymentTypeId, savingsId, transactionId, transactionDate,
|
||||
amount.subtract(overdraftAmount), isReversal);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
else if (savingsTransactionDTO.getTransactionType().isInterestPosting()) {
|
||||
// Post journal entry if earned interest amount is greater than
|
||||
// zero
|
||||
if (savingsTransactionDTO.getAmount().compareTo(BigDecimal.ZERO) > 0) {
|
||||
this.helper.createCashBasedJournalEntriesAndReversalsForSavings(office, currencyCode,
|
||||
CashAccountsForSavings.INTEREST_ON_SAVINGS.getValue(), CashAccountsForSavings.SAVINGS_CONTROL.getValue(),
|
||||
savingsProductId, paymentTypeId, savingsId, transactionId, transactionDate, amount, isReversal);
|
||||
}
|
||||
}
|
||||
|
||||
else if (savingsTransactionDTO.getTransactionType().isWithholdTax()) {
|
||||
this.helper.createCashBasedJournalEntriesAndReversalsForSavingsTax(office, currencyCode,
|
||||
CashAccountsForSavings.SAVINGS_CONTROL, CashAccountsForSavings.SAVINGS_REFERENCE, savingsProductId, paymentTypeId,
|
||||
savingsId, transactionId, transactionDate, amount, isReversal, savingsTransactionDTO.getTaxPayments());
|
||||
}
|
||||
|
||||
/** Handle Fees Deductions and reversals of Fees Deductions **/
|
||||
else if (savingsTransactionDTO.getTransactionType().isFeeDeduction() && savingsTransactionDTO.isOverdraftTransaction()) {
|
||||
boolean isPositive = amount.subtract(overdraftAmount).compareTo(BigDecimal.ZERO) > 0;
|
||||
// Is the Charge a penalty?
|
||||
if (penaltyPayments.size() > 0) {
|
||||
this.helper.createCashBasedJournalEntriesAndReversalsForSavingsCharges(office, currencyCode,
|
||||
CashAccountsForSavings.OVERDRAFT_PORTFOLIO_CONTROL, CashAccountsForSavings.INCOME_FROM_PENALTIES,
|
||||
savingsProductId, paymentTypeId, savingsId, transactionId, transactionDate, overdraftAmount, isReversal,
|
||||
penaltyPayments);
|
||||
if (isPositive) {
|
||||
this.helper.createCashBasedJournalEntriesAndReversalsForSavingsCharges(office, currencyCode,
|
||||
CashAccountsForSavings.SAVINGS_CONTROL, CashAccountsForSavings.INCOME_FROM_PENALTIES, savingsProductId,
|
||||
paymentTypeId, savingsId, transactionId, transactionDate, amount.subtract(overdraftAmount), isReversal,
|
||||
penaltyPayments);
|
||||
}
|
||||
} else {
|
||||
this.helper.createCashBasedJournalEntriesAndReversalsForSavingsCharges(office, currencyCode,
|
||||
CashAccountsForSavings.OVERDRAFT_PORTFOLIO_CONTROL, CashAccountsForSavings.INCOME_FROM_FEES, savingsProductId,
|
||||
paymentTypeId, savingsId, transactionId, transactionDate, overdraftAmount, isReversal, feePayments);
|
||||
if (isPositive) {
|
||||
this.helper.createCashBasedJournalEntriesAndReversalsForSavingsCharges(office, currencyCode,
|
||||
CashAccountsForSavings.SAVINGS_CONTROL, CashAccountsForSavings.INCOME_FROM_FEES, savingsProductId,
|
||||
paymentTypeId, savingsId, transactionId, transactionDate, amount.subtract(overdraftAmount), isReversal,
|
||||
feePayments);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
else if (savingsTransactionDTO.getTransactionType().isFeeDeduction()) {
|
||||
// Is the Charge a penalty?
|
||||
if (penaltyPayments.size() > 0) {
|
||||
this.helper.createCashBasedJournalEntriesAndReversalsForSavingsCharges(office, currencyCode,
|
||||
CashAccountsForSavings.SAVINGS_CONTROL, CashAccountsForSavings.INCOME_FROM_PENALTIES, savingsProductId,
|
||||
paymentTypeId, savingsId, transactionId, transactionDate, amount, isReversal, penaltyPayments);
|
||||
} else {
|
||||
this.helper.createCashBasedJournalEntriesAndReversalsForSavingsCharges(office, currencyCode,
|
||||
CashAccountsForSavings.SAVINGS_CONTROL, CashAccountsForSavings.INCOME_FROM_FEES, savingsProductId,
|
||||
paymentTypeId, savingsId, transactionId, transactionDate, amount, isReversal, feePayments);
|
||||
}
|
||||
}
|
||||
|
||||
/** Handle Transfers proposal **/
|
||||
else if (savingsTransactionDTO.getTransactionType().isInitiateTransfer()) {
|
||||
this.helper.createCashBasedJournalEntriesAndReversalsForSavings(office, currencyCode,
|
||||
CashAccountsForSavings.SAVINGS_CONTROL.getValue(), CashAccountsForSavings.TRANSFERS_SUSPENSE.getValue(),
|
||||
savingsProductId, paymentTypeId, savingsId, transactionId, transactionDate, amount, isReversal);
|
||||
}
|
||||
|
||||
/** Handle Transfer Withdrawal or Acceptance **/
|
||||
else if (savingsTransactionDTO.getTransactionType().isWithdrawTransfer()
|
||||
|| savingsTransactionDTO.getTransactionType().isApproveTransfer()) {
|
||||
this.helper.createCashBasedJournalEntriesAndReversalsForSavings(office, currencyCode,
|
||||
CashAccountsForSavings.TRANSFERS_SUSPENSE.getValue(), CashAccountsForSavings.SAVINGS_CONTROL.getValue(),
|
||||
savingsProductId, paymentTypeId, savingsId, transactionId, transactionDate, amount, isReversal);
|
||||
}
|
||||
|
||||
/** overdraft **/
|
||||
else if (savingsTransactionDTO.getTransactionType().isOverdraftInterest()) {
|
||||
this.helper.createCashBasedJournalEntriesAndReversalsForSavings(office, currencyCode,
|
||||
CashAccountsForSavings.SAVINGS_REFERENCE.getValue(), CashAccountsForSavings.INCOME_FROM_INTEREST.getValue(),
|
||||
savingsProductId, paymentTypeId, savingsId, transactionId, transactionDate, amount, isReversal);
|
||||
} else if (savingsTransactionDTO.getTransactionType().isWrittenoff()) {
|
||||
this.helper.createCashBasedJournalEntriesAndReversalsForSavings(office, currencyCode,
|
||||
CashAccountsForSavings.LOSSES_WRITTEN_OFF.getValue(), CashAccountsForSavings.OVERDRAFT_PORTFOLIO_CONTROL.getValue(),
|
||||
savingsProductId, paymentTypeId, savingsId, transactionId, transactionDate, amount, isReversal);
|
||||
} else if (savingsTransactionDTO.getTransactionType().isOverdraftFee()) {
|
||||
this.helper.createCashBasedJournalEntriesAndReversalsForSavingsCharges(office, currencyCode,
|
||||
CashAccountsForSavings.SAVINGS_REFERENCE, CashAccountsForSavings.INCOME_FROM_FEES, savingsProductId, paymentTypeId,
|
||||
savingsId, transactionId, transactionDate, amount, isReversal, feePayments);
|
||||
}
|
||||
}
|
||||
} finally {
|
||||
AccountingProcessorHelper.clearDepositAccountTypeContext();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+765
-757
File diff suppressed because it is too large
Load Diff
+285
-285
@@ -1,285 +1,285 @@
|
||||
/**
|
||||
* 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.accounting.journalentry.service;
|
||||
|
||||
import java.math.BigDecimal;
|
||||
import java.sql.ResultSet;
|
||||
import java.sql.SQLException;
|
||||
import java.time.LocalDate;
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.apache.fineract.accounting.common.AccountingEnumerations;
|
||||
import org.apache.fineract.accounting.glaccount.domain.GLAccountType;
|
||||
import org.apache.fineract.accounting.journalentry.api.JournalEntryJsonInputParams;
|
||||
import org.apache.fineract.accounting.journalentry.data.JournalEntryData;
|
||||
import org.apache.fineract.accounting.journalentry.data.JournalEntryDataValidator;
|
||||
import org.apache.fineract.accounting.journalentry.domain.JournalEntryType;
|
||||
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.data.EnumOptionData;
|
||||
import org.apache.fineract.infrastructure.core.domain.JdbcSupport;
|
||||
import org.apache.fineract.infrastructure.core.serialization.FromJsonHelper;
|
||||
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.office.domain.OfficeRepositoryWrapper;
|
||||
import org.springframework.dao.EmptyResultDataAccessException;
|
||||
import org.springframework.jdbc.core.JdbcTemplate;
|
||||
import org.springframework.jdbc.core.RowMapper;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
@Service
|
||||
@RequiredArgsConstructor
|
||||
@Slf4j
|
||||
public class JournalEntryRunningBalanceUpdateServiceImpl implements JournalEntryRunningBalanceUpdateService {
|
||||
|
||||
private final JdbcTemplate jdbcTemplate;
|
||||
|
||||
private final OfficeRepositoryWrapper officeRepositoryWrapper;
|
||||
|
||||
private final JournalEntryDataValidator dataValidator;
|
||||
|
||||
private final FromJsonHelper fromApiJsonHelper;
|
||||
private final DatabaseSpecificSQLGenerator sqlGenerator;
|
||||
|
||||
private final GLJournalEntryMapper entryMapper = new GLJournalEntryMapper();
|
||||
|
||||
private final PlatformSecurityContext platformSecurityContext;
|
||||
|
||||
@Override
|
||||
public void updateRunningBalance() {
|
||||
String dateFinder = "select MIN(je.entry_date) as entityDate from acc_gl_journal_entry je "
|
||||
+ "where je.is_running_balance_calculated=false ";
|
||||
try {
|
||||
LocalDate entityDate = this.jdbcTemplate.queryForObject(dateFinder, LocalDate.class);
|
||||
updateOrganizationRunningBalance(entityDate);
|
||||
} catch (EmptyResultDataAccessException e) {
|
||||
log.debug("No results found for updation of running balance ");
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public CommandProcessingResult updateOfficeRunningBalance(JsonCommand command) {
|
||||
this.dataValidator.validateForUpdateRunningBalance(command);
|
||||
final Long officeId = this.fromApiJsonHelper.extractLongNamed(JournalEntryJsonInputParams.OFFICE_ID.getValue(),
|
||||
command.parsedJson());
|
||||
CommandProcessingResultBuilder commandProcessingResultBuilder = new CommandProcessingResultBuilder()
|
||||
.withCommandId(command.commandId());
|
||||
if (officeId == null) {
|
||||
updateRunningBalance();
|
||||
} else {
|
||||
this.officeRepositoryWrapper.findOneWithNotFoundDetection(officeId);
|
||||
String dateFinder = "select MIN(je.entry_date) as entityDate " + "from acc_gl_journal_entry je "
|
||||
+ "where je.is_running_balance_calculated=false and je.office_id=?";
|
||||
try {
|
||||
LocalDate entityDate = this.jdbcTemplate.queryForObject(dateFinder, LocalDate.class, officeId);
|
||||
updateRunningBalance(officeId, entityDate);
|
||||
} catch (EmptyResultDataAccessException e) {
|
||||
log.debug("No results found for updation of office running balance with office id: {}", officeId);
|
||||
}
|
||||
commandProcessingResultBuilder.withOfficeId(officeId);
|
||||
}
|
||||
return commandProcessingResultBuilder.build();
|
||||
}
|
||||
|
||||
private void updateOrganizationRunningBalance(LocalDate entityDate) {
|
||||
Map<Long, BigDecimal> runningBalanceMap = new HashMap<>(5);
|
||||
Map<Long, Map<Long, BigDecimal>> officesRunningBalance = new HashMap<>();
|
||||
|
||||
final String organizationRunningBalanceQuery = "select je.organization_running_balance as runningBalance,je.account_id as accountId from acc_gl_journal_entry je "
|
||||
+ "inner join (select max(id) as id from acc_gl_journal_entry where entry_date < ? group by account_id,entry_date) je2 ON je2.id = je.id "
|
||||
+ "inner join (select max(entry_date) as date from acc_gl_journal_entry where entry_date < ? group by account_id) je3 ON je.entry_date = je3.date "
|
||||
+ "group by je.id order by je.entry_date DESC " + sqlGenerator.limit(10000, 0);
|
||||
|
||||
List<Map<String, Object>> list = jdbcTemplate.queryForList(organizationRunningBalanceQuery, // NOSONAR
|
||||
entityDate, entityDate);
|
||||
|
||||
for (Map<String, Object> entries : list) {
|
||||
Long accountId = Long.parseLong(entries.get("accountId").toString()); // Drizzle
|
||||
// is
|
||||
// returning
|
||||
// Big
|
||||
// Integer
|
||||
// where
|
||||
// as
|
||||
// MySQL
|
||||
// returns
|
||||
// Long.
|
||||
if (!runningBalanceMap.containsKey(accountId)) {
|
||||
runningBalanceMap.put(accountId, (BigDecimal) entries.get("runningBalance"));
|
||||
}
|
||||
}
|
||||
|
||||
final String offlineRunningBalanceQuery = "select je.office_running_balance as runningBalance,je.account_id as accountId,je.office_id as officeId "
|
||||
+ "from acc_gl_journal_entry je "
|
||||
+ "inner join (select max(id) as id from acc_gl_journal_entry where entry_date < ? group by office_id,account_id,entry_date) je2 ON je2.id = je.id "
|
||||
+ "inner join (select max(entry_date) as date from acc_gl_journal_entry where entry_date < ? group by office_id,account_id) je3 ON je.entry_date = je3.date "
|
||||
+ "group by je.id order by je.entry_date DESC " + sqlGenerator.limit(10000, 0);
|
||||
|
||||
List<Map<String, Object>> officesRunningBalanceList = jdbcTemplate.queryForList(offlineRunningBalanceQuery, // NOSONAR
|
||||
entityDate, entityDate);
|
||||
for (Map<String, Object> entries : officesRunningBalanceList) {
|
||||
Long accountId = Long.parseLong(entries.get("accountId").toString());
|
||||
Long officeId = Long.parseLong(entries.get("officeId").toString());
|
||||
Map<Long, BigDecimal> runningBalance;
|
||||
if (officesRunningBalance.containsKey(officeId)) {
|
||||
runningBalance = officesRunningBalance.get(officeId);
|
||||
} else {
|
||||
runningBalance = new HashMap<>();
|
||||
officesRunningBalance.put(officeId, runningBalance);
|
||||
}
|
||||
if (!runningBalance.containsKey(accountId)) {
|
||||
runningBalance.put(accountId, (BigDecimal) entries.get("runningBalance"));
|
||||
}
|
||||
}
|
||||
|
||||
List<JournalEntryData> entryDataList = jdbcTemplate.query(entryMapper.organizationRunningBalanceSchema(), entryMapper, entityDate);
|
||||
if (entryDataList.size() > 0) {
|
||||
// run a batch update of 1000 SQL statements at a time
|
||||
final int batchUpdateSize = 1000;
|
||||
List<Object[]> params = new ArrayList<>();
|
||||
int batchIndex = 0;
|
||||
String sql = "UPDATE acc_gl_journal_entry SET is_running_balance_calculated=?, organization_running_balance=?,"
|
||||
+ "office_running_balance=?, last_modified_by=?, last_modified_on_utc=? WHERE id=?";
|
||||
for (int index = 0; index < entryDataList.size(); index++) {
|
||||
JournalEntryData entryData = entryDataList.get(index);
|
||||
Map<Long, BigDecimal> officeRunningBalanceMap;
|
||||
if (officesRunningBalance.containsKey(entryData.getOfficeId())) {
|
||||
officeRunningBalanceMap = officesRunningBalance.get(entryData.getOfficeId());
|
||||
} else {
|
||||
officeRunningBalanceMap = new HashMap<>();
|
||||
officesRunningBalance.put(entryData.getOfficeId(), officeRunningBalanceMap);
|
||||
}
|
||||
BigDecimal officeRunningBalance = calculateRunningBalance(entryData, officeRunningBalanceMap);
|
||||
BigDecimal runningBalance = calculateRunningBalance(entryData, runningBalanceMap);
|
||||
|
||||
params.add(new Object[] { Boolean.TRUE, runningBalance, officeRunningBalance,
|
||||
platformSecurityContext.authenticatedUser().getId(), DateUtils.getAuditOffsetDateTime(), entryData.getId() });
|
||||
batchIndex++;
|
||||
if (batchIndex == batchUpdateSize || index == entryDataList.size() - 1) {
|
||||
this.jdbcTemplate.batchUpdate(sql, params);
|
||||
// reset counter and string array
|
||||
batchIndex = 0;
|
||||
params.clear();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private void updateRunningBalance(Long officeId, LocalDate entityDate) {
|
||||
Map<Long, BigDecimal> runningBalanceMap = new HashMap<>(5);
|
||||
|
||||
final String offlineRunningBalanceQuery = "select je.office_running_balance as runningBalance,je.account_id as accountId from acc_gl_journal_entry je "
|
||||
+ "inner join (select max(id) as id from acc_gl_journal_entry where office_id=? and entry_date < ? group by account_id,entry_date) je2 ON je2.id = je.id "
|
||||
+ "inner join (select max(entry_date) as date from acc_gl_journal_entry where office_id=? and entry_date < ? group by account_id) je3 ON je.entry_date = je3.date "
|
||||
+ "group by je.id order by je.entry_date DESC " + sqlGenerator.limit(10000, 0);
|
||||
|
||||
List<Map<String, Object>> list = jdbcTemplate.queryForList(offlineRunningBalanceQuery, // NOSONAR
|
||||
officeId, entityDate, officeId, entityDate);
|
||||
for (Map<String, Object> entries : list) {
|
||||
Long accountId = (Long) entries.get("accountId");
|
||||
if (!runningBalanceMap.containsKey(accountId)) {
|
||||
runningBalanceMap.put(accountId, (BigDecimal) entries.get("runningBalance"));
|
||||
}
|
||||
}
|
||||
List<JournalEntryData> entryDataList = jdbcTemplate.query(entryMapper.officeRunningBalanceSchema(), entryMapper, officeId,
|
||||
entityDate);
|
||||
List<Object[]> params = new ArrayList<>();
|
||||
|
||||
String sql = "UPDATE acc_gl_journal_entry SET office_running_balance=?, last_modified_by=?, last_modified_on_utc=? WHERE id=?";
|
||||
for (JournalEntryData entryData : entryDataList) {
|
||||
BigDecimal runningBalance = calculateRunningBalance(entryData, runningBalanceMap);
|
||||
params.add(new Object[] { runningBalance, platformSecurityContext.authenticatedUser().getId(),
|
||||
DateUtils.getAuditOffsetDateTime(), entryData.getId() });
|
||||
}
|
||||
this.jdbcTemplate.batchUpdate(sql, params);
|
||||
}
|
||||
|
||||
private BigDecimal calculateRunningBalance(JournalEntryData entry, Map<Long, BigDecimal> runningBalanceMap) {
|
||||
BigDecimal runningBalance = BigDecimal.ZERO;
|
||||
if (runningBalanceMap.containsKey(entry.getGlAccountId())) {
|
||||
runningBalance = runningBalanceMap.get(entry.getGlAccountId());
|
||||
}
|
||||
GLAccountType accountType = GLAccountType.fromInt(entry.getGlAccountType().getId().intValue());
|
||||
JournalEntryType entryType = JournalEntryType.fromInt(entry.getEntryType().getId().intValue());
|
||||
boolean isIncrease = false;
|
||||
switch (accountType) {
|
||||
case ASSET:
|
||||
case EXPENSE:
|
||||
if (entryType.isDebitType()) {
|
||||
isIncrease = true;
|
||||
}
|
||||
break;
|
||||
case EQUITY:
|
||||
case INCOME:
|
||||
case LIABILITY:
|
||||
if (entryType.isCreditType()) {
|
||||
isIncrease = true;
|
||||
}
|
||||
break;
|
||||
}
|
||||
if (isIncrease) {
|
||||
runningBalance = runningBalance.add(entry.getAmount());
|
||||
} else {
|
||||
runningBalance = runningBalance.subtract(entry.getAmount());
|
||||
}
|
||||
runningBalanceMap.put(entry.getGlAccountId(), runningBalance);
|
||||
return runningBalance;
|
||||
}
|
||||
|
||||
private static final class GLJournalEntryMapper implements RowMapper<JournalEntryData> {
|
||||
|
||||
public String officeRunningBalanceSchema() {
|
||||
return "select je.id as id,je.account_id as glAccountId,je.type_enum as entryType,je.amount as amount, "
|
||||
+ "glAccount.classification_enum as classification,je.office_id as officeId "
|
||||
+ "from acc_gl_journal_entry je , acc_gl_account glAccount " + "where je.account_id = glAccount.id "
|
||||
+ "and je.office_id=? and je.entry_date >= ? order by je.entry_date,je.id";
|
||||
}
|
||||
|
||||
public String organizationRunningBalanceSchema() {
|
||||
return "select je.id as id,je.account_id as glAccountId," + "je.type_enum as entryType,je.amount as amount, "
|
||||
+ "glAccount.classification_enum as classification,je.office_id as officeId "
|
||||
+ "from acc_gl_journal_entry je , acc_gl_account glAccount " + "where je.account_id = glAccount.id "
|
||||
+ "and je.entry_date >= ? order by je.entry_date,je.id";
|
||||
}
|
||||
|
||||
@Override
|
||||
public JournalEntryData mapRow(final ResultSet rs, @SuppressWarnings("unused") final int rowNum) throws SQLException {
|
||||
|
||||
final Long id = rs.getLong("id");
|
||||
final Long glAccountId = rs.getLong("glAccountId");
|
||||
final Long officeId = rs.getLong("officeId");
|
||||
final int accountTypeId = JdbcSupport.getInteger(rs, "classification");
|
||||
final EnumOptionData accountType = AccountingEnumerations.gLAccountType(accountTypeId);
|
||||
final BigDecimal amount = rs.getBigDecimal("amount");
|
||||
final int entryTypeId = JdbcSupport.getInteger(rs, "entryType");
|
||||
final EnumOptionData entryType = AccountingEnumerations.journalEntryType(entryTypeId);
|
||||
|
||||
return new JournalEntryData(id, officeId, null, null, glAccountId, null, accountType, null, entryType, amount, null, null, null,
|
||||
null, null, null, null, null, null, null, null, null, null, null, null, null);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
/**
|
||||
* 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.accounting.journalentry.service;
|
||||
|
||||
import java.math.BigDecimal;
|
||||
import java.sql.ResultSet;
|
||||
import java.sql.SQLException;
|
||||
import java.time.LocalDate;
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.apache.fineract.accounting.common.AccountingEnumerations;
|
||||
import org.apache.fineract.accounting.glaccount.domain.GLAccountType;
|
||||
import org.apache.fineract.accounting.journalentry.api.JournalEntryJsonInputParams;
|
||||
import org.apache.fineract.accounting.journalentry.data.JournalEntryData;
|
||||
import org.apache.fineract.accounting.journalentry.data.JournalEntryDataValidator;
|
||||
import org.apache.fineract.accounting.journalentry.domain.JournalEntryType;
|
||||
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.data.EnumOptionData;
|
||||
import org.apache.fineract.infrastructure.core.domain.JdbcSupport;
|
||||
import org.apache.fineract.infrastructure.core.serialization.FromJsonHelper;
|
||||
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.office.domain.OfficeRepositoryWrapper;
|
||||
import org.springframework.dao.EmptyResultDataAccessException;
|
||||
import org.springframework.jdbc.core.JdbcTemplate;
|
||||
import org.springframework.jdbc.core.RowMapper;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
@Service
|
||||
@RequiredArgsConstructor
|
||||
@Slf4j
|
||||
public class JournalEntryRunningBalanceUpdateServiceImpl implements JournalEntryRunningBalanceUpdateService {
|
||||
|
||||
private final JdbcTemplate jdbcTemplate;
|
||||
|
||||
private final OfficeRepositoryWrapper officeRepositoryWrapper;
|
||||
|
||||
private final JournalEntryDataValidator dataValidator;
|
||||
|
||||
private final FromJsonHelper fromApiJsonHelper;
|
||||
private final DatabaseSpecificSQLGenerator sqlGenerator;
|
||||
|
||||
private final GLJournalEntryMapper entryMapper = new GLJournalEntryMapper();
|
||||
|
||||
private final PlatformSecurityContext platformSecurityContext;
|
||||
|
||||
@Override
|
||||
public void updateRunningBalance() {
|
||||
String dateFinder = "select MIN(je.entry_date) as entityDate from acc_gl_journal_entry je "
|
||||
+ "where je.is_running_balance_calculated=false ";
|
||||
try {
|
||||
LocalDate entityDate = this.jdbcTemplate.queryForObject(dateFinder, LocalDate.class);
|
||||
updateOrganizationRunningBalance(entityDate);
|
||||
} catch (EmptyResultDataAccessException e) {
|
||||
log.debug("No results found for updation of running balance ");
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public CommandProcessingResult updateOfficeRunningBalance(JsonCommand command) {
|
||||
this.dataValidator.validateForUpdateRunningBalance(command);
|
||||
final Long officeId = this.fromApiJsonHelper.extractLongNamed(JournalEntryJsonInputParams.OFFICE_ID.getValue(),
|
||||
command.parsedJson());
|
||||
CommandProcessingResultBuilder commandProcessingResultBuilder = new CommandProcessingResultBuilder()
|
||||
.withCommandId(command.commandId());
|
||||
if (officeId == null) {
|
||||
updateRunningBalance();
|
||||
} else {
|
||||
this.officeRepositoryWrapper.findOneWithNotFoundDetection(officeId);
|
||||
String dateFinder = "select MIN(je.entry_date) as entityDate " + "from acc_gl_journal_entry je "
|
||||
+ "where je.is_running_balance_calculated=false and je.office_id=?";
|
||||
try {
|
||||
LocalDate entityDate = this.jdbcTemplate.queryForObject(dateFinder, LocalDate.class, officeId);
|
||||
updateRunningBalance(officeId, entityDate);
|
||||
} catch (EmptyResultDataAccessException e) {
|
||||
log.debug("No results found for updation of office running balance with office id: {}", officeId);
|
||||
}
|
||||
commandProcessingResultBuilder.withOfficeId(officeId);
|
||||
}
|
||||
return commandProcessingResultBuilder.build();
|
||||
}
|
||||
|
||||
private void updateOrganizationRunningBalance(LocalDate entityDate) {
|
||||
Map<Long, BigDecimal> runningBalanceMap = new HashMap<>(5);
|
||||
Map<Long, Map<Long, BigDecimal>> officesRunningBalance = new HashMap<>();
|
||||
|
||||
final String organizationRunningBalanceQuery = "select je.organization_running_balance as runningBalance,je.account_id as accountId from acc_gl_journal_entry je "
|
||||
+ "inner join (select max(id) as id from acc_gl_journal_entry where entry_date < ? group by account_id,entry_date) je2 ON je2.id = je.id "
|
||||
+ "inner join (select max(entry_date) as date from acc_gl_journal_entry where entry_date < ? group by account_id) je3 ON je.entry_date = je3.date "
|
||||
+ "group by je.id order by je.entry_date DESC " + sqlGenerator.limit(10000, 0);
|
||||
|
||||
List<Map<String, Object>> list = jdbcTemplate.queryForList(organizationRunningBalanceQuery, // NOSONAR
|
||||
entityDate, entityDate);
|
||||
|
||||
for (Map<String, Object> entries : list) {
|
||||
Long accountId = Long.parseLong(entries.get("accountId").toString()); // Drizzle
|
||||
// is
|
||||
// returning
|
||||
// Big
|
||||
// Integer
|
||||
// where
|
||||
// as
|
||||
// MySQL
|
||||
// returns
|
||||
// Long.
|
||||
if (!runningBalanceMap.containsKey(accountId)) {
|
||||
runningBalanceMap.put(accountId, (BigDecimal) entries.get("runningBalance"));
|
||||
}
|
||||
}
|
||||
|
||||
final String offlineRunningBalanceQuery = "select je.office_running_balance as runningBalance,je.account_id as accountId,je.office_id as officeId "
|
||||
+ "from acc_gl_journal_entry je "
|
||||
+ "inner join (select max(id) as id from acc_gl_journal_entry where entry_date < ? group by office_id,account_id,entry_date) je2 ON je2.id = je.id "
|
||||
+ "inner join (select max(entry_date) as date from acc_gl_journal_entry where entry_date < ? group by office_id,account_id) je3 ON je.entry_date = je3.date "
|
||||
+ "group by je.id order by je.entry_date DESC " + sqlGenerator.limit(10000, 0);
|
||||
|
||||
List<Map<String, Object>> officesRunningBalanceList = jdbcTemplate.queryForList(offlineRunningBalanceQuery, // NOSONAR
|
||||
entityDate, entityDate);
|
||||
for (Map<String, Object> entries : officesRunningBalanceList) {
|
||||
Long accountId = Long.parseLong(entries.get("accountId").toString());
|
||||
Long officeId = Long.parseLong(entries.get("officeId").toString());
|
||||
Map<Long, BigDecimal> runningBalance;
|
||||
if (officesRunningBalance.containsKey(officeId)) {
|
||||
runningBalance = officesRunningBalance.get(officeId);
|
||||
} else {
|
||||
runningBalance = new HashMap<>();
|
||||
officesRunningBalance.put(officeId, runningBalance);
|
||||
}
|
||||
if (!runningBalance.containsKey(accountId)) {
|
||||
runningBalance.put(accountId, (BigDecimal) entries.get("runningBalance"));
|
||||
}
|
||||
}
|
||||
|
||||
List<JournalEntryData> entryDataList = jdbcTemplate.query(entryMapper.organizationRunningBalanceSchema(), entryMapper, entityDate);
|
||||
if (entryDataList.size() > 0) {
|
||||
// run a batch update of 1000 SQL statements at a time
|
||||
final int batchUpdateSize = 1000;
|
||||
List<Object[]> params = new ArrayList<>();
|
||||
int batchIndex = 0;
|
||||
String sql = "UPDATE acc_gl_journal_entry SET is_running_balance_calculated=?, organization_running_balance=?,"
|
||||
+ "office_running_balance=?, last_modified_by=?, last_modified_on_utc=? WHERE id=?";
|
||||
for (int index = 0; index < entryDataList.size(); index++) {
|
||||
JournalEntryData entryData = entryDataList.get(index);
|
||||
Map<Long, BigDecimal> officeRunningBalanceMap;
|
||||
if (officesRunningBalance.containsKey(entryData.getOfficeId())) {
|
||||
officeRunningBalanceMap = officesRunningBalance.get(entryData.getOfficeId());
|
||||
} else {
|
||||
officeRunningBalanceMap = new HashMap<>();
|
||||
officesRunningBalance.put(entryData.getOfficeId(), officeRunningBalanceMap);
|
||||
}
|
||||
BigDecimal officeRunningBalance = calculateRunningBalance(entryData, officeRunningBalanceMap);
|
||||
BigDecimal runningBalance = calculateRunningBalance(entryData, runningBalanceMap);
|
||||
|
||||
params.add(new Object[] { Boolean.TRUE, runningBalance, officeRunningBalance,
|
||||
platformSecurityContext.authenticatedUser().getId(), DateUtils.getAuditOffsetDateTime(), entryData.getId() });
|
||||
batchIndex++;
|
||||
if (batchIndex == batchUpdateSize || index == entryDataList.size() - 1) {
|
||||
this.jdbcTemplate.batchUpdate(sql, params);
|
||||
// reset counter and string array
|
||||
batchIndex = 0;
|
||||
params.clear();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private void updateRunningBalance(Long officeId, LocalDate entityDate) {
|
||||
Map<Long, BigDecimal> runningBalanceMap = new HashMap<>(5);
|
||||
|
||||
final String offlineRunningBalanceQuery = "select je.office_running_balance as runningBalance,je.account_id as accountId from acc_gl_journal_entry je "
|
||||
+ "inner join (select max(id) as id from acc_gl_journal_entry where office_id=? and entry_date < ? group by account_id,entry_date) je2 ON je2.id = je.id "
|
||||
+ "inner join (select max(entry_date) as date from acc_gl_journal_entry where office_id=? and entry_date < ? group by account_id) je3 ON je.entry_date = je3.date "
|
||||
+ "group by je.id order by je.entry_date DESC " + sqlGenerator.limit(10000, 0);
|
||||
|
||||
List<Map<String, Object>> list = jdbcTemplate.queryForList(offlineRunningBalanceQuery, // NOSONAR
|
||||
officeId, entityDate, officeId, entityDate);
|
||||
for (Map<String, Object> entries : list) {
|
||||
Long accountId = (Long) entries.get("accountId");
|
||||
if (!runningBalanceMap.containsKey(accountId)) {
|
||||
runningBalanceMap.put(accountId, (BigDecimal) entries.get("runningBalance"));
|
||||
}
|
||||
}
|
||||
List<JournalEntryData> entryDataList = jdbcTemplate.query(entryMapper.officeRunningBalanceSchema(), entryMapper, officeId,
|
||||
entityDate);
|
||||
List<Object[]> params = new ArrayList<>();
|
||||
|
||||
String sql = "UPDATE acc_gl_journal_entry SET office_running_balance=?, last_modified_by=?, last_modified_on_utc=? WHERE id=?";
|
||||
for (JournalEntryData entryData : entryDataList) {
|
||||
BigDecimal runningBalance = calculateRunningBalance(entryData, runningBalanceMap);
|
||||
params.add(new Object[] { runningBalance, platformSecurityContext.authenticatedUser().getId(),
|
||||
DateUtils.getAuditOffsetDateTime(), entryData.getId() });
|
||||
}
|
||||
this.jdbcTemplate.batchUpdate(sql, params);
|
||||
}
|
||||
|
||||
private BigDecimal calculateRunningBalance(JournalEntryData entry, Map<Long, BigDecimal> runningBalanceMap) {
|
||||
BigDecimal runningBalance = BigDecimal.ZERO;
|
||||
if (runningBalanceMap.containsKey(entry.getGlAccountId())) {
|
||||
runningBalance = runningBalanceMap.get(entry.getGlAccountId());
|
||||
}
|
||||
GLAccountType accountType = GLAccountType.fromInt(entry.getGlAccountType().getId().intValue());
|
||||
JournalEntryType entryType = JournalEntryType.fromInt(entry.getEntryType().getId().intValue());
|
||||
boolean isIncrease = false;
|
||||
switch (accountType) {
|
||||
case ASSET:
|
||||
case EXPENSE:
|
||||
if (entryType.isDebitType()) {
|
||||
isIncrease = true;
|
||||
}
|
||||
break;
|
||||
case EQUITY:
|
||||
case INCOME:
|
||||
case LIABILITY:
|
||||
if (entryType.isCreditType()) {
|
||||
isIncrease = true;
|
||||
}
|
||||
break;
|
||||
}
|
||||
if (isIncrease) {
|
||||
runningBalance = runningBalance.add(entry.getAmount());
|
||||
} else {
|
||||
runningBalance = runningBalance.subtract(entry.getAmount());
|
||||
}
|
||||
runningBalanceMap.put(entry.getGlAccountId(), runningBalance);
|
||||
return runningBalance;
|
||||
}
|
||||
|
||||
private static final class GLJournalEntryMapper implements RowMapper<JournalEntryData> {
|
||||
|
||||
public String officeRunningBalanceSchema() {
|
||||
return "select je.id as id,je.account_id as glAccountId,je.type_enum as entryType,je.amount as amount, "
|
||||
+ "glAccount.classification_enum as classification,je.office_id as officeId "
|
||||
+ "from acc_gl_journal_entry je , acc_gl_account glAccount " + "where je.account_id = glAccount.id "
|
||||
+ "and je.office_id=? and je.entry_date >= ? order by je.entry_date,je.id";
|
||||
}
|
||||
|
||||
public String organizationRunningBalanceSchema() {
|
||||
return "select je.id as id,je.account_id as glAccountId," + "je.type_enum as entryType,je.amount as amount, "
|
||||
+ "glAccount.classification_enum as classification,je.office_id as officeId "
|
||||
+ "from acc_gl_journal_entry je , acc_gl_account glAccount " + "where je.account_id = glAccount.id "
|
||||
+ "and je.entry_date >= ? order by je.entry_date,je.id";
|
||||
}
|
||||
|
||||
@Override
|
||||
public JournalEntryData mapRow(final ResultSet rs, @SuppressWarnings("unused") final int rowNum) throws SQLException {
|
||||
|
||||
final Long id = rs.getLong("id");
|
||||
final Long glAccountId = rs.getLong("glAccountId");
|
||||
final Long officeId = rs.getLong("officeId");
|
||||
final int accountTypeId = JdbcSupport.getInteger(rs, "classification");
|
||||
final EnumOptionData accountType = AccountingEnumerations.gLAccountType(accountTypeId);
|
||||
final BigDecimal amount = rs.getBigDecimal("amount");
|
||||
final int entryTypeId = JdbcSupport.getInteger(rs, "entryType");
|
||||
final EnumOptionData entryType = AccountingEnumerations.journalEntryType(entryTypeId);
|
||||
|
||||
return new JournalEntryData(id, officeId, null, null, glAccountId, null, accountType, null, entryType, amount, null, null, null,
|
||||
null, null, null, null, null, null, null, null, null, null, null, null, null, null);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
+4044
-4043
File diff suppressed because it is too large
Load Diff
Reference in New Issue
Block a user