/** * 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.shares.serialization; import java.lang.reflect.Type; import java.math.BigDecimal; import java.util.ArrayList; import java.util.Arrays; 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.charge.domain.Charge; import org.mifosplatform.portfolio.charge.domain.ChargeRepositoryWrapper; import org.mifosplatform.portfolio.common.domain.PeriodFrequencyType; import org.mifosplatform.portfolio.loanproduct.exception.InvalidCurrencyException; import org.mifosplatform.portfolio.shares.constants.ShareProductApiConstants; import org.mifosplatform.portfolio.shares.domain.ShareMarketPrice; import org.mifosplatform.portfolio.shares.domain.ShareProduct; 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; //This class responsibility is to validate data and serialize to entity and return object to the caller @Service public class ShareProductDataSerializer { private final Set<String> supportedParameters = new HashSet<>(Arrays.asList("")); private final FromJsonHelper fromApiJsonHelper; private final ChargeRepositoryWrapper chargeRepository; private final GLAccountRepositoryWrapper glAccountRepository; private final PlatformSecurityContext platformSecurityContext ; @Autowired public ShareProductDataSerializer(final FromJsonHelper fromApiJsonHelper, final ChargeRepositoryWrapper chargeRepository, final GLAccountRepositoryWrapper glAccountRepository, final PlatformSecurityContext platformSecurityContext) { this.fromApiJsonHelper = fromApiJsonHelper; this.chargeRepository = chargeRepository; this.glAccountRepository = glAccountRepository; this.platformSecurityContext = platformSecurityContext ; } public ShareProduct 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("sharesproduct"); JsonElement element = jsonCommand.parsedJson(); final Locale locale = this.fromApiJsonHelper.extractLocaleParameter(element.getAsJsonObject()); final String productName = this.fromApiJsonHelper.extractStringNamed(ShareProductApiConstants.name_paramname, element); baseDataValidator.reset().parameter(ShareProductApiConstants.name_paramname).value(productName).notBlank() .notExceedingLengthOf(200); final String shortName = this.fromApiJsonHelper.extractStringNamed(ShareProductApiConstants.shortname_paramname, element); baseDataValidator.reset().parameter(ShareProductApiConstants.shortname_paramname).value(shortName).notBlank() .notExceedingLengthOf(10); String description = null; if (this.fromApiJsonHelper.parameterExists(ShareProductApiConstants.description_paramname, element)) { description = this.fromApiJsonHelper.extractStringNamed(ShareProductApiConstants.description_paramname, element); } String externalId = this.fromApiJsonHelper.extractStringNamed(ShareProductApiConstants.externalid_paramname, element); Long totalNumberOfShares = this.fromApiJsonHelper.extractLongNamed(ShareProductApiConstants.totalshares_paramname, element); final String currencyCode = this.fromApiJsonHelper.extractStringNamed(ShareProductApiConstants.currency_paramname, element); final Integer digitsAfterDecimal = this.fromApiJsonHelper.extractIntegerWithLocaleNamed( ShareProductApiConstants.digitsafterdecimal_paramname, element); final Integer inMultiplesOf = this.fromApiJsonHelper.extractIntegerWithLocaleNamed( ShareProductApiConstants.inmultiplesof_paramname, element); final MonetaryCurrency currency = new MonetaryCurrency(currencyCode, digitsAfterDecimal, inMultiplesOf); final Long sharesIssued = this.fromApiJsonHelper.extractLongNamed(ShareProductApiConstants.totalsharesissued_paramname, element); final BigDecimal unitPrice = this.fromApiJsonHelper.extractBigDecimalNamed(ShareProductApiConstants.unitprice_paramname, element, locale); final BigDecimal shareCapitalValue = null; Long suspenseAccountId = this.fromApiJsonHelper.extractLongNamed(ShareProductApiConstants.suspenseaccount_paramname, element); Long equityAccountId = this.fromApiJsonHelper.extractLongNamed(ShareProductApiConstants.equityaccount_paramname, element); Long minimumClientShares = this.fromApiJsonHelper.extractLongNamed(ShareProductApiConstants.minimumshares_paramname, element); Long nominalClientShares = this.fromApiJsonHelper.extractLongNamed(ShareProductApiConstants.nominaltshares_paramname, element); Long maximumClientShares = this.fromApiJsonHelper.extractLongNamed(ShareProductApiConstants.maximumshares_paramname, element); Set<ShareMarketPrice> marketPriceSet = asembleShareMarketPrice(element); Set<Charge> charges = assembleListOfProductCharges(element, currencyCode); Boolean allowdividendsForInactiveClients = this.fromApiJsonHelper.extractBooleanNamed( ShareProductApiConstants.allowdividendcalculationforinactiveclients_paramname, element); PeriodFrequencyType lockPeriod = extractPeriodType(ShareProductApiConstants.lockperiod_paramname, element); PeriodFrequencyType minimumActivePeriod = extractPeriodType(ShareProductApiConstants.minimumactiveperiodfordividends_paramname, element); GLAccount suspenseAccount = glAccountRepository.findOneWithNotFoundDetection(suspenseAccountId); GLAccount equityAccount = glAccountRepository.findOneWithNotFoundDetection(equityAccountId); AppUser modifiedBy = null; DateTime modifiedOn = null; AppUser createdBy = platformSecurityContext.authenticatedUser() ; DateTime createdDate = DateUtils.getLocalDateTimeOfTenant().toDateTime() ; ShareProduct product = new ShareProduct(productName, shortName, description, externalId, currency, totalNumberOfShares, sharesIssued, unitPrice, shareCapitalValue, suspenseAccount, equityAccount, minimumClientShares, nominalClientShares, maximumClientShares, marketPriceSet, charges, allowdividendsForInactiveClients, lockPeriod, minimumActivePeriod, createdBy, createdDate, modifiedBy, modifiedOn); return product; } private PeriodFrequencyType extractPeriodType(String paramName, final JsonElement element) { PeriodFrequencyType frequencyType = PeriodFrequencyType.INVALID; frequencyType = PeriodFrequencyType.fromInt(this.fromApiJsonHelper.extractIntegerWithLocaleNamed(paramName, element)); return frequencyType; } private Set<ShareMarketPrice> asembleShareMarketPrice(final JsonElement element) { Set<ShareMarketPrice> set = null; if (this.fromApiJsonHelper.parameterExists(ShareProductApiConstants.marketprice_paramname, element)) { set = new HashSet<>(); JsonArray array = this.fromApiJsonHelper.extractJsonArrayNamed(ShareProductApiConstants.marketprice_paramname, element); for (JsonElement arrayElement : array) { LocalDate localDate = this.fromApiJsonHelper.extractLocalDateNamed(ShareProductApiConstants.startdate_paramname, arrayElement); final BigDecimal shareValue = this.fromApiJsonHelper.extractBigDecimalWithLocaleNamed( ShareProductApiConstants.sharevalue_paramname, arrayElement); ShareMarketPrice obj = new ShareMarketPrice(localDate.toDate(), shareValue); set.add(obj); } } return set; } private Set<Charge> assembleListOfProductCharges(final JsonElement element, final String currencyCode) { final Set<Charge> charges = new HashSet<>(); if (this.fromApiJsonHelper.parameterExists(ShareProductApiConstants.charges_paramname, element)) { JsonArray chargesArray = this.fromApiJsonHelper.extractJsonArrayNamed(ShareProductApiConstants.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 Loan Product must have the same currency."; throw new InvalidCurrencyException("charge", "attach.to.loan.product", errorMessage); } charges.add(charge); } } } } return charges; } public Map<String, Object> validateAndUpdate(JsonCommand jsonCommand, ShareProduct product) { 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("sharesproduct"); JsonElement element = jsonCommand.parsedJson(); final Locale locale = this.fromApiJsonHelper.extractLocaleParameter(element.getAsJsonObject()); if (this.fromApiJsonHelper.parameterExists(ShareProductApiConstants.name_paramname, element)) { final String productName = this.fromApiJsonHelper.extractStringNamed(ShareProductApiConstants.name_paramname, element); if (product.setProductName(productName)) { actualChanges.put(ShareProductApiConstants.name_paramname, productName); } } if (this.fromApiJsonHelper.parameterExists(ShareProductApiConstants.shortname_paramname, element)) { final String shortName = this.fromApiJsonHelper.extractStringNamed(ShareProductApiConstants.shortname_paramname, element); if (product.setShortName(shortName)) { actualChanges.put(ShareProductApiConstants.shortname_paramname, shortName); } } if (this.fromApiJsonHelper.parameterExists(ShareProductApiConstants.description_paramname, element)) { String description = this.fromApiJsonHelper.extractStringNamed(ShareProductApiConstants.description_paramname, element); if (product.setDescription(description)) { actualChanges.put(ShareProductApiConstants.description_paramname, description); } } if (this.fromApiJsonHelper.parameterExists(ShareProductApiConstants.externalid_paramname, element)) { String externalId = this.fromApiJsonHelper.extractStringNamed(ShareProductApiConstants.externalid_paramname, element); if (product.setExternalId(externalId)) { actualChanges.put(ShareProductApiConstants.externalid_paramname, externalId); } } if (this.fromApiJsonHelper.parameterExists(ShareProductApiConstants.totalshares_paramname, element)) { Long totalShares = this.fromApiJsonHelper.extractLongNamed(ShareProductApiConstants.totalshares_paramname, element); if (product.setTotalShares(totalShares)) { actualChanges.put(ShareProductApiConstants.totalshares_paramname, totalShares); } } if (this.fromApiJsonHelper.parameterExists(ShareProductApiConstants.totalsharesissued_paramname, element)) { final Long sharesIssued = this.fromApiJsonHelper .extractLongNamed(ShareProductApiConstants.totalsharesissued_paramname, element); if (product.setTotalIssuedShares(sharesIssued)) { actualChanges.put(ShareProductApiConstants.totalsharesissued_paramname, sharesIssued); } } if (this.fromApiJsonHelper.parameterExists(ShareProductApiConstants.currency_paramname, element) && this.fromApiJsonHelper.parameterExists(ShareProductApiConstants.digitsafterdecimal_paramname, element) && this.fromApiJsonHelper.parameterExists(ShareProductApiConstants.inmultiplesof_paramname, element)) { final String currencyCode = this.fromApiJsonHelper.extractStringNamed(ShareProductApiConstants.currency_paramname, element); final Integer digitsAfterDecimal = this.fromApiJsonHelper.extractIntegerWithLocaleNamed( ShareProductApiConstants.digitsafterdecimal_paramname, element); final Integer inMultiplesOf = this.fromApiJsonHelper.extractIntegerWithLocaleNamed( ShareProductApiConstants.inmultiplesof_paramname, element); final MonetaryCurrency currency = new MonetaryCurrency(currencyCode, digitsAfterDecimal, inMultiplesOf); if (product.setMonetaryCurrency(currency)) { actualChanges.put(ShareProductApiConstants.currency_paramname, currency); } } if (this.fromApiJsonHelper.parameterExists(ShareProductApiConstants.unitprice_paramname, element)) { final BigDecimal unitPrice = this.fromApiJsonHelper.extractBigDecimalNamed(ShareProductApiConstants.unitprice_paramname, element, locale); if (product.setUnitPrice(unitPrice)) { actualChanges.put(ShareProductApiConstants.unitprice_paramname, unitPrice); } } if (this.fromApiJsonHelper.parameterExists(ShareProductApiConstants.suspenseaccount_paramname, element)) { Long suspenseAccountId = this.fromApiJsonHelper.extractLongNamed(ShareProductApiConstants.suspenseaccount_paramname, element); GLAccount suspenseAccount = glAccountRepository.findOneWithNotFoundDetection(suspenseAccountId); if (product.setSuspenseAccount(suspenseAccount)) { actualChanges.put(ShareProductApiConstants.suspenseaccount_paramname, suspenseAccount); } } if (this.fromApiJsonHelper.parameterExists(ShareProductApiConstants.equityaccount_paramname, element)) { Long equityAccountId = this.fromApiJsonHelper.extractLongNamed(ShareProductApiConstants.equityaccount_paramname, element); GLAccount equityAccount = glAccountRepository.findOneWithNotFoundDetection(equityAccountId); if (product.setEquityAccount(equityAccount)) { actualChanges.put(ShareProductApiConstants.equityaccount_paramname, equityAccount); } } if (this.fromApiJsonHelper.parameterExists(ShareProductApiConstants.minimumshares_paramname, element)) { Long minimumClientShares = this.fromApiJsonHelper.extractLongNamed(ShareProductApiConstants.minimumshares_paramname, element); if (product.setMinimumShares(minimumClientShares)) { actualChanges.put(ShareProductApiConstants.minimumshares_paramname, minimumClientShares); } } if (this.fromApiJsonHelper.parameterExists(ShareProductApiConstants.nominaltshares_paramname, element)) { Long nominalClientShares = this.fromApiJsonHelper.extractLongNamed(ShareProductApiConstants.nominaltshares_paramname, element); if (product.setNominalShares(nominalClientShares)) { actualChanges.put(ShareProductApiConstants.nominaltshares_paramname, nominalClientShares); } } if (this.fromApiJsonHelper.parameterExists(ShareProductApiConstants.maximumshares_paramname, element)) { Long maximumClientShares = this.fromApiJsonHelper.extractLongNamed(ShareProductApiConstants.maximumshares_paramname, element); if (product.setMaximumShares(maximumClientShares)) { actualChanges.put(ShareProductApiConstants.maximumshares_paramname, maximumClientShares); } } if (this.fromApiJsonHelper.parameterExists(ShareProductApiConstants.marketprice_paramname, element)) { Set<ShareMarketPrice> marketPrice = asembleShareMarketPrice(element); if (product.setMarketPrice(marketPrice)) { actualChanges.put(ShareProductApiConstants.marketprice_paramname, marketPrice); } } if (this.fromApiJsonHelper.parameterExists(ShareProductApiConstants.charges_paramname, element)) { final String currencyCode = this.fromApiJsonHelper.extractStringNamed(ShareProductApiConstants.currency_paramname, element); Set<Charge> charges = assembleListOfProductCharges(element, currencyCode); if (product.setCharges(charges)) { actualChanges.put(ShareProductApiConstants.charges_paramname, charges); } } if (this.fromApiJsonHelper.parameterExists(ShareProductApiConstants.allowdividendcalculationforinactiveclients_paramname, element)) { Boolean allowdividendsForInactiveClients = this.fromApiJsonHelper.extractBooleanNamed( ShareProductApiConstants.allowdividendcalculationforinactiveclients_paramname, element); if (product.setAllowDividendCalculationForInactiveClients(allowdividendsForInactiveClients)) { actualChanges.put(ShareProductApiConstants.allowdividendcalculationforinactiveclients_paramname, allowdividendsForInactiveClients); } } if (this.fromApiJsonHelper.parameterExists(ShareProductApiConstants.lockperiod_paramname, element)) { PeriodFrequencyType lockPeriod = extractPeriodType(ShareProductApiConstants.lockperiod_paramname, element); if (product.setLockPeriod(lockPeriod)) { actualChanges.put(ShareProductApiConstants.lockperiod_paramname, lockPeriod); } } if (this.fromApiJsonHelper.parameterExists(ShareProductApiConstants.minimumactiveperiodfordividends_paramname, element)) { PeriodFrequencyType minimumActivePeriod = extractPeriodType(ShareProductApiConstants.minimumactiveperiodfordividends_paramname, element); if (product.setminimumActivePeriodForDividends(minimumActivePeriod)) { actualChanges.put(ShareProductApiConstants.minimumactiveperiodfordividends_paramname, minimumActivePeriod); } } return actualChanges; } }