/** * 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.accounts.serialization; import java.lang.reflect.Type; import java.math.BigDecimal; import java.util.ArrayList; import java.util.Arrays; import java.util.Date; import java.util.HashMap; import java.util.HashSet; import java.util.List; import java.util.Locale; import java.util.Map; import java.util.Set; import org.apache.commons.lang.StringUtils; import org.joda.time.DateTime; import org.joda.time.LocalDate; import org.mifosplatform.accounting.glaccount.domain.GLAccount; import org.mifosplatform.accounting.glaccount.domain.GLAccountRepositoryWrapper; import org.mifosplatform.infrastructure.core.api.JsonCommand; import org.mifosplatform.infrastructure.core.data.ApiParameterError; import org.mifosplatform.infrastructure.core.data.DataValidatorBuilder; import org.mifosplatform.infrastructure.core.exception.InvalidJsonException; import org.mifosplatform.infrastructure.core.serialization.FromJsonHelper; import org.mifosplatform.infrastructure.core.service.DateUtils; import org.mifosplatform.infrastructure.security.service.PlatformSecurityContext; import org.mifosplatform.organisation.monetary.domain.MonetaryCurrency; import org.mifosplatform.portfolio.accounts.constants.ShareAccountApiConstants; import org.mifosplatform.portfolio.accounts.domain.PurchasedShares; import org.mifosplatform.portfolio.accounts.domain.ShareAccount; import org.mifosplatform.portfolio.accounts.domain.ShareAccountCharge; import org.mifosplatform.portfolio.charge.domain.Charge; import org.mifosplatform.portfolio.charge.domain.ChargeRepositoryWrapper; import org.mifosplatform.portfolio.client.domain.Client; import org.mifosplatform.portfolio.client.domain.ClientRepositoryWrapper; import org.mifosplatform.portfolio.common.domain.PeriodFrequencyType; import org.mifosplatform.portfolio.loanproduct.exception.InvalidCurrencyException; import org.mifosplatform.portfolio.products.exception.ProductNotFoundException; import org.mifosplatform.portfolio.savings.domain.SavingsAccount; import org.mifosplatform.portfolio.savings.domain.SavingsAccountRepositoryWrapper; import org.mifosplatform.portfolio.shares.domain.ShareProduct; import org.mifosplatform.portfolio.shares.domain.ShareProductTempRepository; import org.mifosplatform.useradministration.domain.AppUser; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; import com.google.gson.JsonArray; import com.google.gson.JsonElement; import com.google.gson.JsonObject; import com.google.gson.reflect.TypeToken; @Service public class ShareAccountDataSerializer { private final Set<String> supportedParameters = new HashSet<>(Arrays.asList("")); private final PlatformSecurityContext platformSecurityContext; private final FromJsonHelper fromApiJsonHelper; private final ChargeRepositoryWrapper chargeRepository; private final GLAccountRepositoryWrapper glAccountRepository; private final SavingsAccountRepositoryWrapper savingsAccountRepositoryWrapper; private final ClientRepositoryWrapper clientRepositoryWrapper; @Autowired public ShareAccountDataSerializer(final PlatformSecurityContext platformSecurityContext, final FromJsonHelper fromApiJsonHelper, final ChargeRepositoryWrapper chargeRepository, GLAccountRepositoryWrapper glAccountRepository, final SavingsAccountRepositoryWrapper savingsAccountRepositoryWrapper, final ClientRepositoryWrapper clientRepositoryWrapper) { this.platformSecurityContext = platformSecurityContext; this.fromApiJsonHelper = fromApiJsonHelper; this.chargeRepository = chargeRepository; this.glAccountRepository = glAccountRepository; this.savingsAccountRepositoryWrapper = savingsAccountRepositoryWrapper; this.clientRepositoryWrapper = clientRepositoryWrapper; } public ShareAccount validateAndCreate(JsonCommand jsonCommand) { if (StringUtils.isBlank(jsonCommand.json())) { throw new InvalidJsonException(); } final Type typeOfMap = new TypeToken<Map<String, Object>>() {}.getType(); //this.fromApiJsonHelper.checkForUnsupportedParameters(typeOfMap, jsonCommand.json(), supportedParameters); final List<ApiParameterError> dataValidationErrors = new ArrayList<>(); final DataValidatorBuilder baseDataValidator = new DataValidatorBuilder(dataValidationErrors).resource("sharesaccount"); JsonElement element = jsonCommand.parsedJson(); final Locale locale = this.fromApiJsonHelper.extractLocaleParameter(element.getAsJsonObject()); final Long clientId = this.fromApiJsonHelper.extractLongNamed(ShareAccountApiConstants.clientid_paramname, element); final Long productId = this.fromApiJsonHelper.extractLongNamed(ShareAccountApiConstants.productid_paramname, element); final Date submittedDate = this.fromApiJsonHelper.extractLocalDateNamed(ShareAccountApiConstants.submitteddate_paramname, element) .toDate(); // On creation submitted date will not be there. final Long fieldOfficerId = this.fromApiJsonHelper.extractLongNamed(ShareAccountApiConstants.fieldofferid_paramname, element); final String externalId = this.fromApiJsonHelper.extractStringNamed(ShareAccountApiConstants.externalid_paramname, element); Long suspenseAccountId = this.fromApiJsonHelper.extractLongNamed(ShareAccountApiConstants.suspenseaccount_paramname, element); Long equityAccountId = this.fromApiJsonHelper.extractLongNamed(ShareAccountApiConstants.equityaccount_paramname, element); Long savingsAccountId = this.fromApiJsonHelper.extractLongNamed(ShareAccountApiConstants.savingsaccountid_paramname, element); Set<PurchasedShares> sharesPurchased = asemblePurchasedShares(element); Boolean allowdividendsForInactiveClients = this.fromApiJsonHelper.extractBooleanNamed( ShareAccountApiConstants.allowdividendcalculationforinactiveclients_paramname, element); PeriodFrequencyType lockPeriod = extractPeriodType(ShareAccountApiConstants.lockperiod_paramname, element); PeriodFrequencyType minimumActivePeriod = extractPeriodType(ShareAccountApiConstants.minimumactiveperiodfordividends_paramname, element); Client client = this.clientRepositoryWrapper.findOneWithNotFoundDetection(clientId); GLAccount suspenseAccount = glAccountRepository.findOneWithNotFoundDetection(suspenseAccountId); GLAccount equityAccount = glAccountRepository.findOneWithNotFoundDetection(equityAccountId); SavingsAccount savingsAccount = this.savingsAccountRepositoryWrapper.findOneWithNotFoundDetection(savingsAccountId); ShareProduct shareProduct = ShareProductTempRepository.getInstance().fineOne(productId); if(shareProduct == null) { throw new ProductNotFoundException(productId, "Share") ; } final MonetaryCurrency currency = shareProduct.getCurrency() ; Set<ShareAccountCharge> charges = assembleListOfAccountCharges(element, currency.getCode()); AppUser modifiedBy = null; DateTime modifiedOn = null; Date approvedDate = null; AppUser createdBy = platformSecurityContext.authenticatedUser(); DateTime createdDate = DateUtils.getLocalDateTimeOfTenant().toDateTime(); ShareAccount account = new ShareAccount(client, shareProduct, submittedDate, approvedDate, fieldOfficerId, externalId, currency, suspenseAccount, equityAccount, savingsAccount, sharesPurchased, allowdividendsForInactiveClients, lockPeriod, minimumActivePeriod, charges, createdBy, createdDate, modifiedBy, modifiedOn); for(PurchasedShares pur: sharesPurchased) { pur.setShareAccount(account) ; } for(ShareAccountCharge charge: charges) { charge.setShareAccount(account) ; } return account; } public Map<String, Object> validateAndUpdate(JsonCommand jsonCommand, ShareAccount account) { Map<String, Object> actualChanges = new HashMap<>(); if (StringUtils.isBlank(jsonCommand.json())) { throw new InvalidJsonException(); } final Type typeOfMap = new TypeToken<Map<String, Object>>() {}.getType(); //this.fromApiJsonHelper.checkForUnsupportedParameters(typeOfMap, jsonCommand.json(), supportedParameters); final List<ApiParameterError> dataValidationErrors = new ArrayList<>(); final DataValidatorBuilder baseDataValidator = new DataValidatorBuilder(dataValidationErrors).resource("sharesaccount"); JsonElement element = jsonCommand.parsedJson(); final Locale locale = this.fromApiJsonHelper.extractLocaleParameter(element.getAsJsonObject()); if(this.fromApiJsonHelper.parameterExists(ShareAccountApiConstants.productid_paramname, element)) { final Long productId = this.fromApiJsonHelper.extractLongNamed(ShareAccountApiConstants.productid_paramname, element); ShareProduct shareProduct = ShareProductTempRepository.getInstance().fineOne(productId); if(account.setShareProduct(shareProduct)) { actualChanges.put(ShareAccountApiConstants.productid_paramname, shareProduct) ; } } if(this.fromApiJsonHelper.parameterExists(ShareAccountApiConstants.submitteddate_paramname, element)) { final Date submittedDate = this.fromApiJsonHelper.extractLocalDateNamed(ShareAccountApiConstants.submitteddate_paramname, element) .toDate(); if(account.setSubmittedDate(submittedDate)) { actualChanges.put(ShareAccountApiConstants.submitteddate_paramname, submittedDate) ; } } if(this.fromApiJsonHelper.parameterExists(ShareAccountApiConstants.fieldofferid_paramname, element)) { final Long fieldOfficerId = this.fromApiJsonHelper.extractLongNamed(ShareAccountApiConstants.fieldofferid_paramname, element); if(account.setFieldOfficer(fieldOfficerId)){ actualChanges.put(ShareAccountApiConstants.fieldofferid_paramname, fieldOfficerId) ; } } if(this.fromApiJsonHelper.parameterExists(ShareAccountApiConstants.externalid_paramname, element)) { final String externalId = this.fromApiJsonHelper.extractStringNamed(ShareAccountApiConstants.externalid_paramname, element); if(account.setExternalId(externalId)) { actualChanges.put(ShareAccountApiConstants.externalid_paramname, externalId) ; } } if(this.fromApiJsonHelper.parameterExists(ShareAccountApiConstants.suspenseaccount_paramname, element)) { Long suspenseAccountId = this.fromApiJsonHelper.extractLongNamed(ShareAccountApiConstants.suspenseaccount_paramname, element); GLAccount suspenseAccount = glAccountRepository.findOneWithNotFoundDetection(suspenseAccountId); if(account.setSuspenseAccount(suspenseAccount)) { actualChanges.put(ShareAccountApiConstants.suspenseaccount_paramname, suspenseAccount) ; } } if(this.fromApiJsonHelper.parameterExists(ShareAccountApiConstants.equityaccount_paramname, element)) { Long equityAccountId = this.fromApiJsonHelper.extractLongNamed(ShareAccountApiConstants.equityaccount_paramname, element); GLAccount equityAccount = glAccountRepository.findOneWithNotFoundDetection(equityAccountId); if(account.setEquityAccount(equityAccount)) { actualChanges.put(ShareAccountApiConstants.equityaccount_paramname, equityAccount) ; } } if(this.fromApiJsonHelper.parameterExists(ShareAccountApiConstants.savingsaccountid_paramname, element)) { Long savingsAccountId = this.fromApiJsonHelper.extractLongNamed(ShareAccountApiConstants.savingsaccountid_paramname, element); SavingsAccount savingsAccount = this.savingsAccountRepositoryWrapper.findOneWithNotFoundDetection(savingsAccountId); if(account.setSavingsAccount(savingsAccount)) { actualChanges.put(ShareAccountApiConstants.savingsaccountid_paramname, savingsAccount) ; } } if(this.fromApiJsonHelper.parameterExists(ShareAccountApiConstants.purchasedshares_paramname, element)) { Set<PurchasedShares> sharesPurchased = asemblePurchasedShares(element); account.setPurchasedShares(sharesPurchased) ; actualChanges.put(ShareAccountApiConstants.purchasedshares_paramname, sharesPurchased) ; } if (this.fromApiJsonHelper.parameterExists(ShareAccountApiConstants.allowdividendcalculationforinactiveclients_paramname, element)) { Boolean allowdividendsForInactiveClients = this.fromApiJsonHelper.extractBooleanNamed( ShareAccountApiConstants.allowdividendcalculationforinactiveclients_paramname, element); if (account.setAllowDividendCalculationForInactiveClients(allowdividendsForInactiveClients)) { actualChanges.put(ShareAccountApiConstants.allowdividendcalculationforinactiveclients_paramname, allowdividendsForInactiveClients); } } if (this.fromApiJsonHelper.parameterExists(ShareAccountApiConstants.lockperiod_paramname, element)) { PeriodFrequencyType lockPeriod = extractPeriodType(ShareAccountApiConstants.lockperiod_paramname, element); if (account.setLockPeriod(lockPeriod)) { actualChanges.put(ShareAccountApiConstants.lockperiod_paramname, lockPeriod); } } if (this.fromApiJsonHelper.parameterExists(ShareAccountApiConstants.minimumactiveperiodfordividends_paramname, element)) { PeriodFrequencyType minimumActivePeriod = extractPeriodType(ShareAccountApiConstants.minimumactiveperiodfordividends_paramname, element); if (account.setminimumActivePeriodForDividends(minimumActivePeriod)) { actualChanges.put(ShareAccountApiConstants.minimumactiveperiodfordividends_paramname, minimumActivePeriod); } } if (this.fromApiJsonHelper.parameterExists(ShareAccountApiConstants.charges_paramname, element)) { ShareProduct shareProduct = account.getShareProduct() ; Set<ShareAccountCharge> charges = assembleListOfAccountCharges(element, shareProduct.getCurrency().getCode()); if(account.setCharges(charges)) { actualChanges.put(ShareAccountApiConstants.charges_paramname, charges); } } AppUser modifiedBy = platformSecurityContext.authenticatedUser(); DateTime modifiedOn = DateUtils.getLocalDateTimeOfTenant().toDateTime(); return actualChanges; } private Set<ShareAccountCharge> assembleListOfAccountCharges(final JsonElement element, final String currencyCode) { final Set<ShareAccountCharge> charges = new HashSet<>(); if (this.fromApiJsonHelper.parameterExists(ShareAccountApiConstants.charges_paramname, element)) { JsonArray chargesArray = this.fromApiJsonHelper.extractJsonArrayNamed(ShareAccountApiConstants.charges_paramname, element); if (chargesArray != null) { for (int i = 0; i < chargesArray.size(); i++) { final JsonObject jsonObject = chargesArray.get(i).getAsJsonObject(); if (jsonObject.has("id")) { final Long id = jsonObject.get("id").getAsLong(); final Charge charge = this.chargeRepository.findOneWithNotFoundDetection(id); if (!currencyCode.equals(charge.getCurrencyCode())) { final String errorMessage = "Charge and Share Account must have the same currency."; throw new InvalidCurrencyException("charge", "attach.to.share.account", errorMessage); } ShareAccountCharge accountCharge = new ShareAccountCharge(charge); charges.add(accountCharge); } } } } return charges; } private PeriodFrequencyType extractPeriodType(String paramName, final JsonElement element) { PeriodFrequencyType frequencyType = PeriodFrequencyType.INVALID; frequencyType = PeriodFrequencyType.fromInt(this.fromApiJsonHelper.extractIntegerWithLocaleNamed(paramName, element)); return frequencyType; } private Set<PurchasedShares> asemblePurchasedShares(final JsonElement element) { Set<PurchasedShares> set = null; if (this.fromApiJsonHelper.parameterExists(ShareAccountApiConstants.purchasedshares_paramname, element)) { set = new HashSet<>(); JsonArray array = this.fromApiJsonHelper.extractJsonArrayNamed(ShareAccountApiConstants.purchasedshares_paramname, element); for (JsonElement arrayElement : array) { LocalDate localDate = this.fromApiJsonHelper.extractLocalDateNamed(ShareAccountApiConstants.purchaseddate_paramname, arrayElement); final Long shares = this.fromApiJsonHelper.extractLongNamed(ShareAccountApiConstants.numberofshares_paramname, arrayElement); final BigDecimal shareValue = this.fromApiJsonHelper.extractBigDecimalWithLocaleNamed( ShareAccountApiConstants.purchasedprice_paramname, arrayElement); PurchasedShares obj = new PurchasedShares(localDate.toDate(), shares, shareValue); set.add(obj); } } return set; } public Set<PurchasedShares> asembleAdditionalShares(final JsonElement element) { Set<PurchasedShares> set = null; if (this.fromApiJsonHelper.parameterExists(ShareAccountApiConstants.additionalshares_paramname, element)) { set = new HashSet<>(); JsonArray array = this.fromApiJsonHelper.extractJsonArrayNamed(ShareAccountApiConstants.additionalshares_paramname, element); for (JsonElement arrayElement : array) { LocalDate localDate = this.fromApiJsonHelper.extractLocalDateNamed(ShareAccountApiConstants.purchaseddate_paramname, arrayElement); final Long shares = this.fromApiJsonHelper.extractLongNamed(ShareAccountApiConstants.numberofshares_paramname, arrayElement); final BigDecimal shareValue = this.fromApiJsonHelper.extractBigDecimalWithLocaleNamed( ShareAccountApiConstants.purchasedprice_paramname, arrayElement); PurchasedShares obj = new PurchasedShares(localDate.toDate(), shares, shareValue); set.add(obj); } } return set; } }