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); + } + +}
