fineract-commits mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From raj...@apache.org
Subject [05/12] incubator-fineract git commit: Shares And Dividends Implementation
Date Wed, 13 Apr 2016 14:35:17 GMT
http://git-wip-us.apache.org/repos/asf/incubator-fineract/blob/08c553f9/fineract-provider/src/main/java/org/apache/fineract/portfolio/shareaccounts/service/ShareAccountReadPlatformServiceImpl.java
----------------------------------------------------------------------
diff --git a/fineract-provider/src/main/java/org/apache/fineract/portfolio/shareaccounts/service/ShareAccountReadPlatformServiceImpl.java b/fineract-provider/src/main/java/org/apache/fineract/portfolio/shareaccounts/service/ShareAccountReadPlatformServiceImpl.java
new file mode 100644
index 0000000..3635aaa
--- /dev/null
+++ b/fineract-provider/src/main/java/org/apache/fineract/portfolio/shareaccounts/service/ShareAccountReadPlatformServiceImpl.java
@@ -0,0 +1,482 @@
+/**
+ * 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.shareaccounts.service;
+
+import java.math.BigDecimal;
+import java.sql.ResultSet;
+import java.sql.SQLException;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Date;
+import java.util.List;
+import java.util.Set;
+
+import org.apache.fineract.infrastructure.core.data.EnumOptionData;
+import org.apache.fineract.infrastructure.core.domain.JdbcSupport;
+import org.apache.fineract.infrastructure.core.service.DateUtils;
+import org.apache.fineract.infrastructure.core.service.RoutingDataSource;
+import org.apache.fineract.organisation.monetary.data.CurrencyData;
+import org.apache.fineract.portfolio.accountdetails.data.ShareAccountSummaryData;
+import org.apache.fineract.portfolio.accounts.constants.AccountsApiConstants;
+import org.apache.fineract.portfolio.accounts.data.AccountData;
+import org.apache.fineract.portfolio.charge.data.ChargeData;
+import org.apache.fineract.portfolio.charge.service.ChargeReadPlatformService;
+import org.apache.fineract.portfolio.client.data.ClientData;
+import org.apache.fineract.portfolio.client.service.ClientReadPlatformService;
+import org.apache.fineract.portfolio.products.constants.ProductsApiConstants;
+import org.apache.fineract.portfolio.products.data.ProductData;
+import org.apache.fineract.portfolio.products.service.ProductReadPlatformService;
+import org.apache.fineract.portfolio.savings.data.SavingsAccountData;
+import org.apache.fineract.portfolio.savings.service.SavingsAccountReadPlatformService;
+import org.apache.fineract.portfolio.shareaccounts.data.PurchasedSharesData;
+import org.apache.fineract.portfolio.shareaccounts.data.ShareAccountApplicationTimelineData;
+import org.apache.fineract.portfolio.shareaccounts.data.ShareAccountDividendData;
+import org.apache.fineract.portfolio.shareaccounts.data.ShareAccountStatusEnumData;
+import org.apache.fineract.portfolio.shareaccounts.data.ShareAccountChargeData;
+import org.apache.fineract.portfolio.shareaccounts.data.ShareAccountData;
+import org.apache.fineract.portfolio.shareaccounts.domain.PurchasedSharesStatusType;
+import org.apache.fineract.portfolio.shareaccounts.domain.ShareAccountStatusType;
+import org.apache.fineract.portfolio.shareproducts.SharePeriodFrequencyType;
+import org.apache.fineract.portfolio.shareproducts.data.ShareProductMarketPriceData;
+import org.apache.fineract.portfolio.shareproducts.data.ShareProductData;
+import org.apache.fineract.portfolio.shareproducts.service.ShareProductDropdownReadPlatformService;
+import org.joda.time.LocalDate;
+import org.joda.time.format.DateTimeFormat;
+import org.joda.time.format.DateTimeFormatter;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.context.ApplicationContext;
+import org.springframework.jdbc.core.JdbcTemplate;
+import org.springframework.jdbc.core.RowMapper;
+import org.springframework.stereotype.Service;
+
+@Service(value = "share" + AccountsApiConstants.READPLATFORM_NAME)
+public class ShareAccountReadPlatformServiceImpl implements ShareAccountReadPlatformService {
+
+    private final ApplicationContext applicationContext;
+    private final ChargeReadPlatformService chargeReadPlatformService;
+    private final ShareProductDropdownReadPlatformService shareProductDropdownReadPlatformService;
+    private final SavingsAccountReadPlatformService savingsAccountReadPlatformService;
+    private final ClientReadPlatformService clientReadPlatformService;
+    private final ShareAccountChargeReadPlatformService shareAccountChargeReadPlatformService;
+    private final PurchasedSharesReadPlatformService purchasedSharesReadPlatformService;
+    private final JdbcTemplate jdbcTemplate;
+    private final DateTimeFormatter formatter = DateTimeFormat.forPattern("yyyy-MM-dd");
+
+    @Autowired
+    public ShareAccountReadPlatformServiceImpl(final RoutingDataSource dataSource, final ApplicationContext applicationContext,
+            final ChargeReadPlatformService chargeReadPlatformService,
+            final ShareProductDropdownReadPlatformService shareProductDropdownReadPlatformService,
+            final SavingsAccountReadPlatformService savingsAccountReadPlatformService,
+            final ClientReadPlatformService clientReadPlatformService,
+            final ShareAccountChargeReadPlatformService shareAccountChargeReadPlatformService,
+            final PurchasedSharesReadPlatformService purchasedSharesReadPlatformService) {
+        this.jdbcTemplate = new JdbcTemplate(dataSource);
+        this.applicationContext = applicationContext;
+        this.chargeReadPlatformService = chargeReadPlatformService;
+        this.shareProductDropdownReadPlatformService = shareProductDropdownReadPlatformService;
+        this.savingsAccountReadPlatformService = savingsAccountReadPlatformService;
+        this.clientReadPlatformService = clientReadPlatformService;
+        this.shareAccountChargeReadPlatformService = shareAccountChargeReadPlatformService;
+        this.purchasedSharesReadPlatformService = purchasedSharesReadPlatformService;
+
+    }
+
+    @Override
+    public ShareAccountData retrieveTemplate(Long clientId, Long productId) {
+        ShareAccountData toReturn = null;
+        String serviceName = "share" + ProductsApiConstants.READPLATFORM_NAME;
+        ProductReadPlatformService service = (ProductReadPlatformService) this.applicationContext.getBean(serviceName);
+        ClientData client = this.clientReadPlatformService.retrieveOne(clientId);
+
+        if (productId != null) {
+            final ShareProductData productData = (ShareProductData) service.retrieveOne(productId, false);
+            final BigDecimal marketPrice = deriveMarketPrice(productData);
+            final Collection<ChargeData> productCharges = this.chargeReadPlatformService.retrieveShareProductCharges(productId);
+            final Collection<ShareAccountChargeData> charges = convertChargesToShareAccountCharges(productCharges);
+            final Collection<EnumOptionData> lockinPeriodFrequencyTypeOptions = this.shareProductDropdownReadPlatformService
+                    .retrieveLockinPeriodFrequencyTypeOptions();
+            final Collection<EnumOptionData> minimumActivePeriodFrequencyTypeOptions = this.shareProductDropdownReadPlatformService
+                    .retrieveMinimumActivePeriodFrequencyTypeOptions();
+            final Collection<SavingsAccountData> clientSavingsAccounts = this.savingsAccountReadPlatformService
+                    .retrieveAllForLookup(clientId);
+            toReturn = new ShareAccountData(client.id(), client.displayName(), productData.getCurrency(), charges, marketPrice,
+                    minimumActivePeriodFrequencyTypeOptions, lockinPeriodFrequencyTypeOptions, clientSavingsAccounts, productData.getNominaltShares());
+        } else {
+            Collection<ProductData> productOptions = service.retrieveAllForLookup();
+            final Collection<ChargeData> chargeOptions = this.chargeReadPlatformService.retrieveSharesApplicableCharges();
+            toReturn = new ShareAccountData(client.id(), client.displayName(), productOptions, chargeOptions);
+        }
+        return toReturn;
+    }
+
+    private BigDecimal deriveMarketPrice(final ShareProductData shareProductData) {
+        BigDecimal marketValue = shareProductData.getUnitPrice();
+        Collection<ShareProductMarketPriceData> marketDataSet = shareProductData.getMarketPrice();
+        if (marketDataSet != null && !marketDataSet.isEmpty()) {
+            Date currentDate = DateUtils.getDateOfTenant();
+            for (ShareProductMarketPriceData data : marketDataSet) {
+                Date futureDate = data.getStartDate();
+                if (currentDate.after(futureDate)) {
+                    marketValue = data.getShareValue();
+                }
+            }
+        }
+        return marketValue;
+    }
+
+    @Override
+    public ShareAccountData retrieveOne(final Long id, final boolean includeTemplate) {
+        Collection<ShareAccountChargeData> charges = this.shareAccountChargeReadPlatformService.retrieveAccountCharges(id, "active");
+        Collection<PurchasedSharesData> purchasedShares = this.purchasedSharesReadPlatformService.retrievePurchasedShares(id);
+        
+        ShareAccountMapper mapper = new ShareAccountMapper(charges, purchasedShares);
+        String query = "select " + mapper.schema() + "where sa.id=?";
+        ShareAccountData data = this.jdbcTemplate.queryForObject(query, mapper, new Object[] { id });
+        String serviceName = "share" + ProductsApiConstants.READPLATFORM_NAME;
+        ProductReadPlatformService service = (ProductReadPlatformService) this.applicationContext.getBean(serviceName);
+        final ShareProductData productData = (ShareProductData) service.retrieveOne(data.getProductId(), false);
+        final BigDecimal currentMarketPrice = deriveMarketPrice(productData);
+        data.setCurrentMarketPrice(currentMarketPrice);
+        if(!includeTemplate) {
+            Collection<ShareAccountDividendData> dividends = this.retrieveAssociatedDividends(id) ;
+            data.setDividends(dividends);    
+        }
+        if (includeTemplate) {
+            final Collection<EnumOptionData> lockinPeriodFrequencyTypeOptions = this.shareProductDropdownReadPlatformService
+                    .retrieveLockinPeriodFrequencyTypeOptions();
+            final Collection<EnumOptionData> minimumActivePeriodFrequencyTypeOptions = lockinPeriodFrequencyTypeOptions;
+            final Collection<SavingsAccountData> clientSavingsAccounts = this.savingsAccountReadPlatformService.retrieveAllForLookup(data
+                    .getClientId());
+            Collection<ProductData> productOptions = service.retrieveAllForLookup();
+            final Collection<ChargeData> chargeOptions = this.chargeReadPlatformService.retrieveSharesApplicableCharges();
+            data = ShareAccountData.template(data, productOptions, chargeOptions, clientSavingsAccounts, lockinPeriodFrequencyTypeOptions,
+                    minimumActivePeriodFrequencyTypeOptions);
+        }
+        return data;
+    }
+
+    private Collection<ShareAccountDividendData> retrieveAssociatedDividends(final Long shareAccountId) {
+        ShareAccountDividendRowMapper mapper = new ShareAccountDividendRowMapper();
+        String query = "select " + mapper.schema() + "where sadd.account_id=?";
+        return this.jdbcTemplate.query(query, mapper, new Object[] { shareAccountId });
+    }
+
+    @Override
+    public Collection<AccountData> retrieveAll() {
+        return null;
+    }
+
+    @Override
+    public Set<String> getResponseDataParams() {
+        return null;
+    }
+
+    @Override
+    public Collection<ShareAccountData> retrieveAllShareAccountDataForDividends(final Long id, final boolean fetchInActiveAccounts,
+            final LocalDate startDate) {
+        ShareAccountMapperForDividents mapper = new ShareAccountMapperForDividents();
+        StringBuilder sb = new StringBuilder("select ");
+        sb.append(mapper.schema);
+        sb.append(" where sa.product_id = ? ");
+
+        List<Object> params = new ArrayList<>(3);
+        params.add(id);
+        params.add(ShareAccountStatusType.ACTIVE.getValue());
+        if (fetchInActiveAccounts) {
+            sb.append(" and (sa.status_enum = ? or (sa.status_enum = ? ");
+            sb.append(" and sa.closed_date >  ?)) ");
+            params.add(ShareAccountStatusType.CLOSED.getValue());
+            params.add(formatter.print(startDate));
+        } else {
+            sb.append(" and sa.status_enum = ? ");
+        }
+        sb.append(" and saps.status_enum = ?");
+        params.add(PurchasedSharesStatusType.APPROVED.getValue());
+        Object[] whereClauseItems = params.toArray();
+        return this.jdbcTemplate.query(sb.toString(), whereClauseItems, mapper);
+    }
+
+    public Collection<ShareAccountChargeData> convertChargesToShareAccountCharges(Collection<ChargeData> productCharges) {
+        final Collection<ShareAccountChargeData> savingsCharges = new ArrayList<>();
+        for (final ChargeData chargeData : productCharges) {
+            final ShareAccountChargeData savingsCharge = chargeData.toShareAccountChargeData();
+            savingsCharges.add(savingsCharge);
+        }
+        return savingsCharges;
+    }
+
+    private final static class ShareAccountMapper implements RowMapper<ShareAccountData> {
+
+        private final Collection<ShareAccountChargeData> charges;
+        private final Collection<PurchasedSharesData> purchasedShares;
+
+        private final String schema;
+
+        public ShareAccountMapper(final Collection<ShareAccountChargeData> charges, final Collection<PurchasedSharesData> purchasedShares) {
+            this.charges = charges;
+            this.purchasedShares = purchasedShares;
+            StringBuffer buff = new StringBuffer()
+                    .append("sa.id as id, sa.external_id as externalId, sa.status_enum as statusEnum, ")
+                    .append("sa.savings_account_id, msa.account_no as savingsAccNo, ")
+                    .append("c.id as clientId, c.display_name as clientName, ")
+                    .append("sa.account_no as accountNo, sa.total_approved_shares as approvedShares, sa.total_pending_shares as pendingShares, ")
+                    .append("sa.savings_account_id as savingsAccountNo, sa.minimum_active_period_frequency as minimumactivePeriod, ")
+                    .append("sa.minimum_active_period_frequency_enum as minimumactivePeriodEnum, ")
+                    .append("sa.lockin_period_frequency as lockinPeriod, sa.lockin_period_frequency_enum as lockinPeriodEnum, ")
+                    .append("sa.allow_dividends_inactive_clients as allowdividendsforinactiveclients, ")
+                    .append("sa.submitted_date as submittedDate, sbu.username as submittedByUsername, ")
+                    .append("sbu.firstname as submittedByFirstname, sbu.lastname as submittedByLastname, ")
+                    .append("sa.rejected_date as rejectedDate, rbu.username as rejectedByUsername, ")
+                    .append("rbu.firstname as rejectedByFirstname, rbu.lastname as rejectedByLastname, ")
+                    .append("sa.approved_date as approvedDate, abu.username as approvedByUsername, ")
+                    .append("abu.firstname as approvedByFirstname, abu.lastname as approvedByLastname, ")
+                    .append("sa.activated_date as activatedDate, avbu.username as activatedByUsername, ")
+                    .append("avbu.firstname as activatedByFirstname, avbu.lastname as activatedByLastname, ")
+                    .append("sa.closed_date as closedDate, cbu.username as closedByUsername, ")
+                    .append("cbu.firstname as closedByFirstname, cbu.lastname as closedByLastname, ")
+                    .append("sa.currency_code as currencyCode, sa.currency_digits as currencyDigits, sa.currency_multiplesof as inMultiplesOf, ")
+                    .append("curr.name as currencyName, curr.internationalized_name_code as currencyNameCode, ")
+                    .append("curr.display_symbol as currencyDisplaySymbol, sa.product_id as productId, p.name as productName, p.short_name as shortProductName ")
+                    .append("from m_share_account sa ").append("join m_share_product as p on p.id = sa.product_id ")
+                    .append("join m_currency curr on curr.code = sa.currency_code ").append("left join m_client c ON c.id = sa.client_id ")
+                    .append("left join m_appuser sbu on sbu.id = sa.submitted_userid ")
+                    .append("left join m_appuser rbu on rbu.id = sa.rejected_userid ")
+                    .append("left join m_appuser abu on abu.id = sa.approved_userid ")
+                    .append("left join m_appuser avbu on rbu.id = sa.activated_userid ")
+                    .append("left join m_appuser cbu on cbu.id = sa.closed_userid ")
+                    .append("left join m_savings_account msa on sa.savings_account_id = msa.id ");
+            this.schema = buff.toString();
+        }
+
+        @Override
+        public ShareAccountData mapRow(ResultSet rs, @SuppressWarnings("unused") int rowNum) throws SQLException {
+            final Long id = rs.getLong("id");
+            final String accountNo = rs.getString("accountNo");
+            final String externalId = rs.getString("externalId");
+            final Long savingsAccountId = JdbcSupport.getLong(rs, "savings_account_id");
+            final String savingsAccountNumber = rs.getString("savingsAccNo");
+            final Long clientId = JdbcSupport.getLong(rs, "clientId");
+            final String clientName = rs.getString("clientName");
+            final Long productId = rs.getLong("productId");
+            final String productName = rs.getString("productName");
+            final Long totalApprovedShares = JdbcSupport.getLong(rs, "approvedShares");
+            final Long totalPendingShares = JdbcSupport.getLong(rs, "pendingShares");
+            final Boolean allowdividendsforinactiveclients = rs.getBoolean("allowdividendsforinactiveclients");
+
+            final Integer statusEnum = JdbcSupport.getInteger(rs, "statusEnum");
+            final ShareAccountStatusEnumData status = SharesEnumerations.status(statusEnum);
+
+            final LocalDate submittedOnDate = JdbcSupport.getLocalDate(rs, "submittedDate");
+            final String submittedByUsername = rs.getString("submittedByUsername");
+            final String submittedByFirstname = rs.getString("submittedByFirstname");
+            final String submittedByLastname = rs.getString("submittedByLastname");
+
+            final LocalDate rejectedOnDate = JdbcSupport.getLocalDate(rs, "rejectedDate");
+            final String rejectedByUsername = rs.getString("rejectedByUsername");
+            final String rejectedByFirstname = rs.getString("rejectedByFirstname");
+            final String rejectedByLastname = rs.getString("rejectedByLastname");
+
+            final LocalDate approvedOnDate = JdbcSupport.getLocalDate(rs, "approvedDate");
+            final String approvedByUsername = rs.getString("approvedByUsername");
+            final String approvedByFirstname = rs.getString("approvedByFirstname");
+            final String approvedByLastname = rs.getString("approvedByLastname");
+
+            final LocalDate activatedOnDate = JdbcSupport.getLocalDate(rs, "activatedDate");
+            final String activatedByUsername = rs.getString("activatedByUsername");
+            final String activatedByFirstname = rs.getString("activatedByFirstname");
+            final String activatedByLastname = rs.getString("activatedByLastname");
+
+            final LocalDate closedOnDate = JdbcSupport.getLocalDate(rs, "closedDate");
+            final String closedByUsername = rs.getString("closedByUsername");
+            final String closedByFirstname = rs.getString("closedByFirstname");
+            final String closedByLastname = rs.getString("closedByLastname");
+
+            final ShareAccountApplicationTimelineData timeline = new ShareAccountApplicationTimelineData(submittedOnDate,
+                    submittedByUsername, submittedByFirstname, submittedByLastname, rejectedOnDate, rejectedByUsername,
+                    rejectedByFirstname, rejectedByLastname, approvedOnDate, approvedByUsername, approvedByFirstname, approvedByLastname,
+                    activatedOnDate, activatedByUsername, activatedByFirstname, activatedByLastname, closedOnDate, closedByUsername,
+                    closedByFirstname, closedByLastname);
+
+            final String currencyCode = rs.getString("currencyCode");
+            final String currencyName = rs.getString("currencyName");
+            final String currencyNameCode = rs.getString("currencyNameCode");
+            final String currencyDisplaySymbol = rs.getString("currencyDisplaySymbol");
+            final Integer currencyDigits = JdbcSupport.getInteger(rs, "currencyDigits");
+            final Integer inMultiplesOf = JdbcSupport.getInteger(rs, "inMultiplesOf");
+            final CurrencyData currency = new CurrencyData(currencyCode, currencyName, currencyDigits, inMultiplesOf,
+                    currencyDisplaySymbol, currencyNameCode);
+
+            final Integer lockinPeriodFrequency = JdbcSupport.getInteger(rs, "lockinPeriod");
+            EnumOptionData lockinPeriodFrequencyType = null;
+
+            final Integer lockinPeriodFrequencyTypeValue = JdbcSupport.getInteger(rs, "lockinPeriodEnum");
+            if (lockinPeriodFrequencyTypeValue != null) {
+                final SharePeriodFrequencyType lockinPeriodType = SharePeriodFrequencyType.fromInt(lockinPeriodFrequencyTypeValue);
+                lockinPeriodFrequencyType = SharesEnumerations.lockinPeriodFrequencyType(lockinPeriodType);
+            }
+
+            final Integer minimumActivePeriod = JdbcSupport.getInteger(rs, "minimumactivePeriod");
+            EnumOptionData minimumActivePeriodType = null;
+            final Integer minimumActivePeriodTypeValue = JdbcSupport.getInteger(rs, "minimumactivePeriodEnum");
+            if (minimumActivePeriodTypeValue != null) {
+                final SharePeriodFrequencyType minmumPeriodType = SharePeriodFrequencyType.fromInt(minimumActivePeriodTypeValue);
+                minimumActivePeriodType = SharesEnumerations.lockinPeriodFrequencyType(minmumPeriodType);
+            }
+
+            final String shortProductName = null;
+            final ShareAccountSummaryData summary = new ShareAccountSummaryData(id, accountNo, externalId, productId, productName,
+                    shortProductName, status, currency, totalApprovedShares, totalPendingShares, timeline);
+            return new ShareAccountData(id, accountNo, externalId, savingsAccountId, savingsAccountNumber, clientId, clientName,
+                    productId, productName, status, timeline, currency, summary, charges, purchasedShares, lockinPeriodFrequency,
+                    lockinPeriodFrequencyType, minimumActivePeriod, minimumActivePeriodType, allowdividendsforinactiveclients);
+
+        }
+
+        public String schema() {
+            return this.schema;
+        }
+    }
+
+    private final static class ShareAccountMapperForDividents implements RowMapper<ShareAccountData> {
+
+        private final String schema;
+        final PurchasedSharesDataRowMapper purchasedSharesDataRowMapper = new PurchasedSharesDataRowMapper();
+
+        public ShareAccountMapperForDividents() {
+            StringBuilder sb = new StringBuilder();
+
+            sb.append("sa.id as id, sa.status_enum as statusEnum, ");
+            sb.append("c.id as clientId, c.display_name as clientName, ");
+            sb.append("sa.account_no as accountNo, ");
+            sb.append("sa.currency_code as currencyCode, sa.currency_digits as currencyDigits, sa.currency_multiplesof as inMultiplesOf, ");
+            sb.append(purchasedSharesDataRowMapper.schema());
+            sb.append(" from m_share_account sa ");
+            sb.append(" join m_client c ON c.id = sa.client_id ");
+            sb.append(" join m_share_account_transactions saps ON saps.account_id = sa.id ");
+            schema = sb.toString();
+        }
+
+        @Override
+        public ShareAccountData mapRow(ResultSet rs, int rowNum) throws SQLException {
+            final Long id = rs.getLong("id");
+            final String accountNo = rs.getString("accountNo");
+            final Long clientId = JdbcSupport.getLong(rs, "clientId");
+            final String clientName = rs.getString("clientName");
+            final Integer statusEnum = JdbcSupport.getInteger(rs, "statusEnum");
+            final ShareAccountStatusEnumData status = SharesEnumerations.status(statusEnum);
+
+            final CurrencyData currency = null;
+            final Long totalApprovedShares = null;
+            final Long totalPendingShares = null;
+            final String externalId = null;
+            final Long productId = null;
+            final String productName = null;
+            final String shortProductName = null;
+            final ShareAccountApplicationTimelineData timeline = null;
+            final Boolean allowdividendsforinactiveclients = null;
+
+            final Collection<ShareAccountChargeData> charges = null;
+            final Collection<PurchasedSharesData> purchasedSharesData = new ArrayList<>();
+            final Integer lockinPeriod = null;
+            final EnumOptionData lockPeriodTypeEnum = null;
+            final Integer minimumActivePeriod = null;
+            final EnumOptionData minimumActivePeriodTypeEnum = null;
+            purchasedSharesData.add(this.purchasedSharesDataRowMapper.mapRow(rs, rowNum));
+
+            while (rs.next()) {
+                if (id.equals(rs.getLong("id"))) {
+                    purchasedSharesData.add(this.purchasedSharesDataRowMapper.mapRow(rs, rowNum));
+                } else {
+                    rs.previous();
+                    break;
+                }
+            }
+
+            final ShareAccountSummaryData summary = new ShareAccountSummaryData(id, accountNo, externalId, productId, productName,
+                    shortProductName, status, currency, totalApprovedShares, totalPendingShares, timeline);
+
+            return new ShareAccountData(id, accountNo, externalId, clientId, clientName, productId, shortProductName, productId,
+                    shortProductName, status, timeline, currency, summary, charges, purchasedSharesData, lockinPeriod, lockPeriodTypeEnum,
+                    minimumActivePeriod, minimumActivePeriodTypeEnum, allowdividendsforinactiveclients);
+
+        }
+    }
+
+    private final static class PurchasedSharesDataRowMapper implements RowMapper<PurchasedSharesData> {
+
+        private final String schema;
+
+        public PurchasedSharesDataRowMapper() {
+            StringBuffer buff = new StringBuffer()
+                    .append("saps.id as purchasedId, saps.account_id as accountId, saps.transaction_date as transactionDate, saps.total_shares as purchasedShares, saps.unit_price as unitPrice, ")
+                    .append("saps.status_enum as purchaseStatus, saps.type_enum as purchaseType, saps.amount as amount, saps.charge_amount as chargeamount ");
+            schema = buff.toString();
+        }
+
+        @Override
+        public PurchasedSharesData mapRow(ResultSet rs, @SuppressWarnings("unused") int rowNum) throws SQLException {
+            final Long id = rs.getLong("purchasedId");
+            final Long accountId = rs.getLong("accountId");
+            final LocalDate transactionDate = new LocalDate(rs.getDate("transactionDate"));
+            final Long numberOfShares = JdbcSupport.getLong(rs, "purchasedShares");
+            final BigDecimal purchasedPrice = rs.getBigDecimal("unitPrice");
+            final Integer status = rs.getInt("purchaseStatus");
+            final EnumOptionData statusEnum = SharesEnumerations.purchasedSharesEnum(status);
+            final Integer type = rs.getInt("purchaseType");
+            final EnumOptionData typeEnum = SharesEnumerations.purchasedSharesEnum(type);
+            final BigDecimal amount = JdbcSupport.getBigDecimalDefaultToNullIfZero(rs, "amount");
+            final BigDecimal chargeAmount = JdbcSupport.getBigDecimalDefaultToNullIfZero(rs, "chargeamount");
+            return new PurchasedSharesData(id, accountId, transactionDate, numberOfShares, purchasedPrice, statusEnum, typeEnum, amount,
+                    chargeAmount);
+        }
+
+        public String schema() {
+            return this.schema;
+        }
+    }
+
+    private final static class ShareAccountDividendRowMapper implements RowMapper<ShareAccountDividendData> {
+
+        private final String schema;
+
+        ShareAccountDividendRowMapper() {
+            StringBuffer buff = new StringBuffer()
+                    .append("spdp.created_date, sadd.id, sadd.amount, sadd.savings_transaction_id, sadd.status ")
+                    .append(" from m_share_account_dividend_details sadd ")
+                    .append("JOIN m_share_product_dividend_pay_out spdp ON spdp.id = sadd.dividend_pay_out_id ");
+            schema = buff.toString();
+        }
+
+        @Override
+        public ShareAccountDividendData mapRow(ResultSet rs, int rowNum) throws SQLException {
+            final Long id = rs.getLong("id");
+            final Date postedDate = JdbcSupport.getLocalDate(rs, "created_date").toDate();
+            final BigDecimal postedAmount = JdbcSupport.getBigDecimalDefaultToNullIfZero(rs, "amount");
+            final Long savingTransactionId = rs.getLong("savings_transaction_id");
+            final Integer status = rs.getInt("status") ;
+            final EnumOptionData statusEnum = SharesEnumerations.ShareAccountDividendStatusEnum(status);
+            final ShareAccountData shareAccountData = null;
+            return new ShareAccountDividendData(id, postedDate, shareAccountData, postedAmount, statusEnum, savingTransactionId);
+        }
+
+        public String schema() {
+            return this.schema;
+        }
+    }
+}

http://git-wip-us.apache.org/repos/asf/incubator-fineract/blob/08c553f9/fineract-provider/src/main/java/org/apache/fineract/portfolio/shareaccounts/service/ShareAccountSchedularService.java
----------------------------------------------------------------------
diff --git a/fineract-provider/src/main/java/org/apache/fineract/portfolio/shareaccounts/service/ShareAccountSchedularService.java b/fineract-provider/src/main/java/org/apache/fineract/portfolio/shareaccounts/service/ShareAccountSchedularService.java
new file mode 100644
index 0000000..31e9309
--- /dev/null
+++ b/fineract-provider/src/main/java/org/apache/fineract/portfolio/shareaccounts/service/ShareAccountSchedularService.java
@@ -0,0 +1,27 @@
+/**
+ * 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.shareaccounts.service;
+
+
+
+public interface ShareAccountSchedularService {
+
+    void postDividend(final Long dividendDetailId, final Long savingsId);
+    
+}

http://git-wip-us.apache.org/repos/asf/incubator-fineract/blob/08c553f9/fineract-provider/src/main/java/org/apache/fineract/portfolio/shareaccounts/service/ShareAccountSchedularServiceImpl.java
----------------------------------------------------------------------
diff --git a/fineract-provider/src/main/java/org/apache/fineract/portfolio/shareaccounts/service/ShareAccountSchedularServiceImpl.java b/fineract-provider/src/main/java/org/apache/fineract/portfolio/shareaccounts/service/ShareAccountSchedularServiceImpl.java
new file mode 100644
index 0000000..bb42540
--- /dev/null
+++ b/fineract-provider/src/main/java/org/apache/fineract/portfolio/shareaccounts/service/ShareAccountSchedularServiceImpl.java
@@ -0,0 +1,61 @@
+/**
+ * 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.shareaccounts.service;
+
+import javax.transaction.Transactional;
+
+import org.apache.fineract.infrastructure.core.service.DateUtils;
+import org.apache.fineract.portfolio.savings.domain.SavingsAccount;
+import org.apache.fineract.portfolio.savings.domain.SavingsAccountAssembler;
+import org.apache.fineract.portfolio.savings.domain.SavingsAccountDomainService;
+import org.apache.fineract.portfolio.savings.domain.SavingsAccountTransaction;
+import org.apache.fineract.portfolio.shareaccounts.domain.ShareAccountDividendDetails;
+import org.apache.fineract.portfolio.shareaccounts.domain.ShareAccountDividendRepository;
+import org.apache.fineract.portfolio.shareaccounts.domain.ShareAccountDividendStatusType;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Service;
+
+@Service
+public class ShareAccountSchedularServiceImpl implements ShareAccountSchedularService {
+
+    private final ShareAccountDividendRepository shareAccountDividendRepository;
+    private final SavingsAccountDomainService savingsAccountDomainService;
+    private final SavingsAccountAssembler savingsAccountAssembler;
+
+    @Autowired
+    public ShareAccountSchedularServiceImpl(final ShareAccountDividendRepository shareAccountDividendRepository,
+            final SavingsAccountDomainService savingsAccountDomainService, final SavingsAccountAssembler savingsAccountAssembler) {
+        this.shareAccountDividendRepository = shareAccountDividendRepository;
+        this.savingsAccountDomainService = savingsAccountDomainService;
+        this.savingsAccountAssembler = savingsAccountAssembler;
+    }
+
+    @Override
+    @Transactional
+    public void postDividend(final Long dividendDetailId, final Long savingsId) {
+
+        ShareAccountDividendDetails shareAccountDividendDetails = this.shareAccountDividendRepository.findOne(dividendDetailId);
+        final SavingsAccount savingsAccount = this.savingsAccountAssembler.assembleFrom(savingsId);
+        SavingsAccountTransaction savingsAccountTransaction = this.savingsAccountDomainService.handleDividendPayout(savingsAccount,
+                DateUtils.getLocalDateOfTenant(), shareAccountDividendDetails.getAmount());
+        shareAccountDividendDetails.update(ShareAccountDividendStatusType.POSTED.getValue(), savingsAccountTransaction.getId());
+        this.shareAccountDividendRepository.save(shareAccountDividendDetails);
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/incubator-fineract/blob/08c553f9/fineract-provider/src/main/java/org/apache/fineract/portfolio/shareaccounts/service/ShareAccountWritePlatformService.java
----------------------------------------------------------------------
diff --git a/fineract-provider/src/main/java/org/apache/fineract/portfolio/shareaccounts/service/ShareAccountWritePlatformService.java b/fineract-provider/src/main/java/org/apache/fineract/portfolio/shareaccounts/service/ShareAccountWritePlatformService.java
new file mode 100644
index 0000000..76c53b2
--- /dev/null
+++ b/fineract-provider/src/main/java/org/apache/fineract/portfolio/shareaccounts/service/ShareAccountWritePlatformService.java
@@ -0,0 +1,49 @@
+/**
+ * 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.shareaccounts.service;
+
+import org.apache.fineract.infrastructure.core.api.JsonCommand;
+import org.apache.fineract.infrastructure.core.data.CommandProcessingResult;
+
+
+public interface ShareAccountWritePlatformService {
+
+    public CommandProcessingResult createShareAccount(JsonCommand jsonCommand) ;
+    
+    public CommandProcessingResult updateShareAccount(Long accountId, JsonCommand jsonCommand) ;
+    
+    public CommandProcessingResult approveShareAccount(Long accountId, JsonCommand jsonCommand) ;
+
+    public CommandProcessingResult activateShareAccount(Long accountId, JsonCommand jsonCommand) ;
+
+    public CommandProcessingResult rejectShareAccount(Long entityId, JsonCommand jsonCommand);
+
+    public CommandProcessingResult undoApproveShareAccount(Long entityId, JsonCommand jsonCommand);
+    
+    public CommandProcessingResult closeShareAccount(Long accountId, JsonCommand jsonCommand) ;
+    
+    public CommandProcessingResult applyAddtionalShares(final Long accountId, JsonCommand jsonCommand) ;
+    
+    public CommandProcessingResult approveAdditionalShares(Long accountId, JsonCommand jsonCommand) ;
+    
+    public CommandProcessingResult rejectAdditionalShares(Long accountId, JsonCommand jsonCommand) ;
+
+    public CommandProcessingResult redeemShares(Long accountId, JsonCommand jsonCommand);
+}
+

http://git-wip-us.apache.org/repos/asf/incubator-fineract/blob/08c553f9/fineract-provider/src/main/java/org/apache/fineract/portfolio/shareaccounts/service/ShareAccountWritePlatformServiceJpaRepositoryImpl.java
----------------------------------------------------------------------
diff --git a/fineract-provider/src/main/java/org/apache/fineract/portfolio/shareaccounts/service/ShareAccountWritePlatformServiceJpaRepositoryImpl.java b/fineract-provider/src/main/java/org/apache/fineract/portfolio/shareaccounts/service/ShareAccountWritePlatformServiceJpaRepositoryImpl.java
new file mode 100644
index 0000000..daad3be
--- /dev/null
+++ b/fineract-provider/src/main/java/org/apache/fineract/portfolio/shareaccounts/service/ShareAccountWritePlatformServiceJpaRepositoryImpl.java
@@ -0,0 +1,404 @@
+/**
+ * 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.shareaccounts.service;
+
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+
+import org.apache.fineract.accounting.journalentry.service.JournalEntryWritePlatformService;
+import org.apache.fineract.infrastructure.accountnumberformat.domain.AccountNumberFormat;
+import org.apache.fineract.infrastructure.accountnumberformat.domain.AccountNumberFormatRepositoryWrapper;
+import org.apache.fineract.infrastructure.accountnumberformat.domain.EntityAccountType;
+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.organisation.monetary.data.CurrencyData;
+import org.apache.fineract.organisation.monetary.domain.MonetaryCurrency;
+import org.apache.fineract.portfolio.accounts.constants.ShareAccountApiConstants;
+import org.apache.fineract.portfolio.client.domain.AccountNumberGenerator;
+import org.apache.fineract.portfolio.shareaccounts.data.ShareAccountTransactionEnumData;
+import org.apache.fineract.portfolio.shareaccounts.domain.ShareAccount;
+import org.apache.fineract.portfolio.shareaccounts.domain.ShareAccountChargePaidBy;
+import org.apache.fineract.portfolio.shareaccounts.domain.ShareAccountRepositoryWrapper;
+import org.apache.fineract.portfolio.shareaccounts.domain.ShareAccountTransaction;
+import org.apache.fineract.portfolio.shareaccounts.serialization.ShareAccountDataSerializer;
+import org.joda.time.LocalDate;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.dao.DataIntegrityViolationException;
+import org.springframework.stereotype.Service;
+
+@Service
+public class ShareAccountWritePlatformServiceJpaRepositoryImpl implements ShareAccountWritePlatformService {
+
+    private final ShareAccountDataSerializer accountDataSerializer;
+
+    private final ShareAccountRepositoryWrapper shareAccountRepository;
+
+    private final AccountNumberGenerator accountNumberGenerator;
+
+    private final AccountNumberFormatRepositoryWrapper accountNumberFormatRepository;
+
+    private final JournalEntryWritePlatformService journalEntryWritePlatformService;
+
+    @Autowired
+    public ShareAccountWritePlatformServiceJpaRepositoryImpl(final ShareAccountDataSerializer accountDataSerializer,
+            final ShareAccountRepositoryWrapper shareAccountRepository,
+            final AccountNumberGenerator accountNumberGenerator,
+            final AccountNumberFormatRepositoryWrapper accountNumberFormatRepository,
+            final JournalEntryWritePlatformService journalEntryWritePlatformService) {
+        this.accountDataSerializer = accountDataSerializer;
+        this.shareAccountRepository = shareAccountRepository;
+        this.accountNumberGenerator = accountNumberGenerator;
+        this.accountNumberFormatRepository = accountNumberFormatRepository;
+        this.journalEntryWritePlatformService = journalEntryWritePlatformService;
+    }
+
+    @Override
+    public CommandProcessingResult createShareAccount(JsonCommand jsonCommand) {
+        try {
+            ShareAccount account = this.accountDataSerializer.validateAndCreate(jsonCommand);
+            this.shareAccountRepository.save(account);
+            generateAccountNumber(account);
+            //this.shareProductRepository.save(account.getShareProduct()); //subscribed shares is increased
+            journalEntryWritePlatformService.createJournalEntriesForShares(populateJournalEntries(account,
+                    account.getPendingForApprovalSharePurchaseTransactions()));
+            return new CommandProcessingResultBuilder() //
+                    .withCommandId(jsonCommand.commandId()) //
+                    .withEntityId(account.getId()) //
+                    .build();
+        } catch (final DataIntegrityViolationException dve) {
+            handleDataIntegrityIssues(jsonCommand, dve);
+            return CommandProcessingResult.empty();
+        }
+    }
+
+    private void generateAccountNumber(final ShareAccount account) {
+        if (account.isAccountNumberRequiresAutoGeneration()) {
+            final AccountNumberFormat accountNumberFormat = this.accountNumberFormatRepository.findByAccountType(EntityAccountType.SHARES);
+            account.updateAccountNumber(this.accountNumberGenerator.generate(account, accountNumberFormat));
+            this.shareAccountRepository.save(account);
+        }
+    }
+
+    private Map<String, Object> populateJournalEntries(final ShareAccount account, final Set<ShareAccountTransaction> transactions) {
+        final Map<String, Object> accountingBridgeData = new HashMap<>();
+        Boolean cashBasedAccounting = account.getShareProduct().getAccountingType().intValue() == 2 ? Boolean.TRUE : Boolean.FALSE;
+        accountingBridgeData.put("cashBasedAccountingEnabled", cashBasedAccounting);
+        accountingBridgeData.put("accrualBasedAccountingEnabled", Boolean.FALSE);
+        accountingBridgeData.put("shareAccountId", account.getId());
+        accountingBridgeData.put("shareProductId", account.getShareProduct().getId());
+        accountingBridgeData.put("officeId", account.getOfficeId());
+        MonetaryCurrency currency = account.getCurrency();
+        final CurrencyData currencyData = new CurrencyData(currency.getCode(), "", currency.getDigitsAfterDecimal(),
+                currency.getCurrencyInMultiplesOf(), "", "");
+        accountingBridgeData.put("currency", currencyData);
+        final List<Map<String, Object>> newTransactionsMap = new ArrayList<>();
+        accountingBridgeData.put("newTransactions", newTransactionsMap);
+
+        for (ShareAccountTransaction transaction : transactions) {
+            final Map<String, Object> transactionDto = new HashMap<>();
+            transactionDto.put("officeId", account.getOfficeId());
+            transactionDto.put("id", transaction.getId());
+            transactionDto.put("date", new LocalDate(transaction.getPurchasedDate()));
+            final Integer status = transaction.getTransactionStatus();
+            final ShareAccountTransactionEnumData statusEnum = new ShareAccountTransactionEnumData(status.longValue(), null, null);
+            final Integer type = transaction.getTransactionType();
+            final ShareAccountTransactionEnumData typeEnum = new ShareAccountTransactionEnumData(type.longValue(), null, null);
+            transactionDto.put("status", statusEnum);
+            transactionDto.put("type", typeEnum);
+            transactionDto.put("amount", transaction.amount());
+            transactionDto.put("chargeAmount", transaction.chargeAmount());
+            transactionDto.put("paymentTypeId", null); // FIXME::make it cash
+                                                       // payment
+            if (transaction.getChargesPaidBy() != null && !transaction.getChargesPaidBy().isEmpty()) {
+                final List<Map<String, Object>> chargesPaidData = new ArrayList<>();
+                transactionDto.put("chargesPaid", chargesPaidData);
+                Set<ShareAccountChargePaidBy> chargesPaidBySet = transaction.getChargesPaidBy();
+                for (ShareAccountChargePaidBy chargesPaidBy : chargesPaidBySet) {
+                    Map<String, Object> chargesPaidDto = new HashMap<>();
+                    chargesPaidDto.put("chargeId", chargesPaidBy.getChargeId());
+                    chargesPaidDto.put("sharesChargeId", chargesPaidBy.getShareChargeId());
+                    chargesPaidDto.put("amount", chargesPaidBy.getAmount());
+                    chargesPaidData.add(chargesPaidDto);
+                }
+            }
+            newTransactionsMap.add(transactionDto);
+        }
+        return accountingBridgeData;
+    }
+
+    @Override
+    public CommandProcessingResult updateShareAccount(Long accountId, JsonCommand jsonCommand) {
+        try {
+            ShareAccount account = this.shareAccountRepository.findOneWithNotFoundDetection(accountId);
+            Map<String, Object> changes = this.accountDataSerializer.validateAndUpdate(jsonCommand, account);
+            if (!changes.isEmpty()) {
+                this.shareAccountRepository.save(account);
+            }
+            return new CommandProcessingResultBuilder() //
+                    .withCommandId(jsonCommand.commandId()) //
+                    .withEntityId(accountId) //
+                    .with(changes) //
+                    .build();
+        } catch (DataIntegrityViolationException dve) {
+            handleDataIntegrityIssues(jsonCommand, dve);
+            return CommandProcessingResult.empty();
+        }
+    }
+
+    @Override
+    public CommandProcessingResult applyAddtionalShares(final Long accountId, JsonCommand jsonCommand) {
+        try {
+            ShareAccount account = this.shareAccountRepository.findOneWithNotFoundDetection(accountId);
+            Map<String, Object> changes = this.accountDataSerializer.validateAndApplyAddtionalShares(jsonCommand, account);
+            ShareAccountTransaction transaction = null;
+            if (!changes.isEmpty()) {
+                this.shareAccountRepository.save(account);
+                transaction = (ShareAccountTransaction) changes.get(ShareAccountApiConstants.additionalshares_paramname);
+                transaction = account.getShareAccountTransaction(transaction);
+                if (transaction != null) {
+                    changes.clear();
+                    changes.put(ShareAccountApiConstants.additionalshares_paramname, transaction.getId());
+                    Set<ShareAccountTransaction> transactions = new HashSet<>();
+                    transactions.add(transaction);
+                    this.journalEntryWritePlatformService.createJournalEntriesForShares(populateJournalEntries(account, transactions));
+                }
+            }
+
+            return new CommandProcessingResultBuilder() //
+                    .withCommandId(jsonCommand.commandId()) //
+                    .withEntityId(accountId) //
+                    .with(changes) //
+                    .build();
+        } catch (final DataIntegrityViolationException dve) {
+            handleDataIntegrityIssues(jsonCommand, dve);
+            return CommandProcessingResult.empty();
+        }
+    }
+
+    @Override
+    public CommandProcessingResult approveShareAccount(Long accountId, JsonCommand jsonCommand) {
+
+        try {
+            ShareAccount account = this.shareAccountRepository.findOneWithNotFoundDetection(accountId);
+            Map<String, Object> changes = this.accountDataSerializer.validateAndApprove(jsonCommand, account);
+            if (!changes.isEmpty()) {
+                this.shareAccountRepository.save(account);
+            }
+            this.journalEntryWritePlatformService.createJournalEntriesForShares(populateJournalEntries(account,
+                    account.getShareAccountTransactions()));
+            return new CommandProcessingResultBuilder() //
+                    .withCommandId(jsonCommand.commandId()) //
+                    .withEntityId(accountId) //
+                    .with(changes) //
+                    .build();
+        } catch (DataIntegrityViolationException dve) {
+            handleDataIntegrityIssues(jsonCommand, dve);
+            return CommandProcessingResult.empty();
+        }
+    }
+
+    @Override
+    public CommandProcessingResult rejectShareAccount(Long accountId, JsonCommand jsonCommand) {
+        try {
+            ShareAccount account = this.shareAccountRepository.findOneWithNotFoundDetection(accountId);
+            Map<String, Object> changes = this.accountDataSerializer.validateAndReject(jsonCommand, account);
+            if (!changes.isEmpty()) {
+                this.shareAccountRepository.save(account);
+            }
+            this.journalEntryWritePlatformService.createJournalEntriesForShares(populateJournalEntries(account,
+                    account.getShareAccountTransactions()));
+            return new CommandProcessingResultBuilder() //
+                    .withCommandId(jsonCommand.commandId()) //
+                    .withEntityId(accountId) //
+                    .with(changes) //
+                    .build();
+        } catch (DataIntegrityViolationException dve) {
+            handleDataIntegrityIssues(jsonCommand, dve);
+            return CommandProcessingResult.empty();
+        }
+    }
+
+    @Override
+    public CommandProcessingResult undoApproveShareAccount(Long accountId, JsonCommand jsonCommand) {
+        try {
+            ShareAccount account = this.shareAccountRepository.findOneWithNotFoundDetection(accountId);
+            Map<String, Object> changes = this.accountDataSerializer.validateAndUndoApprove(jsonCommand, account);
+            if (!changes.isEmpty()) {
+                this.shareAccountRepository.save(account);
+            }
+            /*
+             * this.journalEntryWritePlatformService.createJournalEntriesForShares
+             * (populateJournalEntries(account,
+             * account.getShareAccountTransactions()));
+             */
+            return new CommandProcessingResultBuilder() //
+                    .withCommandId(jsonCommand.commandId()) //
+                    .withEntityId(accountId) //
+                    .with(changes) //
+                    .build();
+        } catch (DataIntegrityViolationException dve) {
+            handleDataIntegrityIssues(jsonCommand, dve);
+            return CommandProcessingResult.empty();
+        }
+    }
+
+    @Override
+    public CommandProcessingResult activateShareAccount(Long accountId, JsonCommand jsonCommand) {
+
+        try {
+            ShareAccount account = this.shareAccountRepository.findOneWithNotFoundDetection(accountId);
+            Map<String, Object> changes = this.accountDataSerializer.validateAndActivate(jsonCommand, account);
+            if (!changes.isEmpty()) {
+                this.shareAccountRepository.save(account);
+            }
+            this.journalEntryWritePlatformService.createJournalEntriesForShares(populateJournalEntries(account,
+                    account.getChargeTransactions()));
+            return new CommandProcessingResultBuilder() //
+                    .withCommandId(jsonCommand.commandId()) //
+                    .withEntityId(accountId) //
+                    .with(changes) //
+                    .build();
+        } catch (DataIntegrityViolationException dve) {
+            handleDataIntegrityIssues(jsonCommand, dve);
+            return CommandProcessingResult.empty();
+        }
+    }
+
+    @Override
+    public CommandProcessingResult approveAdditionalShares(Long accountId, JsonCommand jsonCommand) {
+
+        try {
+            ShareAccount account = this.shareAccountRepository.findOneWithNotFoundDetection(accountId);
+            Map<String, Object> changes = this.accountDataSerializer.validateAndApproveAddtionalShares(jsonCommand, account);
+            if (!changes.isEmpty()) {
+                this.shareAccountRepository.save(account);
+                ArrayList<Long> transactionIds = (ArrayList<Long>) changes.get(ShareAccountApiConstants.requestedshares_paramname);
+                if (transactionIds != null) {
+                    Set<ShareAccountTransaction> transactions = new HashSet<>();
+                    for (Long id : transactionIds) {
+                        ShareAccountTransaction transaction = account.retrievePurchasedShares(id);
+                        transactions.add(transaction);
+                    }
+                    this.journalEntryWritePlatformService.createJournalEntriesForShares(populateJournalEntries(account, transactions));
+                }
+            }
+            return new CommandProcessingResultBuilder() //
+                    .withCommandId(jsonCommand.commandId()) //
+                    .withEntityId(accountId) //
+                    .with(changes) //
+                    .build();
+        } catch (DataIntegrityViolationException dve) {
+            handleDataIntegrityIssues(jsonCommand, dve);
+            return CommandProcessingResult.empty();
+        }
+    }
+
+    @Override
+    public CommandProcessingResult rejectAdditionalShares(Long accountId, JsonCommand jsonCommand) {
+
+        try {
+            ShareAccount account = this.shareAccountRepository.findOneWithNotFoundDetection(accountId);
+            Map<String, Object> changes = this.accountDataSerializer.validateAndRejectAddtionalShares(jsonCommand, account);
+            if (!changes.isEmpty()) {
+                this.shareAccountRepository.save(account);
+                ArrayList<Long> transactionIds = (ArrayList<Long>) changes.get(ShareAccountApiConstants.requestedshares_paramname);
+                if (transactionIds != null) {
+                    Set<ShareAccountTransaction> transactions = new HashSet<>();
+                    for (Long id : transactionIds) {
+                        ShareAccountTransaction transaction = account.retrievePurchasedShares(id);
+                        transactions.add(transaction);
+                    }
+                    this.journalEntryWritePlatformService.createJournalEntriesForShares(populateJournalEntries(account, transactions));
+                }
+            }
+            return new CommandProcessingResultBuilder() //
+                    .withCommandId(jsonCommand.commandId()) //
+                    .withEntityId(accountId) //
+                    .with(changes) //
+                    .build();
+        } catch (DataIntegrityViolationException dve) {
+            handleDataIntegrityIssues(jsonCommand, dve);
+            return CommandProcessingResult.empty();
+        }
+    }
+
+    @Override
+    public CommandProcessingResult redeemShares(Long accountId, JsonCommand jsonCommand) {
+        try {
+            ShareAccount account = this.shareAccountRepository.findOneWithNotFoundDetection(accountId);
+            Map<String, Object> changes = this.accountDataSerializer.validateAndRedeemShares(jsonCommand, account);
+            if (!changes.isEmpty()) {
+                this.shareAccountRepository.save(account);
+                ShareAccountTransaction transaction = (ShareAccountTransaction) changes
+                        .get(ShareAccountApiConstants.requestedshares_paramname);
+                transaction = account.getShareAccountTransaction(transaction);
+                Set<ShareAccountTransaction> transactions = new HashSet<>();
+                transactions.add(transaction);
+                this.journalEntryWritePlatformService.createJournalEntriesForShares(populateJournalEntries(account, transactions));
+                changes.clear();
+                changes.put(ShareAccountApiConstants.requestedshares_paramname, transaction.getId());
+
+            }
+            return new CommandProcessingResultBuilder() //
+                    .withCommandId(jsonCommand.commandId()) //
+                    .withEntityId(accountId) //
+                    .with(changes) //
+                    .build();
+        } catch (DataIntegrityViolationException dve) {
+            handleDataIntegrityIssues(jsonCommand, dve);
+            return CommandProcessingResult.empty();
+        }
+    }
+
+    @Override
+    public CommandProcessingResult closeShareAccount(Long accountId, JsonCommand jsonCommand) {
+        try {
+            ShareAccount account = this.shareAccountRepository.findOneWithNotFoundDetection(accountId);
+            Map<String, Object> changes = this.accountDataSerializer.validateAndClose(jsonCommand, account);
+            if (!changes.isEmpty()) {
+                this.shareAccountRepository.save(account);
+                ShareAccountTransaction transaction = (ShareAccountTransaction) changes
+                        .get(ShareAccountApiConstants.requestedshares_paramname);
+                transaction = account.getShareAccountTransaction(transaction);
+                Set<ShareAccountTransaction> transactions = new HashSet<>();
+                transactions.add(transaction);
+                this.journalEntryWritePlatformService.createJournalEntriesForShares(populateJournalEntries(account, transactions));
+                changes.clear();
+                changes.put(ShareAccountApiConstants.requestedshares_paramname, transaction.getId());
+
+            }
+            return new CommandProcessingResultBuilder() //
+                    .withCommandId(jsonCommand.commandId()) //
+                    .withEntityId(accountId) //
+                    .with(changes) //
+                    .build();
+        } catch (DataIntegrityViolationException dve) {
+            handleDataIntegrityIssues(jsonCommand, dve);
+            return CommandProcessingResult.empty();
+        }
+    }
+    private void handleDataIntegrityIssues(final JsonCommand command, final DataIntegrityViolationException dve) {
+
+    }
+}

