maektwain commented on a change in pull request #796:
URL: https://github.com/apache/fineract/pull/796#discussion_r420966063
##########
File path:
fineract-provider/src/main/java/org/apache/fineract/accounting/journalentry/service/JournalEntryWritePlatformServiceJpaRepositoryImpl.java
##########
@@ -626,6 +623,63 @@ private void saveAllDebitOrCreditEntries(final
JournalEntryCommand command, fina
}
}
+ @Transactional
+ @Override
+ public String createJournalEntryForIncomeAndExpenseBookOff(final
JournalEntryCommand journalEntryCommand) {
+ try{
+ journalEntryCommand.validateForCreate();
+
+ // check office is valid
+ final Long officeId = journalEntryCommand.getOfficeId();
+ final Office office =
this.officeRepositoryWrapper.findOneWithNotFoundDetection(officeId);
+
+ final String currencyCode = journalEntryCommand.getCurrencyCode();
+
+ validateBusinessRulesForJournalEntries(journalEntryCommand);
+ /** Capture payment details **/
+ final PaymentDetail paymentDetail =null;
+
+ /** Set a transaction Id and save these Journal entries **/
+ final Date transactionDate =
journalEntryCommand.getTransactionDate().toDate();
+ final String transactionId = generateTransactionId(officeId);
+ final String referenceNumber =
journalEntryCommand.getReferenceNumber();
+
+
debitOrCreditEntriesForIncomeAndExpenseBooking(journalEntryCommand, office,
paymentDetail, currencyCode, transactionDate,
+ journalEntryCommand.getDebits(), transactionId,
JournalEntryType.DEBIT, referenceNumber);
+
+
debitOrCreditEntriesForIncomeAndExpenseBooking(journalEntryCommand, office,
paymentDetail, currencyCode, transactionDate,
+ journalEntryCommand.getCredits(), transactionId,
JournalEntryType.CREDIT, referenceNumber);
+
+ return transactionId;
+ }catch (final DataIntegrityViolationException dve) {
+ handleJournalEntryDataIntegrityIssues(dve);
+ return null;
Review comment:
I rebased it , it did not push here, 🥇
##########
File path:
fineract-provider/src/main/java/org/apache/fineract/accounting/closure/service/CalculateIncomeAndExpenseBookingImpl.java
##########
@@ -0,0 +1,187 @@
+/**
+ * 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.closure.service;
+
+
+import java.math.BigDecimal;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Date;
+import java.util.List;
+import org.apache.fineract.accounting.closure.command.GLClosureCommand;
+import org.apache.fineract.accounting.closure.data.IncomeAndExpenseBookingData;
+import
org.apache.fineract.accounting.closure.data.IncomeAndExpenseJournalEntryData;
+import org.apache.fineract.accounting.closure.data.JournalEntryData;
+import
org.apache.fineract.accounting.closure.data.SingleDebitOrCreditEntryData;
+import org.apache.fineract.accounting.closure.domain.GLClosure;
+import org.apache.fineract.accounting.closure.domain.GLClosureRepository;
+import
org.apache.fineract.accounting.closure.exception.GLClosureInvalidException;
+import
org.apache.fineract.accounting.closure.exception.RunningBalanceNotCalculatedException;
+import
org.apache.fineract.accounting.closure.serialization.GLClosureCommandFromApiJsonDeserializer;
+import org.apache.fineract.accounting.glaccount.domain.GLAccount;
+import
org.apache.fineract.accounting.glaccount.domain.GLAccountRepositoryWrapper;
+import
org.apache.fineract.accounting.glaccount.exception.GLAccountNotFoundException;
+import org.apache.fineract.infrastructure.core.api.JsonQuery;
+import org.apache.fineract.infrastructure.core.service.DateUtils;
+import org.apache.fineract.organisation.office.domain.Office;
+import org.apache.fineract.organisation.office.domain.OfficeRepositoryWrapper;
+import
org.apache.fineract.organisation.office.exception.OfficeNotFoundException;
+import
org.apache.fineract.organisation.office.service.OfficeReadPlatformService;
+import org.joda.time.LocalDate;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Service;
+
+
+@Service
+public class CalculateIncomeAndExpenseBookingImpl implements
CalculateIncomeAndExpenseBooking {
+
+ private final GLClosureCommandFromApiJsonDeserializer
fromApiJsonDeserializer;
+ private final OfficeRepositoryWrapper officeRepository;
+ private final GLClosureRepository glClosureRepository;
+ private final GLAccountRepositoryWrapper glAccountRepository;
+ private final IncomeAndExpenseReadPlatformService
incomeAndExpenseReadPlatformService;
+ private final OfficeReadPlatformService officeReadPlatformService;
+
+ @Autowired
+ public CalculateIncomeAndExpenseBookingImpl(final
GLClosureCommandFromApiJsonDeserializer fromApiJsonDeserializer,
+ final OfficeRepositoryWrapper officeRepository,final
GLClosureRepository glClosureRepository,
+ final GLAccountRepositoryWrapper glAccountRepository,final
IncomeAndExpenseReadPlatformService incomeAndExpenseReadPlatformService,
+ final OfficeReadPlatformService officeReadPlatformService) {
+ this.fromApiJsonDeserializer = fromApiJsonDeserializer;
+ this.officeRepository = officeRepository;
+ this.glClosureRepository = glClosureRepository;
+ this.glAccountRepository = glAccountRepository;
+ this.incomeAndExpenseReadPlatformService =
incomeAndExpenseReadPlatformService;
+ this.officeReadPlatformService = officeReadPlatformService;
+ }
+
+ @Override
+ public Collection<IncomeAndExpenseBookingData>
CalculateIncomeAndExpenseBookings(JsonQuery query) {
+ final GLClosureCommand closureCommand =
this.fromApiJsonDeserializer.commandFromApiJson(query.json());
+ closureCommand.validateForCreate();
+ final Long officeId = closureCommand.getOfficeId();
+ final Office office =
this.officeRepository.findOneWithNotFoundDetection(officeId);
+ if (office == null) { throw new OfficeNotFoundException(officeId); }
+
+ final Date todaysDate = new Date();
+ final Date closureDate = closureCommand.getClosingDate().toDate();
+ if (closureDate.after(todaysDate)) { throw new
GLClosureInvalidException(GLClosureInvalidException.GL_CLOSURE_INVALID_REASON.FUTURE_DATE,
closureDate); }
+ // shouldn't be before an existing accounting closure
+ final GLClosure latestGLClosure =
this.glClosureRepository.getLatestGLClosureByBranch(officeId);
+ if (latestGLClosure != null) {
+ if (latestGLClosure.getClosingDate().after(closureDate)) { throw
new GLClosureInvalidException(
+
GLClosureInvalidException.GL_CLOSURE_INVALID_REASON.ACCOUNTING_CLOSED,
latestGLClosure.getClosingDate()); }
+ }
+ final LocalDate incomeAndExpenseBookOffDate =
LocalDate.fromDateFields(closureDate);
+
+ /*get all offices underneath it valid closure date for all, get Jl
for all and make bookings*/
+ // final List<Office> childOffices = office.getChildren();
+ final Collection<Long> childOfficesByHierarchy =
this.officeReadPlatformService.officeByHierarchy(officeId);
+ if(closureCommand.getSubBranches() && childOfficesByHierarchy.size() >
0){
+ for(final Long childOffice : childOfficesByHierarchy){
+ final GLClosure latestChildGlClosure =
this.glClosureRepository.getLatestGLClosureByBranch(childOffice);
+ if (latestChildGlClosure != null) {
+ if
(latestChildGlClosure.getClosingDate().after(closureDate)) { throw new
GLClosureInvalidException(
+
GLClosureInvalidException.GL_CLOSURE_INVALID_REASON.ACCOUNTING_CLOSED,
latestChildGlClosure.getClosingDate()); }
+ }
+ }
+ }
+
+ Collection<IncomeAndExpenseBookingData>
incomeAndExpenseBookingCollection = new ArrayList<>();
+ final Long equityGlAccountId = closureCommand.getEquityGlAccountId();
+
+ final GLAccount glAccount=
this.glAccountRepository.findOneWithNotFoundDetection(equityGlAccountId);
+
+ if(glAccount == null){throw new
GLAccountNotFoundException(equityGlAccountId);}
+
+ if(closureCommand.getSubBranches() && childOfficesByHierarchy.size() >
0){
+ for(final Long childOffice : childOfficesByHierarchy){
+ final List<IncomeAndExpenseJournalEntryData>
incomeAndExpenseJournalEntryDataList = this.incomeAndExpenseReadPlatformService.
+
retrieveAllIncomeAndExpenseJournalEntryData(childOffice,
incomeAndExpenseBookOffDate,closureCommand.getCurrencyCode());
+ final IncomeAndExpenseBookingData incomeAndExpBookingData =
this.bookOffIncomeAndExpense(incomeAndExpenseJournalEntryDataList,
closureCommand, true,
glAccount,this.officeRepository.findOneWithNotFoundDetection(childOffice));
+ if(incomeAndExpBookingData.getJournalEntries().size() > 0){
incomeAndExpenseBookingCollection.add(incomeAndExpBookingData);}
+ }
+ }else{
+ final List<IncomeAndExpenseJournalEntryData>
incomeAndExpenseJournalEntryDataList =
this.incomeAndExpenseReadPlatformService.retrieveAllIncomeAndExpenseJournalEntryData(officeId,incomeAndExpenseBookOffDate,closureCommand.getCurrencyCode());
+ final IncomeAndExpenseBookingData incomeAndExpBookingData=
this.bookOffIncomeAndExpense(incomeAndExpenseJournalEntryDataList,
closureCommand, true,glAccount,office);
+ if(incomeAndExpBookingData.getJournalEntries().size() > 0){
incomeAndExpenseBookingCollection.add(incomeAndExpBookingData);}
+ }
+ return incomeAndExpenseBookingCollection;
+ }
+
+ public IncomeAndExpenseBookingData bookOffIncomeAndExpense(final
List<IncomeAndExpenseJournalEntryData> incomeAndExpenseJournalEntryDataList,
+ final
GLClosureCommand closureData,final boolean preview,final GLAccount
glAccount,final Office office){
+ /* All running balances has to be calculated before booking off income
and expense account */
+ boolean isRunningBalanceCalculated = true;
+ for(final IncomeAndExpenseJournalEntryData incomeAndExpenseData
:incomeAndExpenseJournalEntryDataList ){
+ if(!incomeAndExpenseData.isRunningBalanceCalculated()){ throw new
RunningBalanceNotCalculatedException(incomeAndExpenseData.getOfficeId());}
+ }
+ BigDecimal debits = BigDecimal.ZERO;
+ BigDecimal credits = BigDecimal.ZERO;
+
+ final List<SingleDebitOrCreditEntryData> debitsJournalEntry = new
ArrayList<>();
+ final List<SingleDebitOrCreditEntryData> creditsJournalEntry = new
ArrayList<>();
+
+ for(final IncomeAndExpenseJournalEntryData incomeAndExpense :
incomeAndExpenseJournalEntryDataList){
+ if(incomeAndExpense.isIncomeAccountType()){
+ if(incomeAndExpense.getOfficeRunningBalance().signum() == 1){
+ debits =
debits.add(incomeAndExpense.getOfficeRunningBalance());
+ debitsJournalEntry.add(new
SingleDebitOrCreditEntryData(incomeAndExpense.getAccountId(),incomeAndExpense.getGlAccountName(),incomeAndExpense.getOfficeRunningBalance(),null));
+ }else{
+ credits=
credits.add(incomeAndExpense.getOfficeRunningBalance().abs());
+ creditsJournalEntry.add(new
SingleDebitOrCreditEntryData(incomeAndExpense.getAccountId(),incomeAndExpense.getGlAccountName(),incomeAndExpense.getOfficeRunningBalance().abs(),null));;
+ }
+ }
+ if(incomeAndExpense.isExpenseAccountType()){
+ if(incomeAndExpense.getOfficeRunningBalance().signum() == 1){
+ credits =
credits.add(incomeAndExpense.getOfficeRunningBalance());
+ creditsJournalEntry.add(new
SingleDebitOrCreditEntryData(incomeAndExpense.getAccountId(),incomeAndExpense.getGlAccountName(),incomeAndExpense.getOfficeRunningBalance().abs(),null));;
+ }else{
+ debits=
debits.add(incomeAndExpense.getOfficeRunningBalance().abs());
+ debitsJournalEntry.add(new
SingleDebitOrCreditEntryData(incomeAndExpense.getAccountId(),incomeAndExpense.getGlAccountName(),incomeAndExpense.getOfficeRunningBalance().abs(),null));
+ }
+ }
+ }
+ final LocalDate today = DateUtils.getLocalDateOfTenant();
+ final int compare = debits.compareTo(credits);
+ BigDecimal difference = BigDecimal.ZERO;
+ JournalEntryData journalEntry = null;
+ if(compare == 1){
+ /* book with target gl id on the credit side */
+ difference = debits.subtract(credits);
+ SingleDebitOrCreditEntryData targetBooking = new
SingleDebitOrCreditEntryData(closureData.getEquityGlAccountId(),glAccount.getName(),difference,null);
+ creditsJournalEntry.add(targetBooking);
+ journalEntry = new
JournalEntryData(office.getId(),today.toString(),closureData.getComments(),creditsJournalEntry,debitsJournalEntry,null,false,closureData.getCurrencyCode(),office.getName());
+ }else if(compare == -1){
+ /* book with target gl id on the debit side*/
+ difference = credits.subtract(debits);
+ SingleDebitOrCreditEntryData targetBooking = new
SingleDebitOrCreditEntryData(closureData.getEquityGlAccountId(),glAccount.getName(),difference,null);
+ debitsJournalEntry.add(targetBooking);
+ journalEntry = new
JournalEntryData(office.getId(),today.toString(),closureData.getComments(),creditsJournalEntry,debitsJournalEntry,null,false,closureData.getCurrencyCode(),office.getName());
+ }
+ else if(compare == 0){
+ //throw new RunningBalanceZeroException(office.getName());
Review comment:
https://github.com/muellners/fineract/blob/38e19f73fcea5c9165d34d9c83a7be8bf6cec884/fineract-provider/src/main/java/org/apache/fineract/accounting/closure/service/GLClosureWritePlatformServiceJpaRepositoryImpl.java#L353
Kinda of strange , in my repo I updated this, but does it not reflect here,
----------------------------------------------------------------
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.
For queries about this service, please contact Infrastructure at:
[email protected]