fineract-commits mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From raj...@apache.org
Subject [03/12] incubator-fineract git commit: Shares And Dividends Implementation
Date Wed, 13 Apr 2016 14:35:15 GMT
http://git-wip-us.apache.org/repos/asf/incubator-fineract/blob/08c553f9/fineract-provider/src/main/java/org/apache/fineract/portfolio/shareproducts/serialization/ShareProductDataSerializer.java
----------------------------------------------------------------------
diff --git a/fineract-provider/src/main/java/org/apache/fineract/portfolio/shareproducts/serialization/ShareProductDataSerializer.java b/fineract-provider/src/main/java/org/apache/fineract/portfolio/shareproducts/serialization/ShareProductDataSerializer.java
new file mode 100644
index 0000000..345294b
--- /dev/null
+++ b/fineract-provider/src/main/java/org/apache/fineract/portfolio/shareproducts/serialization/ShareProductDataSerializer.java
@@ -0,0 +1,460 @@
+/**
+ * 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.shareproducts.serialization;
+
+import java.lang.reflect.Type;
+import java.math.BigDecimal;
+import java.util.ArrayList;
+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.apache.fineract.accounting.common.AccountingRuleType;
+import org.apache.fineract.infrastructure.core.api.JsonCommand;
+import org.apache.fineract.infrastructure.core.data.ApiParameterError;
+import org.apache.fineract.infrastructure.core.data.DataValidatorBuilder;
+import org.apache.fineract.infrastructure.core.exception.InvalidJsonException;
+import org.apache.fineract.infrastructure.core.exception.PlatformApiDataValidationException;
+import org.apache.fineract.infrastructure.core.serialization.FromJsonHelper;
+import org.apache.fineract.infrastructure.core.service.DateUtils;
+import org.apache.fineract.infrastructure.security.service.PlatformSecurityContext;
+import org.apache.fineract.organisation.monetary.domain.MonetaryCurrency;
+import org.apache.fineract.portfolio.charge.domain.Charge;
+import org.apache.fineract.portfolio.charge.domain.ChargeRepositoryWrapper;
+import org.apache.fineract.portfolio.common.domain.PeriodFrequencyType;
+import org.apache.fineract.portfolio.loanproduct.exception.InvalidCurrencyException;
+import org.apache.fineract.portfolio.shareproducts.constants.ShareProductApiConstants;
+import org.apache.fineract.portfolio.shareproducts.data.ShareProductMarketPriceData;
+import org.apache.fineract.portfolio.shareproducts.domain.ShareProduct;
+import org.apache.fineract.portfolio.shareproducts.domain.ShareProductMarketPrice;
+import org.apache.fineract.useradministration.domain.AppUser;
+import org.joda.time.DateTime;
+import org.joda.time.LocalDate;
+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 ShareProductDataSerializer {
+
+    private final FromJsonHelper fromApiJsonHelper;
+
+    private final ChargeRepositoryWrapper chargeRepository;
+
+    private final PlatformSecurityContext platformSecurityContext;
+
+    @Autowired
+    public ShareProductDataSerializer(final FromJsonHelper fromApiJsonHelper, final ChargeRepositoryWrapper chargeRepository,
+            final PlatformSecurityContext platformSecurityContext) {
+        this.fromApiJsonHelper = fromApiJsonHelper;
+        this.chargeRepository = chargeRepository;
+        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(),
+                ShareProductApiConstants.supportedParametersForCreate);
+
+        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(4);
+        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);
+        // baseDataValidator.reset().parameter(ShareProductApiConstants.externalid_paramname).value(externalId).notBlank();
+
+        Long totalNumberOfShares = this.fromApiJsonHelper.extractLongNamed(ShareProductApiConstants.totalshares_paramname, element);
+        baseDataValidator.reset().parameter(ShareProductApiConstants.totalshares_paramname).value(totalNumberOfShares).notNull()
+                .longGreaterThanZero();
+
+        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);
+        baseDataValidator.reset().parameter(ShareProductApiConstants.unitprice_paramname).value(unitPrice).notNull().positiveAmount();
+
+        BigDecimal shareCapitalValue = BigDecimal.ONE;
+        if (sharesIssued != null && unitPrice != null) {
+            shareCapitalValue = BigDecimal.valueOf(sharesIssued).multiply(unitPrice);
+        }
+
+        Integer accountingRule = this.fromApiJsonHelper.extractIntegerNamed(ShareProductApiConstants.accountingRuleParamName, element,
+                locale);
+        baseDataValidator.reset().parameter(ShareProductApiConstants.accountingRuleParamName).value(accountingRule).notNull()
+                .integerGreaterThanZero();
+        AccountingRuleType accountingRuleType = null;
+        if (accountingRule != null) {
+            accountingRuleType = AccountingRuleType.fromInt(accountingRule);
+        }
+
+        Long minimumClientShares = this.fromApiJsonHelper.extractLongNamed(ShareProductApiConstants.minimumshares_paramname, element);
+        Long nominalClientShares = this.fromApiJsonHelper.extractLongNamed(ShareProductApiConstants.nominaltshares_paramname, element);
+        baseDataValidator.reset().parameter(ShareProductApiConstants.nominaltshares_paramname).value(nominalClientShares).notNull()
+                .longGreaterThanZero();
+        if (minimumClientShares != null && nominalClientShares != null) {
+            baseDataValidator.reset().parameter(ShareProductApiConstants.nominaltshares_paramname).value(nominalClientShares)
+                    .longGreaterThanNumber(minimumClientShares);
+        }
+        Long maximumClientShares = this.fromApiJsonHelper.extractLongNamed(ShareProductApiConstants.maximumshares_paramname, element);
+        if (maximumClientShares != null && nominalClientShares != null) {
+            baseDataValidator.reset().parameter(ShareProductApiConstants.maximumshares_paramname).value(maximumClientShares)
+                    .longGreaterThanNumber(nominalClientShares);
+        }
+
+        Set<ShareProductMarketPrice> marketPriceSet = asembleShareMarketPrice(element);
+        Set<Charge> charges = assembleListOfProductCharges(element, currencyCode);
+        Boolean allowdividendsForInactiveClients = this.fromApiJsonHelper.extractBooleanNamed(
+                ShareProductApiConstants.allowdividendcalculationforinactiveclients_paramname, element);
+
+        Integer minimumActivePeriod = this.fromApiJsonHelper.extractIntegerNamed(
+                ShareProductApiConstants.minimumactiveperiodfordividends_paramname, element, locale);
+        PeriodFrequencyType minimumActivePeriodType = extractPeriodType(
+                ShareProductApiConstants.minimumactiveperiodfrequencytype_paramname, element);
+        if (minimumActivePeriod != null) {
+            baseDataValidator.reset().parameter(ShareProductApiConstants.minimumactiveperiodfrequencytype_paramname)
+                    .value(minimumActivePeriodType.getValue()).integerSameAsNumber(PeriodFrequencyType.DAYS.getValue());
+        }
+
+        Integer lockinPeriod = this.fromApiJsonHelper.extractIntegerNamed(ShareProductApiConstants.lockperiod_paramname, element, locale);
+        PeriodFrequencyType lockPeriodType = extractPeriodType(ShareProductApiConstants.lockinperiodfrequencytype_paramname, element);
+
+        AppUser createdBy = platformSecurityContext.authenticatedUser();
+        AppUser modifiedBy = createdBy;
+        DateTime createdDate = DateUtils.getLocalDateTimeOfTenant().toDateTime();
+        DateTime modifiedOn = createdDate;
+        ShareProduct product = new ShareProduct(productName, shortName, description, externalId, currency, totalNumberOfShares,
+                sharesIssued, unitPrice, shareCapitalValue, minimumClientShares, nominalClientShares, maximumClientShares, marketPriceSet,
+                charges, allowdividendsForInactiveClients, lockinPeriod, lockPeriodType, minimumActivePeriod, minimumActivePeriodType,
+                createdBy, createdDate, modifiedBy, modifiedOn, accountingRuleType);
+        for (ShareProductMarketPrice data : marketPriceSet) {
+            data.setShareProduct(product);
+        }
+        if (!dataValidationErrors.isEmpty()) { throw new PlatformApiDataValidationException(dataValidationErrors); }
+        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<ShareProductMarketPriceData> asembleShareMarketPriceForUpdate(final JsonElement element) {
+        Set<ShareProductMarketPriceData> 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) {
+                Long id = this.fromApiJsonHelper.extractLongNamed(ShareProductApiConstants.id_paramname, arrayElement);
+                LocalDate localDate = this.fromApiJsonHelper.extractLocalDateNamed(ShareProductApiConstants.startdate_paramname,
+                        arrayElement);
+                final BigDecimal shareValue = this.fromApiJsonHelper.extractBigDecimalWithLocaleNamed(
+                        ShareProductApiConstants.sharevalue_paramname, arrayElement);
+                ShareProductMarketPriceData obj = new ShareProductMarketPriceData(id, localDate.toDate(), shareValue);
+                set.add(obj);
+            }
+        }
+        return set;
+    }
+
+    private Set<ShareProductMarketPrice> asembleShareMarketPrice(final JsonElement element) {
+        Set<ShareProductMarketPrice> 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);
+                ShareProductMarketPrice obj = new ShareProductMarketPrice(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 Share Product must have the same currency.";
+                            throw new InvalidCurrencyException("charge", "attach.to.share.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(),
+                ShareProductApiConstants.supportedParametersForCreate);
+
+        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);
+            baseDataValidator.reset().parameter(ShareProductApiConstants.name_paramname).value(productName).notBlank();
+            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);
+            baseDataValidator.reset().parameter(ShareProductApiConstants.shortname_paramname).value(shortName).notBlank();
+            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);
+            baseDataValidator.reset().parameter(ShareProductApiConstants.externalid_paramname).value(externalId).notBlank();
+            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);
+            baseDataValidator.reset().parameter(ShareProductApiConstants.totalshares_paramname).value(totalShares).notNull()
+                    .longGreaterThanZero();
+            if (product.setTotalShares(totalShares)) {
+                actualChanges.put(ShareProductApiConstants.totalshares_paramname, totalShares);
+            }
+        }
+        Long sharesIssued = null;
+        if (this.fromApiJsonHelper.parameterExists(ShareProductApiConstants.totalsharesissued_paramname, element)) {
+            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);
+            }
+        }
+
+        BigDecimal unitPrice = null;
+        if (this.fromApiJsonHelper.parameterExists(ShareProductApiConstants.unitprice_paramname, element)) {
+            unitPrice = this.fromApiJsonHelper.extractBigDecimalNamed(ShareProductApiConstants.unitprice_paramname, element, locale);
+            baseDataValidator.reset().parameter(ShareProductApiConstants.unitprice_paramname).value(unitPrice).notNull().positiveAmount();
+            if (product.setUnitPrice(unitPrice)) {
+                actualChanges.put(ShareProductApiConstants.unitprice_paramname, unitPrice);
+            }
+        }
+
+        if (this.fromApiJsonHelper.parameterExists(ShareProductApiConstants.accountingRuleParamName, element)) {
+            Integer accountingRule = this.fromApiJsonHelper.extractIntegerWithLocaleNamed(ShareProductApiConstants.accountingRuleParamName,
+                    element);
+            baseDataValidator.reset().parameter(ShareProductApiConstants.accountingRuleParamName).value(accountingRule).notNull()
+                    .integerGreaterThanZero();
+            if (product.setAccountingRule(accountingRule)) {
+                actualChanges.put(ShareProductApiConstants.accountingRuleParamName, accountingRule);
+            }
+        }
+
+        if (this.fromApiJsonHelper.parameterExists(ShareProductApiConstants.minimumshares_paramname, element)) {
+            Long minimumClientShares = this.fromApiJsonHelper.extractLongNamed(ShareProductApiConstants.minimumshares_paramname, element);
+            baseDataValidator.reset().parameter(ShareProductApiConstants.minimumshares_paramname).value(minimumClientShares).notNull()
+                    .longGreaterThanZero();
+            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);
+            baseDataValidator.reset().parameter(ShareProductApiConstants.nominaltshares_paramname).value(nominalClientShares).notNull()
+                    .longGreaterThanZero();
+            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);
+            baseDataValidator.reset().parameter(ShareProductApiConstants.maximumshares_paramname).value(maximumClientShares).notNull()
+                    .longGreaterThanZero();
+            if (product.setMaximumShares(maximumClientShares)) {
+                actualChanges.put(ShareProductApiConstants.maximumshares_paramname, maximumClientShares);
+            }
+        }
+
+        if (this.fromApiJsonHelper.parameterExists(ShareProductApiConstants.marketprice_paramname, element)) {
+            Set<ShareProductMarketPriceData> marketPrice = asembleShareMarketPriceForUpdate(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);
+            }
+        }
+
+        Integer minimumActivePeriod = null;
+
+        if (this.fromApiJsonHelper.parameterExists(ShareProductApiConstants.minimumactiveperiodfordividends_paramname, element)) {
+            minimumActivePeriod = this.fromApiJsonHelper.extractIntegerNamed(
+                    ShareProductApiConstants.minimumactiveperiodfordividends_paramname, element, locale);
+            if (product.setminimumActivePeriod(minimumActivePeriod)) {
+                actualChanges.put(ShareProductApiConstants.minimumactiveperiodfordividends_paramname, minimumActivePeriod);
+            }
+        }
+
+        if (this.fromApiJsonHelper.parameterExists(ShareProductApiConstants.minimumactiveperiodfrequencytype_paramname, element)) {
+            PeriodFrequencyType minimumActivePeriodType = extractPeriodType(
+                    ShareProductApiConstants.minimumactiveperiodfrequencytype_paramname, element);
+            if (minimumActivePeriod != null) {
+                baseDataValidator.reset().parameter(ShareProductApiConstants.minimumactiveperiodfrequencytype_paramname)
+                        .value(minimumActivePeriodType.getValue()).integerSameAsNumber(PeriodFrequencyType.DAYS.getValue());
+            }
+            if (product.setminimumActivePeriodFrequencyType(minimumActivePeriodType)) {
+                actualChanges.put(ShareProductApiConstants.minimumactiveperiodfrequencytype_paramname, minimumActivePeriodType);
+            }
+        }
+        final Integer lockinPeriod;
+        if (this.fromApiJsonHelper.parameterExists(ShareProductApiConstants.lockperiod_paramname, element)) {
+            lockinPeriod = this.fromApiJsonHelper.extractIntegerNamed(ShareProductApiConstants.lockperiod_paramname, element, locale);
+            if (product.setLockinPeriod(lockinPeriod)) {
+                actualChanges.put(ShareProductApiConstants.lockperiod_paramname, lockinPeriod);
+            }
+        }
+
+        if (this.fromApiJsonHelper.parameterExists(ShareProductApiConstants.lockinperiodfrequencytype_paramname, element)) {
+            PeriodFrequencyType lockPeriod = extractPeriodType(ShareProductApiConstants.lockinperiodfrequencytype_paramname, element);
+            if (product.setLockPeriodFrequencyType(lockPeriod)) {
+                actualChanges.put(ShareProductApiConstants.lockinperiodfrequencytype_paramname, lockPeriod);
+            }
+        }
+
+        BigDecimal shareCapitalValue;
+        if (sharesIssued != null || unitPrice != null) {
+            if (sharesIssued == null) sharesIssued = product.getSharesIssued();
+            if (unitPrice == null) unitPrice = product.getUnitPrice();
+            shareCapitalValue = BigDecimal.valueOf(sharesIssued).multiply(unitPrice);
+            if (product.setshareCapitalValue(shareCapitalValue)) {
+                actualChanges.put(ShareProductApiConstants.sharecapital_paramname, shareCapitalValue);
+            }
+        }
+
+        if (!dataValidationErrors.isEmpty()) { throw new PlatformApiDataValidationException(dataValidationErrors); }
+        return actualChanges;
+    }
+
+    public void validateDividendDetails(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(),
+                ShareProductApiConstants.supportedParametersForDivident);
+
+        final List<ApiParameterError> dataValidationErrors = new ArrayList<>();
+        final DataValidatorBuilder baseDataValidator = new DataValidatorBuilder(dataValidationErrors)
+                .resource("sharesproduct.dividend.processing");
+
+        JsonElement element = jsonCommand.parsedJson();
+
+        final LocalDate dividendPeriodStartDate = this.fromApiJsonHelper.extractLocalDateNamed(
+                ShareProductApiConstants.dividendPeriodStartDateParamName, element);
+        baseDataValidator.reset().parameter(ShareProductApiConstants.dividendPeriodStartDateParamName).value(dividendPeriodStartDate)
+                .notBlank();
+
+        final LocalDate dividendPeriodEndDate = this.fromApiJsonHelper.extractLocalDateNamed(
+                ShareProductApiConstants.dividendPeriodEndDateParamName, element);
+        baseDataValidator.reset().parameter(ShareProductApiConstants.dividendPeriodStartDateParamName).value(dividendPeriodEndDate)
+                .notBlank().validateDateAfter(dividendPeriodStartDate);
+        final BigDecimal dividendAmount = this.fromApiJsonHelper.extractBigDecimalWithLocaleNamed(
+                ShareProductApiConstants.dividendAmountParamName, element);
+        baseDataValidator.reset().parameter(ShareProductApiConstants.dividendAmountParamName).value(dividendAmount).notBlank()
+                .positiveAmount();
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/incubator-fineract/blob/08c553f9/fineract-provider/src/main/java/org/apache/fineract/portfolio/shareproducts/service/ShareProductCommandsServiceImpl.java
----------------------------------------------------------------------
diff --git a/fineract-provider/src/main/java/org/apache/fineract/portfolio/shareproducts/service/ShareProductCommandsServiceImpl.java b/fineract-provider/src/main/java/org/apache/fineract/portfolio/shareproducts/service/ShareProductCommandsServiceImpl.java
new file mode 100644
index 0000000..ee36863
--- /dev/null
+++ b/fineract-provider/src/main/java/org/apache/fineract/portfolio/shareproducts/service/ShareProductCommandsServiceImpl.java
@@ -0,0 +1,59 @@
+/**
+ * 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.shareproducts.service;
+
+import org.apache.fineract.infrastructure.core.api.JsonCommand;
+import org.apache.fineract.infrastructure.core.data.CommandProcessingResult;
+import org.apache.fineract.infrastructure.core.serialization.FromJsonHelper;
+import org.apache.fineract.portfolio.products.service.ProductCommandsService;
+import org.apache.fineract.portfolio.shareproducts.constants.ShareProductApiConstants;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Service;
+
+import com.google.gson.JsonElement;
+
+@Service(value = "SHAREPRODUCT_COMMANDSERVICE")
+public class ShareProductCommandsServiceImpl implements ProductCommandsService {
+
+    private final FromJsonHelper fromApiJsonHelper;
+
+    @Autowired
+    public ShareProductCommandsServiceImpl(final FromJsonHelper fromApiJsonHelper) {
+        this.fromApiJsonHelper = fromApiJsonHelper;
+    }
+
+
+    public CommandProcessingResult postDividends(Long productId, JsonCommand jsonCommand) {
+        return null ;
+    }
+
+    @Override
+    public Object handleCommand(Long productId, String command, String jsonBody) {
+        final JsonElement parsedCommand = this.fromApiJsonHelper.parse(jsonBody);
+        final JsonCommand jsonCommand = JsonCommand.from(jsonBody, parsedCommand, this.fromApiJsonHelper, null, null, null, null, null,
+                null, null, null, null, null);
+        if (ShareProductApiConstants.PREIEW_DIVIDENDS_COMMAND_STRING.equals(command)) {
+            return null ;
+        } else if (ShareProductApiConstants.POST_DIVIDENdS_COMMAND_STRING.equals(command)) { return postDividends(productId,
+                jsonCommand); }
+        // throw unknow commandexception
+        return CommandProcessingResult.empty();
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/incubator-fineract/blob/08c553f9/fineract-provider/src/main/java/org/apache/fineract/portfolio/shareproducts/service/ShareProductDividendAssembler.java
----------------------------------------------------------------------
diff --git a/fineract-provider/src/main/java/org/apache/fineract/portfolio/shareproducts/service/ShareProductDividendAssembler.java b/fineract-provider/src/main/java/org/apache/fineract/portfolio/shareproducts/service/ShareProductDividendAssembler.java
new file mode 100644
index 0000000..1ff71c7
--- /dev/null
+++ b/fineract-provider/src/main/java/org/apache/fineract/portfolio/shareproducts/service/ShareProductDividendAssembler.java
@@ -0,0 +1,131 @@
+/**
+ * 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.shareproducts.service;
+
+import java.math.BigDecimal;
+import java.util.Collection;
+import java.util.HashMap;
+import java.util.Map;
+
+import org.apache.fineract.organisation.monetary.domain.MonetaryCurrency;
+import org.apache.fineract.organisation.monetary.domain.Money;
+import org.apache.fineract.portfolio.products.service.ProductReadPlatformService;
+import org.apache.fineract.portfolio.shareaccounts.data.PurchasedSharesData;
+import org.apache.fineract.portfolio.shareaccounts.data.ShareAccountData;
+import org.apache.fineract.portfolio.shareaccounts.domain.PurchasedSharesStatusType;
+import org.apache.fineract.portfolio.shareaccounts.domain.ShareAccountDividendDetails;
+import org.apache.fineract.portfolio.shareaccounts.service.ShareAccountReadPlatformService;
+import org.apache.fineract.portfolio.shareproducts.data.ShareProductData;
+import org.apache.fineract.portfolio.shareproducts.domain.ShareProductDividendPayOutDetails;
+import org.joda.time.Days;
+import org.joda.time.LocalDate;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Component;
+
+@Component
+public class ShareProductDividendAssembler {
+
+    private final ProductReadPlatformService shareProductReadPlatformService;
+    private final ShareAccountReadPlatformService ShareAccountReadPlatformService;
+
+    @Autowired
+    public ShareProductDividendAssembler(final ShareProductReadPlatformServiceImpl shareProductReadPlatformService,
+            final ShareAccountReadPlatformService ShareAccountReadPlatformService) {
+        this.shareProductReadPlatformService = shareProductReadPlatformService;
+        this.ShareAccountReadPlatformService = ShareAccountReadPlatformService;
+    }
+
+    public ShareProductDividendPayOutDetails calculateDividends(final Long productId, final BigDecimal amount,
+            final LocalDate dividendPeriodStartDate, final LocalDate dividendPeriodEndDate) {
+
+        ShareProductData product = (ShareProductData) this.shareProductReadPlatformService.retrieveOne(productId, false);
+        MonetaryCurrency currency = new MonetaryCurrency(product.getCurrency().code(), product.getCurrency().decimalPlaces(), product
+                .getCurrency().currencyInMultiplesOf());
+        Collection<ShareAccountData> shareAccountDatas = this.ShareAccountReadPlatformService.retrieveAllShareAccountDataForDividends(
+                productId, product.getAllowDividendCalculationForInactiveClients(), dividendPeriodStartDate);
+        ShareProductDividendPayOutDetails productDividendPayOutDetails = null;
+        final int minimumActivePeriod = product.getMinimumActivePeriod();
+        final Map<Long, Long> numberOfSharesdaysPerAccount = new HashMap<>();
+        long numberOfShareDays = calculateNumberOfShareDays(dividendPeriodEndDate, dividendPeriodStartDate, minimumActivePeriod,
+                shareAccountDatas, numberOfSharesdaysPerAccount);
+
+        if (numberOfShareDays > 0) {
+            double amountPerShareDay = amount.doubleValue() / numberOfShareDays;
+            productDividendPayOutDetails = new ShareProductDividendPayOutDetails(productId, Money.of(currency, amount).getAmount(),
+                    dividendPeriodStartDate.toDate(), dividendPeriodEndDate.toDate());
+            for (ShareAccountData accountData : shareAccountDatas) {
+                long numberOfShareDaysPerAccount = numberOfSharesdaysPerAccount.get(accountData.getId());
+                double amountForAccount = numberOfShareDaysPerAccount * amountPerShareDay;
+                final Money accountAmount = Money.of(currency, BigDecimal.valueOf(amountForAccount));
+                ShareAccountDividendDetails dividendDetails = new ShareAccountDividendDetails(accountData.getId(),
+                        accountAmount.getAmount());
+                productDividendPayOutDetails.getAccountDividendDetails().add(dividendDetails);
+            }
+        }
+
+        return productDividendPayOutDetails;
+    }
+
+    private long calculateNumberOfShareDays(final LocalDate postingDate, final LocalDate lastDividendPostDate,
+            final int minimumActivePeriod, final Collection<ShareAccountData> shareAccountDatas,
+            final Map<Long, Long> numberOfSharesdaysPerAccount) {
+        long numberOfShareDays = 0;
+        for (ShareAccountData accountData : shareAccountDatas) {
+            long numberOfShareDaysPerAccount = 0;
+            Collection<PurchasedSharesData> purchasedShares = accountData.getPurchasedShares();
+            long numberOfShares = 0;
+            LocalDate lastDividendAppliedDate = null;
+            for (PurchasedSharesData purchasedSharesData : purchasedShares) {
+                final PurchasedSharesStatusType status = PurchasedSharesStatusType.fromInt(purchasedSharesData.getStatus().getId()
+                        .intValue());
+                final PurchasedSharesStatusType type = PurchasedSharesStatusType.fromInt(purchasedSharesData.getType().getId()
+                        .intValue());
+                if (status.isApproved() && !type.isChargePayment()) {
+                    
+                    LocalDate shareStartDate = purchasedSharesData.getPurchasedDate();
+                    if (shareStartDate.isBefore(lastDividendPostDate)) {
+                        shareStartDate = lastDividendPostDate;
+                    }
+                    int numberOfPurchseDays = Days.daysBetween(shareStartDate, postingDate).getDays();
+                    if (type.isPurchased() && numberOfPurchseDays < minimumActivePeriod) {
+                        continue;
+                    }
+
+                    if (lastDividendAppliedDate != null) {
+                        numberOfShareDaysPerAccount += (Days.daysBetween(lastDividendAppliedDate, shareStartDate).getDays() * numberOfShares);
+                    }
+                    lastDividendAppliedDate = shareStartDate;
+                    if (type.isPurchased()) {
+                        numberOfShares += purchasedSharesData.getNumberOfShares();
+                    } else {
+                        numberOfShares -= purchasedSharesData.getNumberOfShares();
+                    }
+
+                }
+            }
+            if (lastDividendAppliedDate != null) {
+                numberOfShareDaysPerAccount += (Days.daysBetween(lastDividendAppliedDate, postingDate).getDays() * numberOfShares);
+            }
+            numberOfShareDays += numberOfShareDaysPerAccount;
+            numberOfSharesdaysPerAccount.put(accountData.getId(), numberOfShareDaysPerAccount);
+        }
+        return numberOfShareDays;
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/incubator-fineract/blob/08c553f9/fineract-provider/src/main/java/org/apache/fineract/portfolio/shareproducts/service/ShareProductDividendReadPlatformService.java
----------------------------------------------------------------------
diff --git a/fineract-provider/src/main/java/org/apache/fineract/portfolio/shareproducts/service/ShareProductDividendReadPlatformService.java b/fineract-provider/src/main/java/org/apache/fineract/portfolio/shareproducts/service/ShareProductDividendReadPlatformService.java
new file mode 100644
index 0000000..18eba3a
--- /dev/null
+++ b/fineract-provider/src/main/java/org/apache/fineract/portfolio/shareproducts/service/ShareProductDividendReadPlatformService.java
@@ -0,0 +1,29 @@
+/**
+ * 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.shareproducts.service;
+
+import org.apache.fineract.infrastructure.core.service.Page;
+import org.apache.fineract.infrastructure.core.service.SearchParameters;
+import org.apache.fineract.portfolio.shareproducts.data.ShareProductDividendPayOutData;
+
+public interface ShareProductDividendReadPlatformService {
+
+    Page<ShareProductDividendPayOutData> retriveAll(Long productId, Integer status, SearchParameters searchParameters);
+
+}

http://git-wip-us.apache.org/repos/asf/incubator-fineract/blob/08c553f9/fineract-provider/src/main/java/org/apache/fineract/portfolio/shareproducts/service/ShareProductDividendReadPlatformServiceImpl.java
----------------------------------------------------------------------
diff --git a/fineract-provider/src/main/java/org/apache/fineract/portfolio/shareproducts/service/ShareProductDividendReadPlatformServiceImpl.java b/fineract-provider/src/main/java/org/apache/fineract/portfolio/shareproducts/service/ShareProductDividendReadPlatformServiceImpl.java
new file mode 100644
index 0000000..6760ef9
--- /dev/null
+++ b/fineract-provider/src/main/java/org/apache/fineract/portfolio/shareproducts/service/ShareProductDividendReadPlatformServiceImpl.java
@@ -0,0 +1,128 @@
+/**
+ * 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.shareproducts.service;
+
+import java.math.BigDecimal;
+import java.sql.ResultSet;
+import java.sql.SQLException;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.List;
+
+import org.apache.fineract.infrastructure.core.data.EnumOptionData;
+import org.apache.fineract.infrastructure.core.domain.JdbcSupport;
+import org.apache.fineract.infrastructure.core.service.Page;
+import org.apache.fineract.infrastructure.core.service.PaginationHelper;
+import org.apache.fineract.infrastructure.core.service.RoutingDataSource;
+import org.apache.fineract.infrastructure.core.service.SearchParameters;
+import org.apache.fineract.portfolio.shareaccounts.data.ShareAccountDividendData;
+import org.apache.fineract.portfolio.shareaccounts.service.SharesEnumerations;
+import org.apache.fineract.portfolio.shareproducts.data.ShareProductDividendPayOutData;
+import org.apache.fineract.portfolio.shareproducts.data.ShareProductData;
+import org.joda.time.LocalDate;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.jdbc.core.JdbcTemplate;
+import org.springframework.jdbc.core.RowMapper;
+import org.springframework.stereotype.Service;
+
+@Service
+public class ShareProductDividendReadPlatformServiceImpl implements ShareProductDividendReadPlatformService {
+
+    private final JdbcTemplate jdbcTemplate;
+    private final PaginationHelper<ShareProductDividendPayOutData> paginationHelper = new PaginationHelper<>();
+
+    @Autowired
+    public ShareProductDividendReadPlatformServiceImpl(final RoutingDataSource dataSource) {
+        this.jdbcTemplate = new JdbcTemplate(dataSource);
+    }
+
+    @Override
+    public Page<ShareProductDividendPayOutData> retriveAll(final Long productId, final Integer status,
+            final SearchParameters searchParameters) {
+        ShareProductDividendMapper shareProductDividendMapper = new ShareProductDividendMapper();
+        final StringBuilder sqlBuilder = new StringBuilder(200);
+        sqlBuilder.append("select SQL_CALC_FOUND_ROWS ");
+        sqlBuilder.append(shareProductDividendMapper.schema());
+        sqlBuilder.append(" where sp.id = ? ");
+        List<Object> params = new ArrayList<>(2);
+        params.add(productId);
+        if (status != null) {
+            sqlBuilder.append(" and pod.status = ?");
+            params.add(status);
+        }
+        if (searchParameters.isOrderByRequested()) {
+            sqlBuilder.append(" order by ").append(searchParameters.getOrderBy());
+
+            if (searchParameters.isSortOrderProvided()) {
+                sqlBuilder.append(' ').append(searchParameters.getSortOrder());
+            }
+        }
+
+        if (searchParameters.isLimited()) {
+            sqlBuilder.append(" limit ").append(searchParameters.getLimit());
+            if (searchParameters.isOffset()) {
+                sqlBuilder.append(" offset ").append(searchParameters.getOffset());
+            }
+        }
+
+        final String sqlCountRows = "SELECT FOUND_ROWS()";
+        Object[] paramsObj = params.toArray();
+        return this.paginationHelper.fetchPage(this.jdbcTemplate, sqlCountRows, sqlBuilder.toString(), paramsObj,
+                shareProductDividendMapper);
+    }
+
+    private static final class ShareProductDividendMapper implements RowMapper<ShareProductDividendPayOutData> {
+
+        private final String sql;
+
+        public ShareProductDividendMapper() {
+            StringBuilder sb = new StringBuilder();
+            sb.append(" pod.id as id, pod.amount as amount,");
+            sb.append(" pod.status as status, pod.dividend_period_start_date as startDate,");
+            sb.append(" pod.dividend_period_end_date as endDate,");
+            sb.append(" sp.id as productId,sp.name as productName ");
+            sb.append(" from m_share_product_dividend_pay_out pod");
+            sb.append(" inner join m_share_product sp on sp.id = pod.product_id ");
+            sql = sb.toString();
+        }
+
+        public String schema() {
+            return this.sql;
+        }
+
+        @Override
+        public ShareProductDividendPayOutData mapRow(ResultSet rs, @SuppressWarnings("unused") int rowNum) throws SQLException {
+            final Long id = rs.getLong("id");
+            final BigDecimal amount = rs.getBigDecimal("amount");
+            final Integer status = JdbcSupport.getInteger(rs, "status");
+            final EnumOptionData statusEnum = SharesEnumerations.ShareProductDividendStatusEnum(status);
+            final LocalDate startDate = JdbcSupport.getLocalDate(rs, "startDate");
+            final LocalDate endDate = JdbcSupport.getLocalDate(rs, "endDate");
+
+            final Long productId = rs.getLong("productId");
+            final String productName = rs.getString("productName");
+
+            final ShareProductData productData = ShareProductData.lookup(productId, productName);
+            final Collection<ShareAccountDividendData> accountDividendsData = null;
+            return new ShareProductDividendPayOutData(id, productData, amount, startDate, endDate, accountDividendsData, statusEnum);
+        }
+
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/incubator-fineract/blob/08c553f9/fineract-provider/src/main/java/org/apache/fineract/portfolio/shareproducts/service/ShareProductDropdownReadPlatformService.java
----------------------------------------------------------------------
diff --git a/fineract-provider/src/main/java/org/apache/fineract/portfolio/shareproducts/service/ShareProductDropdownReadPlatformService.java b/fineract-provider/src/main/java/org/apache/fineract/portfolio/shareproducts/service/ShareProductDropdownReadPlatformService.java
new file mode 100644
index 0000000..ae3f98f
--- /dev/null
+++ b/fineract-provider/src/main/java/org/apache/fineract/portfolio/shareproducts/service/ShareProductDropdownReadPlatformService.java
@@ -0,0 +1,30 @@
+/**
+ * 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.shareproducts.service;
+
+import java.util.Collection;
+
+import org.apache.fineract.infrastructure.core.data.EnumOptionData;
+
+public interface ShareProductDropdownReadPlatformService {
+
+	Collection<EnumOptionData> retrieveLockinPeriodFrequencyTypeOptions();
+	
+	Collection<EnumOptionData> retrieveMinimumActivePeriodFrequencyTypeOptions() ;
+}

http://git-wip-us.apache.org/repos/asf/incubator-fineract/blob/08c553f9/fineract-provider/src/main/java/org/apache/fineract/portfolio/shareproducts/service/ShareProductDropdownReadPlatformServiceImpl.java
----------------------------------------------------------------------
diff --git a/fineract-provider/src/main/java/org/apache/fineract/portfolio/shareproducts/service/ShareProductDropdownReadPlatformServiceImpl.java b/fineract-provider/src/main/java/org/apache/fineract/portfolio/shareproducts/service/ShareProductDropdownReadPlatformServiceImpl.java
new file mode 100644
index 0000000..c7c7b80
--- /dev/null
+++ b/fineract-provider/src/main/java/org/apache/fineract/portfolio/shareproducts/service/ShareProductDropdownReadPlatformServiceImpl.java
@@ -0,0 +1,53 @@
+/**
+ * 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.shareproducts.service;
+
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.List;
+
+import org.apache.fineract.infrastructure.core.data.EnumOptionData;
+import org.apache.fineract.portfolio.shareaccounts.service.SharesEnumerations;
+import org.apache.fineract.portfolio.shareproducts.SharePeriodFrequencyType;
+import org.springframework.stereotype.Service;
+
+@Service
+public class ShareProductDropdownReadPlatformServiceImpl implements ShareProductDropdownReadPlatformService {
+
+    @Override
+    public Collection<EnumOptionData> retrieveLockinPeriodFrequencyTypeOptions() {
+        final List<EnumOptionData> allowedLockinPeriodFrequencyTypeOptions = Arrays.asList( //
+                SharesEnumerations.lockinPeriodFrequencyType(SharePeriodFrequencyType.DAYS), //
+                SharesEnumerations.lockinPeriodFrequencyType(SharePeriodFrequencyType.WEEKS), //
+                SharesEnumerations.lockinPeriodFrequencyType(SharePeriodFrequencyType.MONTHS), //
+                SharesEnumerations.lockinPeriodFrequencyType(SharePeriodFrequencyType.YEARS) //
+                );
+
+        return allowedLockinPeriodFrequencyTypeOptions;
+    }
+
+    @Override
+    public Collection<EnumOptionData> retrieveMinimumActivePeriodFrequencyTypeOptions() {
+        final List<EnumOptionData> minimumActivePeriodFrequencyTypeOptions = Arrays.asList( //
+                SharesEnumerations.lockinPeriodFrequencyType(SharePeriodFrequencyType.DAYS) //
+                );
+
+        return minimumActivePeriodFrequencyTypeOptions;
+    }
+}

http://git-wip-us.apache.org/repos/asf/incubator-fineract/blob/08c553f9/fineract-provider/src/main/java/org/apache/fineract/portfolio/shareproducts/service/ShareProductReadPlatformServiceImpl.java
----------------------------------------------------------------------
diff --git a/fineract-provider/src/main/java/org/apache/fineract/portfolio/shareproducts/service/ShareProductReadPlatformServiceImpl.java b/fineract-provider/src/main/java/org/apache/fineract/portfolio/shareproducts/service/ShareProductReadPlatformServiceImpl.java
new file mode 100644
index 0000000..cd3b42e
--- /dev/null
+++ b/fineract-provider/src/main/java/org/apache/fineract/portfolio/shareproducts/service/ShareProductReadPlatformServiceImpl.java
@@ -0,0 +1,283 @@
+/**
+ * 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.shareproducts.service;
+
+import java.math.BigDecimal;
+import java.sql.ResultSet;
+import java.sql.SQLException;
+import java.util.Collection;
+import java.util.Date;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+
+import org.apache.fineract.accounting.common.AccountingDropdownReadPlatformService;
+import org.apache.fineract.accounting.common.AccountingEnumerations;
+import org.apache.fineract.accounting.glaccount.data.GLAccountData;
+import org.apache.fineract.accounting.producttoaccountmapping.data.ChargeToGLAccountMapper;
+import org.apache.fineract.accounting.producttoaccountmapping.data.PaymentTypeToGLAccountMapper;
+import org.apache.fineract.accounting.producttoaccountmapping.service.ProductToGLAccountMappingReadPlatformService;
+import org.apache.fineract.infrastructure.core.data.EnumOptionData;
+import org.apache.fineract.infrastructure.core.domain.JdbcSupport;
+import org.apache.fineract.infrastructure.core.service.Page;
+import org.apache.fineract.infrastructure.core.service.PaginationHelper;
+import org.apache.fineract.infrastructure.core.service.RoutingDataSource;
+import org.apache.fineract.organisation.monetary.data.CurrencyData;
+import org.apache.fineract.organisation.monetary.service.CurrencyReadPlatformService;
+import org.apache.fineract.portfolio.charge.data.ChargeData;
+import org.apache.fineract.portfolio.charge.service.ChargeReadPlatformService;
+import org.apache.fineract.portfolio.products.data.ProductData;
+import org.apache.fineract.portfolio.products.exception.ProductNotFoundException;
+import org.apache.fineract.portfolio.products.service.ProductReadPlatformService;
+import org.apache.fineract.portfolio.savings.service.SavingsEnumerations;
+import org.apache.fineract.portfolio.shareproducts.data.ShareProductMarketPriceData;
+import org.apache.fineract.portfolio.shareproducts.data.ShareProductData;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.dao.EmptyResultDataAccessException;
+import org.springframework.jdbc.core.JdbcTemplate;
+import org.springframework.jdbc.core.RowMapper;
+import org.springframework.stereotype.Service;
+
+@Service(value = "shareReadPlatformService")
+public class ShareProductReadPlatformServiceImpl implements ProductReadPlatformService {
+
+    private final JdbcTemplate jdbcTemplate;
+    private final CurrencyReadPlatformService currencyReadPlatformService;
+    private final ChargeReadPlatformService chargeReadPlatformService;
+    private final ShareProductDropdownReadPlatformService shareProductDropdownReadPlatformService;
+    private final AccountingDropdownReadPlatformService accountingDropdownReadPlatformService;
+    private final ProductToGLAccountMappingReadPlatformService accountMappingReadPlatformService;
+    private final PaginationHelper<ProductData> provisioningEntryDataPaginationHelper = new PaginationHelper<>();
+
+    @Autowired
+    public ShareProductReadPlatformServiceImpl(final RoutingDataSource dataSource,
+            final CurrencyReadPlatformService currencyReadPlatformService, final ChargeReadPlatformService chargeReadPlatformService,
+            final ShareProductDropdownReadPlatformService shareProductDropdownReadPlatformService,
+            final AccountingDropdownReadPlatformService accountingDropdownReadPlatformService,
+            final ProductToGLAccountMappingReadPlatformService accountMappingReadPlatformService) {
+        this.jdbcTemplate = new JdbcTemplate(dataSource);
+        this.currencyReadPlatformService = currencyReadPlatformService;
+        this.chargeReadPlatformService = chargeReadPlatformService;
+        this.shareProductDropdownReadPlatformService = shareProductDropdownReadPlatformService;
+        this.accountingDropdownReadPlatformService = accountingDropdownReadPlatformService;
+        this.accountMappingReadPlatformService = accountMappingReadPlatformService;
+    }
+
+    @Override
+    public Page<ProductData> retrieveAllProducts(Integer offSet, Integer limit) {
+        AllShareProductRowMapper mapper = new AllShareProductRowMapper();
+        StringBuilder sqlBuilder = new StringBuilder();
+        sqlBuilder.append("select SQL_CALC_FOUND_ROWS ");
+        sqlBuilder.append(mapper.schema());
+        if (limit != null) {
+            sqlBuilder.append(" limit ").append(limit);
+        }
+        if (offSet != null) {
+            sqlBuilder.append(" offset ").append(offSet);
+        }
+
+        final String sqlCountRows = "SELECT FOUND_ROWS()";
+        Object[] whereClauseItemsitems = new Object[] {};
+        return this.provisioningEntryDataPaginationHelper.fetchPage(this.jdbcTemplate, sqlCountRows, sqlBuilder.toString(),
+                whereClauseItemsitems, mapper);
+    }
+
+    @Override
+    public ProductData retrieveOne(Long productId, boolean includeTemplate) {
+        MarketPriceRowMapper marketRowMapper = new MarketPriceRowMapper();
+
+        try {
+            final String sql1 = "select " + marketRowMapper.schema() + " where marketData.product_id = ?";
+            final Collection<ShareProductMarketPriceData> shareMarketCollection = this.jdbcTemplate.query(sql1, marketRowMapper,
+                    new Object[] { productId });
+            final Collection<ChargeData> charges = this.chargeReadPlatformService.retrieveShareProductCharges(productId);
+            ShareProductRowMapper mapper = new ShareProductRowMapper(shareMarketCollection, charges);
+            final String sql = "select " + mapper.schema() + " where shareproduct.id = ?";
+            ShareProductData data = (ShareProductData) this.jdbcTemplate.queryForObject(sql, mapper, new Object[] { productId });
+
+            if (data.hasAccountingEnabled()) {
+                final Map<String, Object> accountingMappings = this.accountMappingReadPlatformService
+                        .fetchAccountMappingDetailsForShareProduct(productId, data.accountingRuleTypeId());
+                final Collection<PaymentTypeToGLAccountMapper> paymentChannelToFundSourceMappings = this.accountMappingReadPlatformService
+                        .fetchPaymentTypeToFundSourceMappingsForShareProduct(productId);
+                Collection<ChargeToGLAccountMapper> feeToGLAccountMappings = this.accountMappingReadPlatformService
+                        .fetchFeeToIncomeAccountMappingsForShareProduct(productId);
+                data = ShareProductData.withAccountingDetails(data, accountingMappings, paymentChannelToFundSourceMappings,
+                        feeToGLAccountMappings);
+            }
+
+            if (includeTemplate) {
+                Collection<ChargeData> chargeOptions = this.chargeReadPlatformService.retrieveSharesApplicableCharges();
+                final Collection<CurrencyData> currencyOptions = this.currencyReadPlatformService.retrieveAllowedCurrencies();
+                final Collection<EnumOptionData> lockinPeriodFrequencyTypeOptions = this.shareProductDropdownReadPlatformService
+                        .retrieveLockinPeriodFrequencyTypeOptions();
+                final Collection<EnumOptionData> minimumActivePeriodFrequencyTypeOptions = this.shareProductDropdownReadPlatformService
+                        .retrieveMinimumActivePeriodFrequencyTypeOptions();
+                final Map<String, List<GLAccountData>> accountingMappingOptions = this.accountingDropdownReadPlatformService
+                        .retrieveAccountMappingOptionsForShareProducts();
+                data = ShareProductData.template(data, currencyOptions, chargeOptions, minimumActivePeriodFrequencyTypeOptions,
+                        lockinPeriodFrequencyTypeOptions, accountingMappingOptions);
+            }
+            return data;
+        } catch (final EmptyResultDataAccessException e) {
+            throw new ProductNotFoundException(productId, "share");
+        }
+    }
+
+    @Override
+    public ProductData retrieveTemplate() {
+        Collection<ChargeData> chargeOptions = this.chargeReadPlatformService.retrieveSharesApplicableCharges();
+        final Collection<CurrencyData> currencyOptions = this.currencyReadPlatformService.retrieveAllowedCurrencies();
+        final Collection<EnumOptionData> lockinPeriodFrequencyTypeOptions = this.shareProductDropdownReadPlatformService
+                .retrieveLockinPeriodFrequencyTypeOptions();
+        final Collection<EnumOptionData> minimumActivePeriodFrequencyTypeOptions = this.shareProductDropdownReadPlatformService
+                .retrieveMinimumActivePeriodFrequencyTypeOptions();
+        final Map<String, List<GLAccountData>> accountingMappingOptions = this.accountingDropdownReadPlatformService
+                .retrieveAccountMappingOptionsForShareProducts();
+        return ShareProductData.template(currencyOptions, chargeOptions, minimumActivePeriodFrequencyTypeOptions,
+                lockinPeriodFrequencyTypeOptions, accountingMappingOptions);
+    }
+
+    @Override
+    public Collection<ProductData> retrieveAllForLookup() {
+        AllShareProductRowMapper mapper = new AllShareProductRowMapper();
+        String sql = "select " + mapper.schema();
+        return this.jdbcTemplate.query(sql, mapper, new Object[] {});
+    }
+
+    @Override
+    public Set<String> getResponseDataParams() {
+        return null;
+    }
+
+    private static final class AllShareProductRowMapper implements RowMapper<ProductData> {
+
+        @Override
+        public ShareProductData mapRow(ResultSet rs, int rowNum) throws SQLException {
+            final Long id = rs.getLong("id");
+            final String name = rs.getString("name");
+            final String shortName = rs.getString("short_name");
+            final Long totalShares = rs.getLong("total_shares");
+            return ShareProductData.generic(id, name, shortName, totalShares);
+        }
+
+        public String schema() {
+            return "shareproduct.id, shareproduct.name, shareproduct.short_name, shareproduct.total_shares from m_share_product shareproduct";
+        }
+    }
+
+    private static final class MarketPriceRowMapper implements RowMapper<ShareProductMarketPriceData> {
+
+        @Override
+        public ShareProductMarketPriceData mapRow(ResultSet rs, int rowNum) throws SQLException {
+            final Long id = rs.getLong("id");
+            final Date fromDate = rs.getDate("from_date");
+            final BigDecimal shareValue = rs.getBigDecimal("share_value");
+            return new ShareProductMarketPriceData(id, fromDate, shareValue);
+        }
+
+        public String schema() {
+            return "marketData.id, marketData.from_date, marketData.share_value from m_share_product_market_price marketData";
+        }
+    }
+
+    private final static class ShareProductRowMapper implements RowMapper<ProductData> {
+
+        Collection<ShareProductMarketPriceData> shareMarketCollection;
+        Collection<ChargeData> charges;
+        private StringBuffer buff = new StringBuffer();
+
+        ShareProductRowMapper(Collection<ShareProductMarketPriceData> shareMarketCollection, Collection<ChargeData> charges) {
+            this.shareMarketCollection = shareMarketCollection;
+            this.charges = charges;
+            buff.append("shareproduct.id, shareproduct.name, shareproduct.short_name, ")
+                    .append("shareproduct.external_id, shareproduct.description, shareproduct.start_date,")
+                    .append("shareproduct.end_date, shareproduct.currency_code, shareproduct.currency_digits, ")
+                    .append("shareproduct.currency_multiplesof, shareproduct.total_shares, shareproduct.issued_shares, ")
+                    .append("shareproduct.unit_price, shareproduct.capital_amount,  ")
+                    .append("shareproduct.accounting_type as accountingType, ")
+                    .append("shareproduct.minimum_client_shares, shareproduct.nominal_client_shares, ")
+                    .append("shareproduct.maximum_client_shares, shareproduct.minimum_active_period_frequency, ")
+                    .append("shareproduct.minimum_active_period_frequency_enum, shareproduct.lockin_period_frequency, ")
+                    .append("shareproduct.lockin_period_frequency_enum, shareproduct.allow_dividends_inactive_clients, ")
+                    .append("shareproduct.createdby_id, created.username as createdName, modified.username as modifiedName, ")
+                    .append("shareproduct.created_date, shareproduct.lastmodifiedby_id, shareproduct.lastmodified_date, ")
+                    .append("curr.name as currencyName, curr.internationalized_name_code as currencyNameCode, ")
+                    .append("curr.display_symbol as currencyDisplaySymbol ").append("from m_share_product shareproduct ")
+                    .append("LEFT JOIN m_currency curr on curr.code = shareproduct.currency_code ")
+                    .append("LEFT JOIN m_appuser created ON created.id = shareproduct.createdby_id ")
+                    .append("LEFT JOIN m_appuser modified ON modified.id = shareproduct.lastmodifiedby_id ");
+
+        }
+
+        @Override
+        public ShareProductData mapRow(ResultSet rs, int rowNum) throws SQLException {
+            final Long id = rs.getLong("id");
+            final String name = rs.getString("name");
+            final String shortName = rs.getString("short_name");
+            final String externalId = rs.getString("external_id");
+            final String description = rs.getString("description");
+            final String currencyCode = rs.getString("currency_code");
+            final Integer currencyDigits = rs.getInt("currency_digits");
+            final String currencyName = rs.getString("currencyName");
+            final String currencyNameCode = rs.getString("currencyNameCode");
+            final String currencyDisplaySymbol = rs.getString("currencyDisplaySymbol");
+            final Integer inMultiplesOf = JdbcSupport.getInteger(rs, "currency_multiplesof");
+            final CurrencyData currency = new CurrencyData(currencyCode, currencyName, currencyDigits, inMultiplesOf,
+                    currencyDisplaySymbol, currencyNameCode);
+
+            final Long totalShares = rs.getLong("total_shares");
+            final Long issuedShares = rs.getLong("issued_shares");
+            final BigDecimal unitPrice = rs.getBigDecimal("unit_price");
+            final BigDecimal capitalAmount = rs.getBigDecimal("capital_amount");
+            final Long minimumClientShares = JdbcSupport.getLong(rs, "minimum_client_shares");
+            final Long nominalClientShares = JdbcSupport.getLong(rs, "nominal_client_shares");
+            final Long maximumClientShares = JdbcSupport.getLong(rs, "maximum_client_shares");
+            final Boolean allowDividendsForInactiveClients = rs.getBoolean("allow_dividends_inactive_clients");
+            // final Long createdById = rs.getLong("createdby_id") ;
+            // final Date createdDate = rs.getDate("created_date") ;
+            // final Long modifiedById = rs.getLong("lastmodifiedby_id") ;
+            // final Date modifiedDate = rs.getDate("lastmodified_date") ;
+            final Integer minimumActivePeriod = JdbcSupport.getInteger(rs, "minimum_active_period_frequency");
+            final Integer minimumActviePeriodEnumValue = JdbcSupport.getInteger(rs, "minimum_active_period_frequency_enum");
+            EnumOptionData minimumActivePeriodType = null;
+            if (minimumActviePeriodEnumValue != null) {
+                minimumActivePeriodType = SavingsEnumerations.lockinPeriodFrequencyType(minimumActviePeriodEnumValue);
+            }
+
+            final Integer lockinPeriodFrequency = JdbcSupport.getInteger(rs, "lockin_period_frequency");
+            EnumOptionData lockinPeriodFrequencyType = null;
+            final Integer lockinPeriodFrequencyTypeValue = JdbcSupport.getInteger(rs, "lockin_period_frequency_enum");
+            if (lockinPeriodFrequencyTypeValue != null) {
+                lockinPeriodFrequencyType = SavingsEnumerations.lockinPeriodFrequencyType(lockinPeriodFrequencyTypeValue);
+            }
+            final Integer accountingRuleId = JdbcSupport.getInteger(rs, "accountingType");
+            final EnumOptionData accountingRuleType = AccountingEnumerations.accountingRuleType(accountingRuleId);
+
+            return ShareProductData.data(id, name, shortName, description, externalId, currency, totalShares, issuedShares, unitPrice,
+                    capitalAmount, minimumClientShares, nominalClientShares, maximumClientShares, shareMarketCollection, charges,
+                    allowDividendsForInactiveClients, lockinPeriodFrequency, lockinPeriodFrequencyType, minimumActivePeriod,
+                    minimumActivePeriodType, accountingRuleType);
+        }
+
+        public String schema() {
+            return this.buff.toString();
+        }
+    }
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/incubator-fineract/blob/08c553f9/fineract-provider/src/main/java/org/apache/fineract/portfolio/shareproducts/service/ShareProductWritePlatformService.java
----------------------------------------------------------------------
diff --git a/fineract-provider/src/main/java/org/apache/fineract/portfolio/shareproducts/service/ShareProductWritePlatformService.java b/fineract-provider/src/main/java/org/apache/fineract/portfolio/shareproducts/service/ShareProductWritePlatformService.java
new file mode 100644
index 0000000..7bb8111
--- /dev/null
+++ b/fineract-provider/src/main/java/org/apache/fineract/portfolio/shareproducts/service/ShareProductWritePlatformService.java
@@ -0,0 +1,35 @@
+/**
+ * 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.shareproducts.service;
+
+import org.apache.fineract.infrastructure.core.api.JsonCommand;
+import org.apache.fineract.infrastructure.core.data.CommandProcessingResult;
+
+public interface ShareProductWritePlatformService {
+
+    CommandProcessingResult createShareProduct(JsonCommand jsonCommand);
+
+    CommandProcessingResult updateProduct(Long productId, JsonCommand command);
+
+    CommandProcessingResult createShareProductDividend(Long productId, JsonCommand jsonCommand);
+
+    CommandProcessingResult approveShareProductDividend(Long PayOutDetailId);
+
+    CommandProcessingResult deleteShareProductDividend(Long PayOutDetailId);
+}

http://git-wip-us.apache.org/repos/asf/incubator-fineract/blob/08c553f9/fineract-provider/src/main/java/org/apache/fineract/portfolio/shareproducts/service/ShareProductWritePlatformServiceJpaRepositoryImpl.java
----------------------------------------------------------------------
diff --git a/fineract-provider/src/main/java/org/apache/fineract/portfolio/shareproducts/service/ShareProductWritePlatformServiceJpaRepositoryImpl.java b/fineract-provider/src/main/java/org/apache/fineract/portfolio/shareproducts/service/ShareProductWritePlatformServiceJpaRepositoryImpl.java
new file mode 100644
index 0000000..e9aaac7
--- /dev/null
+++ b/fineract-provider/src/main/java/org/apache/fineract/portfolio/shareproducts/service/ShareProductWritePlatformServiceJpaRepositoryImpl.java
@@ -0,0 +1,190 @@
+/**
+ * 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.shareproducts.service;
+
+import java.math.BigDecimal;
+import java.util.Map;
+
+import org.apache.fineract.accounting.producttoaccountmapping.service.ProductToGLAccountMappingWritePlatformService;
+import org.apache.fineract.infrastructure.core.api.JsonCommand;
+import org.apache.fineract.infrastructure.core.data.CommandProcessingResult;
+import org.apache.fineract.infrastructure.core.data.CommandProcessingResultBuilder;
+import org.apache.fineract.infrastructure.core.exception.PlatformDataIntegrityException;
+import org.apache.fineract.infrastructure.core.serialization.FromJsonHelper;
+import org.apache.fineract.portfolio.shareproducts.constants.ShareProductApiConstants;
+import org.apache.fineract.portfolio.shareproducts.domain.ShareProduct;
+import org.apache.fineract.portfolio.shareproducts.domain.ShareProductDividendPayOutDetails;
+import org.apache.fineract.portfolio.shareproducts.domain.ShareProductDividentPayOutDetailsRepositoryWrapper;
+import org.apache.fineract.portfolio.shareproducts.domain.ShareProductRepositoryWrapper;
+import org.apache.fineract.portfolio.shareproducts.exception.DividentProcessingException;
+import org.apache.fineract.portfolio.shareproducts.serialization.ShareProductDataSerializer;
+import org.joda.time.LocalDate;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.dao.DataIntegrityViolationException;
+import org.springframework.stereotype.Service;
+
+import com.google.gson.JsonElement;
+
+@Service
+public class ShareProductWritePlatformServiceJpaRepositoryImpl implements ShareProductWritePlatformService {
+
+    private final ShareProductRepositoryWrapper repository;
+    private final ShareProductDataSerializer serializer;
+    private final FromJsonHelper fromApiJsonHelper;
+    private final ShareProductDividentPayOutDetailsRepositoryWrapper shareProductDividentPayOutDetailsRepository;
+    private final ShareProductDividendAssembler shareProductDividendAssembler;
+    private final ProductToGLAccountMappingWritePlatformService accountMappingWritePlatformService;
+
+    @Autowired
+    public ShareProductWritePlatformServiceJpaRepositoryImpl(final ShareProductRepositoryWrapper repository,
+            final ShareProductDataSerializer serializer, final FromJsonHelper fromApiJsonHelper,
+            final ShareProductDividentPayOutDetailsRepositoryWrapper shareProductDividentPayOutDetailsRepositor,
+            final ShareProductDividendAssembler shareProductDividendAssembler,
+            final ProductToGLAccountMappingWritePlatformService accountMappingWritePlatformService) {
+        this.repository = repository;
+        this.serializer = serializer;
+        this.fromApiJsonHelper = fromApiJsonHelper;
+        this.shareProductDividentPayOutDetailsRepository = shareProductDividentPayOutDetailsRepositor;
+        this.shareProductDividendAssembler = shareProductDividendAssembler;
+        this.accountMappingWritePlatformService = accountMappingWritePlatformService;
+    }
+
+    @Override
+    public CommandProcessingResult createShareProduct(JsonCommand jsonCommand) {
+        try {
+            ShareProduct product = this.serializer.validateAndCreate(jsonCommand);
+            this.repository.save(product);
+
+            // save accounting mappings
+            this.accountMappingWritePlatformService.createShareProductToGLAccountMapping(product.getId(), jsonCommand);
+
+            return new CommandProcessingResultBuilder() //
+                    .withCommandId(jsonCommand.commandId()) //
+                    .withEntityId(product.getId()) //
+                    .build();
+        } catch (final DataIntegrityViolationException dve) {
+            handleDataIntegrityIssues(jsonCommand, dve);
+            return CommandProcessingResult.empty();
+        }
+
+    }
+
+    @Override
+    public CommandProcessingResult updateProduct(Long productId, JsonCommand jsonCommand) {
+        try {
+            ShareProduct product = this.repository.findOneWithNotFoundDetection(productId);
+            final Map<String, Object> changes = this.serializer.validateAndUpdate(jsonCommand, product);
+
+            // accounting related changes
+            final boolean accountingTypeChanged = changes.containsKey(ShareProductApiConstants.accountingRuleParamName);
+            final Map<String, Object> accountingMappingChanges = this.accountMappingWritePlatformService
+                    .updateShareProductToGLAccountMapping(product.getId(), jsonCommand, accountingTypeChanged, product.getAccountingType());
+            changes.putAll(accountingMappingChanges);
+
+            if (!changes.isEmpty()) {
+                this.repository.saveAndFlush(product);
+            }
+            return new CommandProcessingResultBuilder() //
+                    .withCommandId(jsonCommand.commandId()) //
+                    .withEntityId(productId) //
+                    .with(changes) //
+                    .build();
+        } catch (DataIntegrityViolationException dve) {
+            handleDataIntegrityIssues(jsonCommand, dve);
+            return CommandProcessingResult.empty();
+        }
+    }
+
+    @Override
+    public CommandProcessingResult createShareProductDividend(final Long productId, final JsonCommand jsonCommand) {
+        try {
+            this.serializer.validateDividendDetails(jsonCommand);
+            JsonElement element = jsonCommand.parsedJson();
+            final LocalDate dividendPeriodStartDate = this.fromApiJsonHelper.extractLocalDateNamed(
+                    ShareProductApiConstants.dividendPeriodStartDateParamName, element);
+            final LocalDate dividendPeriodEndDate = this.fromApiJsonHelper.extractLocalDateNamed(
+                    ShareProductApiConstants.dividendPeriodEndDateParamName, element);
+            final BigDecimal dividendAmount = this.fromApiJsonHelper.extractBigDecimalWithLocaleNamed(
+                    ShareProductApiConstants.dividendAmountParamName, element);
+
+            final ShareProductDividendPayOutDetails dividendPayOutDetails = this.shareProductDividendAssembler.calculateDividends(
+                    productId, dividendAmount, dividendPeriodStartDate, dividendPeriodEndDate);
+            if (dividendPayOutDetails == null) { throw new DividentProcessingException("eligible.shares.not.found",
+                    "No eligible shares for creating dividends"); }
+            this.shareProductDividentPayOutDetailsRepository.save(dividendPayOutDetails);
+
+            return new CommandProcessingResultBuilder() //
+                    .withCommandId(jsonCommand.commandId()) //
+                    .withEntityId(productId) //
+                    .withSubEntityId(dividendPayOutDetails.getId())//
+                    .build();
+        } catch (DataIntegrityViolationException dve) {
+            handleDataIntegrityIssues(jsonCommand, dve);
+            return CommandProcessingResult.empty();
+        }
+    }
+
+    @Override
+    public CommandProcessingResult approveShareProductDividend(final Long PayOutDetailId) {
+        try {
+            ShareProductDividendPayOutDetails dividendPayOutDetails = this.shareProductDividentPayOutDetailsRepository
+                    .findOneWithNotFoundDetection(PayOutDetailId);
+            if (dividendPayOutDetails.getStatus().isApproved()) { throw new DividentProcessingException("alreay.approved",
+                    "Can't approve already appoved  dividends "); }
+            dividendPayOutDetails.approveDividendPayout();
+            this.shareProductDividentPayOutDetailsRepository.save(dividendPayOutDetails);
+            return new CommandProcessingResultBuilder() //
+                    .withEntityId(PayOutDetailId) //
+                    .build();
+        } catch (DataIntegrityViolationException dve) {
+            handleDataIntegrityIssues(dve);
+            return CommandProcessingResult.empty();
+        }
+    }
+
+    @Override
+    public CommandProcessingResult deleteShareProductDividend(final Long PayOutDetailId) {
+        try {
+            ShareProductDividendPayOutDetails dividendPayOutDetails = this.shareProductDividentPayOutDetailsRepository
+                    .findOneWithNotFoundDetection(PayOutDetailId);
+            if (dividendPayOutDetails.getStatus().isApproved()) { throw new DividentProcessingException("alreay.approved",
+                    "Can't delete already appoved  dividends "); }
+            this.shareProductDividentPayOutDetailsRepository.delete(dividendPayOutDetails);
+            return new CommandProcessingResultBuilder() //
+                    .withEntityId(PayOutDetailId) //
+                    .build();
+        } catch (DataIntegrityViolationException dve) {
+            handleDataIntegrityIssues(dve);
+            return CommandProcessingResult.empty();
+        }
+    }
+
+    private void handleDataIntegrityIssues(final DataIntegrityViolationException dve) {
+        final Throwable realCause = dve.getMostSpecificCause();
+        throw new PlatformDataIntegrityException("error.msg.glClosure.unknown.data.integrity.issue",
+                "Unknown data integrity issue with resource GL Closure: " + realCause.getMessage());
+    }
+
+    private void handleDataIntegrityIssues(@SuppressWarnings("unused") final JsonCommand command, final DataIntegrityViolationException dve) {
+        final Throwable realCause = dve.getMostSpecificCause();
+        throw new PlatformDataIntegrityException("error.msg.glClosure.unknown.data.integrity.issue",
+                "Unknown data integrity issue with resource GL Closure: " + realCause.getMessage());
+    }
+
+}


Mime
View raw message