http://git-wip-us.apache.org/repos/asf/incubator-fineract/blob/08c553f9/fineract-provider/src/main/java/org/apache/fineract/portfolio/shareaccounts/service/SharesEnumerations.java
----------------------------------------------------------------------
diff --git a/fineract-provider/src/main/java/org/apache/fineract/portfolio/shareaccounts/service/SharesEnumerations.java b/fineract-provider/src/main/java/org/apache/fineract/portfolio/shareaccounts/service/SharesEnumerations.java
new file mode 100644
index 0000000..9be43d9
--- /dev/null
+++ b/fineract-provider/src/main/java/org/apache/fineract/portfolio/shareaccounts/service/SharesEnumerations.java
@@ -0,0 +1,196 @@
+/**
+ * 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.shareaccounts.service;
+
+import org.apache.fineract.infrastructure.core.data.EnumOptionData;
+import org.apache.fineract.portfolio.shareaccounts.data.ShareAccountStatusEnumData;
+import org.apache.fineract.portfolio.shareaccounts.domain.PurchasedSharesStatusType;
+import org.apache.fineract.portfolio.shareaccounts.domain.ShareAccountDividendStatusType;
+import org.apache.fineract.portfolio.shareaccounts.domain.ShareAccountStatusType;
+import org.apache.fineract.portfolio.shareproducts.SharePeriodFrequencyType;
+import org.apache.fineract.portfolio.shareproducts.domain.ShareProductDividendStatusType;
+
+public class SharesEnumerations {
+
+    public static ShareAccountStatusEnumData status(final Integer statusEnum) {
+        return status(ShareAccountStatusType.fromInt(statusEnum));
+    }
+
+    public static ShareAccountStatusEnumData status(final ShareAccountStatusType type) {
+        final boolean submittedAndPendingApproval = type.isSubmittedAndPendingApproval();
+        final boolean isApproved = type.isApproved();
+        final boolean isRejected = type.isRejected();
+        final boolean isActive = type.isActive();
+        final boolean isClosed = type.isClosed();
+
+        ShareAccountStatusEnumData optionData = null;
+        switch (type) {
+            case INVALID:
+                optionData = new ShareAccountStatusEnumData(ShareAccountStatusType.INVALID.getValue().longValue(),
+                        ShareAccountStatusType.INVALID.getCode(), "Invalid", submittedAndPendingApproval, isApproved, isRejected, isActive,
+                        isClosed);
+            break;
+
+            case SUBMITTED_AND_PENDING_APPROVAL:
+                optionData = new ShareAccountStatusEnumData(ShareAccountStatusType.SUBMITTED_AND_PENDING_APPROVAL.getValue().longValue(),
+                        ShareAccountStatusType.SUBMITTED_AND_PENDING_APPROVAL.getCode(), "Submitted and pending approval",
+                        submittedAndPendingApproval, isApproved, isRejected, isActive, isClosed);
+            break;
+            case APPROVED:
+                optionData = new ShareAccountStatusEnumData(ShareAccountStatusType.APPROVED.getValue().longValue(),
+                        ShareAccountStatusType.APPROVED.getCode(), "Approved", submittedAndPendingApproval, isApproved, isRejected,
+                        isActive, isClosed);
+            break;
+
+            case ACTIVE:
+                optionData = new ShareAccountStatusEnumData(ShareAccountStatusType.ACTIVE.getValue().longValue(),
+                        ShareAccountStatusType.ACTIVE.getCode(), "Active", submittedAndPendingApproval, isApproved, isRejected, isActive,
+                        isClosed);
+            break;
+            case REJECTED:
+                optionData = new ShareAccountStatusEnumData(ShareAccountStatusType.REJECTED.getValue().longValue(),
+                        ShareAccountStatusType.REJECTED.getCode(), "Rejected", submittedAndPendingApproval, isApproved, isRejected,
+                        isActive, isClosed);
+            break;
+            case CLOSED:
+                optionData = new ShareAccountStatusEnumData(ShareAccountStatusType.CLOSED.getValue().longValue(),
+                        ShareAccountStatusType.CLOSED.getCode(), "Closed", submittedAndPendingApproval, isApproved, isRejected, isActive,
+                        isClosed);
+            break;
+        }
+
+        return optionData;
+    }
+
+    public static EnumOptionData purchasedSharesEnum(PurchasedSharesStatusType type) {
+        EnumOptionData data = new EnumOptionData(PurchasedSharesStatusType.INVALID.getValue().longValue(),
+                PurchasedSharesStatusType.INVALID.getCode(), "Invalid");
+        switch (type) {
+            case INVALID:
+            break;
+            case APPLIED:
+                data = new EnumOptionData(PurchasedSharesStatusType.APPLIED.getValue().longValue(),
+                        PurchasedSharesStatusType.APPLIED.getCode(), "Pending Approval");
+            break;
+            case APPROVED:
+                data = new EnumOptionData(PurchasedSharesStatusType.APPROVED.getValue().longValue(),
+                        PurchasedSharesStatusType.APPROVED.getCode(), "Approved");
+            break;
+            case REJECTED:
+                data = new EnumOptionData(PurchasedSharesStatusType.REJECTED.getValue().longValue(),
+                        PurchasedSharesStatusType.REJECTED.getCode(), "Rejected");
+            break;
+            case PURCHASED:
+                data = new EnumOptionData(PurchasedSharesStatusType.PURCHASED.getValue().longValue(),
+                        PurchasedSharesStatusType.PURCHASED.getCode(), "Purchase");
+            break;
+            case REDEEMED:
+                data = new EnumOptionData(PurchasedSharesStatusType.REDEEMED.getValue().longValue(),
+                        PurchasedSharesStatusType.REDEEMED.getCode(), "Redeem");
+            break;
+            case CHARGE_PAYMENT:
+                data = new EnumOptionData(PurchasedSharesStatusType.CHARGE_PAYMENT.getValue().longValue(),
+                        PurchasedSharesStatusType.CHARGE_PAYMENT.getCode(), "Charge Payment");
+            break;
+
+        }
+        return data;
+    }
+
+    public static EnumOptionData purchasedSharesEnum(final Integer enumValue) {
+        return purchasedSharesEnum(PurchasedSharesStatusType.fromInt(enumValue));
+    }
+
+    public static EnumOptionData lockinPeriodFrequencyType(final int id) {
+        return lockinPeriodFrequencyType(SharePeriodFrequencyType.fromInt(id));
+    }
+
+    public static EnumOptionData lockinPeriodFrequencyType(final SharePeriodFrequencyType type) {
+        final String codePrefix = "savings.lockin.";
+        EnumOptionData optionData = new EnumOptionData(SharePeriodFrequencyType.INVALID.getValue().longValue(),
+                SharePeriodFrequencyType.INVALID.getCode(), "Invalid");
+        switch (type) {
+            case INVALID:
+            break;
+            case DAYS:
+                optionData = new EnumOptionData(SharePeriodFrequencyType.DAYS.getValue().longValue(), codePrefix
+                        + SharePeriodFrequencyType.DAYS.getCode(), "Days");
+            break;
+            case WEEKS:
+                optionData = new EnumOptionData(SharePeriodFrequencyType.WEEKS.getValue().longValue(), codePrefix
+                        + SharePeriodFrequencyType.WEEKS.getCode(), "Weeks");
+            break;
+            case MONTHS:
+                optionData = new EnumOptionData(SharePeriodFrequencyType.MONTHS.getValue().longValue(), codePrefix
+                        + SharePeriodFrequencyType.MONTHS.getCode(), "Months");
+            break;
+            case YEARS:
+                optionData = new EnumOptionData(SharePeriodFrequencyType.YEARS.getValue().longValue(), codePrefix
+                        + SharePeriodFrequencyType.YEARS.getCode(), "Years");
+            break;
+        }
+        return optionData;
+    }
+
+    public static EnumOptionData ShareAccountDividendStatusEnum(ShareAccountDividendStatusType type) {
+        EnumOptionData data = new EnumOptionData(ShareAccountDividendStatusType.INVALID.getValue().longValue(),
+                ShareAccountDividendStatusType.INVALID.getCode(), "Invalid");
+        switch (type) {
+            case INVALID:
+            break;
+            case POSTED:
+                data = new EnumOptionData(ShareAccountDividendStatusType.POSTED.getValue().longValue(),
+                        ShareAccountDividendStatusType.POSTED.getCode(), "Dividend Posted");
+            break;
+            case INITIATED:
+                data = new EnumOptionData(ShareAccountDividendStatusType.INITIATED.getValue().longValue(),
+                        ShareAccountDividendStatusType.INITIATED.getCode(), "Dividend Initiated");
+            break;
+
+        }
+        return data;
+    }
+
+    public static EnumOptionData ShareAccountDividendStatusEnum(final Integer enumValue) {
+        return ShareAccountDividendStatusEnum(ShareAccountDividendStatusType.fromInt(enumValue));
+    }
+
+    public static EnumOptionData ShareProductDividendStatusEnum(ShareProductDividendStatusType type) {
+        EnumOptionData data = new EnumOptionData(ShareAccountDividendStatusType.INVALID.getValue().longValue(),
+                ShareAccountDividendStatusType.INVALID.getCode(), "Invalid");
+        switch (type) {
+            case INVALID:
+            break;
+            case APPROVED:
+                data = new EnumOptionData(ShareProductDividendStatusType.APPROVED.getValue().longValue(),
+                        ShareProductDividendStatusType.APPROVED.getCode(), "Dividend Approved");
+            break;
+            case INITIATED:
+                data = new EnumOptionData(ShareProductDividendStatusType.INITIATED.getValue().longValue(),
+                        ShareProductDividendStatusType.INITIATED.getCode(), "Dividend Initiated");
+            break;
+
+        }
+        return data;
+    }
+
+    public static EnumOptionData ShareProductDividendStatusEnum(final Integer enumValue) {
+        return ShareProductDividendStatusEnum(ShareProductDividendStatusType.fromInt(enumValue));
+    }
+}

http://git-wip-us.apache.org/repos/asf/incubator-fineract/blob/08c553f9/fineract-provider/src/main/java/org/apache/fineract/portfolio/shareproducts/SharePeriodFrequencyType.java
----------------------------------------------------------------------
diff --git a/fineract-provider/src/main/java/org/apache/fineract/portfolio/shareproducts/SharePeriodFrequencyType.java b/fineract-provider/src/main/java/org/apache/fineract/portfolio/shareproducts/SharePeriodFrequencyType.java
new file mode 100644
index 0000000..d04b5f0
--- /dev/null
+++ b/fineract-provider/src/main/java/org/apache/fineract/portfolio/shareproducts/SharePeriodFrequencyType.java
@@ -0,0 +1,85 @@
+/**
+ * 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;
+
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * An enumeration of supported calendar periods used in savings.
+ */
+public enum SharePeriodFrequencyType {
+    DAYS(0, "sharePeriodFrequencyType.days"), //
+    WEEKS(1, "sharePeriodFrequencyType.weeks"), //
+    MONTHS(2, "sharePeriodFrequencyType.months"), //
+    YEARS(3, "sharePeriodFrequencyType.years"), //
+    INVALID(4, "sharePeriodFrequencyType.invalid");
+
+    private final Integer value;
+    private final String code;
+
+    private SharePeriodFrequencyType(final Integer value, final String code) {
+        this.value = value;
+        this.code = code;
+    }
+
+    public Integer getValue() {
+        return this.value;
+    }
+
+    public String getCode() {
+        return this.code;
+    }
+
+    public static SharePeriodFrequencyType fromInt(final Integer type) {
+    	SharePeriodFrequencyType repaymentFrequencyType = SharePeriodFrequencyType.INVALID;
+        if (type != null) {
+            switch (type) {
+                case 0:
+                    repaymentFrequencyType = SharePeriodFrequencyType.DAYS;
+                break;
+                case 1:
+                    repaymentFrequencyType = SharePeriodFrequencyType.WEEKS;
+                break;
+                case 2:
+                    repaymentFrequencyType = SharePeriodFrequencyType.MONTHS;
+                break;
+                case 3:
+                    repaymentFrequencyType = SharePeriodFrequencyType.YEARS;
+                break;
+            }
+        }
+        return repaymentFrequencyType;
+    }
+
+    public boolean isInvalid() {
+        return this.value.equals(SharePeriodFrequencyType.INVALID.value);
+    }
+
+    public static Object[] integerValues() {
+        final List<Integer> values = new ArrayList<>();
+        for (final SharePeriodFrequencyType enumType : values()) {
+            if (!enumType.isInvalid()) {
+                values.add(enumType.getValue());
+            }
+        }
+
+        return values.toArray();
+    }
+}

