/** * This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this file, * You can obtain one at http://mozilla.org/MPL/2.0/. */ package org.mifosplatform.portfolio.savings.domain; import static org.mifosplatform.portfolio.savings.SavingsApiConstants.SAVINGS_ACCOUNT_RESOURCE_NAME; import static org.mifosplatform.portfolio.savings.SavingsApiConstants.accountNoParamName; import static org.mifosplatform.portfolio.savings.SavingsApiConstants.allowOverdraftParamName; import static org.mifosplatform.portfolio.savings.SavingsApiConstants.clientIdParamName; import static org.mifosplatform.portfolio.savings.SavingsApiConstants.enforceMinRequiredBalanceParamName; import static org.mifosplatform.portfolio.savings.SavingsApiConstants.externalIdParamName; import static org.mifosplatform.portfolio.savings.SavingsApiConstants.fieldOfficerIdParamName; import static org.mifosplatform.portfolio.savings.SavingsApiConstants.groupIdParamName; import static org.mifosplatform.portfolio.savings.SavingsApiConstants.interestCalculationDaysInYearTypeParamName; import static org.mifosplatform.portfolio.savings.SavingsApiConstants.interestCalculationTypeParamName; import static org.mifosplatform.portfolio.savings.SavingsApiConstants.interestCompoundingPeriodTypeParamName; import static org.mifosplatform.portfolio.savings.SavingsApiConstants.interestPostingPeriodTypeParamName; import static org.mifosplatform.portfolio.savings.SavingsApiConstants.lockinPeriodFrequencyParamName; import static org.mifosplatform.portfolio.savings.SavingsApiConstants.lockinPeriodFrequencyTypeParamName; import static org.mifosplatform.portfolio.savings.SavingsApiConstants.minRequiredBalanceParamName; import static org.mifosplatform.portfolio.savings.SavingsApiConstants.minRequiredOpeningBalanceParamName; import static org.mifosplatform.portfolio.savings.SavingsApiConstants.nominalAnnualInterestRateParamName; import static org.mifosplatform.portfolio.savings.SavingsApiConstants.overdraftLimitParamName; import static org.mifosplatform.portfolio.savings.SavingsApiConstants.nominalAnnualInterestRateOverdraftParamName; import static org.mifosplatform.portfolio.savings.SavingsApiConstants.minOverdraftForInterestCalculationParamName; import static org.mifosplatform.portfolio.savings.SavingsApiConstants.productIdParamName; import static org.mifosplatform.portfolio.savings.SavingsApiConstants.submittedOnDateParamName; import static org.mifosplatform.portfolio.savings.SavingsApiConstants.withdrawalFeeForTransfersParamName; import java.math.BigDecimal; import java.util.Set; import org.joda.time.LocalDate; import org.mifosplatform.infrastructure.core.api.JsonCommand; import org.mifosplatform.infrastructure.core.serialization.FromJsonHelper; import org.mifosplatform.infrastructure.core.service.DateUtils; import org.mifosplatform.organisation.staff.domain.Staff; import org.mifosplatform.organisation.staff.domain.StaffRepositoryWrapper; import org.mifosplatform.portfolio.account.service.AccountTransfersReadPlatformService; import org.mifosplatform.portfolio.accountdetails.domain.AccountType; import org.mifosplatform.portfolio.client.domain.Client; import org.mifosplatform.portfolio.client.domain.ClientRepositoryWrapper; import org.mifosplatform.portfolio.client.exception.ClientNotActiveException; import org.mifosplatform.portfolio.group.domain.Group; import org.mifosplatform.portfolio.group.domain.GroupRepositoryWrapper; import org.mifosplatform.portfolio.group.exception.CenterNotActiveException; import org.mifosplatform.portfolio.group.exception.ClientNotInGroupException; import org.mifosplatform.portfolio.group.exception.GroupNotActiveException; import org.mifosplatform.portfolio.savings.SavingsCompoundingInterestPeriodType; import org.mifosplatform.portfolio.savings.SavingsInterestCalculationDaysInYearType; import org.mifosplatform.portfolio.savings.SavingsInterestCalculationType; import org.mifosplatform.portfolio.savings.SavingsPeriodFrequencyType; import org.mifosplatform.portfolio.savings.SavingsPostingInterestPeriodType; import org.mifosplatform.portfolio.savings.exception.SavingsProductNotFoundException; import org.mifosplatform.useradministration.domain.AppUser; 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); } }