diff --git a/config/docker/env/aws.env b/config/docker/env/aws.env index 8a23d992c2b..6c1700c1509 100644 --- a/config/docker/env/aws.env +++ b/config/docker/env/aws.env @@ -17,10 +17,10 @@ # under the License. # -# TODO: remove AWS_ENDPOINT_URL and use FINERACT_AWS_ENDPOINT AWS_EC2_METADATA_DISABLED=true -AWS_ENDPOINT_URL=http://localstack:4666 -#FINERACT_AWS_ENDPOINT=http://localstack:4666 +# AWS_ENDPOINT_URL is deprecated, use FINERACT_AWS_ENDPOINT instead +# AWS_ENDPOINT_URL=http://localstack:4666 +FINERACT_AWS_ENDPOINT=http://localstack:4666 FINERACT_AWS_REGION_STATIC=us-east-1 FINERACT_AWS_CREDENTIALS_INSTANCE_PROFILE=false #FINERACT_AWS_CREDENTIALS_ACCESS_KEY=localstack diff --git a/fineract-core/src/main/java/org/apache/fineract/infrastructure/core/domain/ExternalId.java b/fineract-core/src/main/java/org/apache/fineract/infrastructure/core/domain/ExternalId.java index 0b6972fb978..1274e794500 100644 --- a/fineract-core/src/main/java/org/apache/fineract/infrastructure/core/domain/ExternalId.java +++ b/fineract-core/src/main/java/org/apache/fineract/infrastructure/core/domain/ExternalId.java @@ -49,6 +49,17 @@ public ExternalId(String value) { this.value = value; } + /** + * Creates a new ExternalId instance + * + * @param value + * The external ID value as string + * @return A new ExternalId instance + */ + public static ExternalId of(String value) { + return new ExternalId(value); + } + /** * @return Create a new ExternalId object where value is a newly generated UUID */ diff --git a/fineract-provider/src/main/java/org/apache/fineract/infrastructure/core/domain/ExternalIdConverter.java b/fineract-core/src/main/java/org/apache/fineract/infrastructure/core/domain/ExternalIdConverter.java similarity index 100% rename from fineract-provider/src/main/java/org/apache/fineract/infrastructure/core/domain/ExternalIdConverter.java rename to fineract-core/src/main/java/org/apache/fineract/infrastructure/core/domain/ExternalIdConverter.java diff --git a/fineract-investor/src/main/java/org/apache/fineract/investor/domain/ExternalIdConverter.java b/fineract-investor/src/main/java/org/apache/fineract/investor/domain/ExternalIdConverter.java deleted file mode 100644 index cc7172980f2..00000000000 --- a/fineract-investor/src/main/java/org/apache/fineract/investor/domain/ExternalIdConverter.java +++ /dev/null @@ -1,40 +0,0 @@ -/** - * 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.investor.domain; - -import jakarta.persistence.AttributeConverter; -import jakarta.persistence.Converter; -import org.apache.commons.lang3.StringUtils; -import org.apache.fineract.infrastructure.core.domain.ExternalId; -import org.apache.fineract.infrastructure.core.service.ExternalIdFactory; - -@Converter(autoApply = true) -public class ExternalIdConverter implements AttributeConverter { - - @Override - public String convertToDatabaseColumn(ExternalId externalId) { - return externalId != null ? externalId.getValue() : null; - } - - @Override - public ExternalId convertToEntityAttribute(String externalId) { - return StringUtils.isBlank(externalId) ? ExternalId.empty() : ExternalIdFactory.produce(externalId); - } - -} diff --git a/fineract-investor/src/main/resources/jpa/static-weaving/module/fineract-investor/persistence.xml b/fineract-investor/src/main/resources/jpa/static-weaving/module/fineract-investor/persistence.xml index 656e3f3ea64..5cd652bb5c1 100644 --- a/fineract-investor/src/main/resources/jpa/static-weaving/module/fineract-investor/persistence.xml +++ b/fineract-investor/src/main/resources/jpa/static-weaving/module/fineract-investor/persistence.xml @@ -22,76 +22,60 @@ + xmlns="http://java.sun.com/xml/ns/persistence" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xsi:schemaLocation="http://java.sun.com/xml/ns/persistence http://java.sun.com/xml/ns/persistence/persistence_2_0.xsd"> org.eclipse.persistence.jpa.PersistenceProvider - - - org.apache.fineract.useradministration.domain.Role - org.apache.fineract.portfolio.fund.domain.Fund - org.apache.fineract.infrastructure.documentmanagement.domain.Image - org.apache.fineract.organisation.workingdays.domain.WorkingDays - org.apache.fineract.useradministration.domain.Permission - org.apache.fineract.useradministration.domain.AppUserClientMapping - org.apache.fineract.commands.domain.CommandSource - org.apache.fineract.useradministration.domain.AppUser + + org.apache.fineract.infrastructure.core.domain.ExternalIdConverter org.apache.fineract.accounting.glaccount.domain.GLAccount + org.apache.fineract.accounting.journalentry.domain.JournalEntry + org.apache.fineract.infrastructure.codes.domain.Code + org.apache.fineract.infrastructure.codes.domain.CodeValue + org.apache.fineract.infrastructure.core.domain.AbstractAuditableWithUTCDateTimeCustom + org.apache.fineract.infrastructure.core.domain.AbstractPersistableCustom + org.apache.fineract.infrastructure.documentmanagement.domain.Image + org.apache.fineract.organisation.holiday.domain.Holiday + org.apache.fineract.organisation.monetary.domain.ApplicationCurrency org.apache.fineract.organisation.monetary.domain.OrganisationCurrency + org.apache.fineract.organisation.office.domain.Office org.apache.fineract.organisation.staff.domain.Staff - org.apache.fineract.portfolio.rate.domain.Rate - org.apache.fineract.organisation.monetary.domain.ApplicationCurrency - org.apache.fineract.portfolio.calendar.domain.CalendarInstance - org.apache.fineract.portfolio.paymentdetail.domain.PaymentDetail + org.apache.fineract.organisation.workingdays.domain.WorkingDays org.apache.fineract.portfolio.calendar.domain.Calendar org.apache.fineract.portfolio.calendar.domain.CalendarHistory + org.apache.fineract.portfolio.calendar.domain.CalendarInstance + org.apache.fineract.portfolio.client.domain.Client org.apache.fineract.portfolio.client.domain.ClientIdentifier org.apache.fineract.portfolio.delinquency.domain.DelinquencyBucket org.apache.fineract.portfolio.delinquency.domain.DelinquencyRange - org.apache.fineract.portfolio.group.domain.StaffAssignmentHistory + org.apache.fineract.portfolio.floatingrates.domain.FloatingRate + org.apache.fineract.portfolio.floatingrates.domain.FloatingRatePeriod + org.apache.fineract.portfolio.fund.domain.Fund org.apache.fineract.portfolio.group.domain.Group - org.apache.fineract.portfolio.client.domain.Client - org.apache.fineract.infrastructure.event.external.repository.domain.ExternalEventConfiguration + org.apache.fineract.portfolio.group.domain.GroupLevel org.apache.fineract.portfolio.group.domain.GroupRole + org.apache.fineract.portfolio.group.domain.StaffAssignmentHistory + org.apache.fineract.portfolio.paymentdetail.domain.PaymentDetail org.apache.fineract.portfolio.paymenttype.domain.PaymentType - org.apache.fineract.portfolio.group.domain.GroupLevel - org.apache.fineract.infrastructure.event.external.repository.domain.ExternalEvent - org.apache.fineract.organisation.office.domain.Office - org.apache.fineract.organisation.holiday.domain.Holiday - org.apache.fineract.infrastructure.cache.domain.PlatformCache - org.apache.fineract.infrastructure.codes.domain.Code - org.apache.fineract.infrastructure.businessdate.domain.BusinessDate - org.apache.fineract.infrastructure.codes.domain.CodeValue - - - org.apache.fineract.accounting.closure.domain.GLClosure - org.apache.fineract.accounting.financialactivityaccount.domain.FinancialActivityAccount - org.apache.fineract.accounting.glaccount.domain.TrialBalance - org.apache.fineract.accounting.producttoaccountmapping.domain.ProductToGLAccountMapping - org.apache.fineract.accounting.rule.domain.AccountingRule - org.apache.fineract.accounting.rule.domain.AccountingTagRule - org.apache.fineract.accounting.journalentry.domain.JournalEntry - - - org.apache.fineract.portfolio.charge.domain.Charge - - + org.apache.fineract.portfolio.rate.domain.Rate + org.apache.fineract.useradministration.domain.AppUser + org.apache.fineract.useradministration.domain.AppUserClientMapping + org.apache.fineract.useradministration.domain.Permission + org.apache.fineract.useradministration.domain.Role + org.apache.fineract.investor.domain.ExternalAssetOwner - org.apache.fineract.investor.domain.ExternalAssetOwnerLoanProductAttributes + org.apache.fineract.investor.domain.ExternalAssetOwnerJournalEntryMapping org.apache.fineract.investor.domain.ExternalAssetOwnerTransfer org.apache.fineract.investor.domain.ExternalAssetOwnerTransferDetails org.apache.fineract.investor.domain.ExternalAssetOwnerTransferJournalEntryMapping org.apache.fineract.investor.domain.ExternalAssetOwnerTransferLoanMapping - org.apache.fineract.investor.domain.ExternalAssetOwnerJournalEntryMapping - - - org.apache.fineract.investor.domain.ExternalIdConverter - - + + org.apache.fineract.portfolio.collateral.domain.LoanCollateral + org.apache.fineract.portfolio.collateralmanagement.domain.ClientCollateralManagement + org.apache.fineract.portfolio.collateralmanagement.domain.CollateralManagementDomain org.apache.fineract.portfolio.delinquency.domain.DelinquencyBucketMappings org.apache.fineract.portfolio.delinquency.domain.LoanDelinquencyAction org.apache.fineract.portfolio.delinquency.domain.LoanDelinquencyTagHistory @@ -102,6 +86,7 @@ org.apache.fineract.portfolio.loanaccount.domain.LoanChargePaidBy org.apache.fineract.portfolio.loanaccount.domain.LoanCollateralManagement org.apache.fineract.portfolio.loanaccount.domain.LoanCreditAllocationRule + org.apache.fineract.portfolio.loanaccount.domain.LoanCreditAllocationRule org.apache.fineract.portfolio.loanaccount.domain.LoanDisbursementDetails org.apache.fineract.portfolio.loanaccount.domain.LoanInstallmentCharge org.apache.fineract.portfolio.loanaccount.domain.LoanInterestRecalcualtionAdditionalDetails @@ -120,8 +105,13 @@ org.apache.fineract.portfolio.loanaccount.domain.LoanTransactionRelation org.apache.fineract.portfolio.loanaccount.domain.LoanTransactionToRepaymentScheduleMapping org.apache.fineract.portfolio.loanaccount.domain.reaging.LoanReAgeParameter - org.apache.fineract.portfolio.loanaccount.loanschedule.domain.LoanRepaymentScheduleHistory + org.apache.fineract.portfolio.loanaccount.domain.reaging.LoanReAgeParameter org.apache.fineract.portfolio.loanaccount.rescheduleloan.domain.LoanRescheduleRequest + org.apache.fineract.portfolio.loanproduct.domain.AllocationType + org.apache.fineract.portfolio.loanproduct.domain.AllocationTypeListConverter + org.apache.fineract.portfolio.loanproduct.domain.CreditAllocationTransactionType + org.apache.fineract.portfolio.loanproduct.domain.DueType + org.apache.fineract.portfolio.loanproduct.domain.FutureInstallmentAllocationRule org.apache.fineract.portfolio.loanproduct.domain.LoanProduct org.apache.fineract.portfolio.loanproduct.domain.LoanProductBorrowerCycleVariations org.apache.fineract.portfolio.loanproduct.domain.LoanProductConfigurableAttributes @@ -131,30 +121,48 @@ org.apache.fineract.portfolio.loanproduct.domain.LoanProductInterestRecalculationDetails org.apache.fineract.portfolio.loanproduct.domain.LoanProductPaymentAllocationRule org.apache.fineract.portfolio.loanproduct.domain.LoanProductVariableInstallmentConfig - org.apache.fineract.portfolio.repaymentwithpostdatedchecks.domain.PostDatedChecks - org.apache.fineract.portfolio.collateralmanagement.domain.ClientCollateralManagement - org.apache.fineract.portfolio.collateralmanagement.domain.CollateralManagementDomain - org.apache.fineract.portfolio.collateral.domain.LoanCollateral - - - org.apache.fineract.portfolio.loanproduct.domain.AllocationTypeListConverter - org.apache.fineract.portfolio.loanaccount.domain.AccountingRuleTypeConverter - org.apache.fineract.portfolio.loanaccount.domain.LoanSubStatusConverter - org.apache.fineract.portfolio.loanaccount.domain.LoanTransactionTypeConverter + org.apache.fineract.portfolio.loanproduct.domain.PaymentAllocationTransactionType + org.apache.fineract.portfolio.loanproduct.domain.PaymentAllocationType org.apache.fineract.portfolio.loanproduct.domain.PaymentAllocationTypeListConverter org.apache.fineract.portfolio.loanproduct.domain.SupportedInterestRefundTypesListConverter + org.apache.fineract.portfolio.repaymentwithpostdatedchecks.domain.PostDatedChecks org.apache.fineract.portfolio.loanaccount.domain.LoanStatusConverter - - + + org.apache.fineract.interoperation.domain.InteropIdentifier + org.apache.fineract.portfolio.interestratechart.domain.InterestIncentives + org.apache.fineract.portfolio.interestratechart.domain.InterestRateChart + org.apache.fineract.portfolio.interestratechart.domain.InterestRateChartSlab + org.apache.fineract.portfolio.savings.domain.DepositAccountInterestIncentives + org.apache.fineract.portfolio.savings.domain.DepositAccountInterestRateChart + org.apache.fineract.portfolio.savings.domain.DepositAccountInterestRateChartSlabs + org.apache.fineract.portfolio.savings.domain.DepositAccountOnHoldTransaction + org.apache.fineract.portfolio.savings.domain.DepositAccountTermAndPreClosure + org.apache.fineract.portfolio.savings.domain.DepositProductRecurringDetail + org.apache.fineract.portfolio.savings.domain.DepositProductTermAndPreClosure + org.apache.fineract.portfolio.savings.domain.FixedDepositAccount + org.apache.fineract.portfolio.savings.domain.FixedDepositProduct + org.apache.fineract.portfolio.savings.domain.GroupSavingsIndividualMonitoring + org.apache.fineract.portfolio.savings.domain.RecurringDepositAccount + org.apache.fineract.portfolio.savings.domain.RecurringDepositProduct + org.apache.fineract.portfolio.savings.domain.SavingsAccount + org.apache.fineract.portfolio.savings.domain.SavingsAccountCharge + org.apache.fineract.portfolio.savings.domain.SavingsAccountChargePaidBy + org.apache.fineract.portfolio.savings.domain.SavingsAccountTransaction + org.apache.fineract.portfolio.savings.domain.SavingsAccountTransactionTaxDetails + org.apache.fineract.portfolio.savings.domain.SavingsOfficerAssignmentHistory + org.apache.fineract.portfolio.savings.domain.SavingsProduct + + org.apache.fineract.accounting.rule.domain.AccountingRule + org.apache.fineract.accounting.rule.domain.AccountingTagRule + + org.apache.fineract.infrastructure.documentmanagement.domain.Document + + org.apache.fineract.portfolio.charge.domain.Charge + org.apache.fineract.portfolio.tax.domain.TaxComponent org.apache.fineract.portfolio.tax.domain.TaxComponentHistory org.apache.fineract.portfolio.tax.domain.TaxGroup org.apache.fineract.portfolio.tax.domain.TaxGroupMappings - - - org.apache.fineract.portfolio.floatingrates.domain.FloatingRate - org.apache.fineract.portfolio.floatingrates.domain.FloatingRatePeriod - false diff --git a/fineract-provider/src/main/java/org/apache/fineract/interoperation/service/InteropServiceImpl.java b/fineract-provider/src/main/java/org/apache/fineract/interoperation/service/InteropServiceImpl.java index a911a64db8f..e95a8c40474 100644 --- a/fineract-provider/src/main/java/org/apache/fineract/interoperation/service/InteropServiceImpl.java +++ b/fineract-provider/src/main/java/org/apache/fineract/interoperation/service/InteropServiceImpl.java @@ -45,8 +45,10 @@ import org.apache.fineract.commands.domain.CommandWrapper; import org.apache.fineract.commands.service.CommandWrapperBuilder; import org.apache.fineract.commands.service.PortfolioCommandSourceWritePlatformService; +import org.apache.fineract.infrastructure.configuration.domain.ConfigurationDomainService; import org.apache.fineract.infrastructure.core.api.JsonCommand; import org.apache.fineract.infrastructure.core.data.CommandProcessingResult; +import org.apache.fineract.infrastructure.core.domain.ExternalId; import org.apache.fineract.infrastructure.core.exception.ErrorHandler; import org.apache.fineract.infrastructure.core.exception.PlatformDataIntegrityException; import org.apache.fineract.infrastructure.core.serialization.DefaultToApiJsonSerializer; @@ -121,6 +123,7 @@ public class InteropServiceImpl implements InteropService { private final PlatformSecurityContext securityContext; private final InteropDataValidator dataValidator; + private final ConfigurationDomainService configurationDomainService; private final SavingsAccountRepository savingsAccountRepository; private final SavingsAccountTransactionRepository savingsAccountTransactionRepository; @@ -392,7 +395,7 @@ public InteropTransferResponseData prepareTransfer(@NotNull JsonCommand command) PaymentDetail paymentDetail = instance(findPaymentType(), savingsAccount.getExternalId().getValue(), null, getRoutingCode(), transferCode, null); SavingsAccountTransaction holdTransaction = SavingsAccountTransaction.holdAmount(savingsAccount, savingsAccount.office(), - paymentDetail, transactionDate, Money.of(savingsAccount.getCurrency(), total), false); + paymentDetail, transactionDate, Money.of(savingsAccount.getCurrency(), total), false, ExternalId.empty()); MonetaryCurrency accountCurrency = savingsAccount.getCurrency().copy(); holdTransaction.setRunningBalance( Money.of(accountCurrency, savingsAccount.getWithdrawableBalance().subtract(holdTransaction.getAmount()))); @@ -417,6 +420,15 @@ public InteropTransferResponseData commitTransfer(@NotNull JsonCommand command) SavingsAccount savingsAccount = validateAndGetSavingAccount(request); String transferCode = request.getTransferCode(); + // Check if auto-generation of external ID is enabled + final boolean isAutoGeneratedExternalIdEnabled = this.configurationDomainService.isExternalIdAutoGenerationEnabled(); + ExternalId finalExternalId = ExternalId.empty(); + + // If auto-generation is enabled, generate an external ID + if (isAutoGeneratedExternalIdEnabled) { + finalExternalId = ExternalId.generate(); + } + if (findTransaction(savingsAccount, transferCode, (isDebit ? WITHDRAWAL : DEPOSIT).getValue()) != null) { throw new InteropTransferAlreadyCommittedException(savingsAccount.getExternalId().getValue(), transferCode); } @@ -456,11 +468,11 @@ public InteropTransferResponseData commitTransfer(@NotNull JsonCommand command) SavingsTransactionBooleanValues transactionValues = new SavingsTransactionBooleanValues(false, true, true, false, false); transaction = savingsAccountService.handleWithdrawal(savingsAccount, fmt, transactionDate, request.getAmount().getAmount(), instance(findPaymentType(), savingsAccount.getExternalId().getValue(), null, getRoutingCode(), transferCode, null), - transactionValues, backdatedTxnsAllowedTill); + transactionValues, backdatedTxnsAllowedTill, finalExternalId); } else { transaction = savingsAccountService.handleDeposit(savingsAccount, fmt, transactionDate, request.getAmount().getAmount(), instance(findPaymentType(), savingsAccount.getExternalId().getValue(), null, getRoutingCode(), transferCode, null), - false, true, backdatedTxnsAllowedTill); + false, true, backdatedTxnsAllowedTill, finalExternalId); } String note = request.getNote(); diff --git a/fineract-provider/src/main/java/org/apache/fineract/interoperation/starter/InteroperationConfiguration.java b/fineract-provider/src/main/java/org/apache/fineract/interoperation/starter/InteroperationConfiguration.java index 325baf58840..bd9a1d6320c 100644 --- a/fineract-provider/src/main/java/org/apache/fineract/interoperation/starter/InteroperationConfiguration.java +++ b/fineract-provider/src/main/java/org/apache/fineract/interoperation/starter/InteroperationConfiguration.java @@ -19,6 +19,7 @@ package org.apache.fineract.interoperation.starter; import org.apache.fineract.commands.service.PortfolioCommandSourceWritePlatformService; +import org.apache.fineract.infrastructure.configuration.domain.ConfigurationDomainService; import org.apache.fineract.infrastructure.core.serialization.DefaultToApiJsonSerializer; import org.apache.fineract.infrastructure.core.service.database.DatabaseSpecificSQLGenerator; import org.apache.fineract.infrastructure.security.service.PlatformSecurityContext; @@ -47,7 +48,8 @@ public class InteroperationConfiguration { @Bean @ConditionalOnMissingBean(InteropService.class) public InteropService interopService(PlatformSecurityContext securityContext, InteropDataValidator interopDataValidator, - SavingsAccountRepository savingsAccountRepository, SavingsAccountTransactionRepository savingsAccountTransactionRepository, + ConfigurationDomainService configurationDomainService, SavingsAccountRepository savingsAccountRepository, + SavingsAccountTransactionRepository savingsAccountTransactionRepository, ApplicationCurrencyRepository applicationCurrencyRepository, NoteRepository noteRepository, PaymentTypeRepository paymentTypeRepository, InteropIdentifierRepository identifierRepository, LoanRepositoryWrapper loanRepositoryWrapper, SavingsHelper savingsHelper, @@ -55,9 +57,9 @@ public InteropService interopService(PlatformSecurityContext securityContext, In SavingsAccountDomainService savingsAccountService, JdbcTemplate jdbcTemplate, PortfolioCommandSourceWritePlatformService commandsSourceWritePlatformService, DefaultToApiJsonSerializer toApiJsonSerializer, DatabaseSpecificSQLGenerator sqlGenerator) { - return new InteropServiceImpl(securityContext, interopDataValidator, savingsAccountRepository, savingsAccountTransactionRepository, - applicationCurrencyRepository, noteRepository, paymentTypeRepository, identifierRepository, loanRepositoryWrapper, - savingsHelper, savingsAccountTransactionSummaryWrapper, savingsAccountService, jdbcTemplate, - commandsSourceWritePlatformService, toApiJsonSerializer, sqlGenerator); + return new InteropServiceImpl(securityContext, interopDataValidator, configurationDomainService, savingsAccountRepository, + savingsAccountTransactionRepository, applicationCurrencyRepository, noteRepository, paymentTypeRepository, + identifierRepository, loanRepositoryWrapper, savingsHelper, savingsAccountTransactionSummaryWrapper, savingsAccountService, + jdbcTemplate, commandsSourceWritePlatformService, toApiJsonSerializer, sqlGenerator); } } diff --git a/fineract-provider/src/main/java/org/apache/fineract/portfolio/account/service/AccountTransfersWritePlatformServiceImpl.java b/fineract-provider/src/main/java/org/apache/fineract/portfolio/account/service/AccountTransfersWritePlatformServiceImpl.java index 7eea9969e62..bedf1a2fd4d 100644 --- a/fineract-provider/src/main/java/org/apache/fineract/portfolio/account/service/AccountTransfersWritePlatformServiceImpl.java +++ b/fineract-provider/src/main/java/org/apache/fineract/portfolio/account/service/AccountTransfersWritePlatformServiceImpl.java @@ -126,13 +126,15 @@ public CommandProcessingResult create(final JsonCommand command) { final SavingsTransactionBooleanValues transactionBooleanValues = new SavingsTransactionBooleanValues(isAccountTransfer, isRegularTransaction, fromSavingsAccount.isWithdrawalFeeApplicableForTransfer(), isInterestTransfer, isWithdrawBalance); final SavingsAccountTransaction withdrawal = this.savingsAccountDomainService.handleWithdrawal(fromSavingsAccount, fmt, - transactionDate, transactionAmount, paymentDetail, transactionBooleanValues, backdatedTxnsAllowedTill); + transactionDate, transactionAmount, paymentDetail, transactionBooleanValues, backdatedTxnsAllowedTill, + getExternalId(ExternalId.empty())); final Long toSavingsId = command.longValueOfParameterNamed(toAccountIdParamName); final SavingsAccount toSavingsAccount = this.savingsAccountAssembler.assembleFrom(toSavingsId, backdatedTxnsAllowedTill); final SavingsAccountTransaction deposit = this.savingsAccountDomainService.handleDeposit(toSavingsAccount, fmt, transactionDate, - transactionAmount, paymentDetail, isAccountTransfer, isRegularTransaction, backdatedTxnsAllowedTill); + transactionAmount, paymentDetail, isAccountTransfer, isRegularTransaction, backdatedTxnsAllowedTill, + getExternalId(ExternalId.empty())); if (!fromSavingsAccount.getCurrency().getCode().equals(toSavingsAccount.getCurrency().getCode())) { throw new DifferentCurrenciesException(fromSavingsAccount.getCurrency().getCode(), @@ -153,7 +155,8 @@ public CommandProcessingResult create(final JsonCommand command) { final SavingsTransactionBooleanValues transactionBooleanValues = new SavingsTransactionBooleanValues(isAccountTransfer, isRegularTransaction, fromSavingsAccount.isWithdrawalFeeApplicableForTransfer(), isInterestTransfer, isWithdrawBalance); final SavingsAccountTransaction withdrawal = this.savingsAccountDomainService.handleWithdrawal(fromSavingsAccount, fmt, - transactionDate, transactionAmount, paymentDetail, transactionBooleanValues, backdatedTxnsAllowedTill); + transactionDate, transactionAmount, paymentDetail, transactionBooleanValues, backdatedTxnsAllowedTill, + getExternalId(ExternalId.empty())); final Long toLoanAccountId = command.longValueOfParameterNamed(toAccountIdParamName); Loan toLoanAccount = this.loanAccountAssembler.assembleFrom(toLoanAccountId); @@ -187,7 +190,8 @@ public CommandProcessingResult create(final JsonCommand command) { final SavingsAccount toSavingsAccount = this.savingsAccountAssembler.assembleFrom(toSavingsAccountId, backdatedTxnsAllowedTill); final SavingsAccountTransaction deposit = this.savingsAccountDomainService.handleDeposit(toSavingsAccount, fmt, transactionDate, - transactionAmount, paymentDetail, isAccountTransfer, isRegularTransaction, backdatedTxnsAllowedTill); + transactionAmount, paymentDetail, isAccountTransfer, isRegularTransaction, backdatedTxnsAllowedTill, + ExternalId.empty()); final AccountTransferDetails accountTransferDetails = this.accountTransferAssembler.assembleLoanToSavingsTransfer(command, fromLoanAccount, toSavingsAccount, deposit, loanRefundTransaction); @@ -270,6 +274,17 @@ private void undoTransactions(final List accountTran } } + /** + * Returns an appropriate ExternalId based on configuration settings. If auto-generation is enabled and the provided + * externalId is empty, generates a new one. + */ + private ExternalId getExternalId(ExternalId externalId) { + if (externalId.isEmpty() && configurationDomainService.isExternalIdAutoGenerationEnabled()) { + return ExternalId.generate(); + } + return externalId; + } + @Override @Transactional public Long transferFunds(final AccountTransferDTO accountTransferDTO) { @@ -309,7 +324,8 @@ public Long transferFunds(final AccountTransferDTO accountTransferDTO) { final SavingsAccountTransaction withdrawal = this.savingsAccountDomainService.handleWithdrawal(fromSavingsAccount, accountTransferDTO.getFmt(), accountTransferDTO.getTransactionDate(), accountTransferDTO.getTransactionAmount(), - accountTransferDTO.getPaymentDetail(), transactionBooleanValues, backdatedTxnsAllowedTill); + accountTransferDTO.getPaymentDetail(), transactionBooleanValues, backdatedTxnsAllowedTill, + getExternalId(ExternalId.empty())); LoanTransaction loanTransaction; @@ -388,11 +404,12 @@ public Long transferFunds(final AccountTransferDTO accountTransferDTO) { final SavingsAccountTransaction withdrawal = this.savingsAccountDomainService.handleWithdrawal(fromSavingsAccount, accountTransferDTO.getFmt(), transactionDate, accountTransferDTO.getTransactionAmount(), - accountTransferDTO.getPaymentDetail(), transactionBooleanValues, backdatedTxnsAllowedTill); + accountTransferDTO.getPaymentDetail(), transactionBooleanValues, backdatedTxnsAllowedTill, ExternalId.empty()); final SavingsAccountTransaction deposit = this.savingsAccountDomainService.handleDeposit(toSavingsAccount, accountTransferDTO.getFmt(), transactionDate, accountTransferDTO.getTransactionAmount(), - accountTransferDTO.getPaymentDetail(), isAccountTransfer, isRegularTransaction, backdatedTxnsAllowedTill); + accountTransferDTO.getPaymentDetail(), isAccountTransfer, isRegularTransaction, backdatedTxnsAllowedTill, + getExternalId(ExternalId.empty())); accountTransferDetails = this.accountTransferAssembler.assembleSavingsToSavingsTransfer(accountTransferDTO, fromSavingsAccount, toSavingsAccount, withdrawal, deposit); @@ -434,7 +451,8 @@ public Long transferFunds(final AccountTransferDTO accountTransferDTO) { final SavingsAccountTransaction deposit = this.savingsAccountDomainService.handleDeposit(toSavingsAccount, accountTransferDTO.getFmt(), accountTransferDTO.getTransactionDate(), accountTransferDTO.getTransactionAmount(), - accountTransferDTO.getPaymentDetail(), isAccountTransfer, isRegularTransaction, backdatedTxnsAllowedTill); + accountTransferDTO.getPaymentDetail(), isAccountTransfer, isRegularTransaction, backdatedTxnsAllowedTill, + getExternalId(ExternalId.empty())); accountTransferDetails = this.accountTransferAssembler.assembleLoanToSavingsTransfer(accountTransferDTO, fromLoanAccount, toSavingsAccount, deposit, loanTransaction); this.accountTransferDetailRepository.saveAndFlush(accountTransferDetails); @@ -542,7 +560,7 @@ public CommandProcessingResult refundByTransfer(JsonCommand command) { final SavingsAccount toSavingsAccount = this.savingsAccountAssembler.assembleFrom(toSavingsAccountId, backdatedTxnsAllowedTill); final SavingsAccountTransaction deposit = this.savingsAccountDomainService.handleDeposit(toSavingsAccount, fmt, transactionDate, - transactionAmount, paymentDetail, true, true, backdatedTxnsAllowedTill); + transactionAmount, paymentDetail, true, true, backdatedTxnsAllowedTill, getExternalId(ExternalId.empty())); final AccountTransferDetails accountTransferDetails = this.accountTransferAssembler.assembleLoanToSavingsTransfer(command, fromLoanAccount, toSavingsAccount, deposit, loanRefundTransaction); diff --git a/fineract-provider/src/main/java/org/apache/fineract/portfolio/savings/domain/DepositAccountDomainService.java b/fineract-provider/src/main/java/org/apache/fineract/portfolio/savings/domain/DepositAccountDomainService.java index 3b29b900c14..2a458c6c18e 100644 --- a/fineract-provider/src/main/java/org/apache/fineract/portfolio/savings/domain/DepositAccountDomainService.java +++ b/fineract-provider/src/main/java/org/apache/fineract/portfolio/savings/domain/DepositAccountDomainService.java @@ -23,6 +23,7 @@ import java.time.format.DateTimeFormatter; import java.util.Map; import org.apache.fineract.infrastructure.core.api.JsonCommand; +import org.apache.fineract.infrastructure.core.domain.ExternalId; import org.apache.fineract.portfolio.paymentdetail.domain.PaymentDetail; import org.apache.fineract.useradministration.domain.AppUser; import org.springframework.transaction.annotation.Transactional; @@ -30,30 +31,32 @@ public interface DepositAccountDomainService { SavingsAccountTransaction handleWithdrawal(SavingsAccount account, DateTimeFormatter fmt, LocalDate transactionDate, - BigDecimal transactionAmount, PaymentDetail paymentDetail, boolean applyWithdrawFee, boolean isRegularTransaction); + BigDecimal transactionAmount, PaymentDetail paymentDetail, boolean applyWithdrawFee, boolean isRegularTransaction, + ExternalId externalId); SavingsAccountTransaction handleFDDeposit(FixedDepositAccount account, DateTimeFormatter fmt, LocalDate transactionDate, - BigDecimal transactionAmount, PaymentDetail paymentDetail); + BigDecimal transactionAmount, PaymentDetail paymentDetail, ExternalId externalId); SavingsAccountTransaction handleRDDeposit(RecurringDepositAccount account, DateTimeFormatter fmt, LocalDate transactionDate, - BigDecimal transactionAmount, PaymentDetail paymentDetail, boolean isRegularTransaction); + BigDecimal transactionAmount, PaymentDetail paymentDetail, boolean isRegularTransaction, ExternalId externalId); SavingsAccountTransaction handleSavingDeposit(SavingsAccount account, DateTimeFormatter fmt, LocalDate transactionDate, - BigDecimal transactionAmount, PaymentDetail paymentDetail, boolean isRegularTransaction); + BigDecimal transactionAmount, PaymentDetail paymentDetail, boolean isRegularTransaction, ExternalId externalId); Long handleFDAccountClosure(FixedDepositAccount account, PaymentDetail paymentDetail, AppUser user, JsonCommand command, - Map changes); + Map changes, ExternalId externalId); @Transactional Long handleFDAccountMaturityClosure(FixedDepositAccount account, PaymentDetail paymentDetail, AppUser user, DateTimeFormatter fmt, - LocalDate closedDate, Integer onAccountClosureId, Long toSavingsId, String transferDescription, Map changes); + LocalDate closedDate, Integer onAccountClosureId, Long toSavingsId, String transferDescription, Map changes, + ExternalId externalId); Long handleRDAccountClosure(RecurringDepositAccount account, PaymentDetail paymentDetail, AppUser user, JsonCommand command, - Map changes); + Map changes, ExternalId externalId); Long handleFDAccountPreMatureClosure(FixedDepositAccount account, PaymentDetail paymentDetail, AppUser user, JsonCommand command, - Map changes); + Map changes, ExternalId externalId); Long handleRDAccountPreMatureClosure(RecurringDepositAccount account, PaymentDetail paymentDetail, AppUser user, JsonCommand command, - Map changes); + Map changes, ExternalId externalId); } diff --git a/fineract-provider/src/main/java/org/apache/fineract/portfolio/savings/domain/DepositAccountDomainServiceJpa.java b/fineract-provider/src/main/java/org/apache/fineract/portfolio/savings/domain/DepositAccountDomainServiceJpa.java index 7fe875bedd7..d6921538838 100644 --- a/fineract-provider/src/main/java/org/apache/fineract/portfolio/savings/domain/DepositAccountDomainServiceJpa.java +++ b/fineract-provider/src/main/java/org/apache/fineract/portfolio/savings/domain/DepositAccountDomainServiceJpa.java @@ -101,7 +101,7 @@ public DepositAccountDomainServiceJpa(final SavingsAccountRepositoryWrapper savi @Override public SavingsAccountTransaction handleWithdrawal(final SavingsAccount account, final DateTimeFormatter fmt, final LocalDate transactionDate, final BigDecimal transactionAmount, final PaymentDetail paymentDetail, - final boolean applyWithdrawFee, final boolean isRegularTransaction) { + final boolean applyWithdrawFee, final boolean isRegularTransaction, final ExternalId externalId) { boolean isAccountTransfer = false; boolean isInterestTransfer = false; boolean isWithdrawBalance = false; @@ -109,25 +109,26 @@ public SavingsAccountTransaction handleWithdrawal(final SavingsAccount account, SavingsTransactionBooleanValues transactionBooleanValues = new SavingsTransactionBooleanValues(isAccountTransfer, isRegularTransaction, applyWithdrawFee, isInterestTransfer, isWithdrawBalance); return this.savingsAccountDomainService.handleWithdrawal(account, fmt, transactionDate, transactionAmount, paymentDetail, - transactionBooleanValues, backdatedTxnsAllowedTill); + transactionBooleanValues, backdatedTxnsAllowedTill, externalId); } @Transactional @Override public SavingsAccountTransaction handleFDDeposit(final FixedDepositAccount account, final DateTimeFormatter fmt, - final LocalDate transactionDate, final BigDecimal transactionAmount, final PaymentDetail paymentDetail) { + final LocalDate transactionDate, final BigDecimal transactionAmount, final PaymentDetail paymentDetail, + final ExternalId externalId) { boolean isAccountTransfer = false; boolean isRegularTransaction = false; final boolean backdatedTxnsAllowedTill = false; return this.savingsAccountDomainService.handleDeposit(account, fmt, transactionDate, transactionAmount, paymentDetail, - isAccountTransfer, isRegularTransaction, backdatedTxnsAllowedTill); + isAccountTransfer, isRegularTransaction, backdatedTxnsAllowedTill, externalId); } @Transactional @Override public SavingsAccountTransaction handleRDDeposit(final RecurringDepositAccount account, final DateTimeFormatter fmt, final LocalDate transactionDate, final BigDecimal transactionAmount, final PaymentDetail paymentDetail, - final boolean isRegularTransaction) { + final boolean isRegularTransaction, final ExternalId externalId) { final boolean isSavingsInterestPostingAtCurrentPeriodEnd = this.configurationDomainService .isSavingsInterestPostingAtCurrentPeriodEnd(); final Integer financialYearBeginningMonth = this.configurationDomainService.retrieveFinancialYearBeginningMonth(); @@ -137,12 +138,12 @@ public SavingsAccountTransaction handleRDDeposit(final RecurringDepositAccount a account.updateDepositAmount(transactionAmount); final boolean backdatedTxnsAllowedTill = false; final SavingsAccountTransaction deposit = this.savingsAccountDomainService.handleDeposit(account, fmt, transactionDate, - transactionAmount, paymentDetail, isAccountTransfer, isRegularTransaction, backdatedTxnsAllowedTill); + transactionAmount, paymentDetail, isAccountTransfer, isRegularTransaction, backdatedTxnsAllowedTill, externalId); final Set existingTransactionIds = new HashSet<>(); final Set existingReversedTransactionIds = new HashSet<>(); final boolean isAnyActivationChargesDue = isAnyActivationChargesDue(account); if (isAnyActivationChargesDue) { - updateExistingTransactionsDetails(account, existingTransactionIds, existingReversedTransactionIds); + updateExistingTransactionsDetails(account, existingTransactionIds, existingReversedTransactionIds, externalId); account.processAccountUponActivation(isSavingsInterestPostingAtCurrentPeriodEnd, financialYearBeginningMonth); this.savingsAccountRepository.saveAndFlush(account); } @@ -151,7 +152,7 @@ public SavingsAccountTransaction handleRDDeposit(final RecurringDepositAccount a financialYearBeginningMonth); account.updateOverduePayments(DateUtils.getBusinessLocalDate()); if (isAnyActivationChargesDue) { - postJournalEntries(account, existingTransactionIds, existingReversedTransactionIds, isAccountTransfer); + postJournalEntries(account, existingTransactionIds, existingReversedTransactionIds, isAccountTransfer, externalId); } return deposit; } @@ -160,15 +161,15 @@ public SavingsAccountTransaction handleRDDeposit(final RecurringDepositAccount a @Override public SavingsAccountTransaction handleSavingDeposit(final SavingsAccount account, final DateTimeFormatter fmt, final LocalDate transactionDate, final BigDecimal transactionAmount, final PaymentDetail paymentDetail, - final boolean isRegularTransaction) { + final boolean isRegularTransaction, final ExternalId externalId) { boolean isAccountTransfer = false; final boolean backdatedTxnsAllowedTill = false; final SavingsAccountTransaction deposit = this.savingsAccountDomainService.handleDeposit(account, fmt, transactionDate, - transactionAmount, paymentDetail, isAccountTransfer, isRegularTransaction, backdatedTxnsAllowedTill); + transactionAmount, paymentDetail, isAccountTransfer, isRegularTransaction, backdatedTxnsAllowedTill, externalId); final Set existingTransactionIds = new HashSet<>(); final Set existingReversedTransactionIds = new HashSet<>(); - updateExistingTransactionsDetails(account, existingTransactionIds, existingReversedTransactionIds); - postJournalEntries(account, existingTransactionIds, existingReversedTransactionIds, isAccountTransfer); + updateExistingTransactionsDetails(account, existingTransactionIds, existingReversedTransactionIds, externalId); + postJournalEntries(account, existingTransactionIds, existingReversedTransactionIds, isAccountTransfer, externalId); return deposit; } @@ -185,7 +186,7 @@ private boolean isAnyActivationChargesDue(final RecurringDepositAccount account) @Transactional @Override public Long handleFDAccountClosure(final FixedDepositAccount account, final PaymentDetail paymentDetail, final AppUser user, - final JsonCommand command, final Map changes) { + final JsonCommand command, final Map changes, final ExternalId externalId) { final boolean isSavingsInterestPostingAtCurrentPeriodEnd = this.configurationDomainService .isSavingsInterestPostingAtCurrentPeriodEnd(); final Integer financialYearBeginningMonth = this.configurationDomainService.retrieveFinancialYearBeginningMonth(); @@ -196,7 +197,7 @@ public Long handleFDAccountClosure(final FixedDepositAccount account, final Paym final Set existingTransactionIds = new HashSet<>(); final Set existingReversedTransactionIds = new HashSet<>(); // Update account transactionIds for post journal entries. - updateExistingTransactionsDetails(account, existingTransactionIds, existingReversedTransactionIds); + updateExistingTransactionsDetails(account, existingTransactionIds, existingReversedTransactionIds, externalId); /* * final SavingsAccountTransactionDTO transactionDTO = new SavingsAccountTransactionDTO(fmt, transactionDate, * transactionAmount, paymentDetail, new Date()); final SavingsAccountTransaction deposit = @@ -222,7 +223,7 @@ public Long handleFDAccountClosure(final FixedDepositAccount account, final Paym this.savingsAccountRepository.save(reinvestedDeposit); autoGenerateAccountNumber(reinvestedDeposit); final SavingsAccountTransaction withdrawal = this.handleWithdrawal(account, fmt, closedDate, account.getAccountBalance(), - paymentDetail, false, isRegularTransaction); + paymentDetail, false, isRegularTransaction, externalId); savingsTransactionId = withdrawal.getId(); } else if (onClosureType.isTransferToSavings()) { final Long toSavingsId = command.longValueOfParameterNamed(toSavingsAccountIdParamName); @@ -232,14 +233,14 @@ public Long handleFDAccountClosure(final FixedDepositAccount account, final Paym final boolean isExceptionForBalanceCheck = false; final AccountTransferDTO accountTransferDTO = new AccountTransferDTO(closedDate, account.getAccountBalance(), PortfolioAccountType.SAVINGS, PortfolioAccountType.SAVINGS, null, null, transferDescription, locale, fmt, null, null, - null, null, null, AccountTransferType.ACCOUNT_TRANSFER.getValue(), null, null, ExternalId.empty(), null, - toSavingsAccount, account, isAccountTransfer, isExceptionForBalanceCheck); + null, null, null, AccountTransferType.ACCOUNT_TRANSFER.getValue(), null, null, externalId, null, toSavingsAccount, + account, isAccountTransfer, isExceptionForBalanceCheck); this.accountTransfersWritePlatformService.transferFunds(accountTransferDTO); - updateAlreadyPostedTransactions(existingTransactionIds, account); - postJournalEntries(account, existingTransactionIds, existingReversedTransactionIds, isAccountTransfer); + updateAlreadyPostedTransactions(existingTransactionIds, account, externalId); + postJournalEntries(account, existingTransactionIds, existingReversedTransactionIds, isAccountTransfer, externalId); } else { final SavingsAccountTransaction withdrawal = this.handleWithdrawal(account, fmt, closedDate, account.getAccountBalance(), - paymentDetail, false, isRegularTransaction); + paymentDetail, false, isRegularTransaction, externalId); savingsTransactionId = withdrawal.getId(); } @@ -253,7 +254,7 @@ public Long handleFDAccountClosure(final FixedDepositAccount account, final Paym @Override public Long handleFDAccountMaturityClosure(final FixedDepositAccount account, final PaymentDetail paymentDetail, final AppUser user, final DateTimeFormatter fmt, final LocalDate closedDate, final Integer onAccountClosureId, final Long toSavingsId, - final String transferDescription, Map changes) { + final String transferDescription, Map changes, final ExternalId externalId) { final boolean isSavingsInterestPostingAtCurrentPeriodEnd = this.configurationDomainService .isSavingsInterestPostingAtCurrentPeriodEnd(); @@ -267,7 +268,7 @@ public Long handleFDAccountMaturityClosure(final FixedDepositAccount account, fi /*** * Update account transactionIds for post journal entries. */ - updateExistingTransactionsDetails(account, existingTransactionIds, existingReversedTransactionIds); + updateExistingTransactionsDetails(account, existingTransactionIds, existingReversedTransactionIds, externalId); final MathContext mc = MathContext.DECIMAL64; Long savingsTransactionId = null; @@ -288,7 +289,7 @@ public Long handleFDAccountMaturityClosure(final FixedDepositAccount account, fi this.savingsAccountRepository.save(reinvestedDeposit); autoGenerateAccountNumber(reinvestedDeposit); final SavingsAccountTransaction withdrawal = this.handleWithdrawal(account, fmt, closedDate, reInvestAmount, paymentDetail, - false, isRegularTransaction); + false, isRegularTransaction, externalId); savingsTransactionId = withdrawal.getId(); if (onClosureType.isReinvestPrincipalAndInterest()) { @@ -305,15 +306,15 @@ public Long handleFDAccountMaturityClosure(final FixedDepositAccount account, fi final boolean isExceptionForBalanceCheck = false; final AccountTransferDTO accountTransferDTO = new AccountTransferDTO(closedDate, account.getAccountBalance(), PortfolioAccountType.SAVINGS, PortfolioAccountType.SAVINGS, null, null, transferDescription, null, fmt, null, null, - null, null, null, AccountTransferType.ACCOUNT_TRANSFER.getValue(), null, null, ExternalId.empty(), null, - toSavingsAccount, account, isAccountTransfer, isExceptionForBalanceCheck); + null, null, null, AccountTransferType.ACCOUNT_TRANSFER.getValue(), null, null, externalId, null, toSavingsAccount, + account, isAccountTransfer, isExceptionForBalanceCheck); this.accountTransfersWritePlatformService.transferFunds(accountTransferDTO); - updateAlreadyPostedTransactions(existingTransactionIds, account); + updateAlreadyPostedTransactions(existingTransactionIds, account, externalId); account.updateClosedStatus(); account.updateOnAccountClosureStatus(onClosureType); } else { final SavingsAccountTransaction withdrawal = this.handleWithdrawal(account, fmt, closedDate, account.getAccountBalance(), - paymentDetail, false, isRegularTransaction); + paymentDetail, false, isRegularTransaction, externalId); savingsTransactionId = withdrawal.getId(); } @@ -322,7 +323,7 @@ public Long handleFDAccountMaturityClosure(final FixedDepositAccount account, fi this.savingsAccountRepository.save(account); - postJournalEntries(account, existingTransactionIds, existingReversedTransactionIds, isAccountTransfer); + postJournalEntries(account, existingTransactionIds, existingReversedTransactionIds, isAccountTransfer, externalId); return savingsTransactionId; } @@ -330,7 +331,7 @@ public Long handleFDAccountMaturityClosure(final FixedDepositAccount account, fi @Transactional @Override public Long handleRDAccountClosure(final RecurringDepositAccount account, final PaymentDetail paymentDetail, final AppUser user, - final JsonCommand command, final Map changes) { + final JsonCommand command, final Map changes, final ExternalId externalId) { final boolean isSavingsInterestPostingAtCurrentPeriodEnd = this.configurationDomainService .isSavingsInterestPostingAtCurrentPeriodEnd(); @@ -342,7 +343,7 @@ public Long handleRDAccountClosure(final RecurringDepositAccount account, final final Set existingTransactionIds = new HashSet<>(); final Set existingReversedTransactionIds = new HashSet<>(); // Update account transactionIds for post journal entries. - updateExistingTransactionsDetails(account, existingTransactionIds, existingReversedTransactionIds); + updateExistingTransactionsDetails(account, existingTransactionIds, existingReversedTransactionIds, externalId); final MathContext mc = MathContext.DECIMAL64; final Locale locale = command.extractLocale(); @@ -377,7 +378,7 @@ public Long handleRDAccountClosure(final RecurringDepositAccount account, final autoGenerateAccountNumber(reinvestedDeposit); final SavingsAccountTransaction withdrawal = this.handleWithdrawal(account, fmt, closedDate, account.getAccountBalance(), - paymentDetail, false, isRegularTransaction); + paymentDetail, false, isRegularTransaction, externalId); savingsTransactionId = withdrawal.getId(); } else if (onClosureType.isTransferToSavings()) { @@ -388,13 +389,13 @@ public Long handleRDAccountClosure(final RecurringDepositAccount account, final final boolean isExceptionForBalanceCheck = false; final AccountTransferDTO accountTransferDTO = new AccountTransferDTO(closedDate, transactionAmount, PortfolioAccountType.SAVINGS, PortfolioAccountType.SAVINGS, null, null, transferDescription, locale, fmt, null, null, - null, null, null, AccountTransferType.ACCOUNT_TRANSFER.getValue(), null, null, ExternalId.empty(), null, - toSavingsAccount, account, isRegularTransaction, isExceptionForBalanceCheck); + null, null, null, AccountTransferType.ACCOUNT_TRANSFER.getValue(), null, null, externalId, null, toSavingsAccount, + account, isRegularTransaction, isExceptionForBalanceCheck); this.accountTransfersWritePlatformService.transferFunds(accountTransferDTO); - updateAlreadyPostedTransactions(existingTransactionIds, account); + updateAlreadyPostedTransactions(existingTransactionIds, account, externalId); } else { final SavingsAccountTransaction withdrawal = this.handleWithdrawal(account, fmt, closedDate, account.getAccountBalance(), - paymentDetail, false, isRegularTransaction); + paymentDetail, false, isRegularTransaction, externalId); savingsTransactionId = withdrawal.getId(); } @@ -402,7 +403,7 @@ public Long handleRDAccountClosure(final RecurringDepositAccount account, final this.savingsAccountRepository.save(account); - postJournalEntries(account, existingTransactionIds, existingReversedTransactionIds, isAccountTransfer); + postJournalEntries(account, existingTransactionIds, existingReversedTransactionIds, isAccountTransfer, externalId); return savingsTransactionId; } @@ -443,7 +444,7 @@ private void autoGenerateAccountNumber(final SavingsAccount account) { @Transactional @Override public Long handleFDAccountPreMatureClosure(final FixedDepositAccount account, final PaymentDetail paymentDetail, final AppUser user, - final JsonCommand command, final Map changes) { + final JsonCommand command, final Map changes, final ExternalId externalId) { final boolean isSavingsInterestPostingAtCurrentPeriodEnd = this.configurationDomainService .isSavingsInterestPostingAtCurrentPeriodEnd(); @@ -455,7 +456,7 @@ public Long handleFDAccountPreMatureClosure(final FixedDepositAccount account, f final Set existingTransactionIds = new HashSet<>(); final Set existingReversedTransactionIds = new HashSet<>(); // Update account transactionIds for post journal entries. - updateExistingTransactionsDetails(account, existingTransactionIds, existingReversedTransactionIds); + updateExistingTransactionsDetails(account, existingTransactionIds, existingReversedTransactionIds, externalId); final LocalDate closedDate = command.localDateValueOfParameterNamed(SavingsApiConstants.closedOnDateParamName); final Locale locale = command.extractLocale(); @@ -477,13 +478,13 @@ public Long handleFDAccountPreMatureClosure(final FixedDepositAccount account, f DepositAccountType.SAVINGS_DEPOSIT); final AccountTransferDTO accountTransferDTO = new AccountTransferDTO(closedDate, account.getAccountBalance(), PortfolioAccountType.SAVINGS, PortfolioAccountType.SAVINGS, null, null, transferDescription, locale, fmt, null, null, - null, null, null, AccountTransferType.ACCOUNT_TRANSFER.getValue(), null, null, ExternalId.empty(), null, - toSavingsAccount, account, isRegularTransaction, isExceptionForBalanceCheck); + null, null, null, AccountTransferType.ACCOUNT_TRANSFER.getValue(), null, null, externalId, null, toSavingsAccount, + account, isRegularTransaction, isExceptionForBalanceCheck); this.accountTransfersWritePlatformService.transferFunds(accountTransferDTO); - updateAlreadyPostedTransactions(existingTransactionIds, account); + updateAlreadyPostedTransactions(existingTransactionIds, account, externalId); } else { final SavingsAccountTransaction withdrawal = this.handleWithdrawal(account, fmt, closedDate, account.getAccountBalance(), - paymentDetail, false, isRegularTransaction); + paymentDetail, false, isRegularTransaction, externalId); savingsTransactionId = withdrawal.getId(); } @@ -491,14 +492,14 @@ public Long handleFDAccountPreMatureClosure(final FixedDepositAccount account, f this.savingsAccountRepository.save(account); - postJournalEntries(account, existingTransactionIds, existingReversedTransactionIds, isAccountTransfer); + postJournalEntries(account, existingTransactionIds, existingReversedTransactionIds, isAccountTransfer, externalId); return savingsTransactionId; } @Transactional @Override public Long handleRDAccountPreMatureClosure(final RecurringDepositAccount account, final PaymentDetail paymentDetail, - final AppUser user, final JsonCommand command, final Map changes) { + final AppUser user, final JsonCommand command, final Map changes, final ExternalId externalId) { final boolean isSavingsInterestPostingAtCurrentPeriodEnd = this.configurationDomainService .isSavingsInterestPostingAtCurrentPeriodEnd(); @@ -512,7 +513,7 @@ public Long handleRDAccountPreMatureClosure(final RecurringDepositAccount accoun /*** * Update account transactionIds for post journal entries. */ - updateExistingTransactionsDetails(account, existingTransactionIds, existingReversedTransactionIds); + updateExistingTransactionsDetails(account, existingTransactionIds, existingReversedTransactionIds, externalId); final LocalDate closedDate = command.localDateValueOfParameterNamed(SavingsApiConstants.closedOnDateParamName); final Locale locale = command.extractLocale(); @@ -533,30 +534,30 @@ public Long handleRDAccountPreMatureClosure(final RecurringDepositAccount accoun DepositAccountType.SAVINGS_DEPOSIT); final AccountTransferDTO accountTransferDTO = new AccountTransferDTO(closedDate, account.getAccountBalance(), PortfolioAccountType.SAVINGS, PortfolioAccountType.SAVINGS, null, null, transferDescription, locale, fmt, null, null, - null, null, null, AccountTransferType.ACCOUNT_TRANSFER.getValue(), null, null, ExternalId.empty(), null, - toSavingsAccount, account, isRegularTransaction, isExceptionForBalanceCheck); + null, null, null, AccountTransferType.ACCOUNT_TRANSFER.getValue(), null, null, externalId, null, toSavingsAccount, + account, isRegularTransaction, isExceptionForBalanceCheck); this.accountTransfersWritePlatformService.transferFunds(accountTransferDTO); - updateAlreadyPostedTransactions(existingTransactionIds, account); + updateAlreadyPostedTransactions(existingTransactionIds, account, externalId); } else { final SavingsAccountTransaction withdrawal = this.handleWithdrawal(account, fmt, closedDate, account.getAccountBalance(), - paymentDetail, false, isRegularTransaction); + paymentDetail, false, isRegularTransaction, externalId); savingsTransactionId = withdrawal.getId(); } account.prematureClosure(user, command, changes); this.savingsAccountRepository.save(account); - postJournalEntries(account, existingTransactionIds, existingReversedTransactionIds, isAccountTransfer); + postJournalEntries(account, existingTransactionIds, existingReversedTransactionIds, isAccountTransfer, externalId); return savingsTransactionId; } private void updateExistingTransactionsDetails(SavingsAccount account, Set existingTransactionIds, - Set existingReversedTransactionIds) { + Set existingReversedTransactionIds, final ExternalId externalId) { existingTransactionIds.addAll(account.findExistingTransactionIds()); existingReversedTransactionIds.addAll(account.findExistingReversedTransactionIds()); } private void postJournalEntries(final SavingsAccount savingsAccount, final Set existingTransactionIds, - final Set existingReversedTransactionIds, boolean isAccountTransfer) { + final Set existingReversedTransactionIds, boolean isAccountTransfer, final ExternalId externalId) { final boolean backdatedTxnsAllowedTill = false; @@ -565,7 +566,8 @@ private void postJournalEntries(final SavingsAccount savingsAccount, final Set existingTransactionIds, final SavingsAccount savingsAccount) { + private void updateAlreadyPostedTransactions(final Set existingTransactionIds, final SavingsAccount savingsAccount, + final ExternalId externalId) { List transactions = savingsAccount.getTransactions(); int size = transactions.size(); for (int i = size - 1;; i--) { diff --git a/fineract-provider/src/main/java/org/apache/fineract/portfolio/savings/domain/FixedDepositAccount.java b/fineract-provider/src/main/java/org/apache/fineract/portfolio/savings/domain/FixedDepositAccount.java index 2855bc1e566..c95e2da1b0c 100644 --- a/fineract-provider/src/main/java/org/apache/fineract/portfolio/savings/domain/FixedDepositAccount.java +++ b/fineract-provider/src/main/java/org/apache/fineract/portfolio/savings/domain/FixedDepositAccount.java @@ -83,6 +83,21 @@ public class FixedDepositAccount extends SavingsAccount { @Transient private ConfigurationDomainService configurationDomainService; + public void setConfigurationDomainService(ConfigurationDomainService configurationDomainService) { + this.configurationDomainService = configurationDomainService; + } + + /** + * Returns an appropriate ExternalId based on configuration settings. If auto-generation is enabled and the provided + * externalId is empty, generate a new one. + */ + public ExternalId getExternalId(ExternalId externalId) { + if (externalId.isEmpty() && configurationDomainService != null && configurationDomainService.isExternalIdAutoGenerationEnabled()) { + return ExternalId.generate(); + } + return externalId; + } + protected FixedDepositAccount() { // } @@ -197,7 +212,7 @@ public void updateMaturityDateAndAmountBeforeAccountActivation(final MathContext String refNo = null; final Money transactionAmountMoney = Money.of(getCurrency(), this.accountTermAndPreClosure.depositAmount()); final SavingsAccountTransaction transaction = SavingsAccountTransaction.deposit(null, office(), null, - this.accountSubmittedOrActivationDate(), transactionAmountMoney, refNo); + this.accountSubmittedOrActivationDate(), transactionAmountMoney, refNo, getExternalId(ExternalId.empty())); transaction.setRunningBalance(transactionAmountMoney); transaction.updateCumulativeBalanceAndDates(this.getCurrency(), interestCalculatedUpto()); allTransactions.add(transaction); @@ -541,7 +556,8 @@ public void postMaturityInterest(final boolean isSavingsInterestPostingAtCurrent final SavingsAccountTransaction postingTransaction = findInterestPostingTransactionFor(interestPostingTransactionDate); if (postingTransaction == null) { final SavingsAccountTransaction newPostingTransaction = SavingsAccountTransaction.interestPosting(this, office(), - interestPostingTransactionDate, interestEarnedToBePostedForPeriod, interestPostingPeriod.isUserPosting()); + interestPostingTransactionDate, interestEarnedToBePostedForPeriod, interestPostingPeriod.isUserPosting(), + getExternalId(ExternalId.empty())); this.transactions.add(newPostingTransaction); recalucateDailyBalanceDetails = true; } else { @@ -549,7 +565,8 @@ public void postMaturityInterest(final boolean isSavingsInterestPostingAtCurrent if (correctionRequired) { postingTransaction.reverse(); final SavingsAccountTransaction newPostingTransaction = SavingsAccountTransaction.interestPosting(this, office(), - interestPostingTransactionDate, interestEarnedToBePostedForPeriod, interestPostingPeriod.isUserPosting()); + interestPostingTransactionDate, interestEarnedToBePostedForPeriod, interestPostingPeriod.isUserPosting(), + getExternalId(ExternalId.empty())); this.transactions.add(newPostingTransaction); recalucateDailyBalanceDetails = true; } @@ -583,7 +600,7 @@ public void postPreMaturityInterest(final LocalDate accountCloseDate, final bool if (!remainigInterestToBePosted.isZero()) { final boolean postInterestAsOn = false; final SavingsAccountTransaction newPostingTransaction = SavingsAccountTransaction.interestPosting(this, office(), - accountCloseDate, remainigInterestToBePosted, postInterestAsOn); + accountCloseDate, remainigInterestToBePosted, postInterestAsOn, getExternalId(ExternalId.empty())); this.transactions.add(newPostingTransaction); recalucateDailyBalance = true; } diff --git a/fineract-provider/src/main/java/org/apache/fineract/portfolio/savings/domain/RecurringDepositAccount.java b/fineract-provider/src/main/java/org/apache/fineract/portfolio/savings/domain/RecurringDepositAccount.java index 5eea23621b2..67e519ab761 100644 --- a/fineract-provider/src/main/java/org/apache/fineract/portfolio/savings/domain/RecurringDepositAccount.java +++ b/fineract-provider/src/main/java/org/apache/fineract/portfolio/savings/domain/RecurringDepositAccount.java @@ -30,6 +30,7 @@ import jakarta.persistence.OneToMany; import jakarta.persistence.OneToOne; import jakarta.persistence.OrderBy; +import jakarta.persistence.Transient; import java.math.BigDecimal; import java.math.MathContext; import java.time.LocalDate; @@ -42,6 +43,7 @@ import java.util.Locale; import java.util.Map; import java.util.Set; +import org.apache.fineract.infrastructure.configuration.domain.ConfigurationDomainService; import org.apache.fineract.infrastructure.core.api.JsonCommand; import org.apache.fineract.infrastructure.core.data.ApiParameterError; import org.apache.fineract.infrastructure.core.data.DataValidatorBuilder; @@ -91,6 +93,24 @@ public class RecurringDepositAccount extends SavingsAccount { @OneToMany(cascade = CascadeType.ALL, mappedBy = "account", orphanRemoval = true, fetch = FetchType.LAZY) private List depositScheduleInstallments = new ArrayList<>(); + @Transient + private ConfigurationDomainService configurationDomainService; + + /** + * Returns an appropriate ExternalId based on configuration settings. If auto-generation is enabled and provided + * externalId is empty, generate a new one. + */ + public ExternalId getExternalId(ExternalId externalId) { + if (externalId.isEmpty() && configurationDomainService != null && configurationDomainService.isExternalIdAutoGenerationEnabled()) { + return ExternalId.generate(); + } + return externalId; + } + + public void setConfigurationDomainService(ConfigurationDomainService configurationDomainService) { + this.configurationDomainService = configurationDomainService; + } + protected RecurringDepositAccount() { // } @@ -394,7 +414,7 @@ private List getTransactions(final LocalDate depositE dueDate = latestTransactionDate; } final SavingsAccountTransaction transaction = SavingsAccountTransaction.deposit(null, office(), null, dueDate, - installment.getDepositAmountOutstanding(getCurrency()), refNo); + installment.getDepositAmountOutstanding(getCurrency()), refNo, getExternalId(ExternalId.empty())); allTransactions.add(transaction); } } @@ -662,7 +682,8 @@ public void postMaturityInterest(final boolean isSavingsInterestPostingAtCurrent final SavingsAccountTransaction postingTransaction = findInterestPostingTransactionFor(interestPostingTransactionDate); if (postingTransaction == null) { final SavingsAccountTransaction newPostingTransaction = SavingsAccountTransaction.interestPosting(this, office(), - interestPostingTransactionDate, interestEarnedToBePostedForPeriod, interestPostingPeriod.isUserPosting()); + interestPostingTransactionDate, interestEarnedToBePostedForPeriod, interestPostingPeriod.isUserPosting(), + getExternalId(ExternalId.empty())); addTransaction(newPostingTransaction); recalucateDailyBalanceDetails = true; } else { @@ -670,7 +691,8 @@ public void postMaturityInterest(final boolean isSavingsInterestPostingAtCurrent if (correctionRequired) { postingTransaction.reverse(); final SavingsAccountTransaction newPostingTransaction = SavingsAccountTransaction.interestPosting(this, office(), - interestPostingTransactionDate, interestEarnedToBePostedForPeriod, interestPostingPeriod.isUserPosting()); + interestPostingTransactionDate, interestEarnedToBePostedForPeriod, interestPostingPeriod.isUserPosting(), + getExternalId(ExternalId.empty())); addTransaction(newPostingTransaction); recalucateDailyBalanceDetails = true; } @@ -703,7 +725,7 @@ public void postPreMaturityInterest(final LocalDate accountCloseDate, final bool if (!remainigInterestToBePosted.isZero()) { final boolean postInterestAsOn = false; final SavingsAccountTransaction newPostingTransaction = SavingsAccountTransaction.interestPosting(this, office(), - accountCloseDate, remainigInterestToBePosted, postInterestAsOn); + accountCloseDate, remainigInterestToBePosted, postInterestAsOn, getExternalId(ExternalId.empty())); addTransaction(newPostingTransaction); recalucateDailyBalance = true; } diff --git a/fineract-provider/src/main/java/org/apache/fineract/portfolio/savings/domain/SavingsAccountDomainServiceJpa.java b/fineract-provider/src/main/java/org/apache/fineract/portfolio/savings/domain/SavingsAccountDomainServiceJpa.java index fb16621dc64..62636823921 100644 --- a/fineract-provider/src/main/java/org/apache/fineract/portfolio/savings/domain/SavingsAccountDomainServiceJpa.java +++ b/fineract-provider/src/main/java/org/apache/fineract/portfolio/savings/domain/SavingsAccountDomainServiceJpa.java @@ -30,6 +30,7 @@ import java.util.UUID; import org.apache.fineract.accounting.journalentry.service.JournalEntryWritePlatformService; import org.apache.fineract.infrastructure.configuration.domain.ConfigurationDomainService; +import org.apache.fineract.infrastructure.core.domain.ExternalId; import org.apache.fineract.infrastructure.core.service.DateUtils; import org.apache.fineract.infrastructure.event.business.domain.savings.transaction.SavingsDepositBusinessEvent; import org.apache.fineract.infrastructure.event.business.domain.savings.transaction.SavingsWithdrawalBusinessEvent; @@ -82,7 +83,8 @@ public SavingsAccountDomainServiceJpa(final SavingsAccountRepositoryWrapper savi @Override public SavingsAccountTransaction handleWithdrawal(final SavingsAccount account, final DateTimeFormatter fmt, final LocalDate transactionDate, final BigDecimal transactionAmount, final PaymentDetail paymentDetail, - final SavingsTransactionBooleanValues transactionBooleanValues, final boolean backdatedTxnsAllowedTill) { + final SavingsTransactionBooleanValues transactionBooleanValues, final boolean backdatedTxnsAllowedTill, + final ExternalId externalId) { context.authenticatedUser(); account.validateForAccountBlock(); account.validateForDebitBlock(); @@ -140,7 +142,7 @@ public SavingsAccountTransaction handleWithdrawal(final SavingsAccount account, this.savingsAccountRepository.save(account); postJournalEntries(account, existingTransactionIds, existingReversedTransactionIds, transactionBooleanValues.isAccountTransfer(), - backdatedTxnsAllowedTill); + backdatedTxnsAllowedTill, externalId); businessEventNotifierService.notifyPostBusinessEvent(new SavingsWithdrawalBusinessEvent(withdrawal)); return withdrawal; @@ -150,16 +152,18 @@ public SavingsAccountTransaction handleWithdrawal(final SavingsAccount account, @Override public SavingsAccountTransaction handleDeposit(final SavingsAccount account, final DateTimeFormatter fmt, final LocalDate transactionDate, final BigDecimal transactionAmount, final PaymentDetail paymentDetail, - final boolean isAccountTransfer, final boolean isRegularTransaction, final boolean backdatedTxnsAllowedTill) { + final boolean isAccountTransfer, final boolean isRegularTransaction, final boolean backdatedTxnsAllowedTill, + final ExternalId externalId) { final SavingsAccountTransactionType savingsAccountTransactionType = SavingsAccountTransactionType.DEPOSIT; return handleDeposit(account, fmt, transactionDate, transactionAmount, paymentDetail, isAccountTransfer, isRegularTransaction, - savingsAccountTransactionType, backdatedTxnsAllowedTill); + savingsAccountTransactionType, backdatedTxnsAllowedTill, externalId); } private SavingsAccountTransaction handleDeposit(final SavingsAccount account, final DateTimeFormatter fmt, final LocalDate transactionDate, final BigDecimal transactionAmount, final PaymentDetail paymentDetail, final boolean isAccountTransfer, final boolean isRegularTransaction, - final SavingsAccountTransactionType savingsAccountTransactionType, final boolean backdatedTxnsAllowedTill) { + final SavingsAccountTransactionType savingsAccountTransactionType, final boolean backdatedTxnsAllowedTill, + final ExternalId externalId) { context.authenticatedUser(); account.validateForAccountBlock(); account.validateForCreditBlock(); @@ -210,7 +214,8 @@ private SavingsAccountTransaction handleDeposit(final SavingsAccount account, fi this.savingsAccountRepository.saveAndFlush(account); - postJournalEntries(account, existingTransactionIds, existingReversedTransactionIds, isAccountTransfer, backdatedTxnsAllowedTill); + postJournalEntries(account, existingTransactionIds, existingReversedTransactionIds, isAccountTransfer, backdatedTxnsAllowedTill, + externalId); businessEventNotifierService.notifyPostBusinessEvent(new SavingsDepositBusinessEvent(deposit)); return deposit; } @@ -218,21 +223,21 @@ private SavingsAccountTransaction handleDeposit(final SavingsAccount account, fi @Transactional @Override public SavingsAccountTransaction handleHold(final SavingsAccount account, BigDecimal amount, LocalDate transactionDate, - Boolean lienAllowed) { + Boolean lienAllowed, final ExternalId externalId) { return SavingsAccountTransaction.holdAmount(account, account.office(), null, transactionDate, - Money.of(account.getCurrency(), amount), lienAllowed); + Money.of(account.getCurrency(), amount), lienAllowed, externalId); } @Override public SavingsAccountTransaction handleDividendPayout(final SavingsAccount account, final LocalDate transactionDate, - final BigDecimal transactionAmount, final boolean backdatedTxnsAllowedTill) { + final BigDecimal transactionAmount, final boolean backdatedTxnsAllowedTill, final ExternalId externalId) { final DateTimeFormatter fmt = null; final PaymentDetail paymentDetail = null; final boolean isAccountTransfer = false; final boolean isRegularTransaction = true; final SavingsAccountTransactionType savingsAccountTransactionType = SavingsAccountTransactionType.DIVIDEND_PAYOUT; return handleDeposit(account, fmt, transactionDate, transactionAmount, paymentDetail, isAccountTransfer, isRegularTransaction, - savingsAccountTransactionType, backdatedTxnsAllowedTill); + savingsAccountTransactionType, backdatedTxnsAllowedTill, externalId); } private void updateExistingTransactionsDetails(SavingsAccount account, Set existingTransactionIds, @@ -257,25 +262,27 @@ private void updateTransactionDetailsWithPivotConfig(final SavingsAccount accoun } private void postJournalEntries(final SavingsAccount savingsAccount, final Set existingTransactionIds, - final Set existingReversedTransactionIds, boolean isAccountTransfer, final boolean backdatedTxnsAllowedTill) { + final Set existingReversedTransactionIds, boolean isAccountTransfer, final boolean backdatedTxnsAllowedTill, + final ExternalId externalId) { final Map accountingBridgeData = savingsAccount.deriveAccountingBridgeData(savingsAccount.getCurrency().getCode(), existingTransactionIds, existingReversedTransactionIds, isAccountTransfer, backdatedTxnsAllowedTill); this.journalEntryWritePlatformService.createJournalEntriesForSavings(accountingBridgeData); } - @Transactional @Override + @Transactional public void postJournalEntries(final SavingsAccount account, final Set existingTransactionIds, final Set existingReversedTransactionIds, final boolean backdatedTxnsAllowedTill) { final boolean isAccountTransfer = false; - postJournalEntries(account, existingTransactionIds, existingReversedTransactionIds, isAccountTransfer, backdatedTxnsAllowedTill); + postJournalEntries(account, existingTransactionIds, existingReversedTransactionIds, isAccountTransfer, backdatedTxnsAllowedTill, + null); } @Override public SavingsAccountTransaction handleReversal(SavingsAccount account, List savingsAccountTransactions, - boolean backdatedTxnsAllowedTill) { + boolean backdatedTxnsAllowedTill, ExternalId externalId) { final boolean isSavingsInterestPostingAtCurrentPeriodEnd = this.configurationDomainService .isSavingsInterestPostingAtCurrentPeriodEnd(); @@ -326,7 +333,7 @@ public SavingsAccountTransaction handleReversal(SavingsAccount account, List changes = new LinkedHashMap<>(); final PaymentDetail paymentDetail = this.paymentDetailWritePlatformService.createAndPersistPaymentDetail(command, changes); final SavingsAccountTransaction deposit = this.depositAccountDomainService.handleFDDeposit(account, fmt, transactionDate, - transactionAmount, paymentDetail); + transactionAmount, paymentDetail, ExternalId.empty()); return new CommandProcessingResultBuilder().withEntityId(deposit.getId()).withOfficeId(account.officeId()) .withClientId(account.clientId()).withGroupId(account.groupId()).withSavingsId(savingsId).with(changes).build(); @@ -420,8 +422,9 @@ public CommandProcessingResult depositToRDAccount(final Long savingsId, final Js final Map changes = new LinkedHashMap<>(); final PaymentDetail paymentDetail = this.paymentDetailWritePlatformService.createAndPersistPaymentDetail(command, changes); + account.setConfigurationDomainService(this.configurationDomainService); final SavingsAccountTransaction deposit = this.depositAccountDomainService.handleRDDeposit(account, fmt, transactionDate, - transactionAmount, paymentDetail, isRegularTransaction); + transactionAmount, paymentDetail, isRegularTransaction, account.getExternalId(ExternalId.empty())); return new CommandProcessingResultBuilder() // .withEntityId(deposit.getId()) // @@ -460,8 +463,9 @@ public CommandProcessingResult withdrawal(final Long savingsId, final JsonComman checkClientOrGroupActive(account); + account.setConfigurationDomainService(this.configurationDomainService); final SavingsAccountTransaction withdrawal = this.depositAccountDomainService.handleWithdrawal(account, fmt, transactionDate, - transactionAmount, paymentDetail, true, isRegularTransaction); + transactionAmount, paymentDetail, true, isRegularTransaction, account.getExternalId(ExternalId.empty())); return new CommandProcessingResultBuilder() // .withEntityId(withdrawal.getId()) // @@ -773,7 +777,7 @@ public CommandProcessingResult closeFDAccount(final Long savingsId, final JsonCo DepositAccountType.FIXED_DEPOSIT); checkClientOrGroupActive(account); - this.depositAccountDomainService.handleFDAccountClosure(account, paymentDetail, user, command, changes); + this.depositAccountDomainService.handleFDAccountClosure(account, paymentDetail, user, command, changes, ExternalId.empty()); final String noteText = command.stringValueOfParameterNamed("note"); if (StringUtils.isNotBlank(noteText)) { @@ -806,7 +810,9 @@ public CommandProcessingResult closeRDAccount(final Long savingsId, final JsonCo DepositAccountType.RECURRING_DEPOSIT); checkClientOrGroupActive(account); - this.depositAccountDomainService.handleRDAccountClosure(account, paymentDetail, user, command, changes); + account.setConfigurationDomainService(this.configurationDomainService); + this.depositAccountDomainService.handleRDAccountClosure(account, paymentDetail, user, command, changes, + account.getExternalId(ExternalId.empty())); final String noteText = command.stringValueOfParameterNamed("note"); if (StringUtils.isNotBlank(noteText)) { @@ -839,7 +845,9 @@ public CommandProcessingResult prematureCloseFDAccount(final Long savingsId, fin DepositAccountType.FIXED_DEPOSIT); checkClientOrGroupActive(account); - this.depositAccountDomainService.handleFDAccountPreMatureClosure(account, paymentDetail, user, command, changes); + account.setConfigurationDomainService(this.configurationDomainService); + this.depositAccountDomainService.handleFDAccountPreMatureClosure(account, paymentDetail, user, command, changes, + account.getExternalId(ExternalId.empty())); final String noteText = command.stringValueOfParameterNamed("note"); if (StringUtils.isNotBlank(noteText)) { @@ -881,7 +889,9 @@ public CommandProcessingResult prematureCloseRDAccount(final Long savingsId, fin } } - this.depositAccountDomainService.handleRDAccountPreMatureClosure(account, paymentDetail, user, command, changes); + account.setConfigurationDomainService(this.configurationDomainService); + this.depositAccountDomainService.handleRDAccountPreMatureClosure(account, paymentDetail, user, command, changes, + account.getExternalId(ExternalId.empty())); final String noteText = command.stringValueOfParameterNamed("note"); if (StringUtils.isNotBlank(noteText)) { @@ -915,8 +925,9 @@ public SavingsAccountTransaction initiateSavingsTransfer(final Long accountId, f final Set existingReversedTransactionIds = new HashSet<>(); updateExistingTransactionsDetails(savingsAccount, existingTransactionIds, existingReversedTransactionIds); + savingsAccount.setConfigurationDomainService(this.configurationDomainService); final SavingsAccountTransaction newTransferTransaction = SavingsAccountTransaction.initiateTransfer(savingsAccount, - savingsAccount.office(), transferDate); + savingsAccount.office(), transferDate, savingsAccount.getExternalId(ExternalId.empty())); savingsAccount.addTransaction(newTransferTransaction); savingsAccount.setStatus(SavingsAccountStatusType.TRANSFER_IN_PROGRESS.getValue()); final MathContext mc = MathContext.DECIMAL64; @@ -948,8 +959,9 @@ public SavingsAccountTransaction withdrawSavingsTransfer(final Long accountId, f final Set existingReversedTransactionIds = new HashSet<>(); updateExistingTransactionsDetails(savingsAccount, existingTransactionIds, existingReversedTransactionIds); + savingsAccount.setConfigurationDomainService(this.configurationDomainService); final SavingsAccountTransaction withdrawtransferTransaction = SavingsAccountTransaction.withdrawTransfer(savingsAccount, - savingsAccount.office(), transferDate); + savingsAccount.office(), transferDate, savingsAccount.getExternalId(ExternalId.empty())); savingsAccount.addTransaction(withdrawtransferTransaction); savingsAccount.setStatus(SavingsAccountStatusType.ACTIVE.getValue()); final boolean postReversals = false; @@ -989,8 +1001,9 @@ public SavingsAccountTransaction acceptSavingsTransfer(final Long accountId, fin final Set existingReversedTransactionIds = new HashSet<>(); updateExistingTransactionsDetails(savingsAccount, existingTransactionIds, existingReversedTransactionIds); + savingsAccount.setConfigurationDomainService(this.configurationDomainService); final SavingsAccountTransaction acceptTransferTransaction = SavingsAccountTransaction.approveTransfer(savingsAccount, - acceptedInOffice, transferDate); + acceptedInOffice, transferDate, savingsAccount.getExternalId(ExternalId.empty())); savingsAccount.addTransaction(acceptTransferTransaction); savingsAccount.setStatus(SavingsAccountStatusType.ACTIVE.getValue()); if (fieldOfficer != null) { @@ -1337,8 +1350,10 @@ public void updateMaturityDetails(Long depositAccountId, DepositAccountType depo Map changes = new HashMap<>(); final AppUser user = context.authenticatedUser(); Long toSavingsId = fdAccount.getTransferToSavingsAccountId(); + fdAccount.setConfigurationDomainService(this.configurationDomainService); this.depositAccountDomainService.handleFDAccountMaturityClosure(fdAccount, null, user, fmt, fdAccount.maturityDate(), - fdAccount.getOnAccountClosureId(), toSavingsId, "Apply maturity instructions", changes); + fdAccount.getOnAccountClosureId(), toSavingsId, "Apply maturity instructions", changes, + fdAccount.getExternalId(ExternalId.empty())); if (changes.get("reinvestedDepositId") != null) { Long reinvestedDepositId = (Long) changes.get("reinvestedDepositId"); @@ -1350,8 +1365,9 @@ public void updateMaturityDetails(Long depositAccountId, DepositAccountType depo payActivationCharge(reinvestAccount); amountForDeposit = amountForDeposit.plus(activationChargeAmount); } + reinvestAccount.setConfigurationDomainService(this.configurationDomainService); this.depositAccountDomainService.handleFDDeposit(reinvestAccount, fmt, fdAccount.maturityDate(), - amountForDeposit.getAmount(), null); + amountForDeposit.getAmount(), null, reinvestAccount.getExternalId(ExternalId.empty())); } } } else if (depositAccountType.isRecurringDeposit()) { @@ -1388,9 +1404,10 @@ public SavingsAccountTransaction mandatorySavingsAccountDeposit(final SavingsAcc if (accountTransactionDTO.getAccountType().equals(DepositAccountType.RECURRING_DEPOSIT.getValue())) { RecurringDepositAccount account = (RecurringDepositAccount) this.depositAccountAssembler .assembleFrom(accountTransactionDTO.getSavingsAccountId(), DepositAccountType.RECURRING_DEPOSIT); + account.setConfigurationDomainService(this.configurationDomainService); return this.depositAccountDomainService.handleRDDeposit(account, accountTransactionDTO.getFormatter(), accountTransactionDTO.getTransactionDate(), accountTransactionDTO.getTransactionAmount(), paymentDetail, - isRegularTransaction); + isRegularTransaction, account.getExternalId(ExternalId.empty())); } SavingsAccount account = null; if (accountTransactionDTO.getAccountType().equals(DepositAccountType.SAVINGS_DEPOSIT.getValue())) { @@ -1400,9 +1417,10 @@ public SavingsAccountTransaction mandatorySavingsAccountDeposit(final SavingsAcc account = this.depositAccountAssembler.assembleFrom(accountTransactionDTO.getSavingsAccountId(), DepositAccountType.CURRENT_DEPOSIT); } + account.setConfigurationDomainService(this.configurationDomainService); return this.depositAccountDomainService.handleSavingDeposit(account, accountTransactionDTO.getFormatter(), accountTransactionDTO.getTransactionDate(), accountTransactionDTO.getTransactionAmount(), paymentDetail, - isRegularTransaction); + isRegularTransaction, account.getExternalId(ExternalId.empty())); } } diff --git a/fineract-provider/src/main/java/org/apache/fineract/portfolio/savings/service/SavingsAccountWritePlatformServiceJpaRepositoryImpl.java b/fineract-provider/src/main/java/org/apache/fineract/portfolio/savings/service/SavingsAccountWritePlatformServiceJpaRepositoryImpl.java index b6705759cb4..7b75e8a9efa 100644 --- a/fineract-provider/src/main/java/org/apache/fineract/portfolio/savings/service/SavingsAccountWritePlatformServiceJpaRepositoryImpl.java +++ b/fineract-provider/src/main/java/org/apache/fineract/portfolio/savings/service/SavingsAccountWritePlatformServiceJpaRepositoryImpl.java @@ -57,6 +57,7 @@ import org.apache.fineract.infrastructure.core.data.CommandProcessingResult; import org.apache.fineract.infrastructure.core.data.CommandProcessingResultBuilder; import org.apache.fineract.infrastructure.core.data.DataValidatorBuilder; +import org.apache.fineract.infrastructure.core.domain.ExternalId; import org.apache.fineract.infrastructure.core.exception.ErrorHandler; import org.apache.fineract.infrastructure.core.exception.GeneralPlatformDomainRuleException; import org.apache.fineract.infrastructure.core.exception.PlatformApiDataValidationException; @@ -243,8 +244,9 @@ public void processPostActiveActions(final SavingsAccount account, final DateTim boolean isRegularTransaction = false; if (amountForDeposit.isGreaterThanZero()) { boolean isAccountTransfer = false; + account.setConfigurationDomainService(this.configurationDomainService); this.savingsAccountDomainService.handleDeposit(account, fmt, account.getActivationDate(), amountForDeposit.getAmount(), null, - isAccountTransfer, isRegularTransaction, false); + isAccountTransfer, isRegularTransaction, false, account.getExternalId(ExternalId.empty())); updateExistingTransactionsDetails(account, existingTransactionIds, existingReversedTransactionIds); } @@ -303,8 +305,10 @@ public CommandProcessingResult deposit(final Long savingsId, final JsonCommand c final PaymentDetail paymentDetail = this.paymentDetailWritePlatformService.createAndPersistPaymentDetail(command, changes); boolean isAccountTransfer = false; boolean isRegularTransaction = true; + account.setConfigurationDomainService(this.configurationDomainService); final SavingsAccountTransaction deposit = this.savingsAccountDomainService.handleDeposit(account, fmt, transactionDate, - transactionAmount, paymentDetail, isAccountTransfer, isRegularTransaction, backdatedTxnsAllowedTill); + transactionAmount, paymentDetail, isAccountTransfer, isRegularTransaction, backdatedTxnsAllowedTill, + account.getExternalId(ExternalId.empty())); if (isGsim && (deposit.getId() != null)) { @@ -378,8 +382,10 @@ public CommandProcessingResult withdrawal(final Long savingsId, final JsonComman final boolean isWithdrawBalance = false; final SavingsTransactionBooleanValues transactionBooleanValues = new SavingsTransactionBooleanValues(isAccountTransfer, isRegularTransaction, isApplyWithdrawFee, isInterestTransfer, isWithdrawBalance); + account.setConfigurationDomainService(this.configurationDomainService); final SavingsAccountTransaction withdrawal = this.savingsAccountDomainService.handleWithdrawal(account, fmt, transactionDate, - transactionAmount, paymentDetail, transactionBooleanValues, backdatedTxnsAllowedTill); + transactionAmount, paymentDetail, transactionBooleanValues, backdatedTxnsAllowedTill, + account.getExternalId(ExternalId.empty())); if (isGsim && (withdrawal.getId() != null)) { GroupSavingsIndividualMonitoring gsim = gsimRepository.findById(account.getGsim().getId()).orElseThrow(); @@ -639,10 +645,13 @@ public CommandProcessingResult reverseTransaction(final Long savingsId, final Lo if (isBulk) { String transactionRefNo = savingsAccountTransaction.getRefNo(); savingsAccountTransactions = this.savingsAccountTransactionRepository.findByRefNo(transactionRefNo); - reversal = this.savingsAccountDomainService.handleReversal(account, savingsAccountTransactions, backdatedTxnsAllowedTill); + account.setConfigurationDomainService(this.configurationDomainService); + reversal = this.savingsAccountDomainService.handleReversal(account, savingsAccountTransactions, backdatedTxnsAllowedTill, + account.getExternalId(ExternalId.empty())); } else { + account.setConfigurationDomainService(this.configurationDomainService); reversal = this.savingsAccountDomainService.handleReversal(account, Collections.singletonList(savingsAccountTransaction), - backdatedTxnsAllowedTill); + backdatedTxnsAllowedTill, account.getExternalId(ExternalId.empty())); } reversalId = reversal.getId(); return new CommandProcessingResultBuilder() // @@ -942,9 +951,9 @@ public CommandProcessingResult close(final Long savingsId, final JsonCommand com final boolean isInterestTransfer = false; final SavingsTransactionBooleanValues transactionBooleanValues = new SavingsTransactionBooleanValues(isAccountTransfer, isRegularTransaction, isApplyWithdrawFee, isInterestTransfer, isWithdrawBalance); - + account.setConfigurationDomainService(this.configurationDomainService); this.savingsAccountDomainService.handleWithdrawal(account, fmt, closedDate, transactionAmount, paymentDetail, - transactionBooleanValues, false); + transactionBooleanValues, false, account.getExternalId(ExternalId.empty())); } @@ -989,8 +998,9 @@ public SavingsAccountTransaction initiateSavingsTransfer(final SavingsAccount sa final Set existingReversedTransactionIds = new HashSet<>(); updateExistingTransactionsDetails(savingsAccount, existingTransactionIds, existingReversedTransactionIds); + savingsAccount.setConfigurationDomainService(this.configurationDomainService); final SavingsAccountTransaction newTransferTransaction = SavingsAccountTransaction.initiateTransfer(savingsAccount, - savingsAccount.office(), transferDate); + savingsAccount.office(), transferDate, savingsAccount.getExternalId(ExternalId.empty())); savingsAccount.addTransaction(newTransferTransaction); savingsAccount.setStatus(SavingsAccountStatusType.TRANSFER_IN_PROGRESS.getValue()); final MathContext mc = MathContext.DECIMAL64; @@ -1020,8 +1030,9 @@ public SavingsAccountTransaction withdrawSavingsTransfer(final SavingsAccount sa final Set existingReversedTransactionIds = new HashSet<>(); updateExistingTransactionsDetails(savingsAccount, existingTransactionIds, existingReversedTransactionIds); + savingsAccount.setConfigurationDomainService(this.configurationDomainService); final SavingsAccountTransaction withdrawtransferTransaction = SavingsAccountTransaction.withdrawTransfer(savingsAccount, - savingsAccount.office(), transferDate); + savingsAccount.office(), transferDate, savingsAccount.getExternalId(ExternalId.empty())); savingsAccount.addTransaction(withdrawtransferTransaction); savingsAccount.setStatus(SavingsAccountStatusType.ACTIVE.getValue()); final MathContext mc = MathContext.DECIMAL64; @@ -1059,8 +1070,9 @@ public SavingsAccountTransaction acceptSavingsTransfer(final SavingsAccount savi final Set existingReversedTransactionIds = new HashSet<>(); updateExistingTransactionsDetails(savingsAccount, existingTransactionIds, existingReversedTransactionIds); + savingsAccount.setConfigurationDomainService(this.configurationDomainService); final SavingsAccountTransaction acceptTransferTransaction = SavingsAccountTransaction.approveTransfer(savingsAccount, - acceptedInOffice, transferDate); + acceptedInOffice, transferDate, savingsAccount.getExternalId(ExternalId.empty())); savingsAccount.addTransaction(acceptTransferTransaction); savingsAccount.setStatus(SavingsAccountStatusType.ACTIVE.getValue()); if (fieldOfficer != null) { @@ -1748,7 +1760,9 @@ public CommandProcessingResult holdAmount(final Long savingsId, final JsonComman this.savingsAccountTransactionDataValidator.validateHoldAndAssembleForm(command.json(), account, submittedBy, backdatedTxnsAllowedTill); - SavingsAccountTransaction transaction = this.savingsAccountDomainService.handleHold(account, amount, transactionDate, lienAllowed); + account.setConfigurationDomainService(this.configurationDomainService); + SavingsAccountTransaction transaction = this.savingsAccountDomainService.handleHold(account, amount, transactionDate, lienAllowed, + account.getExternalId(ExternalId.empty())); account.holdAmount(amount); transaction.setRunningBalance(runningBalance); diff --git a/fineract-provider/src/main/java/org/apache/fineract/portfolio/shareaccounts/service/ShareAccountSchedularServiceImpl.java b/fineract-provider/src/main/java/org/apache/fineract/portfolio/shareaccounts/service/ShareAccountSchedularServiceImpl.java index 5cfbf289507..6d08731ba39 100644 --- a/fineract-provider/src/main/java/org/apache/fineract/portfolio/shareaccounts/service/ShareAccountSchedularServiceImpl.java +++ b/fineract-provider/src/main/java/org/apache/fineract/portfolio/shareaccounts/service/ShareAccountSchedularServiceImpl.java @@ -19,6 +19,8 @@ package org.apache.fineract.portfolio.shareaccounts.service; import lombok.RequiredArgsConstructor; +import org.apache.fineract.infrastructure.configuration.domain.ConfigurationDomainService; +import org.apache.fineract.infrastructure.core.domain.ExternalId; import org.apache.fineract.infrastructure.core.service.DateUtils; import org.apache.fineract.portfolio.savings.domain.SavingsAccount; import org.apache.fineract.portfolio.savings.domain.SavingsAccountAssembler; @@ -35,6 +37,7 @@ public class ShareAccountSchedularServiceImpl implements ShareAccountSchedularSe private final ShareAccountDividendRepository shareAccountDividendRepository; private final SavingsAccountDomainService savingsAccountDomainService; private final SavingsAccountAssembler savingsAccountAssembler; + private final ConfigurationDomainService configurationDomainService; @Override @Transactional @@ -43,8 +46,10 @@ public void postDividend(final Long dividendDetailId, final Long savingsId) { ShareAccountDividendDetails shareAccountDividendDetails = this.shareAccountDividendRepository.findById(dividendDetailId) .orElseThrow(); final SavingsAccount savingsAccount = this.savingsAccountAssembler.assembleFrom(savingsId, false); + savingsAccount.setConfigurationDomainService(this.configurationDomainService); SavingsAccountTransaction savingsAccountTransaction = this.savingsAccountDomainService.handleDividendPayout(savingsAccount, - DateUtils.getBusinessLocalDate(), shareAccountDividendDetails.getAmount(), false); + DateUtils.getBusinessLocalDate(), shareAccountDividendDetails.getAmount(), false, + savingsAccount.getExternalId(ExternalId.empty())); shareAccountDividendDetails.update(ShareAccountDividendStatusType.POSTED.getValue(), savingsAccountTransaction.getId()); this.shareAccountDividendRepository.saveAndFlush(shareAccountDividendDetails); } diff --git a/fineract-provider/src/main/java/org/apache/fineract/portfolio/shareaccounts/start/ShareAccountsConfiguration.java b/fineract-provider/src/main/java/org/apache/fineract/portfolio/shareaccounts/start/ShareAccountsConfiguration.java index 6daf958342d..fc3659eb1d6 100644 --- a/fineract-provider/src/main/java/org/apache/fineract/portfolio/shareaccounts/start/ShareAccountsConfiguration.java +++ b/fineract-provider/src/main/java/org/apache/fineract/portfolio/shareaccounts/start/ShareAccountsConfiguration.java @@ -20,6 +20,7 @@ import org.apache.fineract.accounting.journalentry.service.JournalEntryWritePlatformService; import org.apache.fineract.infrastructure.accountnumberformat.domain.AccountNumberFormatRepositoryWrapper; +import org.apache.fineract.infrastructure.configuration.domain.ConfigurationDomainService; import org.apache.fineract.infrastructure.core.serialization.FromJsonHelper; import org.apache.fineract.infrastructure.core.service.PaginationHelper; import org.apache.fineract.infrastructure.core.service.database.DatabaseSpecificSQLGenerator; @@ -105,8 +106,10 @@ public ShareAccountReadPlatformService shareAccountReadPlatformService(Applicati @Bean @ConditionalOnMissingBean(ShareAccountSchedularService.class) public ShareAccountSchedularService shareAccountSchedularService(ShareAccountDividendRepository shareAccountDividendRepository, - SavingsAccountDomainService savingsAccountDomainService, SavingsAccountAssembler savingsAccountAssembler) { - return new ShareAccountSchedularServiceImpl(shareAccountDividendRepository, savingsAccountDomainService, savingsAccountAssembler); + SavingsAccountDomainService savingsAccountDomainService, SavingsAccountAssembler savingsAccountAssembler, + ConfigurationDomainService configurationDomainService) { + return new ShareAccountSchedularServiceImpl(shareAccountDividendRepository, savingsAccountDomainService, savingsAccountAssembler, + configurationDomainService); } @Bean diff --git a/fineract-savings/src/main/java/org/apache/fineract/portfolio/savings/domain/SavingsAccount.java b/fineract-savings/src/main/java/org/apache/fineract/portfolio/savings/domain/SavingsAccount.java index 5db6e32dc14..0eb51d394ff 100644 --- a/fineract-savings/src/main/java/org/apache/fineract/portfolio/savings/domain/SavingsAccount.java +++ b/fineract-savings/src/main/java/org/apache/fineract/portfolio/savings/domain/SavingsAccount.java @@ -344,6 +344,17 @@ public class SavingsAccount extends AbstractAuditableWithUTCDateTimeCustom public transient ConfigurationDomainService configurationDomainService; + public ExternalId getExternalId(ExternalId externalId) { + if (externalId.isEmpty() && configurationDomainService != null && configurationDomainService.isExternalIdAutoGenerationEnabled()) { + return ExternalId.generate(); + } + return externalId; + } + + public void setConfigurationDomainService(ConfigurationDomainService configurationDomainService) { + this.configurationDomainService = configurationDomainService; + } + protected SavingsAccount() { // } @@ -549,10 +560,12 @@ public void postInterest(final MathContext mc, final LocalDate interestPostingUp if (interestEarnedToBePostedForPeriod.isGreaterThanOrEqualTo(Money.zero(currency))) { newPostingTransaction = SavingsAccountTransaction.interestPosting(this, office(), interestPostingTransactionDate, - interestEarnedToBePostedForPeriod, interestPostingPeriod.isUserPosting()); + interestEarnedToBePostedForPeriod, interestPostingPeriod.isUserPosting(), + getExternalId(ExternalId.empty())); } else { newPostingTransaction = SavingsAccountTransaction.overdraftInterest(this, office(), interestPostingTransactionDate, - interestEarnedToBePostedForPeriod.negated(), interestPostingPeriod.isUserPosting()); + interestEarnedToBePostedForPeriod.negated(), interestPostingPeriod.isUserPosting(), + getExternalId(ExternalId.empty())); } if (backdatedTxnsAllowedTill) { addTransactionToExisting(newPostingTransaction); @@ -588,11 +601,11 @@ public void postInterest(final MathContext mc, final LocalDate interestPostingUp if (interestEarnedToBePostedForPeriod.isGreaterThanOrEqualTo(Money.zero(currency))) { newPostingTransaction = SavingsAccountTransaction.interestPosting(this, office(), interestPostingTransactionDate, interestEarnedToBePostedForPeriod, - interestPostingPeriod.isUserPosting()); + interestPostingPeriod.isUserPosting(), getExternalId(ExternalId.empty())); } else { newPostingTransaction = SavingsAccountTransaction.overdraftInterest(this, office(), interestPostingTransactionDate, interestEarnedToBePostedForPeriod.negated(), - interestPostingPeriod.isUserPosting()); + interestPostingPeriod.isUserPosting(), getExternalId(ExternalId.empty())); } if (backdatedTxnsAllowedTill) { addTransactionToExisting(newPostingTransaction); @@ -713,7 +726,7 @@ protected boolean createWithHoldTransaction(final BigDecimal amount, final Local BigDecimal totalTax = TaxUtils.totalTaxAmount(taxSplit); if (totalTax.compareTo(BigDecimal.ZERO) > 0) { SavingsAccountTransaction withholdTransaction = SavingsAccountTransaction.withHoldTax(this, office(), date, - Money.of(currency, totalTax), taxSplit); + Money.of(currency, totalTax), ExternalId.empty(), taxSplit); if (backdatedTxnsAllowedTill) { addTransactionToExisting(withholdTransaction); } else { @@ -740,7 +753,7 @@ protected boolean updateWithHoldTransaction(final BigDecimal amount, final Savin } else if (totalTax.compareTo(withholdTransaction.getAmount()) != 0) { withholdTransaction.reverse(); SavingsAccountTransaction newWithholdTransaction = SavingsAccountTransaction.withHoldTax(this, office(), - withholdTransaction.getTransactionDate(), Money.of(currency, totalTax), taxSplit); + withholdTransaction.getTransactionDate(), Money.of(currency, totalTax), ExternalId.empty(), taxSplit); addTransaction(newWithholdTransaction); isTaxAdded = true; } @@ -1153,7 +1166,7 @@ public SavingsAccountTransaction deposit(final SavingsAccountTransactionDTO tran final Money amount = Money.of(this.currency, transactionDTO.getTransactionAmount()); final SavingsAccountTransaction transaction = SavingsAccountTransaction.deposit(this, office(), transactionDTO.getPaymentDetail(), - transactionDTO.getTransactionDate(), amount, savingsAccountTransactionType, refNo); + transactionDTO.getTransactionDate(), amount, savingsAccountTransactionType, refNo, ExternalId.empty()); if (backdatedTxnsAllowedTill) { addTransactionToExisting(transaction); @@ -1288,7 +1301,8 @@ public SavingsAccountTransaction withdraw(final SavingsAccountTransactionDTO tra final Money transactionAmountMoney = Money.of(this.currency, transactionDTO.getTransactionAmount()); final SavingsAccountTransaction transaction = SavingsAccountTransaction.withdrawal(this, office(), - transactionDTO.getPaymentDetail(), transactionDTO.getTransactionDate(), transactionAmountMoney, refNo); + transactionDTO.getPaymentDetail(), transactionDTO.getTransactionDate(), transactionAmountMoney, refNo, + getExternalId(ExternalId.empty())); if (backdatedTxnsAllowedTill) { addTransactionToExisting(transaction); @@ -3173,11 +3187,14 @@ private SavingsAccountTransaction handlePayChargeTransactions(SavingsAccountChar SavingsAccountTransaction chargeTransaction; if (savingsAccountCharge.isWithdrawalFee()) { - chargeTransaction = SavingsAccountTransaction.withdrawalFee(this, office(), transactionDate, transactionAmount, refNo); + chargeTransaction = SavingsAccountTransaction.withdrawalFee(this, office(), transactionDate, transactionAmount, refNo, + getExternalId(ExternalId.empty())); } else if (savingsAccountCharge.isAnnualFee()) { - chargeTransaction = SavingsAccountTransaction.annualFee(this, office(), transactionDate, transactionAmount); + chargeTransaction = SavingsAccountTransaction.annualFee(this, office(), transactionDate, transactionAmount, null, + getExternalId(ExternalId.empty())); } else { - chargeTransaction = SavingsAccountTransaction.charge(this, office(), transactionDate, transactionAmount); + chargeTransaction = SavingsAccountTransaction.charge(this, office(), transactionDate, transactionAmount, null, + getExternalId(ExternalId.empty())); } handleChargeTransactions(savingsAccountCharge, chargeTransaction, backdatedTxnsAllowedTill); @@ -3187,7 +3204,7 @@ private SavingsAccountTransaction handlePayChargeTransactions(SavingsAccountChar private void handleWaiverChargeTransactions(SavingsAccountCharge savingsAccountCharge, Money transactionAmount, boolean backdatedTxnsAllowedTill) { final SavingsAccountTransaction chargeTransaction = SavingsAccountTransaction.waiver(this, office(), - DateUtils.getBusinessLocalDate(), transactionAmount); + DateUtils.getBusinessLocalDate(), transactionAmount, null, ExternalId.empty()); handleChargeTransactions(savingsAccountCharge, chargeTransaction, backdatedTxnsAllowedTill); } @@ -3483,7 +3500,8 @@ public void escheat(AppUser appUser) { boolean postReversals = false; LocalDate transactionDate = DateUtils.getBusinessLocalDate(); if (this.getSummary().getAccountBalance(this.getCurrency()).isGreaterThanZero()) { - SavingsAccountTransaction transaction = SavingsAccountTransaction.escheat(this, transactionDate, postInterestAsOnDate); + SavingsAccountTransaction transaction = SavingsAccountTransaction.escheat(this, transactionDate, postInterestAsOnDate, + ExternalId.empty()); this.transactions.add(transaction); } recalculateDailyBalances(Money.zero(this.currency), transactionDate, false, postReversals); diff --git a/fineract-savings/src/main/java/org/apache/fineract/portfolio/savings/domain/SavingsAccountTransaction.java b/fineract-savings/src/main/java/org/apache/fineract/portfolio/savings/domain/SavingsAccountTransaction.java index 96aef542849..be70ed2ddb0 100644 --- a/fineract-savings/src/main/java/org/apache/fineract/portfolio/savings/domain/SavingsAccountTransaction.java +++ b/fineract-savings/src/main/java/org/apache/fineract/portfolio/savings/domain/SavingsAccountTransaction.java @@ -1,3 +1,21 @@ +/** + * 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. + */ /** * Licensed to the Apache Software Foundation (ASF) under one * or more contributor license agreements. See the NOTICE file @@ -22,6 +40,7 @@ import jakarta.persistence.CascadeType; import jakarta.persistence.Column; +import jakarta.persistence.Convert; import jakarta.persistence.Entity; import jakarta.persistence.FetchType; import jakarta.persistence.JoinColumn; @@ -41,6 +60,8 @@ import java.util.Optional; import java.util.Set; import org.apache.fineract.infrastructure.core.domain.AbstractAuditableWithUTCDateTimeCustom; +import org.apache.fineract.infrastructure.core.domain.ExternalId; +import org.apache.fineract.infrastructure.core.domain.ExternalIdConverter; import org.apache.fineract.infrastructure.core.domain.LocalDateInterval; import org.apache.fineract.infrastructure.core.service.DateUtils; import org.apache.fineract.organisation.monetary.domain.MonetaryCurrency; @@ -66,6 +87,10 @@ public final class SavingsAccountTransaction extends AbstractAuditableWithUTCDat @JoinColumn(name = "savings_account_id", referencedColumnName = "id", nullable = false) private SavingsAccount savingsAccount; + @Column(name = "external_id", length = 100, nullable = true, unique = true) + @Convert(converter = ExternalIdConverter.class) + private ExternalId externalId; + @ManyToOne @JoinColumn(name = "office_id", nullable = false) private Office office; @@ -142,7 +167,7 @@ public final class SavingsAccountTransaction extends AbstractAuditableWithUTCDat private SavingsAccountTransaction(final SavingsAccount savingsAccount, final Office office, final PaymentDetail paymentDetail, final Integer typeOf, final LocalDate transactionLocalDate, final BigDecimal amount, final boolean isReversed, - final boolean isManualTransaction, final Boolean lienTransaction, final String refNo) { + final boolean isManualTransaction, final Boolean lienTransaction, final String refNo, final ExternalId externalId) { this.savingsAccount = savingsAccount; this.office = office; this.typeOf = typeOf; @@ -155,186 +180,225 @@ private SavingsAccountTransaction(final SavingsAccount savingsAccount, final Off this.isManualTransaction = isManualTransaction; this.lienTransaction = lienTransaction; this.refNo = refNo; + this.externalId = externalId; } private SavingsAccountTransaction(final SavingsAccount savingsAccount, final Office office, final Integer typeOf, final LocalDate transactionLocalDate, final Money amount, final boolean isReversed, final boolean isManualTransaction, - final Boolean lienTransaction, final String refNo) { - this(savingsAccount, office, null, typeOf, transactionLocalDate, amount, isReversed, isManualTransaction, lienTransaction, refNo); + final Boolean lienTransaction, final String refNo, final ExternalId externalId) { + this(savingsAccount, office, null, typeOf, transactionLocalDate, amount, isReversed, isManualTransaction, lienTransaction, refNo, + externalId); } private SavingsAccountTransaction(final SavingsAccount savingsAccount, final Office office, final PaymentDetail paymentDetail, final Integer typeOf, final LocalDate transactionLocalDate, final Money amount, final boolean isReversed, - final boolean isManualTransaction, final Boolean lienTransaction, final String refNo) { + final boolean isManualTransaction, final Boolean lienTransaction, final String refNo, final ExternalId externalId) { this(savingsAccount, office, paymentDetail, typeOf, transactionLocalDate, amount.getAmount(), isReversed, isManualTransaction, - lienTransaction, refNo); + lienTransaction, refNo, externalId); } public static SavingsAccountTransaction deposit(final SavingsAccount savingsAccount, final Office office, - final PaymentDetail paymentDetail, final LocalDate date, final Money amount, final String refNo) { + final PaymentDetail paymentDetail, final LocalDate date, final Money amount, final String refNo, final ExternalId externalId) { final boolean isReversed = false; final boolean isManualTransaction = false; final Boolean lienTransaction = false; - return new SavingsAccountTransaction(savingsAccount, office, paymentDetail, SavingsAccountTransactionType.DEPOSIT.getValue(), date, - amount, isReversed, isManualTransaction, lienTransaction, refNo); + SavingsAccountTransaction transaction = new SavingsAccountTransaction(savingsAccount, office, paymentDetail, + SavingsAccountTransactionType.DEPOSIT.getValue(), date, amount, isReversed, isManualTransaction, lienTransaction, refNo, + externalId); + transaction.setExternalId(externalId); + return transaction; } public static SavingsAccountTransaction deposit(final SavingsAccount savingsAccount, final Office office, final PaymentDetail paymentDetail, final LocalDate date, final Money amount, - final SavingsAccountTransactionType savingsAccountTransactionType, final String refNo) { + final SavingsAccountTransactionType savingsAccountTransactionType, final String refNo, final ExternalId externalId) { final boolean isReversed = false; final boolean isManualTransaction = false; final Boolean lienTransaction = false; - return new SavingsAccountTransaction(savingsAccount, office, paymentDetail, savingsAccountTransactionType.getValue(), date, amount, - isReversed, isManualTransaction, lienTransaction, refNo); + SavingsAccountTransaction transaction = new SavingsAccountTransaction(savingsAccount, office, paymentDetail, + savingsAccountTransactionType.getValue(), date, amount, isReversed, isManualTransaction, lienTransaction, refNo, + externalId); + transaction.setExternalId(externalId); + return transaction; } public static SavingsAccountTransaction withdrawal(final SavingsAccount savingsAccount, final Office office, - final PaymentDetail paymentDetail, final LocalDate date, final Money amount, final String refNo) { + final PaymentDetail paymentDetail, final LocalDate date, final Money amount, final String refNo, final ExternalId externalId) { final boolean isReversed = false; final boolean isManualTransaction = false; final Boolean lienTransaction = false; - return new SavingsAccountTransaction(savingsAccount, office, paymentDetail, SavingsAccountTransactionType.WITHDRAWAL.getValue(), - date, amount, isReversed, isManualTransaction, lienTransaction, refNo); + SavingsAccountTransaction transaction = new SavingsAccountTransaction(savingsAccount, office, paymentDetail, + SavingsAccountTransactionType.WITHDRAWAL.getValue(), date, amount, isReversed, isManualTransaction, lienTransaction, refNo, + externalId); + transaction.setExternalId(externalId); + return transaction; } public static SavingsAccountTransaction interestPosting(final SavingsAccount savingsAccount, final Office office, final LocalDate date, - final Money amount, final boolean isManualTransaction) { + final Money amount, final boolean isManualTransaction, final ExternalId externalId) { final boolean isReversed = false; final Boolean lienTransaction = false; final String refNo = null; - return new SavingsAccountTransaction(savingsAccount, office, SavingsAccountTransactionType.INTEREST_POSTING.getValue(), date, - amount, isReversed, isManualTransaction, lienTransaction, refNo); + SavingsAccountTransaction transaction = new SavingsAccountTransaction(savingsAccount, office, + SavingsAccountTransactionType.INTEREST_POSTING.getValue(), date, amount, isReversed, isManualTransaction, lienTransaction, + refNo, externalId); + transaction.setExternalId(externalId); + return transaction; } public static SavingsAccountTransaction overdraftInterest(final SavingsAccount savingsAccount, final Office office, - final LocalDate date, final Money amount, final boolean isManualTransaction) { + final LocalDate date, final Money amount, final boolean isManualTransaction, final ExternalId externalId) { final boolean isReversed = false; final Boolean lienTransaction = false; final String refNo = null; - return new SavingsAccountTransaction(savingsAccount, office, SavingsAccountTransactionType.OVERDRAFT_INTEREST.getValue(), date, - amount, isReversed, isManualTransaction, lienTransaction, refNo); + SavingsAccountTransaction transaction = new SavingsAccountTransaction(savingsAccount, office, + SavingsAccountTransactionType.OVERDRAFT_INTEREST.getValue(), date, amount, isReversed, isManualTransaction, lienTransaction, + refNo, externalId); + transaction.setExternalId(externalId); + return transaction; } public static SavingsAccountTransaction withdrawalFee(final SavingsAccount savingsAccount, final Office office, final LocalDate date, - final Money amount, final String refNo) { + final Money amount, final String refNo, final ExternalId externalId) { final boolean isReversed = false; final boolean isManualTransaction = false; final Boolean lienTransaction = false; - return new SavingsAccountTransaction(savingsAccount, office, SavingsAccountTransactionType.WITHDRAWAL_FEE.getValue(), date, amount, - isReversed, isManualTransaction, lienTransaction, refNo); + SavingsAccountTransaction transaction = new SavingsAccountTransaction(savingsAccount, office, + SavingsAccountTransactionType.WITHDRAWAL_FEE.getValue(), date, amount, isReversed, isManualTransaction, lienTransaction, + refNo, externalId); + transaction.setExternalId(externalId); + return transaction; } public static SavingsAccountTransaction annualFee(final SavingsAccount savingsAccount, final Office office, final LocalDate date, - final Money amount) { + final Money amount, final String refNo, final ExternalId externalId) { final boolean isReversed = false; final boolean isManualTransaction = false; final Boolean lienTransaction = false; - final String refNo = null; - return new SavingsAccountTransaction(savingsAccount, office, SavingsAccountTransactionType.ANNUAL_FEE.getValue(), date, amount, - isReversed, isManualTransaction, lienTransaction, refNo); + SavingsAccountTransaction transaction = new SavingsAccountTransaction(savingsAccount, office, + SavingsAccountTransactionType.ANNUAL_FEE.getValue(), date, amount, isReversed, isManualTransaction, lienTransaction, refNo, + externalId); + transaction.setExternalId(externalId); + return transaction; } public static SavingsAccountTransaction charge(final SavingsAccount savingsAccount, final Office office, final LocalDate date, - final Money amount) { + final Money amount, final String refNo, final ExternalId externalId) { final boolean isReversed = false; final boolean isManualTransaction = false; final Boolean lienTransaction = false; - final String refNo = null; - return new SavingsAccountTransaction(savingsAccount, office, SavingsAccountTransactionType.PAY_CHARGE.getValue(), date, amount, - isReversed, isManualTransaction, lienTransaction, refNo); + SavingsAccountTransaction transaction = new SavingsAccountTransaction(savingsAccount, office, + SavingsAccountTransactionType.PAY_CHARGE.getValue(), date, amount, isReversed, isManualTransaction, lienTransaction, refNo, + externalId); + transaction.setExternalId(externalId); + return transaction; } public static SavingsAccountTransaction waiver(final SavingsAccount savingsAccount, final Office office, final LocalDate date, - final Money amount) { + final Money amount, final String refNo, final ExternalId externalId) { final boolean isReversed = false; final boolean isManualTransaction = false; final Boolean lienTransaction = false; - final String refNo = null; - return new SavingsAccountTransaction(savingsAccount, office, SavingsAccountTransactionType.WAIVE_CHARGES.getValue(), date, amount, - isReversed, isManualTransaction, lienTransaction, refNo); + SavingsAccountTransaction transaction = new SavingsAccountTransaction(savingsAccount, office, + SavingsAccountTransactionType.WAIVE_CHARGES.getValue(), date, amount, isReversed, isManualTransaction, lienTransaction, + refNo, externalId); + transaction.setExternalId(externalId); + return transaction; } - public static SavingsAccountTransaction initiateTransfer(final SavingsAccount savingsAccount, final Office office, - final LocalDate date) { + public static SavingsAccountTransaction initiateTransfer(final SavingsAccount savingsAccount, final Office office, final LocalDate date, + final ExternalId externalId) { final boolean isReversed = false; final boolean isManualTransaction = false; final PaymentDetail paymentDetail = null; final Boolean lienTransaction = false; final String refNo = null; - return new SavingsAccountTransaction(savingsAccount, office, paymentDetail, + SavingsAccountTransaction transaction = new SavingsAccountTransaction(savingsAccount, office, paymentDetail, SavingsAccountTransactionType.INITIATE_TRANSFER.getValue(), date, savingsAccount.getSummary().getAccountBalance(), - isReversed, isManualTransaction, lienTransaction, refNo); + isReversed, isManualTransaction, lienTransaction, refNo, externalId); + transaction.setExternalId(externalId); + return transaction; } - public static SavingsAccountTransaction approveTransfer(final SavingsAccount savingsAccount, final Office office, - final LocalDate date) { + public static SavingsAccountTransaction approveTransfer(final SavingsAccount savingsAccount, final Office office, final LocalDate date, + final ExternalId externalId) { final boolean isReversed = false; final boolean isManualTransaction = false; final PaymentDetail paymentDetail = null; final Boolean lienTransaction = false; final String refNo = null; - return new SavingsAccountTransaction(savingsAccount, office, paymentDetail, + SavingsAccountTransaction transaction = new SavingsAccountTransaction(savingsAccount, office, paymentDetail, SavingsAccountTransactionType.APPROVE_TRANSFER.getValue(), date, savingsAccount.getSummary().getAccountBalance(), - isReversed, isManualTransaction, lienTransaction, refNo); + isReversed, isManualTransaction, lienTransaction, refNo, externalId); + transaction.setExternalId(externalId); + return transaction; } - public static SavingsAccountTransaction withdrawTransfer(final SavingsAccount savingsAccount, final Office office, - final LocalDate date) { + public static SavingsAccountTransaction withdrawTransfer(final SavingsAccount savingsAccount, final Office office, final LocalDate date, + final ExternalId externalId) { final boolean isReversed = false; final boolean isManualTransaction = false; final PaymentDetail paymentDetail = null; final Boolean lienTransaction = false; final String refNo = null; - return new SavingsAccountTransaction(savingsAccount, office, paymentDetail, + SavingsAccountTransaction transaction = new SavingsAccountTransaction(savingsAccount, office, paymentDetail, SavingsAccountTransactionType.WITHDRAW_TRANSFER.getValue(), date, savingsAccount.getSummary().getAccountBalance(), - isReversed, isManualTransaction, lienTransaction, refNo); + isReversed, isManualTransaction, lienTransaction, refNo, externalId); + transaction.setExternalId(externalId); + return transaction; } public static SavingsAccountTransaction withHoldTax(final SavingsAccount savingsAccount, final Office office, final LocalDate date, - final Money amount, final Map taxDetails) { + final Money amount, final ExternalId externalId, final Map taxDetails) { final boolean isReversed = false; final boolean isManualTransaction = false; final Boolean lienTransaction = false; final String refNo = null; SavingsAccountTransaction accountTransaction = new SavingsAccountTransaction(savingsAccount, office, SavingsAccountTransactionType.WITHHOLD_TAX.getValue(), date, amount, isReversed, isManualTransaction, lienTransaction, - refNo); + refNo, externalId); updateTaxDetails(taxDetails, accountTransaction); return accountTransaction; } public static SavingsAccountTransaction escheat(final SavingsAccount savingsAccount, final LocalDate date, - final boolean accountTransaction) { + final boolean accountTransaction, final ExternalId externalId) { final boolean isReversed = false; final PaymentDetail paymentDetail = null; final Boolean lienTransaction = false; final String refNo = null; - return new SavingsAccountTransaction(savingsAccount, savingsAccount.office(), paymentDetail, + SavingsAccountTransaction transaction = new SavingsAccountTransaction(savingsAccount, savingsAccount.office(), paymentDetail, SavingsAccountTransactionType.ESCHEAT.getValue(), date, savingsAccount.getSummary().getAccountBalance(), isReversed, - accountTransaction, lienTransaction, refNo); + accountTransaction, lienTransaction, refNo, externalId); + transaction.setExternalId(externalId); + return transaction; } public static SavingsAccountTransaction copyTransaction(SavingsAccountTransaction accountTransaction) { return new SavingsAccountTransaction(accountTransaction.savingsAccount, accountTransaction.office, accountTransaction.paymentDetail, accountTransaction.typeOf, accountTransaction.getTransactionDate(), accountTransaction.amount, accountTransaction.reversed, - accountTransaction.isManualTransaction, accountTransaction.lienTransaction, accountTransaction.refNo); + accountTransaction.isManualTransaction, accountTransaction.lienTransaction, accountTransaction.refNo, + accountTransaction.externalId); } public static SavingsAccountTransaction holdAmount(final SavingsAccount savingsAccount, final Office office, - final PaymentDetail paymentDetail, final LocalDate date, final Money amount, final Boolean lienTransaction) { + final PaymentDetail paymentDetail, final LocalDate date, final Money amount, final Boolean lienTransaction, + final ExternalId externalId) { final boolean isReversed = false; final boolean isManualTransaction = false; final String refNo = null; - return new SavingsAccountTransaction(savingsAccount, office, paymentDetail, SavingsAccountTransactionType.AMOUNT_HOLD.getValue(), - date, amount, isReversed, isManualTransaction, lienTransaction, refNo); + SavingsAccountTransaction transaction = new SavingsAccountTransaction(savingsAccount, office, paymentDetail, + SavingsAccountTransactionType.AMOUNT_HOLD.getValue(), date, amount, isReversed, isManualTransaction, lienTransaction, refNo, + externalId); + transaction.setExternalId(externalId); + return transaction; } public static SavingsAccountTransaction releaseAmount(SavingsAccountTransaction accountTransaction, LocalDate transactionDate) { return new SavingsAccountTransaction(accountTransaction.savingsAccount, accountTransaction.office, accountTransaction.paymentDetail, SavingsAccountTransactionType.AMOUNT_RELEASE.getValue(), transactionDate, accountTransaction.amount, accountTransaction.reversed, accountTransaction.isManualTransaction, accountTransaction.lienTransaction, - accountTransaction.refNo); + accountTransaction.refNo, accountTransaction.externalId); } public static SavingsAccountTransaction reversal(SavingsAccountTransaction accountTransaction) { @@ -355,6 +419,14 @@ public static void updateTaxDetails(final Map taxDetai } } + public ExternalId getExternalId() { + return this.externalId; + } + + public void setExternalId(ExternalId externalId) { + this.externalId = externalId; + } + public SavingsAccount getSavingsAccount() { return this.savingsAccount; } @@ -592,6 +664,11 @@ public boolean hasNotAmount(final Money amountToCheck) { public Map toMapData(final String currencyCode) { final Map thisTransactionData = new LinkedHashMap<>(); + thisTransactionData.put("id", getId()); + + if (this.externalId != null) { + thisTransactionData.put("externalId", this.externalId.getValue()); + } final SavingsAccountTransactionEnumData transactionType = SavingsEnumerations.transactionType(this.typeOf); diff --git a/fineract-savings/src/main/java/org/apache/fineract/portfolio/savings/service/SavingsAccountDomainService.java b/fineract-savings/src/main/java/org/apache/fineract/portfolio/savings/service/SavingsAccountDomainService.java index 325c9dd8a63..048ba78d707 100644 --- a/fineract-savings/src/main/java/org/apache/fineract/portfolio/savings/service/SavingsAccountDomainService.java +++ b/fineract-savings/src/main/java/org/apache/fineract/portfolio/savings/service/SavingsAccountDomainService.java @@ -23,6 +23,7 @@ import java.time.format.DateTimeFormatter; import java.util.List; import java.util.Set; +import org.apache.fineract.infrastructure.core.domain.ExternalId; import org.apache.fineract.portfolio.paymentdetail.domain.PaymentDetail; import org.apache.fineract.portfolio.savings.SavingsTransactionBooleanValues; import org.apache.fineract.portfolio.savings.domain.SavingsAccount; @@ -32,20 +33,21 @@ public interface SavingsAccountDomainService { SavingsAccountTransaction handleWithdrawal(SavingsAccount account, DateTimeFormatter fmt, LocalDate transactionDate, BigDecimal transactionAmount, PaymentDetail paymentDetail, SavingsTransactionBooleanValues transactionBooleanValues, - boolean backdatedTxnsAllowedTill); + boolean backdatedTxnsAllowedTill, ExternalId externalId); SavingsAccountTransaction handleDeposit(SavingsAccount account, DateTimeFormatter fmt, LocalDate transactionDate, BigDecimal transactionAmount, PaymentDetail paymentDetail, boolean isAccountTransfer, boolean isRegularTransaction, - boolean backdatedTxnsAllowedTill); + boolean backdatedTxnsAllowedTill, ExternalId externalId); void postJournalEntries(SavingsAccount savingsAccount, Set existingTransactionIds, Set existingReversedTransactionIds, boolean backdatedTxnsAllowedTill); SavingsAccountTransaction handleDividendPayout(SavingsAccount account, LocalDate transactionDate, BigDecimal transactionAmount, - boolean backdatedTxnsAllowedTill); + boolean backdatedTxnsAllowedTill, ExternalId externalId); SavingsAccountTransaction handleReversal(SavingsAccount account, List savingsAccountTransactions, - boolean backdatedTxnsAllowedTill); + boolean backdatedTxnsAllowedTill, ExternalId externalId); - SavingsAccountTransaction handleHold(SavingsAccount account, BigDecimal amount, LocalDate transactionDate, Boolean lienAllowed); + SavingsAccountTransaction handleHold(SavingsAccount account, BigDecimal amount, LocalDate transactionDate, Boolean lienAllowed, + ExternalId externalId); } diff --git a/fineract-tax/src/main/resources/jpa/static-weaving/module/fineract-tax/persistence.xml b/fineract-tax/src/main/resources/jpa/static-weaving/module/fineract-tax/persistence.xml index 5a440edccc6..b730faf4e2a 100644 --- a/fineract-tax/src/main/resources/jpa/static-weaving/module/fineract-tax/persistence.xml +++ b/fineract-tax/src/main/resources/jpa/static-weaving/module/fineract-tax/persistence.xml @@ -22,57 +22,54 @@ + xmlns="http://java.sun.com/xml/ns/persistence" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xsi:schemaLocation="http://java.sun.com/xml/ns/persistence http://java.sun.com/xml/ns/persistence/persistence_2_0.xsd"> org.eclipse.persistence.jpa.PersistenceProvider - - org.apache.fineract.useradministration.domain.Role - org.apache.fineract.portfolio.fund.domain.Fund - org.apache.fineract.infrastructure.documentmanagement.domain.Image - org.apache.fineract.organisation.workingdays.domain.WorkingDays - org.apache.fineract.useradministration.domain.Permission - org.apache.fineract.useradministration.domain.AppUserClientMapping - org.apache.fineract.commands.domain.CommandSource - org.apache.fineract.useradministration.domain.AppUser + + org.apache.fineract.infrastructure.core.domain.ExternalIdConverter + + org.apache.fineract.infrastructure.core.domain.ExternalIdConverter org.apache.fineract.accounting.glaccount.domain.GLAccount - org.apache.fineract.organisation.monetary.domain.OrganisationCurrency + org.apache.fineract.accounting.journalentry.domain.JournalEntry + org.apache.fineract.infrastructure.core.domain.AbstractPersistableCustom + org.apache.fineract.infrastructure.core.domain.AbstractAuditableWithUTCDateTimeCustom + org.apache.fineract.infrastructure.codes.domain.Code + org.apache.fineract.infrastructure.codes.domain.CodeValue + org.apache.fineract.infrastructure.documentmanagement.domain.Image org.apache.fineract.organisation.staff.domain.Staff - org.apache.fineract.portfolio.rate.domain.Rate + org.apache.fineract.organisation.office.domain.Office + org.apache.fineract.organisation.office.domain.OrganisationCurrency org.apache.fineract.organisation.monetary.domain.ApplicationCurrency - org.apache.fineract.portfolio.calendar.domain.CalendarInstance - org.apache.fineract.portfolio.paymentdetail.domain.PaymentDetail - org.apache.fineract.portfolio.calendar.domain.Calendar - org.apache.fineract.portfolio.calendar.domain.CalendarHistory - org.apache.fineract.portfolio.client.domain.ClientIdentifier - org.apache.fineract.portfolio.delinquency.domain.DelinquencyBucket - org.apache.fineract.portfolio.delinquency.domain.DelinquencyRange - org.apache.fineract.portfolio.group.domain.StaffAssignmentHistory + org.apache.fineract.organisation.holiday.domain.Holiday + org.apache.fineract.organisation.workingdays.domain.WorkingDays org.apache.fineract.portfolio.group.domain.Group - org.apache.fineract.portfolio.client.domain.Client - org.apache.fineract.infrastructure.event.external.repository.domain.ExternalEventConfiguration + org.apache.fineract.portfolio.group.domain.GroupLevel + org.apache.fineract.portfolio.group.domain.StaffAssignmentHistory org.apache.fineract.portfolio.group.domain.GroupRole + org.apache.fineract.portfolio.client.domain.Client + org.apache.fineract.portfolio.client.domain.ClientIdentifier + org.apache.fineract.portfolio.fund.domain.Fund org.apache.fineract.portfolio.paymenttype.domain.PaymentType - org.apache.fineract.portfolio.group.domain.GroupLevel - org.apache.fineract.infrastructure.event.external.repository.domain.ExternalEvent - org.apache.fineract.organisation.office.domain.Office - org.apache.fineract.organisation.holiday.domain.Holiday - org.apache.fineract.infrastructure.cache.domain.PlatformCache - org.apache.fineract.infrastructure.codes.domain.Code - org.apache.fineract.infrastructure.businessdate.domain.BusinessDate - org.apache.fineract.infrastructure.codes.domain.CodeValue - - - org.apache.fineract.portfolio.tax.domain.TaxComponent - org.apache.fineract.portfolio.tax.domain.TaxComponentHistory + org.apache.fineract.portfolio.paymentdetail.domain.PaymentDetail + org.apache.fineract.portfolio.calendar.domain.Calendar + org.apache.fineract.portfolio.calendar.domain.CalendarHistory + org.apache.fineract.portfolio.calendar.domain.CalendarInstance + org.apache.fineract.useradministration.domain.AppUser + org.apache.fineract.useradministration.domain.Role + org.apache.fineract.useradministration.domain.Permission + org.apache.fineract.useradministration.domain.AppUserClientMapping + + org.apache.fineract.portfolio.charge.domain.Charge + org.apache.fineract.portfolio.tax.domain.TaxGroup org.apache.fineract.portfolio.tax.domain.TaxGroupMappings - + org.apache.fineract.portfolio.tax.domain.TaxComponent + org.apache.fineract.portfolio.tax.domain.TaxComponentHistory false diff --git a/gradlew b/gradlew index 1aa94a42690..f310503944e 100755 --- a/gradlew +++ b/gradlew @@ -168,36 +168,36 @@ fi # * DEFAULT_JVM_OPTS, JAVA_OPTS, and GRADLE_OPTS environment variables. # For Cygwin or MSYS, switch paths to Windows format before running java -if "$cygwin" || "$msys" ; then - APP_HOME=$( cygpath --path --mixed "$APP_HOME" ) - CLASSPATH=$( cygpath --path --mixed "$CLASSPATH" ) - +# Convert JAVACMD differently for Cygwin and MSYS +if "$cygwin"; then JAVACMD=$( cygpath --unix "$JAVACMD" ) - - # Now convert the arguments - kludge to limit ourselves to /bin/sh - for arg do - if - case $arg in #( - -*) false ;; # don't mess with options #( - /?*) t=${arg#/} t=/${t%%/*} # looks like a POSIX filepath - [ -e "$t" ] ;; #( - *) false ;; - esac - then - arg=$( cygpath --path --ignore --mixed "$arg" ) - fi - # Roll the args list around exactly as many times as the number of - # args, so each arg winds up back in the position where it started, but - # possibly modified. - # - # NB: a `for` loop captures its iteration list before it begins, so - # changing the positional parameters here affects neither the number of - # iterations, nor the values presented in `arg`. - shift # remove old arg - set -- "$@" "$arg" # push replacement arg - done +elif "$msys"; then + # For MSYS/MinGW, keep the Java path as is, with forward slashes + # This helps avoid the problematic /cygdrive prefix + echo "MinGW environment detected, using direct path: $JAVACMD" fi +# Now convert the arguments - kludge to limit ourselves to /bin/sh +for arg do + if case $arg in + -*) false ;; # don't mess with options + /?*) t=${arg#/} t=/${t%%/*} # looks like a POSIX filepath + [ -e "$t" ] ;; # check if file exists + *) false ;; + esac + then + arg=$( cygpath --path --ignore --mixed "$arg" ) + fi + # Roll the args list around exactly as many times as the number of + # args, so each arg winds up back in the position where it started, but + # possibly modified. + # + # NB: a `for` loop captures its iteration list before it begins, so + # changing the positional parameters here affects neither the number of + # iterations, nor the values presented in `arg`. + shift # remove old arg + set -- "$@" "$arg" # push replacement arg +done # Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"'