http://git-wip-us.apache.org/repos/asf/incubator-fineract/blob/08c553f9/fineract-provider/src/main/java/org/apache/fineract/portfolio/shareproducts/api/ShareDividendApiResource.java
----------------------------------------------------------------------
diff --git a/fineract-provider/src/main/java/org/apache/fineract/portfolio/shareproducts/api/ShareDividendApiResource.java b/fineract-provider/src/main/java/org/apache/fineract/portfolio/shareproducts/api/ShareDividendApiResource.java
new file mode 100644
index 0000000..41eba0e
--- /dev/null
+++ b/fineract-provider/src/main/java/org/apache/fineract/portfolio/shareproducts/api/ShareDividendApiResource.java
@@ -0,0 +1,153 @@
+/**
+ * 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.api;
+
+import javax.ws.rs.Consumes;
+import javax.ws.rs.DELETE;
+import javax.ws.rs.GET;
+import javax.ws.rs.POST;
+import javax.ws.rs.PUT;
+import javax.ws.rs.Path;
+import javax.ws.rs.PathParam;
+import javax.ws.rs.Produces;
+import javax.ws.rs.QueryParam;
+import javax.ws.rs.core.MediaType;
+
+import org.apache.commons.lang.StringUtils;
+import org.apache.fineract.commands.domain.CommandWrapper;
+import org.apache.fineract.commands.service.CommandWrapperBuilder;
+import org.apache.fineract.commands.service.PortfolioCommandSourceWritePlatformService;
+import org.apache.fineract.infrastructure.core.data.CommandProcessingResult;
+import org.apache.fineract.infrastructure.core.exception.UnrecognizedQueryParamException;
+import org.apache.fineract.infrastructure.core.serialization.DefaultToApiJsonSerializer;
+import org.apache.fineract.infrastructure.core.service.Page;
+import org.apache.fineract.infrastructure.core.service.SearchParameters;
+import org.apache.fineract.infrastructure.security.service.PlatformSecurityContext;
+import org.apache.fineract.portfolio.shareaccounts.data.ShareAccountDividendData;
+import org.apache.fineract.portfolio.shareaccounts.service.ShareAccountDividendReadPlatformService;
+import org.apache.fineract.portfolio.shareproducts.data.ShareProductDividendPayOutData;
+import org.apache.fineract.portfolio.shareproducts.service.ShareProductDividendReadPlatformService;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.context.annotation.Scope;
+import org.springframework.stereotype.Component;
+
+@Path("/shareproduct/{productId}/dividend")
+@Component
+@Scope("singleton")
+public class ShareDividendApiResource {
+
+    private final DefaultToApiJsonSerializer<ShareProductDividendPayOutData> toApiJsonSerializer;
+    private final DefaultToApiJsonSerializer<ShareAccountDividendData> toApiAccountDetailJsonSerializer;
+    private final PlatformSecurityContext platformSecurityContext;
+    private final PortfolioCommandSourceWritePlatformService commandsSourceWritePlatformService;
+    private final ShareAccountDividendReadPlatformService shareAccountDividendReadPlatformService;
+    private final ShareProductDividendReadPlatformService shareProductDividendReadPlatformService;
+    private final String resourceNameForPermissions = "DIVIDEND_SHAREPRODUCT";
+
+    @Autowired
+    public ShareDividendApiResource(final DefaultToApiJsonSerializer<ShareProductDividendPayOutData> toApiJsonSerializer,
+            final PlatformSecurityContext platformSecurityContext,
+            final PortfolioCommandSourceWritePlatformService commandsSourceWritePlatformService,
+            final DefaultToApiJsonSerializer<ShareAccountDividendData> toApiDividendsJsonSerializer,
+            final ShareAccountDividendReadPlatformService shareAccountDividendReadPlatformService,
+            final ShareProductDividendReadPlatformService shareProductDividendReadPlatformService) {
+        this.toApiJsonSerializer = toApiJsonSerializer;
+        this.platformSecurityContext = platformSecurityContext;
+        this.commandsSourceWritePlatformService = commandsSourceWritePlatformService;
+        this.toApiAccountDetailJsonSerializer = toApiDividendsJsonSerializer;
+        this.shareAccountDividendReadPlatformService = shareAccountDividendReadPlatformService;
+        this.shareProductDividendReadPlatformService = shareProductDividendReadPlatformService;
+    }
+
+    @GET
+    @Consumes({ MediaType.APPLICATION_JSON })
+    @Produces({ MediaType.APPLICATION_JSON })
+    public String retrieveAll(@PathParam("productId") final Long productId, @QueryParam("offset") final Integer offset,
+            @QueryParam("limit") final Integer limit, @QueryParam("orderBy") final String orderBy,
+            @QueryParam("sortOrder") final String sortOrder, @QueryParam("status") final Integer status) {
+
+        this.platformSecurityContext.authenticatedUser().validateHasReadPermission(this.resourceNameForPermissions);
+        final SearchParameters searchParameters = SearchParameters.forPagination(offset, limit, orderBy, sortOrder);
+        Page<ShareProductDividendPayOutData> dividendPayoutDetails = this.shareProductDividendReadPlatformService.retriveAll(productId,
+                status, searchParameters);
+        return this.toApiJsonSerializer.serialize(dividendPayoutDetails);
+    }
+
+    @GET
+    @Path("{dividendId}")
+    @Consumes({ MediaType.APPLICATION_JSON })
+    @Produces({ MediaType.APPLICATION_JSON })
+    public String retrieveDividendDetails(@PathParam("dividendId") final Long dividendId, @QueryParam("offset") final Integer offset,
+            @QueryParam("limit") final Integer limit, @QueryParam("orderBy") final String orderBy,
+            @QueryParam("sortOrder") final String sortOrder, @QueryParam("accountNo") final String accountNo) {
+
+        this.platformSecurityContext.authenticatedUser().validateHasReadPermission(this.resourceNameForPermissions);
+        final SearchParameters searchParameters = SearchParameters.forPaginationAndAccountNumberSearch(offset, limit, orderBy, sortOrder,
+                accountNo);
+        Page<ShareAccountDividendData> dividendDetails = this.shareAccountDividendReadPlatformService.retriveAll(dividendId,
+                searchParameters);
+        return this.toApiAccountDetailJsonSerializer.serialize(dividendDetails);
+    }
+
+    @POST
+    @Consumes({ MediaType.APPLICATION_JSON })
+    @Produces({ MediaType.APPLICATION_JSON })
+    public String createDividendDetail(@PathParam("productId") final Long productId, final String apiRequestBodyAsJson) {
+        this.platformSecurityContext.authenticatedUser();
+        CommandWrapper commandWrapper = new CommandWrapperBuilder().createShareProductDividendPayoutCommand(productId)
+                .withJson(apiRequestBodyAsJson).build();
+        final CommandProcessingResult commandProcessingResult = this.commandsSourceWritePlatformService.logCommandSource(commandWrapper);
+        return this.toApiJsonSerializer.serialize(commandProcessingResult);
+    }
+
+    @PUT
+    @Path("{dividendId}")
+    @Consumes({ MediaType.APPLICATION_JSON })
+    @Produces({ MediaType.APPLICATION_JSON })
+    public String updateDividendDetail(@PathParam("productId") final Long productId, @PathParam("dividendId") final Long dividendId,
+            @QueryParam("command") final String commandParam, final String apiRequestBodyAsJson) {
+        CommandWrapper commandWrapper = null;
+        this.platformSecurityContext.authenticatedUser();
+        if (is(commandParam, "approve")) {
+            commandWrapper = new CommandWrapperBuilder().approveShareProductDividendPayoutCommand(productId, dividendId)
+                    .withJson(apiRequestBodyAsJson).build();
+        } else {
+            throw new UnrecognizedQueryParamException("command", commandParam);
+        }
+        final CommandProcessingResult commandProcessingResult = this.commandsSourceWritePlatformService.logCommandSource(commandWrapper);
+        return this.toApiJsonSerializer.serialize(commandProcessingResult);
+    }
+
+    @DELETE
+    @Path("{dividendId}")
+    @Consumes({ MediaType.APPLICATION_JSON })
+    @Produces({ MediaType.APPLICATION_JSON })
+    public String deleteDividendDetail(@PathParam("productId") final Long productId, @PathParam("dividendId") final Long dividendId) {
+        this.platformSecurityContext.authenticatedUser();
+        final CommandWrapper commandWrapper = new CommandWrapperBuilder().deleteShareProductDividendPayoutCommand(productId, dividendId)
+                .build();
+        final CommandProcessingResult commandProcessingResult = this.commandsSourceWritePlatformService.logCommandSource(commandWrapper);
+        return this.toApiJsonSerializer.serialize(commandProcessingResult);
+    }
+
+    private boolean is(final String commandParam, final String commandValue) {
+        return StringUtils.isNotBlank(commandParam) && commandParam.trim().equalsIgnoreCase(commandValue);
+    }
+
+}


Mime
View raw message