| /** |
| * Licensed to the Apache Software Foundation (ASF) under one |
| * or more contributor license agreements. See the NOTICE file |
| * distributed with this work for additional information |
| * regarding copyright ownership. The ASF licenses this file |
| * to you under the Apache License, Version 2.0 (the |
| * "License"); you may not use this file except in compliance |
| * with the License. You may obtain a copy of the License at |
| * |
| * http://www.apache.org/licenses/LICENSE-2.0 |
| * |
| * Unless required by applicable law or agreed to in writing, |
| * software distributed under the License is distributed on an |
| * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY |
| * KIND, either express or implied. See the License for the |
| * specific language governing permissions and limitations |
| * under the License. |
| */ |
| package org.apache.fineract.portfolio.savings.domain; |
| |
| import static org.apache.fineract.portfolio.savings.SavingsApiConstants.SAVINGS_ACCOUNT_RESOURCE_NAME; |
| import static org.apache.fineract.portfolio.savings.SavingsApiConstants.accountNoParamName; |
| import static org.apache.fineract.portfolio.savings.SavingsApiConstants.allowOverdraftParamName; |
| import static org.apache.fineract.portfolio.savings.SavingsApiConstants.clientIdParamName; |
| import static org.apache.fineract.portfolio.savings.SavingsApiConstants.enforceMinRequiredBalanceParamName; |
| import static org.apache.fineract.portfolio.savings.SavingsApiConstants.externalIdParamName; |
| import static org.apache.fineract.portfolio.savings.SavingsApiConstants.fieldOfficerIdParamName; |
| import static org.apache.fineract.portfolio.savings.SavingsApiConstants.groupIdParamName; |
| import static org.apache.fineract.portfolio.savings.SavingsApiConstants.interestCalculationDaysInYearTypeParamName; |
| import static org.apache.fineract.portfolio.savings.SavingsApiConstants.interestCalculationTypeParamName; |
| import static org.apache.fineract.portfolio.savings.SavingsApiConstants.interestCompoundingPeriodTypeParamName; |
| import static org.apache.fineract.portfolio.savings.SavingsApiConstants.interestPostingPeriodTypeParamName; |
| import static org.apache.fineract.portfolio.savings.SavingsApiConstants.lockinPeriodFrequencyParamName; |
| import static org.apache.fineract.portfolio.savings.SavingsApiConstants.lockinPeriodFrequencyTypeParamName; |
| import static org.apache.fineract.portfolio.savings.SavingsApiConstants.minOverdraftForInterestCalculationParamName; |
| import static org.apache.fineract.portfolio.savings.SavingsApiConstants.minRequiredBalanceParamName; |
| import static org.apache.fineract.portfolio.savings.SavingsApiConstants.minRequiredOpeningBalanceParamName; |
| import static org.apache.fineract.portfolio.savings.SavingsApiConstants.nominalAnnualInterestRateOverdraftParamName; |
| import static org.apache.fineract.portfolio.savings.SavingsApiConstants.nominalAnnualInterestRateParamName; |
| import static org.apache.fineract.portfolio.savings.SavingsApiConstants.overdraftLimitParamName; |
| import static org.apache.fineract.portfolio.savings.SavingsApiConstants.productIdParamName; |
| import static org.apache.fineract.portfolio.savings.SavingsApiConstants.submittedOnDateParamName; |
| import static org.apache.fineract.portfolio.savings.SavingsApiConstants.withdrawalFeeForTransfersParamName; |
| |
| import java.math.BigDecimal; |
| import java.util.Set; |
| |
| import org.apache.fineract.infrastructure.core.api.JsonCommand; |
| import org.apache.fineract.infrastructure.core.serialization.FromJsonHelper; |
| import org.apache.fineract.infrastructure.core.service.DateUtils; |
| import org.apache.fineract.organisation.staff.domain.Staff; |
| import org.apache.fineract.organisation.staff.domain.StaffRepositoryWrapper; |
| import org.apache.fineract.portfolio.account.service.AccountTransfersReadPlatformService; |
| import org.apache.fineract.portfolio.accountdetails.domain.AccountType; |
| import org.apache.fineract.portfolio.client.domain.Client; |
| import org.apache.fineract.portfolio.client.domain.ClientRepositoryWrapper; |
| import org.apache.fineract.portfolio.client.exception.ClientNotActiveException; |
| import org.apache.fineract.portfolio.group.domain.Group; |
| import org.apache.fineract.portfolio.group.domain.GroupRepositoryWrapper; |
| import org.apache.fineract.portfolio.group.exception.CenterNotActiveException; |
| import org.apache.fineract.portfolio.group.exception.ClientNotInGroupException; |
| import org.apache.fineract.portfolio.group.exception.GroupNotActiveException; |
| import org.apache.fineract.portfolio.savings.SavingsCompoundingInterestPeriodType; |
| import org.apache.fineract.portfolio.savings.SavingsInterestCalculationDaysInYearType; |
| import org.apache.fineract.portfolio.savings.SavingsInterestCalculationType; |
| import org.apache.fineract.portfolio.savings.SavingsPeriodFrequencyType; |
| import org.apache.fineract.portfolio.savings.SavingsPostingInterestPeriodType; |
| import org.apache.fineract.portfolio.savings.exception.SavingsProductNotFoundException; |
| import org.apache.fineract.useradministration.domain.AppUser; |
| import org.joda.time.LocalDate; |
| import org.springframework.beans.factory.annotation.Autowired; |
| import org.springframework.stereotype.Service; |
| |
| import com.google.gson.JsonElement; |
| |
| @Service |
| public class SavingsAccountAssembler { |
| |
| private final SavingsAccountTransactionSummaryWrapper savingsAccountTransactionSummaryWrapper; |
| private final SavingsHelper savingsHelper; |
| private final ClientRepositoryWrapper clientRepository; |
| private final GroupRepositoryWrapper groupRepository; |
| private final StaffRepositoryWrapper staffRepository; |
| private final SavingsProductRepository savingProductRepository; |
| private final SavingsAccountRepositoryWrapper savingsAccountRepository; |
| private final SavingsAccountChargeAssembler savingsAccountChargeAssembler; |
| private final FromJsonHelper fromApiJsonHelper; |
| |
| @Autowired |
| public SavingsAccountAssembler(final SavingsAccountTransactionSummaryWrapper savingsAccountTransactionSummaryWrapper, |
| final ClientRepositoryWrapper clientRepository, final GroupRepositoryWrapper groupRepository, |
| final StaffRepositoryWrapper staffRepository, final SavingsProductRepository savingProductRepository, |
| final SavingsAccountRepositoryWrapper savingsAccountRepository, |
| final SavingsAccountChargeAssembler savingsAccountChargeAssembler, final FromJsonHelper fromApiJsonHelper, |
| final AccountTransfersReadPlatformService accountTransfersReadPlatformService) { |
| this.savingsAccountTransactionSummaryWrapper = savingsAccountTransactionSummaryWrapper; |
| this.clientRepository = clientRepository; |
| this.groupRepository = groupRepository; |
| this.staffRepository = staffRepository; |
| this.savingProductRepository = savingProductRepository; |
| this.savingsAccountRepository = savingsAccountRepository; |
| this.savingsAccountChargeAssembler = savingsAccountChargeAssembler; |
| this.fromApiJsonHelper = fromApiJsonHelper; |
| savingsHelper = new SavingsHelper(accountTransfersReadPlatformService); |
| } |
| |
| /** |
| * Assembles a new {@link SavingsAccount} from JSON details passed in |
| * request inheriting details where relevant from chosen |
| * {@link SavingsProduct}. |
| */ |
| public SavingsAccount assembleFrom(final JsonCommand command, final AppUser submittedBy) { |
| |
| final JsonElement element = command.parsedJson(); |
| |
| final String accountNo = this.fromApiJsonHelper.extractStringNamed(accountNoParamName, element); |
| final String externalId = this.fromApiJsonHelper.extractStringNamed(externalIdParamName, element); |
| final Long productId = this.fromApiJsonHelper.extractLongNamed(productIdParamName, element); |
| |
| final SavingsProduct product = this.savingProductRepository.findOne(productId); |
| if (product == null) { throw new SavingsProductNotFoundException(productId); } |
| |
| Client client = null; |
| Group group = null; |
| Staff fieldOfficer = null; |
| AccountType accountType = AccountType.INVALID; |
| final Long clientId = this.fromApiJsonHelper.extractLongNamed(clientIdParamName, element); |
| if (clientId != null) { |
| client = this.clientRepository.findOneWithNotFoundDetection(clientId); |
| accountType = AccountType.INDIVIDUAL; |
| if (client.isNotActive()) { throw new ClientNotActiveException(clientId); } |
| } |
| |
| final Long groupId = this.fromApiJsonHelper.extractLongNamed(groupIdParamName, element); |
| if (groupId != null) { |
| group = this.groupRepository.findOneWithNotFoundDetection(groupId); |
| accountType = AccountType.GROUP; |
| if (group.isNotActive()) { |
| if (group.isCenter()) { throw new CenterNotActiveException(groupId); } |
| throw new GroupNotActiveException(groupId); |
| } |
| } |
| |
| if (group != null && client != null) { |
| if (!group.hasClientAsMember(client)) { throw new ClientNotInGroupException(clientId, groupId); } |
| accountType = AccountType.JLG; |
| } |
| |
| final Long fieldOfficerId = this.fromApiJsonHelper.extractLongNamed(fieldOfficerIdParamName, element); |
| if (fieldOfficerId != null) { |
| fieldOfficer = this.staffRepository.findOneWithNotFoundDetection(fieldOfficerId); |
| } |
| |
| final LocalDate submittedOnDate = this.fromApiJsonHelper.extractLocalDateNamed(submittedOnDateParamName, element); |
| |
| BigDecimal interestRate = null; |
| if (command.parameterExists(nominalAnnualInterestRateParamName)) { |
| interestRate = command.bigDecimalValueOfParameterNamed(nominalAnnualInterestRateParamName); |
| } else { |
| interestRate = product.nominalAnnualInterestRate(); |
| } |
| |
| SavingsCompoundingInterestPeriodType interestCompoundingPeriodType = null; |
| final Integer interestPeriodTypeValue = command.integerValueOfParameterNamed(interestCompoundingPeriodTypeParamName); |
| if (interestPeriodTypeValue != null) { |
| interestCompoundingPeriodType = SavingsCompoundingInterestPeriodType.fromInt(interestPeriodTypeValue); |
| } else { |
| interestCompoundingPeriodType = product.interestCompoundingPeriodType(); |
| } |
| |
| SavingsPostingInterestPeriodType interestPostingPeriodType = null; |
| final Integer interestPostingPeriodTypeValue = command.integerValueOfParameterNamed(interestPostingPeriodTypeParamName); |
| if (interestPostingPeriodTypeValue != null) { |
| interestPostingPeriodType = SavingsPostingInterestPeriodType.fromInt(interestPostingPeriodTypeValue); |
| } else { |
| interestPostingPeriodType = product.interestPostingPeriodType(); |
| } |
| |
| SavingsInterestCalculationType interestCalculationType = null; |
| final Integer interestCalculationTypeValue = command.integerValueOfParameterNamed(interestCalculationTypeParamName); |
| if (interestCalculationTypeValue != null) { |
| interestCalculationType = SavingsInterestCalculationType.fromInt(interestCalculationTypeValue); |
| } else { |
| interestCalculationType = product.interestCalculationType(); |
| } |
| |
| SavingsInterestCalculationDaysInYearType interestCalculationDaysInYearType = null; |
| final Integer interestCalculationDaysInYearTypeValue = command |
| .integerValueOfParameterNamed(interestCalculationDaysInYearTypeParamName); |
| if (interestCalculationDaysInYearTypeValue != null) { |
| interestCalculationDaysInYearType = SavingsInterestCalculationDaysInYearType.fromInt(interestCalculationDaysInYearTypeValue); |
| } else { |
| interestCalculationDaysInYearType = product.interestCalculationDaysInYearType(); |
| } |
| |
| BigDecimal minRequiredOpeningBalance = null; |
| if (command.parameterExists(minRequiredOpeningBalanceParamName)) { |
| minRequiredOpeningBalance = command.bigDecimalValueOfParameterNamed(minRequiredOpeningBalanceParamName); |
| } else { |
| minRequiredOpeningBalance = product.minRequiredOpeningBalance(); |
| } |
| |
| Integer lockinPeriodFrequency = null; |
| if (command.parameterExists(lockinPeriodFrequencyParamName)) { |
| lockinPeriodFrequency = command.integerValueOfParameterNamed(lockinPeriodFrequencyParamName); |
| } else { |
| lockinPeriodFrequency = product.lockinPeriodFrequency(); |
| } |
| |
| SavingsPeriodFrequencyType lockinPeriodFrequencyType = null; |
| Integer lockinPeriodFrequencyTypeValue = null; |
| if (command.parameterExists(lockinPeriodFrequencyTypeParamName)) { |
| lockinPeriodFrequencyTypeValue = command.integerValueOfParameterNamed(lockinPeriodFrequencyTypeParamName); |
| if (lockinPeriodFrequencyTypeValue != null) { |
| lockinPeriodFrequencyType = SavingsPeriodFrequencyType.fromInt(lockinPeriodFrequencyTypeValue); |
| } |
| } else { |
| lockinPeriodFrequencyType = product.lockinPeriodFrequencyType(); |
| } |
| boolean iswithdrawalFeeApplicableForTransfer = false; |
| if (command.parameterExists(withdrawalFeeForTransfersParamName)) { |
| iswithdrawalFeeApplicableForTransfer = command.booleanPrimitiveValueOfParameterNamed(withdrawalFeeForTransfersParamName); |
| } |
| |
| final Set<SavingsAccountCharge> charges = this.savingsAccountChargeAssembler.fromParsedJson(element, product.currency().getCode()); |
| |
| boolean allowOverdraft = false; |
| if (command.parameterExists(allowOverdraftParamName)) { |
| allowOverdraft = command.booleanPrimitiveValueOfParameterNamed(allowOverdraftParamName); |
| } else { |
| allowOverdraft = product.isAllowOverdraft(); |
| } |
| |
| BigDecimal overdraftLimit = BigDecimal.ZERO; |
| if (command.parameterExists(overdraftLimitParamName)) { |
| overdraftLimit = command.bigDecimalValueOfParameterNamedDefaultToNullIfZero(overdraftLimitParamName); |
| } else { |
| overdraftLimit = product.overdraftLimit(); |
| } |
| |
| BigDecimal nominalAnnualInterestRateOverdraft = BigDecimal.ZERO; |
| if (command.parameterExists(nominalAnnualInterestRateOverdraftParamName)) { |
| nominalAnnualInterestRateOverdraft = command.bigDecimalValueOfParameterNamedDefaultToNullIfZero(nominalAnnualInterestRateOverdraftParamName); |
| } else { |
| nominalAnnualInterestRateOverdraft = product.nominalAnnualInterestRateOverdraft(); |
| } |
| |
| BigDecimal minOverdraftForInterestCalculation = BigDecimal.ZERO; |
| if (command.parameterExists(minOverdraftForInterestCalculationParamName)) { |
| minOverdraftForInterestCalculation = command.bigDecimalValueOfParameterNamedDefaultToNullIfZero(minOverdraftForInterestCalculationParamName); |
| } else { |
| minOverdraftForInterestCalculation = product.minOverdraftForInterestCalculation(); |
| } |
| |
| boolean enforceMinRequiredBalance = false; |
| if (command.parameterExists(enforceMinRequiredBalanceParamName)) { |
| enforceMinRequiredBalance = command.booleanPrimitiveValueOfParameterNamed(enforceMinRequiredBalanceParamName); |
| } else { |
| enforceMinRequiredBalance = product.isMinRequiredBalanceEnforced(); |
| } |
| |
| BigDecimal minRequiredBalance = BigDecimal.ZERO; |
| if (command.parameterExists(minRequiredBalanceParamName)) { |
| minRequiredBalance = command.bigDecimalValueOfParameterNamedDefaultToNullIfZero(minRequiredBalanceParamName); |
| } else { |
| minRequiredBalance = product.minRequiredBalance(); |
| } |
| |
| final SavingsAccount account = SavingsAccount.createNewApplicationForSubmittal(client, group, product, fieldOfficer, accountNo, |
| externalId, accountType, submittedOnDate, submittedBy, interestRate, interestCompoundingPeriodType, |
| interestPostingPeriodType, interestCalculationType, interestCalculationDaysInYearType, minRequiredOpeningBalance, |
| lockinPeriodFrequency, lockinPeriodFrequencyType, iswithdrawalFeeApplicableForTransfer, charges, allowOverdraft, |
| overdraftLimit, enforceMinRequiredBalance, minRequiredBalance, |
| nominalAnnualInterestRateOverdraft, minOverdraftForInterestCalculation); |
| account.setHelpers(this.savingsAccountTransactionSummaryWrapper, this.savingsHelper); |
| |
| account.validateNewApplicationState(DateUtils.getLocalDateOfTenant(), SAVINGS_ACCOUNT_RESOURCE_NAME); |
| |
| account.validateAccountValuesWithProduct(); |
| |
| return account; |
| } |
| |
| public SavingsAccount assembleFrom(final Long savingsId) { |
| final SavingsAccount account = this.savingsAccountRepository.findOneWithNotFoundDetection(savingsId); |
| account.setHelpers(this.savingsAccountTransactionSummaryWrapper, this.savingsHelper); |
| return account; |
| } |
| |
| public void setHelpers(final SavingsAccount account) { |
| account.setHelpers(this.savingsAccountTransactionSummaryWrapper, this.savingsHelper); |
| } |
| |
| /** |
| * Assembles a new {@link SavingsAccount} from JSON details passed in |
| * request inheriting details where relevant from chosen |
| * {@link SavingsProduct}. |
| */ |
| public SavingsAccount assembleFrom(final Client client, final Group group, final SavingsProduct product, final LocalDate appliedonDate, |
| final AppUser appliedBy) { |
| |
| AccountType accountType = AccountType.INVALID; |
| if (client != null) { |
| accountType = AccountType.INDIVIDUAL; |
| if (client.isNotActive()) { throw new ClientNotActiveException(client.getId()); } |
| } |
| |
| if (group != null) { |
| accountType = AccountType.GROUP; |
| if (group.isNotActive()) { |
| if (group.isCenter()) { throw new CenterNotActiveException(group.getId()); } |
| throw new GroupNotActiveException(group.getId()); |
| } |
| } |
| |
| if (group != null && client != null) { |
| if (!group.hasClientAsMember(client)) { throw new ClientNotInGroupException(client.getId(), group.getId()); } |
| accountType = AccountType.JLG; |
| } |
| |
| final Set<SavingsAccountCharge> charges = this.savingsAccountChargeAssembler.fromSavingsProduct(product); |
| |
| final SavingsAccount account = SavingsAccount.createNewApplicationForSubmittal(client, group, product, null, null, null, |
| accountType, appliedonDate, appliedBy, product.nominalAnnualInterestRate(), product.interestCompoundingPeriodType(), |
| product.interestPostingPeriodType(), product.interestCalculationType(), product.interestCalculationDaysInYearType(), |
| product.minRequiredOpeningBalance(), product.lockinPeriodFrequency(), product.lockinPeriodFrequencyType(), |
| product.isWithdrawalFeeApplicableForTransfer(), charges, product.isAllowOverdraft(), product.overdraftLimit(), |
| product.isMinRequiredBalanceEnforced(), product.minRequiredBalance(), product.nominalAnnualInterestRateOverdraft(), |
| product.minOverdraftForInterestCalculation()); |
| account.setHelpers(this.savingsAccountTransactionSummaryWrapper, this.savingsHelper); |
| |
| account.validateNewApplicationState(DateUtils.getLocalDateOfTenant(), SAVINGS_ACCOUNT_RESOURCE_NAME); |
| |
| account.validateAccountValuesWithProduct(); |
| |
| return account; |
| } |
| |
| public void assignSavingAccountHelpers(final SavingsAccount savingsAccount) { |
| savingsAccount.setHelpers(this.savingsAccountTransactionSummaryWrapper, this.savingsHelper); |
| } |
| } |