Issue fixes on shares and dividends reported by QA
This commit is contained in:
+4
@@ -39,4 +39,8 @@ public interface JournalEntryRepository extends JpaRepository<JournalEntry, Long
|
|||||||
|
|
||||||
@Query("from JournalEntry journalEntry where journalEntry.entityId= :entityId and journalEntry.entityType = :entityType")
|
@Query("from JournalEntry journalEntry where journalEntry.entityId= :entityId and journalEntry.entityType = :entityType")
|
||||||
List<JournalEntry> findProvisioningJournalEntriesByEntityId(@Param("entityId") Long entityId, @Param("entityType") Integer entityType) ;
|
List<JournalEntry> findProvisioningJournalEntriesByEntityId(@Param("entityId") Long entityId, @Param("entityType") Integer entityType) ;
|
||||||
|
|
||||||
|
@Query("from JournalEntry journalEntry where journalEntry.transactionId= :transactionId and journalEntry.reversed is false and journalEntry.entityType = :entityType")
|
||||||
|
List<JournalEntry> findJournalEntries(@Param("transactionId") String transactionId, @Param("entityType") Integer entityType) ;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
+31
@@ -1001,6 +1001,37 @@ public class AccountingProcessorHelper {
|
|||||||
"Recent Portfolio changes w.r.t Charges for shares have Broken the accounting code"); }
|
"Recent Portfolio changes w.r.t Charges for shares have Broken the accounting code"); }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void revertCashBasedJournalEntryForSharesCharges(final Office office, final String currencyCode,
|
||||||
|
final CASH_ACCOUNTS_FOR_SHARES accountTypeToBeCredited, final Long shareProductId, final Long shareAccountId,
|
||||||
|
final String transactionId, final Date transactionDate, final BigDecimal totalAmount,
|
||||||
|
final List<ChargePaymentDTO> chargePaymentDTOs) {
|
||||||
|
final Map<GLAccount, BigDecimal> creditDetailsMap = new LinkedHashMap<>();
|
||||||
|
for (final ChargePaymentDTO chargePaymentDTO : chargePaymentDTOs) {
|
||||||
|
final GLAccount chargeSpecificAccount = getLinkedGLAccountForShareCharges(shareProductId, accountTypeToBeCredited.getValue(),
|
||||||
|
chargePaymentDTO.getChargeId());
|
||||||
|
BigDecimal chargeSpecificAmount = chargePaymentDTO.getAmount();
|
||||||
|
|
||||||
|
// adjust net credit amount if the account is already present in the
|
||||||
|
// map
|
||||||
|
if (creditDetailsMap.containsKey(chargeSpecificAccount)) {
|
||||||
|
final BigDecimal existingAmount = creditDetailsMap.get(chargeSpecificAccount);
|
||||||
|
chargeSpecificAmount = chargeSpecificAmount.add(existingAmount);
|
||||||
|
}
|
||||||
|
creditDetailsMap.put(chargeSpecificAccount, chargeSpecificAmount);
|
||||||
|
}
|
||||||
|
|
||||||
|
BigDecimal totalCreditedAmount = BigDecimal.ZERO;
|
||||||
|
for (final Map.Entry<GLAccount, BigDecimal> entry : creditDetailsMap.entrySet()) {
|
||||||
|
final GLAccount account = entry.getKey();
|
||||||
|
final BigDecimal amount = entry.getValue();
|
||||||
|
totalCreditedAmount = totalCreditedAmount.add(amount);
|
||||||
|
createDebitJournalEntryForShares(office, currencyCode, account, shareAccountId, transactionId, transactionDate, amount);
|
||||||
|
}
|
||||||
|
if (totalAmount.compareTo(totalCreditedAmount) != 0) { throw new PlatformDataIntegrityException(
|
||||||
|
"Recent Portfolio changes w.r.t Charges for shares have Broken the accounting code",
|
||||||
|
"Recent Portfolio changes w.r.t Charges for shares have Broken the accounting code"); }
|
||||||
|
}
|
||||||
|
|
||||||
private void createDebitJournalEntryForShares(final Office office, final String currencyCode, final GLAccount account,
|
private void createDebitJournalEntryForShares(final Office office, final String currencyCode, final GLAccount account,
|
||||||
final Long shareAccountId, final String transactionId, final Date transactionDate, final BigDecimal amount) {
|
final Long shareAccountId, final String transactionId, final Date transactionDate, final BigDecimal amount) {
|
||||||
final boolean manualEntry = false;
|
final boolean manualEntry = false;
|
||||||
|
|||||||
+2
@@ -119,6 +119,8 @@ public class CashBasedAccountingProcessorForShares implements AccountingProcesso
|
|||||||
BigDecimal amountForJE = amount;
|
BigDecimal amountForJE = amount;
|
||||||
if (chargeAmount != null && chargeAmount.compareTo(BigDecimal.ZERO) == 1) {
|
if (chargeAmount != null && chargeAmount.compareTo(BigDecimal.ZERO) == 1) {
|
||||||
amountForJE = amount.subtract(chargeAmount);
|
amountForJE = amount.subtract(chargeAmount);
|
||||||
|
/*this.helper.revertCashBasedJournalEntryForSharesCharges(office, currencyCode, CASH_ACCOUNTS_FOR_SHARES.INCOME_FROM_FEES,
|
||||||
|
shareProductId, shareAccountId, transactionId, transactionDate, chargeAmount, feePayments);*/
|
||||||
}
|
}
|
||||||
this.helper.createJournalEntriesForShares(office, currencyCode, CASH_ACCOUNTS_FOR_SHARES.SHARES_SUSPENSE.getValue(),
|
this.helper.createJournalEntriesForShares(office, currencyCode, CASH_ACCOUNTS_FOR_SHARES.SHARES_SUSPENSE.getValue(),
|
||||||
CASH_ACCOUNTS_FOR_SHARES.SHARES_REFERENCE.getValue(), shareProductId, paymentTypeId, shareAccountId, transactionId,
|
CASH_ACCOUNTS_FOR_SHARES.SHARES_REFERENCE.getValue(), shareProductId, paymentTypeId, shareAccountId, transactionId,
|
||||||
|
|||||||
+3
@@ -18,6 +18,7 @@
|
|||||||
*/
|
*/
|
||||||
package org.apache.fineract.accounting.journalentry.service;
|
package org.apache.fineract.accounting.journalentry.service;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
import java.util.Date;
|
import java.util.Date;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
|
||||||
@@ -44,4 +45,6 @@ public interface JournalEntryWritePlatformService {
|
|||||||
public String createProvisioningJournalEntries(ProvisioningEntry entry) ;
|
public String createProvisioningJournalEntries(ProvisioningEntry entry) ;
|
||||||
|
|
||||||
void createJournalEntriesForShares(Map<String, Object> accountingBridgeData);
|
void createJournalEntriesForShares(Map<String, Object> accountingBridgeData);
|
||||||
|
|
||||||
|
void revertShareAccountJournalEntries(final ArrayList<Long> transactionId, final Date transactionDate);
|
||||||
}
|
}
|
||||||
|
|||||||
+40
@@ -53,6 +53,7 @@ import org.apache.fineract.accounting.journalentry.exception.JournalEntriesNotFo
|
|||||||
import org.apache.fineract.accounting.journalentry.exception.JournalEntryInvalidException;
|
import org.apache.fineract.accounting.journalentry.exception.JournalEntryInvalidException;
|
||||||
import org.apache.fineract.accounting.journalentry.exception.JournalEntryInvalidException.GL_JOURNAL_ENTRY_INVALID_REASON;
|
import org.apache.fineract.accounting.journalentry.exception.JournalEntryInvalidException.GL_JOURNAL_ENTRY_INVALID_REASON;
|
||||||
import org.apache.fineract.accounting.journalentry.serialization.JournalEntryCommandFromApiJsonDeserializer;
|
import org.apache.fineract.accounting.journalentry.serialization.JournalEntryCommandFromApiJsonDeserializer;
|
||||||
|
import org.apache.fineract.accounting.producttoaccountmapping.domain.PortfolioProductType;
|
||||||
import org.apache.fineract.accounting.provisioning.domain.LoanProductProvisioningEntry;
|
import org.apache.fineract.accounting.provisioning.domain.LoanProductProvisioningEntry;
|
||||||
import org.apache.fineract.accounting.provisioning.domain.ProvisioningEntry;
|
import org.apache.fineract.accounting.provisioning.domain.ProvisioningEntry;
|
||||||
import org.apache.fineract.accounting.rule.domain.AccountingRule;
|
import org.apache.fineract.accounting.rule.domain.AccountingRule;
|
||||||
@@ -383,6 +384,7 @@ public class JournalEntryWritePlatformServiceJpaRepositoryImpl implements Journa
|
|||||||
// save the reversal entry
|
// save the reversal entry
|
||||||
this.glJournalEntryRepository.save(reversalJournalEntry);
|
this.glJournalEntryRepository.save(reversalJournalEntry);
|
||||||
journalEntry.setReversalJournalEntry(reversalJournalEntry);
|
journalEntry.setReversalJournalEntry(reversalJournalEntry);
|
||||||
|
journalEntry.setReversed(true);
|
||||||
// save the updated journal entry
|
// save the updated journal entry
|
||||||
this.glJournalEntryRepository.save(journalEntry);
|
this.glJournalEntryRepository.save(journalEntry);
|
||||||
}
|
}
|
||||||
@@ -516,6 +518,44 @@ public class JournalEntryWritePlatformServiceJpaRepositoryImpl implements Journa
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void revertShareAccountJournalEntries(final ArrayList<Long> transactionIds, final Date transactionDate) {
|
||||||
|
for (Long shareTransactionId : transactionIds) {
|
||||||
|
String transactionId = AccountingProcessorHelper.SHARE_TRANSACTION_IDENTIFIER + shareTransactionId.longValue();
|
||||||
|
List<JournalEntry> journalEntries = this.glJournalEntryRepository.findJournalEntries(transactionId,
|
||||||
|
PortfolioProductType.SHARES.getValue());
|
||||||
|
if (journalEntries == null || journalEntries.isEmpty()) continue;
|
||||||
|
final Long officeId = journalEntries.get(0).getOffice().getId();
|
||||||
|
final String reversalTransactionId = generateTransactionId(officeId);
|
||||||
|
for (final JournalEntry journalEntry : journalEntries) {
|
||||||
|
JournalEntry reversalJournalEntry;
|
||||||
|
String reversalComment = "Reversal entry for Journal Entry with id :" + journalEntry.getId() + " and transaction Id "
|
||||||
|
+ journalEntry.getTransactionId();
|
||||||
|
if (journalEntry.isDebitEntry()) {
|
||||||
|
reversalJournalEntry = JournalEntry.createNew(journalEntry.getOffice(), journalEntry.getPaymentDetails(),
|
||||||
|
journalEntry.getGlAccount(), journalEntry.getCurrencyCode(), reversalTransactionId, Boolean.FALSE,
|
||||||
|
transactionDate, JournalEntryType.CREDIT, journalEntry.getAmount(), reversalComment,
|
||||||
|
journalEntry.getEntityType(), journalEntry.getEntityId(), journalEntry.getReferenceNumber(),
|
||||||
|
journalEntry.getLoanTransaction(), journalEntry.getSavingsTransaction(), journalEntry.getClientTransaction(),
|
||||||
|
journalEntry.getShareTransactionId());
|
||||||
|
} else {
|
||||||
|
reversalJournalEntry = JournalEntry.createNew(journalEntry.getOffice(), journalEntry.getPaymentDetails(),
|
||||||
|
journalEntry.getGlAccount(), journalEntry.getCurrencyCode(), reversalTransactionId, Boolean.FALSE,
|
||||||
|
transactionDate, JournalEntryType.DEBIT, journalEntry.getAmount(), reversalComment,
|
||||||
|
journalEntry.getEntityType(), journalEntry.getEntityId(), journalEntry.getReferenceNumber(),
|
||||||
|
journalEntry.getLoanTransaction(), journalEntry.getSavingsTransaction(), journalEntry.getClientTransaction(),
|
||||||
|
journalEntry.getShareTransactionId());
|
||||||
|
}
|
||||||
|
// save the reversal entry
|
||||||
|
this.glJournalEntryRepository.save(reversalJournalEntry);
|
||||||
|
journalEntry.setReversalJournalEntry(reversalJournalEntry);
|
||||||
|
journalEntry.setReversed(true);
|
||||||
|
// save the updated journal entry
|
||||||
|
this.glJournalEntryRepository.save(journalEntry);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private void validateBusinessRulesForJournalEntries(final JournalEntryCommand command) {
|
private void validateBusinessRulesForJournalEntries(final JournalEntryCommand command) {
|
||||||
/** check if date of Journal entry is valid ***/
|
/** check if date of Journal entry is valid ***/
|
||||||
final LocalDate entryLocalDate = command.getTransactionDate();
|
final LocalDate entryLocalDate = command.getTransactionDate();
|
||||||
|
|||||||
+3
-1
@@ -290,9 +290,11 @@ public class ChargeData implements Comparable<ChargeData>, Serializable {
|
|||||||
final BigDecimal amountPercentageAppliedTo = BigDecimal.ZERO;
|
final BigDecimal amountPercentageAppliedTo = BigDecimal.ZERO;
|
||||||
final Collection<ChargeData> chargeOptions = null;
|
final Collection<ChargeData> chargeOptions = null;
|
||||||
final Boolean isActive = null;
|
final Boolean isActive = null;
|
||||||
|
final BigDecimal chargeAmountOrPercentage = BigDecimal.ZERO ;
|
||||||
|
|
||||||
return new ShareAccountChargeData(shareChargeId, this.id, shareAccountId, this.name, this.currency, this.amount, amountPaid,
|
return new ShareAccountChargeData(shareChargeId, this.id, shareAccountId, this.name, this.currency, this.amount, amountPaid,
|
||||||
amountWaived, amountWrittenOff, amountOutstanding, this.chargeTimeType, this.chargeCalculationType, percentage,
|
amountWaived, amountWrittenOff, amountOutstanding, this.chargeTimeType, this.chargeCalculationType, percentage,
|
||||||
amountPercentageAppliedTo, chargeOptions, isActive);
|
amountPercentageAppliedTo, chargeOptions, isActive, chargeAmountOrPercentage);
|
||||||
}
|
}
|
||||||
|
|
||||||
public boolean isPenalty() {
|
public boolean isPenalty() {
|
||||||
|
|||||||
+2
@@ -34,6 +34,8 @@ public interface SavingsAccountReadPlatformService {
|
|||||||
|
|
||||||
Collection<SavingsAccountData> retrieveActiveForLookup(Long clientId, DepositAccountType depositAccountType);
|
Collection<SavingsAccountData> retrieveActiveForLookup(Long clientId, DepositAccountType depositAccountType);
|
||||||
|
|
||||||
|
public Collection<SavingsAccountData> retrieveActiveForLookup(final Long clientId, DepositAccountType depositAccountType, String currencyCode) ;
|
||||||
|
|
||||||
SavingsAccountData retrieveOne(Long savingsId);
|
SavingsAccountData retrieveOne(Long savingsId);
|
||||||
|
|
||||||
SavingsAccountData retrieveTemplate(Long clientId, Long groupId, Long productId, boolean staffInSelectedOfficeOnly);
|
SavingsAccountData retrieveTemplate(Long clientId, Long groupId, Long productId, boolean staffInSelectedOfficeOnly);
|
||||||
|
|||||||
+9
@@ -132,6 +132,15 @@ public class SavingsAccountReadPlatformServiceImpl implements SavingsAccountRead
|
|||||||
return this.jdbcTemplate.query(sqlBuilder.toString(), this.savingAccountMapper, queryParameters);
|
return this.jdbcTemplate.query(sqlBuilder.toString(), this.savingAccountMapper, queryParameters);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Collection<SavingsAccountData> retrieveActiveForLookup(final Long clientId, DepositAccountType depositAccountType, String currencyCode) {
|
||||||
|
final StringBuilder sqlBuilder = new StringBuilder("select " + this.savingAccountMapper.schema());
|
||||||
|
sqlBuilder.append(" where sa.client_id = ? and sa.status_enum = 300 and sa.deposit_type_enum = ? and sa.currency_code = ? ");
|
||||||
|
|
||||||
|
final Object[] queryParameters = new Object[] { clientId, depositAccountType.getValue(), currencyCode };
|
||||||
|
return this.jdbcTemplate.query(sqlBuilder.toString(), this.savingAccountMapper, queryParameters);
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Page<SavingsAccountData> retrieveAll(final SearchParameters searchParameters) {
|
public Page<SavingsAccountData> retrieveAll(final SearchParameters searchParameters) {
|
||||||
|
|
||||||
|
|||||||
+3
-2
@@ -69,7 +69,7 @@ public class ShareAccountChargeData {
|
|||||||
final CurrencyData currency, final BigDecimal amount, final BigDecimal amountPaid, final BigDecimal amountWaived,
|
final CurrencyData currency, final BigDecimal amount, final BigDecimal amountPaid, final BigDecimal amountWaived,
|
||||||
final BigDecimal amountWrittenOff, final BigDecimal amountOutstanding, final EnumOptionData chargeTimeType,
|
final BigDecimal amountWrittenOff, final BigDecimal amountOutstanding, final EnumOptionData chargeTimeType,
|
||||||
final EnumOptionData chargeCalculationType, final BigDecimal percentage, final BigDecimal amountPercentageAppliedTo,
|
final EnumOptionData chargeCalculationType, final BigDecimal percentage, final BigDecimal amountPercentageAppliedTo,
|
||||||
final Collection<ChargeData> chargeOptions, final Boolean isActive) {
|
final Collection<ChargeData> chargeOptions, final Boolean isActive, final BigDecimal chargeamountorpercentage) {
|
||||||
this.id = id;
|
this.id = id;
|
||||||
this.chargeId = chargeId;
|
this.chargeId = chargeId;
|
||||||
this.accountId = accountId;
|
this.accountId = accountId;
|
||||||
@@ -84,11 +84,12 @@ public class ShareAccountChargeData {
|
|||||||
this.amountWaived = amountWaived;
|
this.amountWaived = amountWaived;
|
||||||
this.amountWrittenOff = amountWrittenOff;
|
this.amountWrittenOff = amountWrittenOff;
|
||||||
this.amountOutstanding = amountOutstanding;
|
this.amountOutstanding = amountOutstanding;
|
||||||
this.amountOrPercentage = getAmountOrPercentage();
|
this.amountOrPercentage = chargeamountorpercentage;
|
||||||
this.chargeOptions = chargeOptions;
|
this.chargeOptions = chargeOptions;
|
||||||
this.isActive = isActive;
|
this.isActive = isActive;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
private BigDecimal getAmountOrPercentage() {
|
private BigDecimal getAmountOrPercentage() {
|
||||||
return (this.chargeCalculationType != null) && (this.chargeCalculationType.getId().intValue() > 1) ? this.percentage : this.amount;
|
return (this.chargeCalculationType != null) && (this.chargeCalculationType.getId().intValue() > 1) ? this.percentage : this.amount;
|
||||||
}
|
}
|
||||||
|
|||||||
+5
-5
@@ -61,7 +61,7 @@ public class ShareAccountData implements AccountData {
|
|||||||
|
|
||||||
private ShareAccountSummaryData summary;
|
private ShareAccountSummaryData summary;
|
||||||
|
|
||||||
private Collection<PurchasedSharesData> purchasedShares;
|
private Collection<ShareAccountTransactionData> purchasedShares;
|
||||||
|
|
||||||
private Long savingsAccountId;
|
private Long savingsAccountId;
|
||||||
|
|
||||||
@@ -92,7 +92,7 @@ public class ShareAccountData implements AccountData {
|
|||||||
final String savingsAccountNumber, final Long clientId, final String clientName, final Long productId,
|
final String savingsAccountNumber, final Long clientId, final String clientName, final Long productId,
|
||||||
final String productName, final ShareAccountStatusEnumData status, final ShareAccountApplicationTimelineData timeline,
|
final String productName, final ShareAccountStatusEnumData status, final ShareAccountApplicationTimelineData timeline,
|
||||||
final CurrencyData currency, final ShareAccountSummaryData summaryData, final Collection<ShareAccountChargeData> charges,
|
final CurrencyData currency, final ShareAccountSummaryData summaryData, final Collection<ShareAccountChargeData> charges,
|
||||||
final Collection<PurchasedSharesData> purchasedSharesData, final Integer lockinPeriod, final EnumOptionData lockPeriodTypeEnum,
|
final Collection<ShareAccountTransactionData> purchasedSharesData, final Integer lockinPeriod, final EnumOptionData lockPeriodTypeEnum,
|
||||||
final Integer minimumActivePeriod, final EnumOptionData minimumActivePeriodTypeEnum, Boolean allowdividendsforinactiveclients) {
|
final Integer minimumActivePeriod, final EnumOptionData minimumActivePeriodTypeEnum, Boolean allowdividendsforinactiveclients) {
|
||||||
this.id = id;
|
this.id = id;
|
||||||
this.accountNo = accountNo;
|
this.accountNo = accountNo;
|
||||||
@@ -145,7 +145,7 @@ public class ShareAccountData implements AccountData {
|
|||||||
final String savingsAccountNumber, final Long clientId, final String clientName, final Long productId,
|
final String savingsAccountNumber, final Long clientId, final String clientName, final Long productId,
|
||||||
final String productName, final ShareAccountStatusEnumData status, final ShareAccountApplicationTimelineData timeline,
|
final String productName, final ShareAccountStatusEnumData status, final ShareAccountApplicationTimelineData timeline,
|
||||||
final CurrencyData currency, final ShareAccountSummaryData summaryData, final Collection<ShareAccountChargeData> charges,
|
final CurrencyData currency, final ShareAccountSummaryData summaryData, final Collection<ShareAccountChargeData> charges,
|
||||||
final Collection<PurchasedSharesData> purchasedSharesData, final Integer lockinPeriod, final EnumOptionData lockPeriodTypeEnum,
|
final Collection<ShareAccountTransactionData> purchasedSharesData, final Integer lockinPeriod, final EnumOptionData lockPeriodTypeEnum,
|
||||||
final Integer minimumActivePeriod, final EnumOptionData minimumActivePeriodTypeEnum,
|
final Integer minimumActivePeriod, final EnumOptionData minimumActivePeriodTypeEnum,
|
||||||
final Boolean allowDividendCalculationForInactiveClients, final Collection<ProductData> productOptions,
|
final Boolean allowDividendCalculationForInactiveClients, final Collection<ProductData> productOptions,
|
||||||
final Collection<ChargeData> chargeOptions, final Collection<SavingsAccountData> clientSavingsAccounts,
|
final Collection<ChargeData> chargeOptions, final Collection<SavingsAccountData> clientSavingsAccounts,
|
||||||
@@ -200,7 +200,7 @@ public class ShareAccountData implements AccountData {
|
|||||||
public static ShareAccountData lookup(final Long id, final String accountNo, final Long clientId, final String clientName) {
|
public static ShareAccountData lookup(final Long id, final String accountNo, final Long clientId, final String clientName) {
|
||||||
String externalId = null;
|
String externalId = null;
|
||||||
ShareAccountSummaryData summaryData = null;
|
ShareAccountSummaryData summaryData = null;
|
||||||
Collection<PurchasedSharesData> purchasedSharesData = null;
|
Collection<ShareAccountTransactionData> purchasedSharesData = null;
|
||||||
GLAccountData suspenseAccount = null;
|
GLAccountData suspenseAccount = null;
|
||||||
Integer lockinPeriod = null;
|
Integer lockinPeriod = null;
|
||||||
EnumOptionData lockPeriodTypeEnum = null;
|
EnumOptionData lockPeriodTypeEnum = null;
|
||||||
@@ -233,7 +233,7 @@ public class ShareAccountData implements AccountData {
|
|||||||
return this.id;
|
return this.id;
|
||||||
}
|
}
|
||||||
|
|
||||||
public Collection<PurchasedSharesData> getPurchasedShares() {
|
public Collection<ShareAccountTransactionData> getPurchasedShares() {
|
||||||
return this.purchasedShares;
|
return this.purchasedShares;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+8
-3
@@ -23,7 +23,8 @@ import java.math.BigDecimal;
|
|||||||
import org.apache.fineract.infrastructure.core.data.EnumOptionData;
|
import org.apache.fineract.infrastructure.core.data.EnumOptionData;
|
||||||
import org.joda.time.LocalDate;
|
import org.joda.time.LocalDate;
|
||||||
|
|
||||||
public class PurchasedSharesData {
|
@SuppressWarnings("unused")
|
||||||
|
public class ShareAccountTransactionData {
|
||||||
|
|
||||||
private final Long id;
|
private final Long id;
|
||||||
|
|
||||||
@@ -43,8 +44,11 @@ public class PurchasedSharesData {
|
|||||||
|
|
||||||
private final BigDecimal chargeAmount ;
|
private final BigDecimal chargeAmount ;
|
||||||
|
|
||||||
public PurchasedSharesData(final Long id, final Long accountId, final LocalDate purchasedDate, final Long numberOfShares,
|
private final BigDecimal amountPaid ;
|
||||||
final BigDecimal purchasedPrice, final EnumOptionData status, final EnumOptionData type, final BigDecimal amount, final BigDecimal chargeAmount) {
|
|
||||||
|
public ShareAccountTransactionData(final Long id, final Long accountId, final LocalDate purchasedDate, final Long numberOfShares,
|
||||||
|
final BigDecimal purchasedPrice, final EnumOptionData status, final EnumOptionData type, final BigDecimal amount, final BigDecimal chargeAmount,
|
||||||
|
final BigDecimal amountPaid) {
|
||||||
this.id = id;
|
this.id = id;
|
||||||
this.accountId = accountId;
|
this.accountId = accountId;
|
||||||
this.purchasedDate = purchasedDate;
|
this.purchasedDate = purchasedDate;
|
||||||
@@ -54,6 +58,7 @@ public class PurchasedSharesData {
|
|||||||
this.type = type;
|
this.type = type;
|
||||||
this.amount = amount ;
|
this.amount = amount ;
|
||||||
this.chargeAmount = chargeAmount ;
|
this.chargeAmount = chargeAmount ;
|
||||||
|
this.amountPaid = amountPaid ;
|
||||||
}
|
}
|
||||||
|
|
||||||
public LocalDate getPurchasedDate() {
|
public LocalDate getPurchasedDate() {
|
||||||
+52
-23
@@ -18,10 +18,8 @@
|
|||||||
*/
|
*/
|
||||||
package org.apache.fineract.portfolio.shareaccounts.domain;
|
package org.apache.fineract.portfolio.shareaccounts.domain;
|
||||||
|
|
||||||
import java.math.BigDecimal;
|
|
||||||
import java.util.Date;
|
import java.util.Date;
|
||||||
import java.util.HashSet;
|
import java.util.HashSet;
|
||||||
import java.util.Iterator;
|
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
|
|
||||||
import javax.persistence.CascadeType;
|
import javax.persistence.CascadeType;
|
||||||
@@ -261,6 +259,17 @@ public class ShareAccount extends AbstractPersistable<Long> {
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void addTransaction(final ShareAccountTransaction transaction) {
|
||||||
|
transaction.setShareAccount(this);
|
||||||
|
if(transaction.isPendingForApprovalTransaction()) {
|
||||||
|
this.totalSharesPending += transaction.getTotalShares() ;
|
||||||
|
}else if(transaction.isPurchasTransaction()) {
|
||||||
|
this.totalSharesApproved += transaction.getTotalShares() ;
|
||||||
|
}
|
||||||
|
|
||||||
|
this.shareAccountTransactions.add(transaction);
|
||||||
|
}
|
||||||
|
|
||||||
public boolean setAllowDividendCalculationForInactiveClients(Boolean allowDividendCalculationForInactiveClients) {
|
public boolean setAllowDividendCalculationForInactiveClients(Boolean allowDividendCalculationForInactiveClients) {
|
||||||
boolean returnValue = false;
|
boolean returnValue = false;
|
||||||
if (this.allowDividendCalculationForInactiveClients == null) {
|
if (this.allowDividendCalculationForInactiveClients == null) {
|
||||||
@@ -346,7 +355,7 @@ public class ShareAccount extends AbstractPersistable<Long> {
|
|||||||
public Set<ShareAccountTransaction> getChargeTransactions() {
|
public Set<ShareAccountTransaction> getChargeTransactions() {
|
||||||
Set<ShareAccountTransaction> chargeTransactions = new HashSet<>();
|
Set<ShareAccountTransaction> chargeTransactions = new HashSet<>();
|
||||||
for (ShareAccountTransaction transaction : this.shareAccountTransactions) {
|
for (ShareAccountTransaction transaction : this.shareAccountTransactions) {
|
||||||
if (transaction.isChargeTransaction()) {
|
if (transaction.isActive() && transaction.isChargeTransaction()) {
|
||||||
chargeTransactions.add(transaction);
|
chargeTransactions.add(transaction);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -380,18 +389,6 @@ public class ShareAccount extends AbstractPersistable<Long> {
|
|||||||
this.charges.add(charge);
|
this.charges.add(charge);
|
||||||
}
|
}
|
||||||
|
|
||||||
public ShareAccountCharge updateShareCharge(final Long id, final Long chargeId, final BigDecimal amount) {
|
|
||||||
ShareAccountCharge updatedCharge = null;
|
|
||||||
for (ShareAccountCharge charge : this.charges) {
|
|
||||||
if (charge.getId() == id && charge.getChargeId() == chargeId) {
|
|
||||||
updatedCharge = charge;
|
|
||||||
charge.update(amount);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return updatedCharge;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void approve(final Date approvedDate, final AppUser approvedUser) {
|
public void approve(final Date approvedDate, final AppUser approvedUser) {
|
||||||
this.approvedDate = approvedDate;
|
this.approvedDate = approvedDate;
|
||||||
this.approvedBy = approvedUser;
|
this.approvedBy = approvedUser;
|
||||||
@@ -418,10 +415,14 @@ public class ShareAccount extends AbstractPersistable<Long> {
|
|||||||
this.closedDate = null;
|
this.closedDate = null;
|
||||||
this.closedBy = null;
|
this.closedBy = null;
|
||||||
this.totalSharesApproved = null;
|
this.totalSharesApproved = null;
|
||||||
Iterator<ShareAccountTransaction> iter = this.shareAccountTransactions.iterator();
|
Long tempTotalShares = new Long(0);
|
||||||
ShareAccountTransaction share = iter.next();
|
for (ShareAccountTransaction transaction : this.shareAccountTransactions) {
|
||||||
share.undoApprove();
|
if(transaction.isPurchasTransaction()) {
|
||||||
this.totalSharesPending = share.getTotalShares();
|
transaction.undoApprove();
|
||||||
|
tempTotalShares += transaction.getTotalShares() ;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
this.totalSharesPending = tempTotalShares;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void reject(final Date rejectedDate, final AppUser rejectedUser) {
|
public void reject(final Date rejectedDate, final AppUser rejectedUser) {
|
||||||
@@ -430,9 +431,11 @@ public class ShareAccount extends AbstractPersistable<Long> {
|
|||||||
this.status = ShareAccountStatusType.REJECTED.getValue();
|
this.status = ShareAccountStatusType.REJECTED.getValue();
|
||||||
this.totalSharesPending = null;
|
this.totalSharesPending = null;
|
||||||
this.totalSharesApproved = null;
|
this.totalSharesApproved = null;
|
||||||
Iterator<ShareAccountTransaction> iter = this.shareAccountTransactions.iterator();
|
for (ShareAccountTransaction transaction : this.shareAccountTransactions) {
|
||||||
ShareAccountTransaction share = iter.next();
|
if(transaction.isPurchasTransaction()) {
|
||||||
share.reject();
|
transaction.reject();
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public void close(final Date closedDate, final AppUser closedBy) {
|
public void close(final Date closedDate, final AppUser closedBy) {
|
||||||
@@ -469,7 +472,7 @@ public class ShareAccount extends AbstractPersistable<Long> {
|
|||||||
public Set<ShareAccountTransaction> getPendingForApprovalSharePurchaseTransactions() {
|
public Set<ShareAccountTransaction> getPendingForApprovalSharePurchaseTransactions() {
|
||||||
Set<ShareAccountTransaction> purchaseTransactions = new HashSet<>();
|
Set<ShareAccountTransaction> purchaseTransactions = new HashSet<>();
|
||||||
for (ShareAccountTransaction transaction : this.shareAccountTransactions) {
|
for (ShareAccountTransaction transaction : this.shareAccountTransactions) {
|
||||||
if (transaction.isPendingForApprovalTransaction()) {
|
if (transaction.isActive() && transaction.isPendingForApprovalTransaction()) {
|
||||||
purchaseTransactions.add(transaction);
|
purchaseTransactions.add(transaction);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -523,4 +526,30 @@ public class ShareAccount extends AbstractPersistable<Long> {
|
|||||||
public Date getApprovedDate() {
|
public Date getApprovedDate() {
|
||||||
return this.approvedDate ;
|
return this.approvedDate ;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void removeTransactions() {
|
||||||
|
for(ShareAccountTransaction transaction: this.shareAccountTransactions) {
|
||||||
|
transaction.setActive(false);
|
||||||
|
}
|
||||||
|
this.totalSharesApproved = new Long(0) ;
|
||||||
|
this.totalSharesPending = new Long(0) ;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void removeCharges() {
|
||||||
|
for(ShareAccountCharge charge: this.charges) {
|
||||||
|
charge.setActive(false);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void addCharges(Set<ShareAccountCharge> charges) {
|
||||||
|
this.charges.addAll(charges) ;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Integer getLockinPeriodFrequency() {
|
||||||
|
return this.lockinPeriodFrequency ;
|
||||||
|
}
|
||||||
|
|
||||||
|
public PeriodFrequencyType getLockinPeriodFrequencyType() {
|
||||||
|
return this.lockinPeriodFrequencyType ;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+14
-18
@@ -83,7 +83,7 @@ public class ShareAccountCharge extends AbstractPersistable<Long> {
|
|||||||
private boolean waived = false;
|
private boolean waived = false;
|
||||||
|
|
||||||
@Column(name = "is_active", nullable = false)
|
@Column(name = "is_active", nullable = false)
|
||||||
private boolean status = true;
|
private boolean active = true;
|
||||||
|
|
||||||
@Column(name = "charge_amount_or_percentage")
|
@Column(name = "charge_amount_or_percentage")
|
||||||
private BigDecimal amountOrPercentage;
|
private BigDecimal amountOrPercentage;
|
||||||
@@ -118,13 +118,13 @@ public class ShareAccountCharge extends AbstractPersistable<Long> {
|
|||||||
|
|
||||||
populateDerivedFields(transactionAmount, chargeAmount);
|
populateDerivedFields(transactionAmount, chargeAmount);
|
||||||
this.paid = determineIfFullyPaid();
|
this.paid = determineIfFullyPaid();
|
||||||
this.status = status;
|
this.active = status;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void populateDerivedFields(final BigDecimal transactionAmount, final BigDecimal chargeAmount) {
|
private void populateDerivedFields(final BigDecimal transactionAmount, final BigDecimal chargeAmount) {
|
||||||
|
this.amountOrPercentage = chargeAmount ;
|
||||||
if (this.chargeCalculation.equals(ChargeCalculationType.FLAT.getValue())) {
|
if (this.chargeCalculation.equals(ChargeCalculationType.FLAT.getValue())) {
|
||||||
this.percentage = null;
|
this.percentage = null;
|
||||||
this.amountOrPercentage = chargeAmount ;
|
|
||||||
this.amount = BigDecimal.ZERO;
|
this.amount = BigDecimal.ZERO;
|
||||||
this.amountPercentageAppliedTo = null;
|
this.amountPercentageAppliedTo = null;
|
||||||
this.amountPaid = null;
|
this.amountPaid = null;
|
||||||
@@ -149,6 +149,7 @@ public class ShareAccountCharge extends AbstractPersistable<Long> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public void resetToOriginal(final MonetaryCurrency currency) {
|
public void resetToOriginal(final MonetaryCurrency currency) {
|
||||||
|
this.amount = BigDecimal.ZERO ;
|
||||||
this.amountPaid = BigDecimal.ZERO;
|
this.amountPaid = BigDecimal.ZERO;
|
||||||
this.amountWaived = BigDecimal.ZERO;
|
this.amountWaived = BigDecimal.ZERO;
|
||||||
this.amountWrittenOff = BigDecimal.ZERO;
|
this.amountWrittenOff = BigDecimal.ZERO;
|
||||||
@@ -163,7 +164,7 @@ public class ShareAccountCharge extends AbstractPersistable<Long> {
|
|||||||
this.amountPaid = amountPaid.getAmount();
|
this.amountPaid = amountPaid.getAmount();
|
||||||
this.amountOutstanding = calculateAmountOutstanding(currency);
|
this.amountOutstanding = calculateAmountOutstanding(currency);
|
||||||
this.paid = false;
|
this.paid = false;
|
||||||
this.status = true;
|
this.active = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
public Money waive(final MonetaryCurrency currency) {
|
public Money waive(final MonetaryCurrency currency) {
|
||||||
@@ -181,7 +182,7 @@ public class ShareAccountCharge extends AbstractPersistable<Long> {
|
|||||||
this.amountWaived = amountWaived.getAmount();
|
this.amountWaived = amountWaived.getAmount();
|
||||||
this.amountOutstanding = calculateAmountOutstanding(currency);
|
this.amountOutstanding = calculateAmountOutstanding(currency);
|
||||||
this.waived = false;
|
this.waived = false;
|
||||||
this.status = true;
|
this.active = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
public Money pay(final MonetaryCurrency currency, final Money amountPaid) {
|
public Money pay(final MonetaryCurrency currency, final Money amountPaid) {
|
||||||
@@ -203,17 +204,8 @@ public class ShareAccountCharge extends AbstractPersistable<Long> {
|
|||||||
this.shareAccount = shareAccount;
|
this.shareAccount = shareAccount;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void update(final BigDecimal amount) {
|
public void update(final BigDecimal transactionAmount, final BigDecimal amount) {
|
||||||
final BigDecimal transactionAmount = BigDecimal.ZERO;
|
populateDerivedFields(transactionAmount, amount);
|
||||||
if (this.chargeCalculation.equals(ChargeCalculationType.FLAT.getValue())) {
|
|
||||||
this.amountOrPercentage = amount;
|
|
||||||
this.amountOutstanding = calculateOutstanding();
|
|
||||||
} else if (this.chargeCalculation.equals(ChargeCalculationType.PERCENT_OF_AMOUNT.getValue())) {
|
|
||||||
this.percentage = amount;
|
|
||||||
this.amountPercentageAppliedTo = transactionAmount;
|
|
||||||
this.amount = percentageOf(this.amountPercentageAppliedTo, this.percentage);
|
|
||||||
this.amountOutstanding = calculateOutstanding();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private boolean isGreaterThanZero(final BigDecimal value) {
|
private boolean isGreaterThanZero(final BigDecimal value) {
|
||||||
@@ -360,7 +352,7 @@ public class ShareAccountCharge extends AbstractPersistable<Long> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public boolean isActive() {
|
public boolean isActive() {
|
||||||
return this.status;
|
return this.active;
|
||||||
}
|
}
|
||||||
|
|
||||||
public boolean isNotActive() {
|
public boolean isNotActive() {
|
||||||
@@ -420,6 +412,10 @@ public class ShareAccountCharge extends AbstractPersistable<Long> {
|
|||||||
return toReturnAmount;
|
return toReturnAmount;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void setActive(boolean active) {
|
||||||
|
this.active = active ;
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean equals(final Object obj) {
|
public boolean equals(final Object obj) {
|
||||||
if (obj == null) { return false; }
|
if (obj == null) { return false; }
|
||||||
|
|||||||
+5
@@ -74,4 +74,9 @@ public class ShareAccountChargePaidBy extends AbstractPersistable<Long>{
|
|||||||
public Long getShareChargeId() {
|
public Long getShareChargeId() {
|
||||||
return this.shareAccountCharge.getId() ;
|
return this.shareAccountCharge.getId() ;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void reset() {
|
||||||
|
this.shareAccountTransaction = null ;
|
||||||
|
this.shareAccountCharge = null ;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+51
-13
@@ -58,8 +58,11 @@ public class ShareAccountTransaction extends AbstractPersistable<Long> {
|
|||||||
@Column(name = "amount")
|
@Column(name = "amount")
|
||||||
private BigDecimal amount ;
|
private BigDecimal amount ;
|
||||||
|
|
||||||
|
@Column(name = "amount_paid")
|
||||||
|
private BigDecimal amountPaid ;
|
||||||
|
|
||||||
@Column(name = "charge_amount")
|
@Column(name = "charge_amount")
|
||||||
private BigDecimal totalChargeAmount ;
|
private BigDecimal chargeAmount ;
|
||||||
|
|
||||||
@Column(name = "status_enum", nullable = true)
|
@Column(name = "status_enum", nullable = true)
|
||||||
private Integer status;
|
private Integer status;
|
||||||
@@ -67,6 +70,9 @@ public class ShareAccountTransaction extends AbstractPersistable<Long> {
|
|||||||
@Column(name = "type_enum", nullable = true)
|
@Column(name = "type_enum", nullable = true)
|
||||||
private Integer type ;
|
private Integer type ;
|
||||||
|
|
||||||
|
@Column(name = "is_active", nullable = false)
|
||||||
|
private boolean active = true ;
|
||||||
|
|
||||||
@LazyCollection(LazyCollectionOption.FALSE)
|
@LazyCollection(LazyCollectionOption.FALSE)
|
||||||
@OneToMany(cascade = CascadeType.ALL, mappedBy = "shareAccountTransaction", orphanRemoval = true)
|
@OneToMany(cascade = CascadeType.ALL, mappedBy = "shareAccountTransaction", orphanRemoval = true)
|
||||||
private final Set<ShareAccountChargePaidBy> shareAccountChargesPaid = new HashSet<>();
|
private final Set<ShareAccountChargePaidBy> shareAccountChargesPaid = new HashSet<>();
|
||||||
@@ -86,24 +92,27 @@ public class ShareAccountTransaction extends AbstractPersistable<Long> {
|
|||||||
this.status = PurchasedSharesStatusType.APPLIED.getValue();
|
this.status = PurchasedSharesStatusType.APPLIED.getValue();
|
||||||
this.type = PurchasedSharesStatusType.PURCHASED.getValue() ;
|
this.type = PurchasedSharesStatusType.PURCHASED.getValue() ;
|
||||||
this.amount = shareValue.multiply(BigDecimal.valueOf(totalShares)) ;
|
this.amount = shareValue.multiply(BigDecimal.valueOf(totalShares)) ;
|
||||||
|
this.amountPaid = new BigDecimal(this.amount.doubleValue()) ;
|
||||||
}
|
}
|
||||||
|
|
||||||
private ShareAccountTransaction(final Date transactionDate, final Long totalShares, final BigDecimal shareValue,
|
private ShareAccountTransaction(final Date transactionDate, final Long totalShares, final BigDecimal shareValue,
|
||||||
final Integer status, final Integer type, final BigDecimal amount, final BigDecimal chargeAmount) {
|
final Integer status, final Integer type, final BigDecimal amount, final BigDecimal chargeAmount, final BigDecimal amountPaid) {
|
||||||
this.transactionDate = transactionDate;
|
this.transactionDate = transactionDate;
|
||||||
this.totalShares = totalShares;
|
this.totalShares = totalShares;
|
||||||
this.shareValue = shareValue;
|
this.shareValue = shareValue;
|
||||||
this.status = status ;
|
this.status = status ;
|
||||||
this.type = type ;
|
this.type = type ;
|
||||||
this.amount = amount ;
|
this.amount = amount ;
|
||||||
this.totalChargeAmount = chargeAmount ;
|
this.chargeAmount = chargeAmount ;
|
||||||
|
this.amountPaid = amountPaid ;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static ShareAccountTransaction createRedeemTransaction(final Date transactionDate, final Long totalShares, final BigDecimal shareValue) {
|
public static ShareAccountTransaction createRedeemTransaction(final Date transactionDate, final Long totalShares, final BigDecimal shareValue) {
|
||||||
final Integer status = PurchasedSharesStatusType.APPROVED.getValue() ;
|
final Integer status = PurchasedSharesStatusType.APPROVED.getValue() ;
|
||||||
final Integer type = PurchasedSharesStatusType.REDEEMED.getValue() ;
|
final Integer type = PurchasedSharesStatusType.REDEEMED.getValue() ;
|
||||||
final BigDecimal amount = shareValue.multiply(BigDecimal.valueOf(totalShares)) ;
|
final BigDecimal amount = shareValue.multiply(BigDecimal.valueOf(totalShares)) ;
|
||||||
return new ShareAccountTransaction(transactionDate, totalShares, shareValue, status, type, amount, null) ;
|
BigDecimal amountPaid = new BigDecimal(amount.doubleValue()) ;
|
||||||
|
return new ShareAccountTransaction(transactionDate, totalShares, shareValue, status, type, amount, null, amountPaid) ;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static ShareAccountTransaction createChargeTransaction(final Date transactionDate, final ShareAccountCharge charge) {
|
public static ShareAccountTransaction createChargeTransaction(final Date transactionDate, final ShareAccountCharge charge) {
|
||||||
@@ -113,7 +122,8 @@ public class ShareAccountTransaction extends AbstractPersistable<Long> {
|
|||||||
final Integer type = PurchasedSharesStatusType.CHARGE_PAYMENT.getValue() ;
|
final Integer type = PurchasedSharesStatusType.CHARGE_PAYMENT.getValue() ;
|
||||||
BigDecimal amount = charge.percentageOrAmount() ;
|
BigDecimal amount = charge.percentageOrAmount() ;
|
||||||
BigDecimal chargeAmount = null ;
|
BigDecimal chargeAmount = null ;
|
||||||
return new ShareAccountTransaction(transactionDate, totalShares, unitPrice, status, type, amount, chargeAmount) ;
|
BigDecimal amountPaid = null ;
|
||||||
|
return new ShareAccountTransaction(transactionDate, totalShares, unitPrice, status, type, amount, chargeAmount, amountPaid) ;
|
||||||
}
|
}
|
||||||
|
|
||||||
public Date getPurchasedDate() {
|
public Date getPurchasedDate() {
|
||||||
@@ -133,6 +143,7 @@ public class ShareAccountTransaction extends AbstractPersistable<Long> {
|
|||||||
this.totalShares = totalShares;
|
this.totalShares = totalShares;
|
||||||
this.shareValue = shareValue;
|
this.shareValue = shareValue;
|
||||||
this.amount = shareValue.multiply(BigDecimal.valueOf(totalShares)) ;
|
this.amount = shareValue.multiply(BigDecimal.valueOf(totalShares)) ;
|
||||||
|
this.chargeAmount = BigDecimal.ZERO ;
|
||||||
this.status = PurchasedSharesStatusType.APPLIED.getValue();
|
this.status = PurchasedSharesStatusType.APPLIED.getValue();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -146,8 +157,8 @@ public class ShareAccountTransaction extends AbstractPersistable<Long> {
|
|||||||
|
|
||||||
public void reject() {
|
public void reject() {
|
||||||
this.status = PurchasedSharesStatusType.REJECTED.getValue() ;
|
this.status = PurchasedSharesStatusType.REJECTED.getValue() ;
|
||||||
if(this.totalChargeAmount != null) {
|
if(this.chargeAmount != null) {
|
||||||
this.amount = this.amount.subtract(totalChargeAmount) ;
|
this.amount = this.amount.subtract(chargeAmount) ;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -167,6 +178,10 @@ public class ShareAccountTransaction extends AbstractPersistable<Long> {
|
|||||||
return this.status.equals(PurchasedSharesStatusType.APPROVED.getValue()) && this.type.equals(PurchasedSharesStatusType.CHARGE_PAYMENT.getValue()) ;
|
return this.status.equals(PurchasedSharesStatusType.APPROVED.getValue()) && this.type.equals(PurchasedSharesStatusType.CHARGE_PAYMENT.getValue()) ;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public boolean isPurchaseRejectedTransaction() {
|
||||||
|
return this.status.equals(PurchasedSharesStatusType.REJECTED.getValue()) && this.type.equals(PurchasedSharesStatusType.PURCHASED.getValue()) ;
|
||||||
|
}
|
||||||
|
|
||||||
public void addShareAccountChargePaidBy(final ShareAccountChargePaidBy chargePaidBy) {
|
public void addShareAccountChargePaidBy(final ShareAccountChargePaidBy chargePaidBy) {
|
||||||
this.shareAccountChargesPaid.add(chargePaidBy) ;
|
this.shareAccountChargesPaid.add(chargePaidBy) ;
|
||||||
}
|
}
|
||||||
@@ -176,17 +191,17 @@ public class ShareAccountTransaction extends AbstractPersistable<Long> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public BigDecimal chargeAmount() {
|
public BigDecimal chargeAmount() {
|
||||||
return this.totalChargeAmount ;
|
return this.chargeAmount ;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void updateChargeAmount(BigDecimal totalChargeAmount) {
|
public void updateChargeAmount(BigDecimal totalChargeAmount) {
|
||||||
this.amount = this.amount.add(totalChargeAmount);
|
this.amount = this.amount.add(totalChargeAmount);
|
||||||
this.totalChargeAmount = totalChargeAmount ;
|
this.chargeAmount = totalChargeAmount ;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void deductChargesFromTotalAmount(BigDecimal totalChargeAmount) {
|
public void deductChargesFromTotalAmount(BigDecimal totalChargeAmount) {
|
||||||
this.amount = this.amount.subtract(totalChargeAmount);
|
this.amount = this.amount.subtract(totalChargeAmount);
|
||||||
this.totalChargeAmount = totalChargeAmount ;
|
this.chargeAmount = totalChargeAmount ;
|
||||||
}
|
}
|
||||||
|
|
||||||
public Set<ShareAccountChargePaidBy> getChargesPaidBy() {
|
public Set<ShareAccountChargePaidBy> getChargesPaidBy() {
|
||||||
@@ -201,9 +216,32 @@ public class ShareAccountTransaction extends AbstractPersistable<Long> {
|
|||||||
return this.type ;
|
return this.type ;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void adjustRedeemAmount() {
|
public void updateAmountPaid(final BigDecimal amountPaid) {
|
||||||
if(this.totalChargeAmount != null) {
|
this.amountPaid = amountPaid ;
|
||||||
this.amount = this.amount.subtract(totalChargeAmount) ;
|
}
|
||||||
|
|
||||||
|
public void addAmountPaid(final BigDecimal amountPaid) {
|
||||||
|
if(isRedeemTransaction()) {
|
||||||
|
this.amountPaid = this.amountPaid.subtract(amountPaid) ;
|
||||||
|
}else if(isPurchasTransaction() /*|| isPurchaseRejectedTransaction()*/) {
|
||||||
|
this.amountPaid = this.amountPaid.add(amountPaid) ;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void resetAmountPaid() {
|
||||||
|
this.amountPaid = BigDecimal.ZERO ;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setActive(boolean active) {
|
||||||
|
this.active = active ;
|
||||||
|
if(!this.active) {
|
||||||
|
//this.shareAccountChargesPaid.clear();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean isActive() {
|
||||||
|
return this.active ;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
+319
-131
@@ -49,7 +49,6 @@ import org.apache.fineract.portfolio.client.domain.Client;
|
|||||||
import org.apache.fineract.portfolio.client.domain.ClientRepositoryWrapper;
|
import org.apache.fineract.portfolio.client.domain.ClientRepositoryWrapper;
|
||||||
import org.apache.fineract.portfolio.common.domain.PeriodFrequencyType;
|
import org.apache.fineract.portfolio.common.domain.PeriodFrequencyType;
|
||||||
import org.apache.fineract.portfolio.loanproduct.exception.InvalidCurrencyException;
|
import org.apache.fineract.portfolio.loanproduct.exception.InvalidCurrencyException;
|
||||||
import org.apache.fineract.portfolio.savings.SavingsApiConstants;
|
|
||||||
import org.apache.fineract.portfolio.savings.domain.SavingsAccount;
|
import org.apache.fineract.portfolio.savings.domain.SavingsAccount;
|
||||||
import org.apache.fineract.portfolio.savings.domain.SavingsAccountRepositoryWrapper;
|
import org.apache.fineract.portfolio.savings.domain.SavingsAccountRepositoryWrapper;
|
||||||
import org.apache.fineract.portfolio.shareaccounts.domain.ShareAccount;
|
import org.apache.fineract.portfolio.shareaccounts.domain.ShareAccount;
|
||||||
@@ -87,9 +86,8 @@ public class ShareAccountDataSerializer {
|
|||||||
|
|
||||||
@Autowired
|
@Autowired
|
||||||
public ShareAccountDataSerializer(final PlatformSecurityContext platformSecurityContext, final FromJsonHelper fromApiJsonHelper,
|
public ShareAccountDataSerializer(final PlatformSecurityContext platformSecurityContext, final FromJsonHelper fromApiJsonHelper,
|
||||||
final ChargeRepositoryWrapper chargeRepository,
|
final ChargeRepositoryWrapper chargeRepository, final SavingsAccountRepositoryWrapper savingsAccountRepositoryWrapper,
|
||||||
final SavingsAccountRepositoryWrapper savingsAccountRepositoryWrapper, final ClientRepositoryWrapper clientRepositoryWrapper,
|
final ClientRepositoryWrapper clientRepositoryWrapper, final ShareProductRepositoryWrapper shareProductRepository) {
|
||||||
final ShareProductRepositoryWrapper shareProductRepository) {
|
|
||||||
this.platformSecurityContext = platformSecurityContext;
|
this.platformSecurityContext = platformSecurityContext;
|
||||||
this.fromApiJsonHelper = fromApiJsonHelper;
|
this.fromApiJsonHelper = fromApiJsonHelper;
|
||||||
this.chargeRepository = chargeRepository;
|
this.chargeRepository = chargeRepository;
|
||||||
@@ -117,7 +115,7 @@ public class ShareAccountDataSerializer {
|
|||||||
baseDataValidator.reset().parameter(ShareAccountApiConstants.submitteddate_paramname).value(submittedDate).notNull();
|
baseDataValidator.reset().parameter(ShareAccountApiConstants.submitteddate_paramname).value(submittedDate).notNull();
|
||||||
|
|
||||||
final String externalId = this.fromApiJsonHelper.extractStringNamed(ShareAccountApiConstants.externalid_paramname, element);
|
final String externalId = this.fromApiJsonHelper.extractStringNamed(ShareAccountApiConstants.externalid_paramname, element);
|
||||||
baseDataValidator.reset().parameter(ShareAccountApiConstants.externalid_paramname).value(externalId).notNull();
|
// baseDataValidator.reset().parameter(ShareAccountApiConstants.externalid_paramname).value(externalId).notNull();
|
||||||
|
|
||||||
Long savingsAccountId = this.fromApiJsonHelper.extractLongNamed(ShareAccountApiConstants.savingsaccountid_paramname, element);
|
Long savingsAccountId = this.fromApiJsonHelper.extractLongNamed(ShareAccountApiConstants.savingsaccountid_paramname, element);
|
||||||
baseDataValidator.reset().parameter(ShareAccountApiConstants.savingsaccountid_paramname).value(savingsAccountId).notNull()
|
baseDataValidator.reset().parameter(ShareAccountApiConstants.savingsaccountid_paramname).value(savingsAccountId).notNull()
|
||||||
@@ -126,24 +124,15 @@ public class ShareAccountDataSerializer {
|
|||||||
final Long requestedShares = this.fromApiJsonHelper.extractLongNamed(ShareAccountApiConstants.requestedshares_paramname, element);
|
final Long requestedShares = this.fromApiJsonHelper.extractLongNamed(ShareAccountApiConstants.requestedshares_paramname, element);
|
||||||
baseDataValidator.reset().parameter(ShareAccountApiConstants.requestedshares_paramname).value(requestedShares).notNull()
|
baseDataValidator.reset().parameter(ShareAccountApiConstants.requestedshares_paramname).value(requestedShares).notNull()
|
||||||
.longGreaterThanZero();
|
.longGreaterThanZero();
|
||||||
boolean allowed = shareProduct.isSharesAllowed(requestedShares) ;
|
if(requestedShares < shareProduct.getMinimumClientShares()) {
|
||||||
if(!allowed) {
|
baseDataValidator.reset().parameter(ShareAccountApiConstants.requestedshares_paramname).value(requestedShares)
|
||||||
baseDataValidator.reset().parameter(ShareAccountApiConstants.requestedshares_paramname).value(requestedShares).failWithCode("differ.from.productdefinition", "Out of range");;
|
.failWithCode("client.can.not.purchase.shares.lessthan.product.definition", "Client can not purchase shares less than product definition");
|
||||||
}
|
}
|
||||||
|
|
||||||
/*Long subscribedShares = shareProduct.getSubscribedShares() ;
|
if(requestedShares > shareProduct.getMaximumClientShares()) {
|
||||||
if(subscribedShares == null) subscribedShares = new Long(0) ;
|
baseDataValidator.reset().parameter(ShareAccountApiConstants.requestedshares_paramname).value(requestedShares)
|
||||||
Long totalShares = shareProduct.getTotalShares() ;
|
.failWithCode("client.can.not.purchase.shares.morethan.product.definition", "Client can not purchase shares more than product definition");
|
||||||
Long issuedShares = shareProduct.getSharesIssued() ;
|
|
||||||
if(issuedShares == null) issuedShares = totalShares ;
|
|
||||||
if((subscribedShares+requestedShares) > issuedShares) {
|
|
||||||
throw new IssueableSharesExceededException() ;
|
|
||||||
}
|
}
|
||||||
shareProduct.addSubscribedShares(requestedShares);*/
|
|
||||||
|
|
||||||
/*BigDecimal unitPrice = this.fromApiJsonHelper.extractBigDecimalNamed(ShareAccountApiConstants.purchasedprice_paramname, element,
|
|
||||||
locale);
|
|
||||||
baseDataValidator.reset().parameter(ShareAccountApiConstants.purchasedprice_paramname).value(unitPrice).notNull().positiveAmount();*/
|
|
||||||
|
|
||||||
LocalDate applicationDate = this.fromApiJsonHelper.extractLocalDateNamed(ShareAccountApiConstants.applicationdate_param, element);
|
LocalDate applicationDate = this.fromApiJsonHelper.extractLocalDateNamed(ShareAccountApiConstants.applicationdate_param, element);
|
||||||
baseDataValidator.reset().parameter(ShareAccountApiConstants.applicationdate_param).value(applicationDate).notNull();
|
baseDataValidator.reset().parameter(ShareAccountApiConstants.applicationdate_param).value(applicationDate).notNull();
|
||||||
@@ -185,7 +174,7 @@ public class ShareAccountDataSerializer {
|
|||||||
String accountNo = null;
|
String accountNo = null;
|
||||||
Long approvedShares = null;
|
Long approvedShares = null;
|
||||||
Long pendingShares = requestedShares;
|
Long pendingShares = requestedShares;
|
||||||
BigDecimal unitPrice = shareProduct.deriveMarketPrice(applicationDate.toDate()) ;
|
BigDecimal unitPrice = shareProduct.deriveMarketPrice(applicationDate.toDate());
|
||||||
ShareAccountTransaction transaction = new ShareAccountTransaction(applicationDate.toDate(), requestedShares, unitPrice);
|
ShareAccountTransaction transaction = new ShareAccountTransaction(applicationDate.toDate(), requestedShares, unitPrice);
|
||||||
Set<ShareAccountTransaction> sharesPurchased = new HashSet<>();
|
Set<ShareAccountTransaction> sharesPurchased = new HashSet<>();
|
||||||
sharesPurchased.add(transaction);
|
sharesPurchased.add(transaction);
|
||||||
@@ -204,17 +193,17 @@ public class ShareAccountDataSerializer {
|
|||||||
charge.update(account);
|
charge.update(account);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
createChargeTransaction(account, transaction);
|
createChargeTransaction(account);
|
||||||
return account;
|
return account;
|
||||||
}
|
}
|
||||||
|
|
||||||
private void createChargeTransaction(ShareAccount account, final ShareAccountTransaction transaction) {
|
private void createChargeTransaction(ShareAccount account) {
|
||||||
BigDecimal totalChargeAmount = BigDecimal.ZERO;
|
BigDecimal totalChargeAmount = BigDecimal.ZERO;
|
||||||
Set<ShareAccountCharge> charges = account.getCharges();
|
Set<ShareAccountCharge> charges = account.getCharges();
|
||||||
Date currentDate = DateUtils.getLocalDateOfTenant().toDate();
|
Date currentDate = DateUtils.getLocalDateOfTenant().toDate();
|
||||||
for (ShareAccountCharge charge : charges) {
|
for (ShareAccountCharge charge : charges) {
|
||||||
if (charge.isShareAccountActivation()) {
|
if (charge.isActive() && charge.isShareAccountActivation()) {
|
||||||
charge.deriveChargeAmount(totalChargeAmount) ;
|
charge.deriveChargeAmount(totalChargeAmount);
|
||||||
ShareAccountTransaction chargeTransaction = ShareAccountTransaction.createChargeTransaction(currentDate, charge);
|
ShareAccountTransaction chargeTransaction = ShareAccountTransaction.createChargeTransaction(currentDate, charge);
|
||||||
ShareAccountChargePaidBy paidBy = new ShareAccountChargePaidBy(chargeTransaction, charge, charge.percentageOrAmount());
|
ShareAccountChargePaidBy paidBy = new ShareAccountChargePaidBy(chargeTransaction, charge, charge.percentageOrAmount());
|
||||||
chargeTransaction.addShareAccountChargePaidBy(paidBy);
|
chargeTransaction.addShareAccountChargePaidBy(paidBy);
|
||||||
@@ -225,7 +214,7 @@ public class ShareAccountDataSerializer {
|
|||||||
Set<ShareAccountTransaction> pendingApprovalTransaction = account.getPendingForApprovalSharePurchaseTransactions();
|
Set<ShareAccountTransaction> pendingApprovalTransaction = account.getPendingForApprovalSharePurchaseTransactions();
|
||||||
for (ShareAccountTransaction pending : pendingApprovalTransaction) {
|
for (ShareAccountTransaction pending : pendingApprovalTransaction) {
|
||||||
for (ShareAccountCharge charge : charges) {
|
for (ShareAccountCharge charge : charges) {
|
||||||
if (charge.isSharesPurchaseCharge()) {
|
if (charge.isActive() && charge.isSharesPurchaseCharge()) {
|
||||||
BigDecimal amount = charge.deriveChargeAmount(pending.amount());
|
BigDecimal amount = charge.deriveChargeAmount(pending.amount());
|
||||||
ShareAccountChargePaidBy paidBy = new ShareAccountChargePaidBy(pending, charge, amount);
|
ShareAccountChargePaidBy paidBy = new ShareAccountChargePaidBy(pending, charge, amount);
|
||||||
pending.addShareAccountChargePaidBy(paidBy);
|
pending.addShareAccountChargePaidBy(paidBy);
|
||||||
@@ -245,7 +234,7 @@ public class ShareAccountDataSerializer {
|
|||||||
final List<ApiParameterError> dataValidationErrors = new ArrayList<>();
|
final List<ApiParameterError> dataValidationErrors = new ArrayList<>();
|
||||||
final DataValidatorBuilder baseDataValidator = new DataValidatorBuilder(dataValidationErrors).resource("sharesaccount");
|
final DataValidatorBuilder baseDataValidator = new DataValidatorBuilder(dataValidationErrors).resource("sharesaccount");
|
||||||
JsonElement element = jsonCommand.parsedJson();
|
JsonElement element = jsonCommand.parsedJson();
|
||||||
ShareProduct shareProduct = account.getShareProduct() ;
|
ShareProduct shareProduct = account.getShareProduct();
|
||||||
final Locale locale = this.fromApiJsonHelper.extractLocaleParameter(element.getAsJsonObject());
|
final Locale locale = this.fromApiJsonHelper.extractLocaleParameter(element.getAsJsonObject());
|
||||||
if (this.fromApiJsonHelper.parameterExists(ShareAccountApiConstants.productid_paramname, element)) {
|
if (this.fromApiJsonHelper.parameterExists(ShareAccountApiConstants.productid_paramname, element)) {
|
||||||
final Long productId = this.fromApiJsonHelper.extractLongNamed(ShareAccountApiConstants.productid_paramname, element);
|
final Long productId = this.fromApiJsonHelper.extractLongNamed(ShareAccountApiConstants.productid_paramname, element);
|
||||||
@@ -266,7 +255,7 @@ public class ShareAccountDataSerializer {
|
|||||||
|
|
||||||
if (this.fromApiJsonHelper.parameterExists(ShareAccountApiConstants.externalid_paramname, element)) {
|
if (this.fromApiJsonHelper.parameterExists(ShareAccountApiConstants.externalid_paramname, element)) {
|
||||||
final String externalId = this.fromApiJsonHelper.extractStringNamed(ShareAccountApiConstants.externalid_paramname, element);
|
final String externalId = this.fromApiJsonHelper.extractStringNamed(ShareAccountApiConstants.externalid_paramname, element);
|
||||||
baseDataValidator.reset().parameter(ShareAccountApiConstants.externalid_paramname).value(externalId).notNull();
|
// baseDataValidator.reset().parameter(ShareAccountApiConstants.externalid_paramname).value(externalId).notNull();
|
||||||
if (account.setExternalId(externalId)) {
|
if (account.setExternalId(externalId)) {
|
||||||
actualChanges.put(ShareAccountApiConstants.externalid_paramname, externalId);
|
actualChanges.put(ShareAccountApiConstants.externalid_paramname, externalId);
|
||||||
}
|
}
|
||||||
@@ -274,25 +263,51 @@ public class ShareAccountDataSerializer {
|
|||||||
|
|
||||||
if (this.fromApiJsonHelper.parameterExists(ShareAccountApiConstants.savingsaccountid_paramname, element)) {
|
if (this.fromApiJsonHelper.parameterExists(ShareAccountApiConstants.savingsaccountid_paramname, element)) {
|
||||||
Long savingsAccountId = this.fromApiJsonHelper.extractLongNamed(ShareAccountApiConstants.savingsaccountid_paramname, element);
|
Long savingsAccountId = this.fromApiJsonHelper.extractLongNamed(ShareAccountApiConstants.savingsaccountid_paramname, element);
|
||||||
SavingsAccount savingsAccount = this.savingsAccountRepositoryWrapper.findOneWithNotFoundDetection(savingsAccountId);
|
baseDataValidator.reset().parameter(ShareAccountApiConstants.savingsaccountid_paramname).value(savingsAccountId).notNull()
|
||||||
if (account.setSavingsAccount(savingsAccount)) {
|
.longGreaterThanZero();
|
||||||
actualChanges.put(ShareAccountApiConstants.savingsaccountid_paramname, savingsAccount);
|
if(savingsAccountId != null) {
|
||||||
|
SavingsAccount savingsAccount = this.savingsAccountRepositoryWrapper.findOneWithNotFoundDetection(savingsAccountId);
|
||||||
|
if (account.setSavingsAccount(savingsAccount)) {
|
||||||
|
actualChanges.put(ShareAccountApiConstants.savingsaccountid_paramname, savingsAccount.getId());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (this.fromApiJsonHelper.parameterExists(ShareAccountApiConstants.requestedshares_paramname, element)
|
||||||
|
|| this.fromApiJsonHelper.parameterExists(ShareAccountApiConstants.charges_paramname, element)) {
|
||||||
|
Set<ShareAccountTransaction> transactions = account.getShareAccountTransactions();
|
||||||
|
List<Long> reveralIds = new ArrayList<>();
|
||||||
|
for (ShareAccountTransaction transaction : transactions) {
|
||||||
|
reveralIds.add(transaction.getId());
|
||||||
|
}
|
||||||
|
actualChanges.put("reversalIds", reveralIds);
|
||||||
|
account.removeTransactions();
|
||||||
|
account.removeCharges();
|
||||||
|
}
|
||||||
|
|
||||||
if (this.fromApiJsonHelper.parameterExists(ShareAccountApiConstants.requestedshares_paramname, element)) {
|
if (this.fromApiJsonHelper.parameterExists(ShareAccountApiConstants.requestedshares_paramname, element)) {
|
||||||
Long requestedShares = this.fromApiJsonHelper.extractLongNamed(ShareAccountApiConstants.requestedshares_paramname, element);
|
Long requestedShares = this.fromApiJsonHelper.extractLongNamed(ShareAccountApiConstants.requestedshares_paramname, element);
|
||||||
/*BigDecimal unitPrice = this.fromApiJsonHelper.extractBigDecimalNamed(ShareAccountApiConstants.purchasedprice_paramname,
|
/*
|
||||||
element, locale);*/
|
* BigDecimal unitPrice =
|
||||||
|
* this.fromApiJsonHelper.extractBigDecimalNamed
|
||||||
|
* (ShareAccountApiConstants.purchasedprice_paramname, element,
|
||||||
|
* locale);
|
||||||
|
*/
|
||||||
Date applicationDate = this.fromApiJsonHelper.extractLocalDateNamed(ShareAccountApiConstants.applicationdate_param, element)
|
Date applicationDate = this.fromApiJsonHelper.extractLocalDateNamed(ShareAccountApiConstants.applicationdate_param, element)
|
||||||
.toDate();
|
.toDate();
|
||||||
BigDecimal unitPrice = shareProduct.deriveMarketPrice(applicationDate) ;
|
BigDecimal unitPrice = shareProduct.deriveMarketPrice(applicationDate);
|
||||||
ShareAccountTransaction purchased = new ShareAccountTransaction(applicationDate, requestedShares, unitPrice);
|
ShareAccountTransaction transaction = new ShareAccountTransaction(applicationDate, requestedShares, unitPrice);
|
||||||
account.updateRequestedShares(purchased);
|
account.addTransaction(transaction);
|
||||||
actualChanges.put(ShareAccountApiConstants.requestedshares_paramname, purchased);
|
actualChanges.put(ShareAccountApiConstants.requestedshares_paramname, "Transaction");
|
||||||
boolean allowed = shareProduct.isSharesAllowed(requestedShares) ;
|
|
||||||
if(!allowed) {
|
if(requestedShares < shareProduct.getMinimumClientShares()) {
|
||||||
baseDataValidator.reset().parameter(ShareAccountApiConstants.requestedshares_paramname).value(requestedShares).failWithCode("differ.from.productdefinition", "Out of range");;
|
baseDataValidator.reset().parameter(ShareAccountApiConstants.requestedshares_paramname).value(requestedShares)
|
||||||
|
.failWithCode("client.can.not.purchase.shares.lessthan.product.definition", "Client can not purchase shares less than product definition");
|
||||||
|
}
|
||||||
|
|
||||||
|
if(requestedShares > shareProduct.getMaximumClientShares()) {
|
||||||
|
baseDataValidator.reset().parameter(ShareAccountApiConstants.requestedshares_paramname).value(requestedShares)
|
||||||
|
.failWithCode("client.can.not.purchase.shares.morethan.product.definition", "Client can not purchase shares more than product definition");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -340,13 +355,19 @@ public class ShareAccountDataSerializer {
|
|||||||
}
|
}
|
||||||
if (this.fromApiJsonHelper.parameterExists(ShareAccountApiConstants.charges_paramname, element)) {
|
if (this.fromApiJsonHelper.parameterExists(ShareAccountApiConstants.charges_paramname, element)) {
|
||||||
shareProduct = account.getShareProduct();
|
shareProduct = account.getShareProduct();
|
||||||
Set<ShareAccountCharge> updatedCharges = assembleListOfAccountChargesforUpdate(account, element, shareProduct.getCurrency()
|
final MonetaryCurrency currency = shareProduct.getCurrency();
|
||||||
.getCode());
|
Set<ShareAccountCharge> charges = assembleListOfAccountCharges(element, currency.getCode());
|
||||||
if (!updatedCharges.isEmpty()) {
|
if (charges != null) {
|
||||||
actualChanges.put(ShareAccountApiConstants.charges_paramname, new HashSet<ShareAccountCharge>());
|
for (ShareAccountCharge charge : charges) {
|
||||||
|
charge.update(account);
|
||||||
|
}
|
||||||
|
account.addCharges(charges);
|
||||||
|
if (!charges.isEmpty()) {
|
||||||
|
actualChanges.put(ShareAccountApiConstants.charges_paramname, new HashSet<ShareAccountCharge>());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
createChargeTransaction(account);
|
||||||
if (!dataValidationErrors.isEmpty()) { throw new PlatformApiDataValidationException(dataValidationErrors); }
|
if (!dataValidationErrors.isEmpty()) { throw new PlatformApiDataValidationException(dataValidationErrors); }
|
||||||
return actualChanges;
|
return actualChanges;
|
||||||
}
|
}
|
||||||
@@ -366,8 +387,16 @@ public class ShareAccountDataSerializer {
|
|||||||
final DateTimeFormatter formatter = DateTimeFormat.forPattern(jsonCommand.dateFormat()).withLocale(jsonCommand.extractLocale());
|
final DateTimeFormatter formatter = DateTimeFormat.forPattern(jsonCommand.dateFormat()).withLocale(jsonCommand.extractLocale());
|
||||||
final String submittalDateAsString = formatter.print(submittalDate);
|
final String submittalDateAsString = formatter.print(submittalDate);
|
||||||
baseDataValidator.reset().parameter(ShareAccountApiConstants.approveddate_paramname).value(submittalDateAsString)
|
baseDataValidator.reset().parameter(ShareAccountApiConstants.approveddate_paramname).value(submittalDateAsString)
|
||||||
.failWithCodeNoParameterAddedToErrorCode("cannot.be.before.submittal.date");
|
.failWithCodeNoParameterAddedToErrorCode("approved.date.cannot.be.before.submitted.date");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Set<ShareAccountTransaction> transactions = account.getShareAccountTransactions() ;
|
||||||
|
for(ShareAccountTransaction transaction: transactions) {
|
||||||
|
if(transaction.isActive() && transaction.isPendingForApprovalTransaction()) {
|
||||||
|
validateTotalSubsribedShares(account, transaction, baseDataValidator) ;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (!dataValidationErrors.isEmpty()) { throw new PlatformApiDataValidationException(dataValidationErrors); }
|
if (!dataValidationErrors.isEmpty()) { throw new PlatformApiDataValidationException(dataValidationErrors); }
|
||||||
|
|
||||||
AppUser approvedUser = this.platformSecurityContext.authenticatedUser();
|
AppUser approvedUser = this.platformSecurityContext.authenticatedUser();
|
||||||
@@ -377,19 +406,38 @@ public class ShareAccountDataSerializer {
|
|||||||
return actualChanges;
|
return actualChanges;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void validateTotalSubsribedShares(final ShareAccount account, final ShareAccountTransaction transaction, final DataValidatorBuilder baseDataValidator) {
|
||||||
|
Long totalSubsribedShares = account.getShareProduct().getSubscribedShares() ;
|
||||||
|
Long requested = new Long(0) ;
|
||||||
|
if(transaction.isActive() && transaction.isPendingForApprovalTransaction()) {
|
||||||
|
requested +=transaction.getTotalShares() ;
|
||||||
|
}
|
||||||
|
Long totalSharesIssuable = account.getShareProduct().getSharesIssued() ;
|
||||||
|
if(totalSharesIssuable == null) totalSharesIssuable = account.getShareProduct().getTotalShares() ;
|
||||||
|
if(totalSubsribedShares == null) totalSubsribedShares = new Long(0) ;
|
||||||
|
if((totalSubsribedShares+requested) > totalSharesIssuable) {
|
||||||
|
baseDataValidator.reset().parameter(ShareAccountApiConstants.requestedshares_paramname).value(requested)
|
||||||
|
.failWithCodeNoParameterAddedToErrorCode("shares.requested.can.not.be.approved.exceeding.totalshares.issuable");
|
||||||
|
}
|
||||||
|
}
|
||||||
private void updateTotalChargeDerived(final ShareAccount shareAccount) {
|
private void updateTotalChargeDerived(final ShareAccount shareAccount) {
|
||||||
// Set<ShareAccountCharge> charges = shareAccount.getCharges() ;
|
// Set<ShareAccountCharge> charges = shareAccount.getCharges() ;
|
||||||
Set<ShareAccountTransaction> transactions = shareAccount.getShareAccountTransactions();
|
Set<ShareAccountTransaction> transactions = shareAccount.getShareAccountTransactions();
|
||||||
for (ShareAccountTransaction transaction : transactions) {
|
for (ShareAccountTransaction transaction : transactions) {
|
||||||
Set<ShareAccountChargePaidBy> paidBySet = transaction.getChargesPaidBy();
|
if (transaction.isActive()) {
|
||||||
if (paidBySet != null && !paidBySet.isEmpty()) {
|
Set<ShareAccountChargePaidBy> paidBySet = transaction.getChargesPaidBy();
|
||||||
for (ShareAccountChargePaidBy chargePaidBy : paidBySet) {
|
if (paidBySet != null && !paidBySet.isEmpty()) {
|
||||||
ShareAccountCharge charge = chargePaidBy.getCharge();
|
for (ShareAccountChargePaidBy chargePaidBy : paidBySet) {
|
||||||
if (charge.isSharesPurchaseCharge()) {
|
ShareAccountCharge charge = chargePaidBy.getCharge();
|
||||||
Money money = Money.of(shareAccount.getCurrency(), chargePaidBy.getAmount());
|
if (charge.isActive() && charge.isSharesPurchaseCharge()) {
|
||||||
charge.updatePaidAmountBy(money);
|
Money money = Money.of(shareAccount.getCurrency(), chargePaidBy.getAmount());
|
||||||
|
charge.updatePaidAmountBy(money);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if (!transaction.isChargeTransaction()) {
|
||||||
|
transaction.addAmountPaid(transaction.chargeAmount());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -397,19 +445,54 @@ public class ShareAccountDataSerializer {
|
|||||||
public Map<String, Object> validateAndUndoApprove(JsonCommand jsonCommand, ShareAccount account) {
|
public Map<String, Object> validateAndUndoApprove(JsonCommand jsonCommand, ShareAccount account) {
|
||||||
Map<String, Object> actualChanges = new HashMap<>();
|
Map<String, Object> actualChanges = new HashMap<>();
|
||||||
if (StringUtils.isBlank(jsonCommand.json())) { throw new InvalidJsonException(); }
|
if (StringUtils.isBlank(jsonCommand.json())) { throw new InvalidJsonException(); }
|
||||||
//final Type typeOfMap = new TypeToken<Map<String, Object>>() {}.getType();
|
// final Type typeOfMap = new TypeToken<Map<String, Object>>()
|
||||||
//this.fromApiJsonHelper.checkForUnsupportedParameters(typeOfMap, jsonCommand.json(), ShareAccountApiConstants.activateParameters);
|
// {}.getType();
|
||||||
//final List<ApiParameterError> dataValidationErrors = new ArrayList<>();
|
// this.fromApiJsonHelper.checkForUnsupportedParameters(typeOfMap,
|
||||||
//final DataValidatorBuilder baseDataValidator = new DataValidatorBuilder(dataValidationErrors).resource("sharesaccount");
|
// jsonCommand.json(), ShareAccountApiConstants.activateParameters);
|
||||||
//JsonElement element = jsonCommand.parsedJson();
|
// final List<ApiParameterError> dataValidationErrors = new
|
||||||
//String notes = this.fromApiJsonHelper.extractStringNamed(ShareAccountApiConstants.note_paramname, element);
|
// ArrayList<>();
|
||||||
|
// final DataValidatorBuilder baseDataValidator = new
|
||||||
|
// DataValidatorBuilder(dataValidationErrors).resource("sharesaccount");
|
||||||
|
// JsonElement element = jsonCommand.parsedJson();
|
||||||
|
// String notes =
|
||||||
|
// this.fromApiJsonHelper.extractStringNamed(ShareAccountApiConstants.note_paramname,
|
||||||
|
// element);
|
||||||
// baseDataValidator.reset().parameter(ShareAccountApiConstants.approveddate_paramname).validateDateAfter(account.get)
|
// baseDataValidator.reset().parameter(ShareAccountApiConstants.approveddate_paramname).validateDateAfter(account.get)
|
||||||
//AppUser approvedUser = this.platformSecurityContext.authenticatedUser();
|
// AppUser approvedUser =
|
||||||
|
// this.platformSecurityContext.authenticatedUser();
|
||||||
account.undoApprove();
|
account.undoApprove();
|
||||||
|
updateTotalChargeDerivedForUndoApproval(account) ;
|
||||||
actualChanges.put(ShareAccountApiConstants.charges_paramname, Boolean.TRUE);
|
actualChanges.put(ShareAccountApiConstants.charges_paramname, Boolean.TRUE);
|
||||||
return actualChanges;
|
return actualChanges;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void updateTotalChargeDerivedForUndoApproval(final ShareAccount shareAccount) {
|
||||||
|
Set<ShareAccountTransaction> purchaseTransactions = shareAccount.getPendingForApprovalSharePurchaseTransactions() ;
|
||||||
|
//we will have only 1 purchase transaction. Take that
|
||||||
|
ShareAccountTransaction purchaseTransaction = null ;
|
||||||
|
for (ShareAccountTransaction transaction : purchaseTransactions) {
|
||||||
|
purchaseTransaction = transaction ;
|
||||||
|
}
|
||||||
|
BigDecimal transactionAmount = BigDecimal.ZERO ;
|
||||||
|
if(purchaseTransaction != null) {
|
||||||
|
transactionAmount = purchaseTransaction.amount().subtract(purchaseTransaction.chargeAmount()) ;
|
||||||
|
}
|
||||||
|
Set<ShareAccountCharge> charges = shareAccount.getCharges() ;
|
||||||
|
for(ShareAccountCharge charge: charges) {
|
||||||
|
if(charge.isActive() && charge.isSharesPurchaseCharge()) {
|
||||||
|
charge.update(transactionAmount, charge.percentageOrAmount()) ;
|
||||||
|
charge.deriveChargeAmount(transactionAmount);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Set<ShareAccountTransaction> transactions = shareAccount.getShareAccountTransactions();
|
||||||
|
for (ShareAccountTransaction transaction : transactions) {
|
||||||
|
if (transaction.isActive()) {
|
||||||
|
if (!transaction.isChargeTransaction()) {
|
||||||
|
transaction.resetAmountPaid();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@SuppressWarnings("unused")
|
@SuppressWarnings("unused")
|
||||||
public Map<String, Object> validateAndReject(JsonCommand jsonCommand, ShareAccount account) {
|
public Map<String, Object> validateAndReject(JsonCommand jsonCommand, ShareAccount account) {
|
||||||
Map<String, Object> actualChanges = new HashMap<>();
|
Map<String, Object> actualChanges = new HashMap<>();
|
||||||
@@ -449,10 +532,17 @@ public class ShareAccountDataSerializer {
|
|||||||
private void handlechargesOnActivation(final ShareAccount account) {
|
private void handlechargesOnActivation(final ShareAccount account) {
|
||||||
Set<ShareAccountCharge> charges = account.getCharges();
|
Set<ShareAccountCharge> charges = account.getCharges();
|
||||||
for (ShareAccountCharge charge : charges) {
|
for (ShareAccountCharge charge : charges) {
|
||||||
if (charge.isShareAccountActivation()) {
|
if (charge.isActive() && charge.isShareAccountActivation()) {
|
||||||
charge.markAsFullyPaid();
|
charge.markAsFullyPaid();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Set<ShareAccountTransaction> transactions = account.getChargeTransactions();
|
||||||
|
for (ShareAccountTransaction transaction : transactions) {
|
||||||
|
if (transaction.isChargeTransaction()) {
|
||||||
|
transaction.updateAmountPaid(transaction.amount());
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private Set<ShareAccountCharge> assembleListOfAccountCharges(final JsonElement element, final String currencyCode) {
|
private Set<ShareAccountCharge> assembleListOfAccountCharges(final JsonElement element, final String currencyCode) {
|
||||||
@@ -484,49 +574,6 @@ public class ShareAccountDataSerializer {
|
|||||||
return charges;
|
return charges;
|
||||||
}
|
}
|
||||||
|
|
||||||
private Set<ShareAccountCharge> assembleListOfAccountChargesforUpdate(final ShareAccount account, final JsonElement element,
|
|
||||||
final String currencyCode) {
|
|
||||||
Set<ShareAccountCharge> updated = new HashSet<>();
|
|
||||||
if (this.fromApiJsonHelper.parameterExists(ShareAccountApiConstants.charges_paramname, element)) {
|
|
||||||
JsonArray chargesArray = this.fromApiJsonHelper.extractJsonArrayNamed(ShareAccountApiConstants.charges_paramname, element);
|
|
||||||
if (chargesArray != null) {
|
|
||||||
for (int i = 0; i < chargesArray.size(); i++) {
|
|
||||||
final JsonObject jsonObject = chargesArray.get(i).getAsJsonObject();
|
|
||||||
if (jsonObject.has("id")) {
|
|
||||||
final Long id = jsonObject.get("id").getAsLong();
|
|
||||||
final Long chargeId = jsonObject.get("chargeId").getAsLong();
|
|
||||||
BigDecimal amount = jsonObject.get("amount").getAsBigDecimal();
|
|
||||||
final Charge charge = this.chargeRepository.findOneWithNotFoundDetection(chargeId);
|
|
||||||
if (!currencyCode.equals(charge.getCurrencyCode())) {
|
|
||||||
final String errorMessage = "Charge and Share Account must have the same currency.";
|
|
||||||
throw new InvalidCurrencyException("charge", "attach.to.share.account", errorMessage);
|
|
||||||
}
|
|
||||||
ShareAccountCharge updatedCharge = account.updateShareCharge(id, chargeId, amount);
|
|
||||||
updated.add(updatedCharge);
|
|
||||||
} else {
|
|
||||||
if (jsonObject.has("chargeId")) {
|
|
||||||
final Long id = jsonObject.get("chargeId").getAsLong();
|
|
||||||
BigDecimal amount = jsonObject.get("amount").getAsBigDecimal();
|
|
||||||
final Charge charge = this.chargeRepository.findOneWithNotFoundDetection(id);
|
|
||||||
if (!currencyCode.equals(charge.getCurrencyCode())) {
|
|
||||||
final String errorMessage = "Charge and Share Account must have the same currency.";
|
|
||||||
throw new InvalidCurrencyException("charge", "attach.to.share.account", errorMessage);
|
|
||||||
}
|
|
||||||
ChargeTimeType chargeTime = ChargeTimeType.fromInt(charge.getChargeTimeType());
|
|
||||||
ChargeCalculationType chargeCalculation = ChargeCalculationType.fromInt(charge.getChargeCalculation());
|
|
||||||
Boolean status = Boolean.TRUE;
|
|
||||||
ShareAccountCharge accountCharge = ShareAccountCharge.createNewWithoutShareAccount(charge, amount, chargeTime,
|
|
||||||
chargeCalculation, status);
|
|
||||||
account.addShareAccountCharge(accountCharge);
|
|
||||||
updated.add(accountCharge);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return updated;
|
|
||||||
}
|
|
||||||
|
|
||||||
private PeriodFrequencyType extractPeriodType(String paramName, final JsonElement element) {
|
private PeriodFrequencyType extractPeriodType(String paramName, final JsonElement element) {
|
||||||
PeriodFrequencyType frequencyType = PeriodFrequencyType.INVALID;
|
PeriodFrequencyType frequencyType = PeriodFrequencyType.INVALID;
|
||||||
frequencyType = PeriodFrequencyType.fromInt(this.fromApiJsonHelper.extractIntegerWithLocaleNamed(paramName, element));
|
frequencyType = PeriodFrequencyType.fromInt(this.fromApiJsonHelper.extractIntegerWithLocaleNamed(paramName, element));
|
||||||
@@ -546,15 +593,33 @@ public class ShareAccountDataSerializer {
|
|||||||
baseDataValidator.reset().parameter(ShareAccountApiConstants.requesteddate_paramname).value(requestedDate).notNull();
|
baseDataValidator.reset().parameter(ShareAccountApiConstants.requesteddate_paramname).value(requestedDate).notNull();
|
||||||
final Long sharesRequested = this.fromApiJsonHelper.extractLongNamed(ShareAccountApiConstants.requestedshares_paramname, element);
|
final Long sharesRequested = this.fromApiJsonHelper.extractLongNamed(ShareAccountApiConstants.requestedshares_paramname, element);
|
||||||
baseDataValidator.reset().parameter(ShareAccountApiConstants.requestedshares_paramname).value(sharesRequested).notNull();
|
baseDataValidator.reset().parameter(ShareAccountApiConstants.requestedshares_paramname).value(sharesRequested).notNull();
|
||||||
ShareProduct shareProduct = account.getShareProduct() ;
|
ShareProduct shareProduct = account.getShareProduct();
|
||||||
if(sharesRequested != null) {
|
if (sharesRequested != null) {
|
||||||
boolean allowed = shareProduct.isSharesAllowed(sharesRequested) ;
|
Long totalSharesAfterapproval = account.getTotalApprovedShares() + sharesRequested;
|
||||||
if(!allowed) {
|
if(totalSharesAfterapproval > shareProduct.getMaximumClientShares()) {
|
||||||
baseDataValidator.reset().parameter(ShareAccountApiConstants.requestedshares_paramname).value(sharesRequested).failWithCode("differ.from.productdefinition", "Out of range");;
|
baseDataValidator.reset().parameter(ShareAccountApiConstants.requestedshares_paramname).value(sharesRequested)
|
||||||
|
.failWithCode("exceeding.maximum.limit.defined.in.the.shareproduct", "Existing and requested shares count is more than product definition");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
boolean isTransactionBeforeExistingTransactions = false ;
|
||||||
|
Set<ShareAccountTransaction> transactions = account.getShareAccountTransactions() ;
|
||||||
|
for(ShareAccountTransaction transaction: transactions) {
|
||||||
|
if(!transaction.isChargeTransaction()) {
|
||||||
|
LocalDate transactionDate = new LocalDate(transaction.getPurchasedDate()) ;
|
||||||
|
if(requestedDate.isBefore(transactionDate)) {
|
||||||
|
isTransactionBeforeExistingTransactions = true ;
|
||||||
|
break ;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if(isTransactionBeforeExistingTransactions) {
|
||||||
|
baseDataValidator.reset().parameter(ShareAccountApiConstants.requesteddate_paramname)
|
||||||
|
.value(requestedDate)
|
||||||
|
.failWithCodeNoParameterAddedToErrorCode("purchase.transaction.date.cannot.be.before.existing.transactions");
|
||||||
|
}
|
||||||
|
|
||||||
if (!dataValidationErrors.isEmpty()) { throw new PlatformApiDataValidationException(dataValidationErrors); }
|
if (!dataValidationErrors.isEmpty()) { throw new PlatformApiDataValidationException(dataValidationErrors); }
|
||||||
final BigDecimal unitPrice = shareProduct.deriveMarketPrice(requestedDate.toDate()) ;
|
final BigDecimal unitPrice = shareProduct.deriveMarketPrice(requestedDate.toDate());
|
||||||
ShareAccountTransaction purchaseTransaction = new ShareAccountTransaction(requestedDate.toDate(), sharesRequested, unitPrice);
|
ShareAccountTransaction purchaseTransaction = new ShareAccountTransaction(requestedDate.toDate(), sharesRequested, unitPrice);
|
||||||
account.addAdditionalPurchasedShares(purchaseTransaction);
|
account.addAdditionalPurchasedShares(purchaseTransaction);
|
||||||
handleAdditionalSharesChargeTransactions(account, purchaseTransaction);
|
handleAdditionalSharesChargeTransactions(account, purchaseTransaction);
|
||||||
@@ -566,7 +631,7 @@ public class ShareAccountDataSerializer {
|
|||||||
Set<ShareAccountCharge> charges = account.getCharges();
|
Set<ShareAccountCharge> charges = account.getCharges();
|
||||||
BigDecimal totalChargeAmount = BigDecimal.ZERO;
|
BigDecimal totalChargeAmount = BigDecimal.ZERO;
|
||||||
for (ShareAccountCharge charge : charges) {
|
for (ShareAccountCharge charge : charges) {
|
||||||
if (charge.isSharesPurchaseCharge()) {
|
if (charge.isActive() && charge.isSharesPurchaseCharge()) {
|
||||||
BigDecimal amount = charge.updateChargeDetailsForAdditionalSharesRequest(purchaseTransaction.amount());
|
BigDecimal amount = charge.updateChargeDetailsForAdditionalSharesRequest(purchaseTransaction.amount());
|
||||||
ShareAccountChargePaidBy paidBy = new ShareAccountChargePaidBy(purchaseTransaction, charge, amount);
|
ShareAccountChargePaidBy paidBy = new ShareAccountChargePaidBy(purchaseTransaction, charge, amount);
|
||||||
purchaseTransaction.addShareAccountChargePaidBy(paidBy);
|
purchaseTransaction.addShareAccountChargePaidBy(paidBy);
|
||||||
@@ -588,20 +653,21 @@ public class ShareAccountDataSerializer {
|
|||||||
final ArrayList<Long> purchasedShares = new ArrayList<>();
|
final ArrayList<Long> purchasedShares = new ArrayList<>();
|
||||||
if (this.fromApiJsonHelper.parameterExists(ShareAccountApiConstants.requestedshares_paramname, element)) {
|
if (this.fromApiJsonHelper.parameterExists(ShareAccountApiConstants.requestedshares_paramname, element)) {
|
||||||
JsonArray array = this.fromApiJsonHelper.extractJsonArrayNamed(ShareAccountApiConstants.requestedshares_paramname, element);
|
JsonArray array = this.fromApiJsonHelper.extractJsonArrayNamed(ShareAccountApiConstants.requestedshares_paramname, element);
|
||||||
long totalShares = 0 ;
|
long totalShares = 0;
|
||||||
for (JsonElement arrayElement : array) {
|
for (JsonElement arrayElement : array) {
|
||||||
final Long purchasedSharesId = this.fromApiJsonHelper.extractLongNamed(ShareAccountApiConstants.id_paramname, arrayElement);
|
final Long purchasedSharesId = this.fromApiJsonHelper.extractLongNamed(ShareAccountApiConstants.id_paramname, arrayElement);
|
||||||
baseDataValidator.reset().parameter(ShareAccountApiConstants.requestedshares_paramname).value(purchasedSharesId).notBlank() ;
|
baseDataValidator.reset().parameter(ShareAccountApiConstants.requestedshares_paramname).value(purchasedSharesId).notBlank();
|
||||||
ShareAccountTransaction transaction = account.retrievePurchasedShares(purchasedSharesId);
|
ShareAccountTransaction transaction = account.retrievePurchasedShares(purchasedSharesId);
|
||||||
if (transaction != null) {
|
if (transaction != null) {
|
||||||
totalShares+=transaction.getTotalShares().longValue() ;
|
validateTotalSubsribedShares(account, transaction, baseDataValidator) ;
|
||||||
|
totalShares += transaction.getTotalShares().longValue();
|
||||||
transaction.approve();
|
transaction.approve();
|
||||||
updateTotalChargeDerivedForAdditonalShares(account, transaction);
|
updateTotalChargeDerivedForAdditonalShares(account, transaction);
|
||||||
}
|
}
|
||||||
purchasedShares.add(purchasedSharesId);
|
purchasedShares.add(purchasedSharesId);
|
||||||
}
|
}
|
||||||
if(totalShares > 0) {
|
if (totalShares > 0) {
|
||||||
account.updateApprovedShares(new Long(totalShares)) ;
|
account.updateApprovedShares(new Long(totalShares));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (!dataValidationErrors.isEmpty()) { throw new PlatformApiDataValidationException(dataValidationErrors); }
|
if (!dataValidationErrors.isEmpty()) { throw new PlatformApiDataValidationException(dataValidationErrors); }
|
||||||
@@ -614,11 +680,14 @@ public class ShareAccountDataSerializer {
|
|||||||
if (paidBySet != null && !paidBySet.isEmpty()) {
|
if (paidBySet != null && !paidBySet.isEmpty()) {
|
||||||
for (ShareAccountChargePaidBy chargePaidBy : paidBySet) {
|
for (ShareAccountChargePaidBy chargePaidBy : paidBySet) {
|
||||||
ShareAccountCharge charge = chargePaidBy.getCharge();
|
ShareAccountCharge charge = chargePaidBy.getCharge();
|
||||||
if (charge.isSharesPurchaseCharge()) {
|
if (charge.isActive() && charge.isSharesPurchaseCharge()) {
|
||||||
Money money = Money.of(shareAccount.getCurrency(), chargePaidBy.getAmount());
|
Money money = Money.of(shareAccount.getCurrency(), chargePaidBy.getAmount());
|
||||||
charge.updatePaidAmountBy(money);
|
charge.updatePaidAmountBy(money);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if (!transaction.isChargeTransaction()) {
|
||||||
|
transaction.addAmountPaid(transaction.chargeAmount());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -631,20 +700,20 @@ public class ShareAccountDataSerializer {
|
|||||||
JsonElement element = jsonCommand.parsedJson();
|
JsonElement element = jsonCommand.parsedJson();
|
||||||
final ArrayList<Long> purchasedShares = new ArrayList<>();
|
final ArrayList<Long> purchasedShares = new ArrayList<>();
|
||||||
if (this.fromApiJsonHelper.parameterExists(ShareAccountApiConstants.requestedshares_paramname, element)) {
|
if (this.fromApiJsonHelper.parameterExists(ShareAccountApiConstants.requestedshares_paramname, element)) {
|
||||||
long totalShares = 0 ;
|
long totalShares = 0;
|
||||||
JsonArray array = this.fromApiJsonHelper.extractJsonArrayNamed(ShareAccountApiConstants.requestedshares_paramname, element);
|
JsonArray array = this.fromApiJsonHelper.extractJsonArrayNamed(ShareAccountApiConstants.requestedshares_paramname, element);
|
||||||
for (JsonElement arrayElement : array) {
|
for (JsonElement arrayElement : array) {
|
||||||
final Long purchasedSharesId = this.fromApiJsonHelper.extractLongNamed(ShareAccountApiConstants.id_paramname, arrayElement);
|
final Long purchasedSharesId = this.fromApiJsonHelper.extractLongNamed(ShareAccountApiConstants.id_paramname, arrayElement);
|
||||||
ShareAccountTransaction shares = account.retrievePurchasedShares(purchasedSharesId);
|
ShareAccountTransaction shares = account.retrievePurchasedShares(purchasedSharesId);
|
||||||
if (shares != null) {
|
if (shares != null) {
|
||||||
shares.reject();
|
shares.reject();
|
||||||
updateTotalChargeDerivedForAdditonalSharesReject(account, shares) ;
|
updateTotalChargeDerivedForAdditonalSharesReject(account, shares);
|
||||||
totalShares +=shares.getTotalShares().longValue() ;
|
totalShares += shares.getTotalShares().longValue();
|
||||||
}
|
}
|
||||||
purchasedShares.add(purchasedSharesId);
|
purchasedShares.add(purchasedSharesId);
|
||||||
}
|
}
|
||||||
if(totalShares > 0) {
|
if (totalShares > 0) {
|
||||||
account.removePendingShares(new Long(totalShares)) ;
|
account.removePendingShares(new Long(totalShares));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
actualChanges.put(ShareAccountApiConstants.requestedshares_paramname, purchasedShares);
|
actualChanges.put(ShareAccountApiConstants.requestedshares_paramname, purchasedShares);
|
||||||
@@ -656,11 +725,14 @@ public class ShareAccountDataSerializer {
|
|||||||
if (paidBySet != null && !paidBySet.isEmpty()) {
|
if (paidBySet != null && !paidBySet.isEmpty()) {
|
||||||
for (ShareAccountChargePaidBy chargePaidBy : paidBySet) {
|
for (ShareAccountChargePaidBy chargePaidBy : paidBySet) {
|
||||||
ShareAccountCharge charge = chargePaidBy.getCharge();
|
ShareAccountCharge charge = chargePaidBy.getCharge();
|
||||||
if (charge.isSharesPurchaseCharge()) {
|
if (charge.isActive() && charge.isSharesPurchaseCharge()) {
|
||||||
Money money = Money.of(shareAccount.getCurrency(), chargePaidBy.getAmount());
|
Money money = Money.of(shareAccount.getCurrency(), chargePaidBy.getAmount());
|
||||||
charge.updatePaidAmountBy(money);
|
charge.updatePaidAmountBy(money);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if (!transaction.isChargeTransaction()) {
|
||||||
|
transaction.addAmountPaid(transaction.chargeAmount());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -683,19 +755,116 @@ public class ShareAccountDataSerializer {
|
|||||||
final BigDecimal unitPrice = this.fromApiJsonHelper.extractBigDecimalNamed(ShareAccountApiConstants.purchasedprice_paramname,
|
final BigDecimal unitPrice = this.fromApiJsonHelper.extractBigDecimalNamed(ShareAccountApiConstants.purchasedprice_paramname,
|
||||||
element, locale);
|
element, locale);
|
||||||
baseDataValidator.reset().parameter(ShareAccountApiConstants.purchasedprice_paramname).value(unitPrice).notNull().positiveAmount();
|
baseDataValidator.reset().parameter(ShareAccountApiConstants.purchasedprice_paramname).value(unitPrice).notNull().positiveAmount();
|
||||||
|
boolean isTransactionBeforeExistingTransactions = false ;
|
||||||
|
Set<ShareAccountTransaction> transactions = account.getShareAccountTransactions() ;
|
||||||
|
for(ShareAccountTransaction transaction: transactions) {
|
||||||
|
if(!transaction.isChargeTransaction()) {
|
||||||
|
LocalDate transactionDate = new LocalDate(transaction.getPurchasedDate()) ;
|
||||||
|
if(requestedDate.isBefore(transactionDate)) {
|
||||||
|
isTransactionBeforeExistingTransactions = true ;
|
||||||
|
break ;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if(isTransactionBeforeExistingTransactions) {
|
||||||
|
baseDataValidator.reset().parameter(ShareAccountApiConstants.requesteddate_paramname)
|
||||||
|
.value(requestedDate)
|
||||||
|
.failWithCodeNoParameterAddedToErrorCode("redeem.transaction.date.cannot.be.before.existing.transactions");
|
||||||
|
}
|
||||||
|
if (!dataValidationErrors.isEmpty()) { throw new PlatformApiDataValidationException(dataValidationErrors); }
|
||||||
|
|
||||||
ShareAccountTransaction transaction = ShareAccountTransaction.createRedeemTransaction(requestedDate.toDate(), sharesRequested,
|
ShareAccountTransaction transaction = ShareAccountTransaction.createRedeemTransaction(requestedDate.toDate(), sharesRequested,
|
||||||
unitPrice);
|
unitPrice);
|
||||||
account.addAdditionalPurchasedShares(transaction);
|
account.addAdditionalPurchasedShares(transaction);
|
||||||
actualChanges.put(ShareAccountApiConstants.requestedshares_paramname, transaction);
|
actualChanges.put(ShareAccountApiConstants.requestedshares_paramname, transaction);
|
||||||
|
validateRedeemRequest(account, transaction, baseDataValidator, dataValidationErrors) ;
|
||||||
handleRedeemSharesChargeTransactions(account, transaction);
|
handleRedeemSharesChargeTransactions(account, transaction);
|
||||||
return actualChanges;
|
return actualChanges;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void validateRedeemRequest(final ShareAccount account, ShareAccountTransaction redeemTransaction,
|
||||||
|
final DataValidatorBuilder baseDataValidator, final List<ApiParameterError> dataValidationErrors ) {
|
||||||
|
|
||||||
|
if (account.getTotalApprovedShares() < redeemTransaction.getTotalShares()) {
|
||||||
|
baseDataValidator.reset().parameter(ShareAccountApiConstants.requestedshares_paramname)
|
||||||
|
.value(redeemTransaction.getTotalShares())
|
||||||
|
.failWithCodeNoParameterAddedToErrorCode("cannot.be.redeemed.due.to.insufficient.shares");
|
||||||
|
}
|
||||||
|
if (!dataValidationErrors.isEmpty()) { throw new PlatformApiDataValidationException(dataValidationErrors); }
|
||||||
|
|
||||||
|
LocalDate redeemDate = new LocalDate(redeemTransaction.getPurchasedDate());
|
||||||
|
final Integer lockinPeriod = account.getLockinPeriodFrequency();
|
||||||
|
final PeriodFrequencyType periodType = account.getLockinPeriodFrequencyType();
|
||||||
|
if (lockinPeriod == null && periodType == null) { return; }
|
||||||
|
Long totalSharesCanBeRedeemed = new Long(0);
|
||||||
|
Long totalSharesPurchasedBeforeRedeem = new Long(0) ;
|
||||||
|
boolean isPurchaseTransactionExist = false ;
|
||||||
|
|
||||||
|
Set<ShareAccountTransaction> transactions = account.getShareAccountTransactions();
|
||||||
|
for (ShareAccountTransaction transaction : transactions) {
|
||||||
|
if (transaction.isActive() && !transaction.isChargeTransaction()) {
|
||||||
|
LocalDate purchaseDate = new LocalDate(transaction.getPurchasedDate());
|
||||||
|
LocalDate lockinDate = deriveLockinPeriodDuration(lockinPeriod, periodType, purchaseDate);
|
||||||
|
if (!lockinDate.isAfter(redeemDate)) {
|
||||||
|
if (transaction.isPurchasTransaction()) {
|
||||||
|
totalSharesCanBeRedeemed += transaction.getTotalShares();
|
||||||
|
} else if (transaction.isRedeemTransaction()) {
|
||||||
|
totalSharesCanBeRedeemed -= transaction.getTotalShares();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if(!purchaseDate.isAfter(redeemDate)) {
|
||||||
|
isPurchaseTransactionExist = true ;
|
||||||
|
if (transaction.isPurchasTransaction()) {
|
||||||
|
totalSharesPurchasedBeforeRedeem += transaction.getTotalShares();
|
||||||
|
} else if (transaction.isRedeemTransaction()) {
|
||||||
|
totalSharesPurchasedBeforeRedeem -= transaction.getTotalShares();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if(!isPurchaseTransactionExist) {
|
||||||
|
baseDataValidator.reset().parameter(ShareAccountApiConstants.requesteddate_paramname)
|
||||||
|
.value(redeemDate)
|
||||||
|
.failWithCodeNoParameterAddedToErrorCode("no.purchase.transaction.found.before.redeem.date");
|
||||||
|
}else if (totalSharesPurchasedBeforeRedeem < redeemTransaction.getTotalShares()) {
|
||||||
|
baseDataValidator.reset().parameter(ShareAccountApiConstants.requestedshares_paramname)
|
||||||
|
.value(redeemTransaction.getTotalShares())
|
||||||
|
.failWithCodeNoParameterAddedToErrorCode("cannot.be.redeemed.due.to.insufficient.shares.for.this.redeem.date");
|
||||||
|
}else if (totalSharesCanBeRedeemed < redeemTransaction.getTotalShares()) {
|
||||||
|
baseDataValidator.reset().parameter(ShareAccountApiConstants.requestedshares_paramname)
|
||||||
|
.value(redeemTransaction.getTotalShares())
|
||||||
|
.failWithCodeNoParameterAddedToErrorCode("cannot.be.redeemed.due.to.lockinperiod");
|
||||||
|
}
|
||||||
|
if (!dataValidationErrors.isEmpty()) { throw new PlatformApiDataValidationException(dataValidationErrors); }
|
||||||
|
}
|
||||||
|
|
||||||
|
private LocalDate deriveLockinPeriodDuration(final Integer lockinPeriod, final PeriodFrequencyType periodType, LocalDate purchaseDate) {
|
||||||
|
LocalDate lockinDate = null ;
|
||||||
|
switch(periodType) {
|
||||||
|
case INVALID: //It never comes in to this state.
|
||||||
|
break ;
|
||||||
|
case DAYS:
|
||||||
|
lockinDate = purchaseDate.plusDays(lockinPeriod) ;
|
||||||
|
break ;
|
||||||
|
case WEEKS:
|
||||||
|
lockinDate = purchaseDate.plusWeeks(lockinPeriod) ;
|
||||||
|
break ;
|
||||||
|
case MONTHS:
|
||||||
|
lockinDate = purchaseDate.plusMonths(lockinPeriod) ;
|
||||||
|
break ;
|
||||||
|
case YEARS:
|
||||||
|
lockinDate = purchaseDate.plusYears(lockinPeriod) ;
|
||||||
|
break ;
|
||||||
|
}
|
||||||
|
return lockinDate ;
|
||||||
|
}
|
||||||
|
|
||||||
private void handleRedeemSharesChargeTransactions(final ShareAccount account, final ShareAccountTransaction transaction) {
|
private void handleRedeemSharesChargeTransactions(final ShareAccount account, final ShareAccountTransaction transaction) {
|
||||||
Set<ShareAccountCharge> charges = account.getCharges();
|
Set<ShareAccountCharge> charges = account.getCharges();
|
||||||
BigDecimal totalChargeAmount = BigDecimal.ZERO;
|
BigDecimal totalChargeAmount = BigDecimal.ZERO;
|
||||||
for (ShareAccountCharge charge : charges) {
|
for (ShareAccountCharge charge : charges) {
|
||||||
if (charge.isSharesRedeemCharge()) {
|
if (charge.isActive() && charge.isSharesRedeemCharge()) {
|
||||||
BigDecimal amount = charge.updateChargeDetailsForAdditionalSharesRequest(transaction.amount());
|
BigDecimal amount = charge.updateChargeDetailsForAdditionalSharesRequest(transaction.amount());
|
||||||
ShareAccountChargePaidBy paidBy = new ShareAccountChargePaidBy(transaction, charge, amount);
|
ShareAccountChargePaidBy paidBy = new ShareAccountChargePaidBy(transaction, charge, amount);
|
||||||
transaction.addShareAccountChargePaidBy(paidBy);
|
transaction.addShareAccountChargePaidBy(paidBy);
|
||||||
@@ -707,14 +876,13 @@ public class ShareAccountDataSerializer {
|
|||||||
if (paidBySet != null && !paidBySet.isEmpty()) {
|
if (paidBySet != null && !paidBySet.isEmpty()) {
|
||||||
for (ShareAccountChargePaidBy chargePaidBy : paidBySet) {
|
for (ShareAccountChargePaidBy chargePaidBy : paidBySet) {
|
||||||
ShareAccountCharge charge = chargePaidBy.getCharge();
|
ShareAccountCharge charge = chargePaidBy.getCharge();
|
||||||
if (charge.isSharesRedeemCharge()) {
|
if (charge.isActive() && charge.isSharesRedeemCharge()) {
|
||||||
Money money = Money.of(account.getCurrency(), chargePaidBy.getAmount());
|
Money money = Money.of(account.getCurrency(), chargePaidBy.getAmount());
|
||||||
charge.updatePaidAmountBy(money);
|
charge.updatePaidAmountBy(money);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
transaction.addAmountPaid(transaction.chargeAmount());
|
||||||
// transaction.adjustRedeemAmount();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public Map<String, Object> validateAndClose(JsonCommand jsonCommand, ShareAccount account) {
|
public Map<String, Object> validateAndClose(JsonCommand jsonCommand, ShareAccount account) {
|
||||||
@@ -727,15 +895,35 @@ public class ShareAccountDataSerializer {
|
|||||||
JsonElement element = jsonCommand.parsedJson();
|
JsonElement element = jsonCommand.parsedJson();
|
||||||
LocalDate closedDate = this.fromApiJsonHelper.extractLocalDateNamed(ShareAccountApiConstants.closeddate_paramname, element);
|
LocalDate closedDate = this.fromApiJsonHelper.extractLocalDateNamed(ShareAccountApiConstants.closeddate_paramname, element);
|
||||||
baseDataValidator.reset().parameter(ShareAccountApiConstants.approveddate_paramname).value(closedDate).notNull();
|
baseDataValidator.reset().parameter(ShareAccountApiConstants.approveddate_paramname).value(closedDate).notNull();
|
||||||
|
boolean isTransactionBeforeExistingTransactions = false ;
|
||||||
|
Set<ShareAccountTransaction> transactions = account.getShareAccountTransactions() ;
|
||||||
|
for(ShareAccountTransaction transaction: transactions) {
|
||||||
|
if(!transaction.isChargeTransaction()) {
|
||||||
|
LocalDate transactionDate = new LocalDate(transaction.getPurchasedDate()) ;
|
||||||
|
if(closedDate.isBefore(transactionDate)) {
|
||||||
|
isTransactionBeforeExistingTransactions = true ;
|
||||||
|
break ;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if(isTransactionBeforeExistingTransactions) {
|
||||||
|
baseDataValidator.reset().parameter(ShareAccountApiConstants.closeddate_paramname)
|
||||||
|
.value(closedDate)
|
||||||
|
.failWithCodeNoParameterAddedToErrorCode("share.account.cannot.be.closed.before.existing.transactions");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!dataValidationErrors.isEmpty()) { throw new PlatformApiDataValidationException(dataValidationErrors); }
|
||||||
|
|
||||||
AppUser approvedUser = this.platformSecurityContext.authenticatedUser();
|
AppUser approvedUser = this.platformSecurityContext.authenticatedUser();
|
||||||
final BigDecimal unitPrice = account.getShareProduct().deriveMarketPrice(DateUtils.getDateOfTenant()) ;
|
final BigDecimal unitPrice = account.getShareProduct().deriveMarketPrice(DateUtils.getDateOfTenant());
|
||||||
ShareAccountTransaction transaction = ShareAccountTransaction.createRedeemTransaction(closedDate.toDate(), account.getTotalApprovedShares(), unitPrice) ;
|
ShareAccountTransaction transaction = ShareAccountTransaction.createRedeemTransaction(closedDate.toDate(),
|
||||||
|
account.getTotalApprovedShares(), unitPrice);
|
||||||
account.addAdditionalPurchasedShares(transaction);
|
account.addAdditionalPurchasedShares(transaction);
|
||||||
account.close(closedDate.toDate(), approvedUser);
|
account.close(closedDate.toDate(), approvedUser);
|
||||||
handleRedeemSharesChargeTransactions(account, transaction) ;
|
handleRedeemSharesChargeTransactions(account, transaction);
|
||||||
actualChanges.put(ShareAccountApiConstants.requestedshares_paramname, transaction);
|
actualChanges.put(ShareAccountApiConstants.requestedshares_paramname, transaction);
|
||||||
updateTotalChargeDerived(account);
|
updateTotalChargeDerived(account);
|
||||||
if (!dataValidationErrors.isEmpty()) { throw new PlatformApiDataValidationException(dataValidationErrors); }
|
|
||||||
return actualChanges;
|
return actualChanges;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+2
-2
@@ -20,9 +20,9 @@ package org.apache.fineract.portfolio.shareaccounts.service;
|
|||||||
|
|
||||||
import java.util.Collection;
|
import java.util.Collection;
|
||||||
|
|
||||||
import org.apache.fineract.portfolio.shareaccounts.data.PurchasedSharesData;
|
import org.apache.fineract.portfolio.shareaccounts.data.ShareAccountTransactionData;
|
||||||
|
|
||||||
public interface PurchasedSharesReadPlatformService {
|
public interface PurchasedSharesReadPlatformService {
|
||||||
|
|
||||||
public Collection<PurchasedSharesData> retrievePurchasedShares(final Long accountId) ;
|
public Collection<ShareAccountTransactionData> retrievePurchasedShares(final Long accountId) ;
|
||||||
}
|
}
|
||||||
|
|||||||
+10
-7
@@ -26,7 +26,7 @@ import java.util.Collection;
|
|||||||
import org.apache.fineract.infrastructure.core.data.EnumOptionData;
|
import org.apache.fineract.infrastructure.core.data.EnumOptionData;
|
||||||
import org.apache.fineract.infrastructure.core.domain.JdbcSupport;
|
import org.apache.fineract.infrastructure.core.domain.JdbcSupport;
|
||||||
import org.apache.fineract.infrastructure.core.service.RoutingDataSource;
|
import org.apache.fineract.infrastructure.core.service.RoutingDataSource;
|
||||||
import org.apache.fineract.portfolio.shareaccounts.data.PurchasedSharesData;
|
import org.apache.fineract.portfolio.shareaccounts.data.ShareAccountTransactionData;
|
||||||
import org.joda.time.LocalDate;
|
import org.joda.time.LocalDate;
|
||||||
import org.springframework.beans.factory.annotation.Autowired;
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
import org.springframework.jdbc.core.JdbcTemplate;
|
import org.springframework.jdbc.core.JdbcTemplate;
|
||||||
@@ -44,26 +44,27 @@ public class PurchasedSharesReadPlatformServiceImpl implements
|
|||||||
this.jdbcTemplate = new JdbcTemplate(dataSource) ;
|
this.jdbcTemplate = new JdbcTemplate(dataSource) ;
|
||||||
}
|
}
|
||||||
@Override
|
@Override
|
||||||
public Collection<PurchasedSharesData> retrievePurchasedShares(
|
public Collection<ShareAccountTransactionData> retrievePurchasedShares(
|
||||||
Long accountId) {
|
Long accountId) {
|
||||||
PurchasedSharesDataRowMapper mapper = new PurchasedSharesDataRowMapper() ;
|
PurchasedSharesDataRowMapper mapper = new PurchasedSharesDataRowMapper() ;
|
||||||
final String sql = "select " + mapper.schema() + " where saps.account_id=?";
|
final String sql = "select " + mapper.schema() + " where saps.account_id=? and saps.is_active = 1";
|
||||||
return this.jdbcTemplate.query(sql, mapper, new Object[] { accountId});
|
return this.jdbcTemplate.query(sql, mapper, new Object[] { accountId});
|
||||||
}
|
}
|
||||||
|
|
||||||
private final static class PurchasedSharesDataRowMapper implements RowMapper<PurchasedSharesData> {
|
private final static class PurchasedSharesDataRowMapper implements RowMapper<ShareAccountTransactionData> {
|
||||||
|
|
||||||
private final String schema ;
|
private final String schema ;
|
||||||
|
|
||||||
public PurchasedSharesDataRowMapper() {
|
public PurchasedSharesDataRowMapper() {
|
||||||
StringBuffer buff = new StringBuffer()
|
StringBuffer buff = new StringBuffer()
|
||||||
.append("saps.id, saps.account_id, saps.transaction_date, saps.total_shares, saps.unit_price, ")
|
.append("saps.id, saps.account_id, saps.transaction_date, saps.total_shares, saps.unit_price, ")
|
||||||
.append("saps.status_enum, saps.type_enum, saps.amount, saps.charge_amount as chargeamount ")
|
.append("saps.status_enum, saps.type_enum, saps.amount, saps.charge_amount as chargeamount, ")
|
||||||
|
.append("saps.amount_paid as amountPaid")
|
||||||
.append(" from m_share_account_transactions saps ");
|
.append(" from m_share_account_transactions saps ");
|
||||||
schema = buff.toString() ;
|
schema = buff.toString() ;
|
||||||
}
|
}
|
||||||
@Override
|
@Override
|
||||||
public PurchasedSharesData mapRow(ResultSet rs, int rowNum)
|
public ShareAccountTransactionData mapRow(ResultSet rs, int rowNum)
|
||||||
throws SQLException {
|
throws SQLException {
|
||||||
final Long id = rs.getLong("id") ;
|
final Long id = rs.getLong("id") ;
|
||||||
final Long accountId = rs.getLong("account_id") ;
|
final Long accountId = rs.getLong("account_id") ;
|
||||||
@@ -76,7 +77,9 @@ public class PurchasedSharesReadPlatformServiceImpl implements
|
|||||||
final EnumOptionData typeEnum = SharesEnumerations.purchasedSharesEnum(type) ;
|
final EnumOptionData typeEnum = SharesEnumerations.purchasedSharesEnum(type) ;
|
||||||
final BigDecimal amount = JdbcSupport.getBigDecimalDefaultToZeroIfNull(rs, "amount") ;
|
final BigDecimal amount = JdbcSupport.getBigDecimalDefaultToZeroIfNull(rs, "amount") ;
|
||||||
final BigDecimal chargeAmount = JdbcSupport.getBigDecimalDefaultToZeroIfNull(rs, "chargeamount") ;
|
final BigDecimal chargeAmount = JdbcSupport.getBigDecimalDefaultToZeroIfNull(rs, "chargeamount") ;
|
||||||
return new PurchasedSharesData(id,accountId, purchasedDate, numberOfShares, purchasedPrice, statusEnum, typeEnum, amount, chargeAmount);
|
final BigDecimal amountPaid = JdbcSupport.getBigDecimalDefaultToZeroIfNull(rs, "amountPaid") ;
|
||||||
|
|
||||||
|
return new ShareAccountTransactionData(id,accountId, purchasedDate, numberOfShares, purchasedPrice, statusEnum, typeEnum, amount, chargeAmount, amountPaid);
|
||||||
}
|
}
|
||||||
|
|
||||||
public String schema() {
|
public String schema() {
|
||||||
|
|||||||
+3
-1
@@ -80,6 +80,7 @@ public class ShareAccountChargeReadPlatformServiceImpl implements
|
|||||||
.append("sc.charge_calculation_enum as chargeCalculation, c.is_active as isActive, ")
|
.append("sc.charge_calculation_enum as chargeCalculation, c.is_active as isActive, ")
|
||||||
.append("c.currency_code as currencyCode, oc.name as currencyName, ")
|
.append("c.currency_code as currencyCode, oc.name as currencyName, ")
|
||||||
.append("oc.decimal_places as currencyDecimalPlaces, oc.currency_multiplesof as inMultiplesOf, oc.display_symbol as currencyDisplaySymbol, ")
|
.append("oc.decimal_places as currencyDecimalPlaces, oc.currency_multiplesof as inMultiplesOf, oc.display_symbol as currencyDisplaySymbol, ")
|
||||||
|
.append("sc.charge_amount_or_percentage, ")
|
||||||
.append("oc.internationalized_name_code as currencyNameCode from m_charge c ")
|
.append("oc.internationalized_name_code as currencyNameCode from m_charge c ")
|
||||||
.append("join m_organisation_currency oc on c.currency_code = oc.code ")
|
.append("join m_organisation_currency oc on c.currency_code = oc.code ")
|
||||||
.append("join m_share_account_charge sc on sc.charge_id = c.id ");
|
.append("join m_share_account_charge sc on sc.charge_id = c.id ");
|
||||||
@@ -132,13 +133,14 @@ public class ShareAccountChargeReadPlatformServiceImpl implements
|
|||||||
final EnumOptionData chargeCalculationType = ChargeEnumerations
|
final EnumOptionData chargeCalculationType = ChargeEnumerations
|
||||||
.chargeCalculationType(chargeCalculation);
|
.chargeCalculationType(chargeCalculation);
|
||||||
final Boolean isActive = rs.getBoolean("isActive");
|
final Boolean isActive = rs.getBoolean("isActive");
|
||||||
|
final BigDecimal chargeamountorpercentage = rs.getBigDecimal("charge_amount_or_percentage") ;
|
||||||
|
|
||||||
final Collection<ChargeData> chargeOptions = null;
|
final Collection<ChargeData> chargeOptions = null;
|
||||||
return new ShareAccountChargeData(id, chargeId, accountId, name,
|
return new ShareAccountChargeData(id, chargeId, accountId, name,
|
||||||
currency, amount, amountPaid, amountWaived,
|
currency, amount, amountPaid, amountWaived,
|
||||||
amountWrittenOff, amountOutstanding, chargeTimeType,
|
amountWrittenOff, amountOutstanding, chargeTimeType,
|
||||||
chargeCalculationType, percentageOf,
|
chargeCalculationType, percentageOf,
|
||||||
amountPercentageAppliedTo, chargeOptions, isActive);
|
amountPercentageAppliedTo, chargeOptions, isActive, chargeamountorpercentage);
|
||||||
}
|
}
|
||||||
|
|
||||||
public String schema() {
|
public String schema() {
|
||||||
|
|||||||
+17
-13
@@ -42,9 +42,10 @@ import org.apache.fineract.portfolio.client.service.ClientReadPlatformService;
|
|||||||
import org.apache.fineract.portfolio.products.constants.ProductsApiConstants;
|
import org.apache.fineract.portfolio.products.constants.ProductsApiConstants;
|
||||||
import org.apache.fineract.portfolio.products.data.ProductData;
|
import org.apache.fineract.portfolio.products.data.ProductData;
|
||||||
import org.apache.fineract.portfolio.products.service.ProductReadPlatformService;
|
import org.apache.fineract.portfolio.products.service.ProductReadPlatformService;
|
||||||
|
import org.apache.fineract.portfolio.savings.DepositAccountType;
|
||||||
import org.apache.fineract.portfolio.savings.data.SavingsAccountData;
|
import org.apache.fineract.portfolio.savings.data.SavingsAccountData;
|
||||||
import org.apache.fineract.portfolio.savings.service.SavingsAccountReadPlatformService;
|
import org.apache.fineract.portfolio.savings.service.SavingsAccountReadPlatformService;
|
||||||
import org.apache.fineract.portfolio.shareaccounts.data.PurchasedSharesData;
|
import org.apache.fineract.portfolio.shareaccounts.data.ShareAccountTransactionData;
|
||||||
import org.apache.fineract.portfolio.shareaccounts.data.ShareAccountApplicationTimelineData;
|
import org.apache.fineract.portfolio.shareaccounts.data.ShareAccountApplicationTimelineData;
|
||||||
import org.apache.fineract.portfolio.shareaccounts.data.ShareAccountDividendData;
|
import org.apache.fineract.portfolio.shareaccounts.data.ShareAccountDividendData;
|
||||||
import org.apache.fineract.portfolio.shareaccounts.data.ShareAccountStatusEnumData;
|
import org.apache.fineract.portfolio.shareaccounts.data.ShareAccountStatusEnumData;
|
||||||
@@ -114,7 +115,7 @@ public class ShareAccountReadPlatformServiceImpl implements ShareAccountReadPlat
|
|||||||
final Collection<EnumOptionData> minimumActivePeriodFrequencyTypeOptions = this.shareProductDropdownReadPlatformService
|
final Collection<EnumOptionData> minimumActivePeriodFrequencyTypeOptions = this.shareProductDropdownReadPlatformService
|
||||||
.retrieveMinimumActivePeriodFrequencyTypeOptions();
|
.retrieveMinimumActivePeriodFrequencyTypeOptions();
|
||||||
final Collection<SavingsAccountData> clientSavingsAccounts = this.savingsAccountReadPlatformService
|
final Collection<SavingsAccountData> clientSavingsAccounts = this.savingsAccountReadPlatformService
|
||||||
.retrieveAllForLookup(clientId);
|
.retrieveActiveForLookup(clientId, DepositAccountType.SAVINGS_DEPOSIT, productData.getCurrency().code());
|
||||||
toReturn = new ShareAccountData(client.id(), client.displayName(), productData.getCurrency(), charges, marketPrice,
|
toReturn = new ShareAccountData(client.id(), client.displayName(), productData.getCurrency(), charges, marketPrice,
|
||||||
minimumActivePeriodFrequencyTypeOptions, lockinPeriodFrequencyTypeOptions, clientSavingsAccounts, productData.getNominaltShares());
|
minimumActivePeriodFrequencyTypeOptions, lockinPeriodFrequencyTypeOptions, clientSavingsAccounts, productData.getNominaltShares());
|
||||||
} else {
|
} else {
|
||||||
@@ -143,7 +144,7 @@ public class ShareAccountReadPlatformServiceImpl implements ShareAccountReadPlat
|
|||||||
@Override
|
@Override
|
||||||
public ShareAccountData retrieveOne(final Long id, final boolean includeTemplate) {
|
public ShareAccountData retrieveOne(final Long id, final boolean includeTemplate) {
|
||||||
Collection<ShareAccountChargeData> charges = this.shareAccountChargeReadPlatformService.retrieveAccountCharges(id, "active");
|
Collection<ShareAccountChargeData> charges = this.shareAccountChargeReadPlatformService.retrieveAccountCharges(id, "active");
|
||||||
Collection<PurchasedSharesData> purchasedShares = this.purchasedSharesReadPlatformService.retrievePurchasedShares(id);
|
Collection<ShareAccountTransactionData> purchasedShares = this.purchasedSharesReadPlatformService.retrievePurchasedShares(id);
|
||||||
|
|
||||||
ShareAccountMapper mapper = new ShareAccountMapper(charges, purchasedShares);
|
ShareAccountMapper mapper = new ShareAccountMapper(charges, purchasedShares);
|
||||||
String query = "select " + mapper.schema() + "where sa.id=?";
|
String query = "select " + mapper.schema() + "where sa.id=?";
|
||||||
@@ -161,8 +162,8 @@ public class ShareAccountReadPlatformServiceImpl implements ShareAccountReadPlat
|
|||||||
final Collection<EnumOptionData> lockinPeriodFrequencyTypeOptions = this.shareProductDropdownReadPlatformService
|
final Collection<EnumOptionData> lockinPeriodFrequencyTypeOptions = this.shareProductDropdownReadPlatformService
|
||||||
.retrieveLockinPeriodFrequencyTypeOptions();
|
.retrieveLockinPeriodFrequencyTypeOptions();
|
||||||
final Collection<EnumOptionData> minimumActivePeriodFrequencyTypeOptions = lockinPeriodFrequencyTypeOptions;
|
final Collection<EnumOptionData> minimumActivePeriodFrequencyTypeOptions = lockinPeriodFrequencyTypeOptions;
|
||||||
final Collection<SavingsAccountData> clientSavingsAccounts = this.savingsAccountReadPlatformService.retrieveAllForLookup(data
|
final Collection<SavingsAccountData> clientSavingsAccounts = this.savingsAccountReadPlatformService
|
||||||
.getClientId());
|
.retrieveActiveForLookup(data.getClientId(), DepositAccountType.SAVINGS_DEPOSIT, productData.getCurrency().code());
|
||||||
Collection<ProductData> productOptions = service.retrieveAllForLookup();
|
Collection<ProductData> productOptions = service.retrieveAllForLookup();
|
||||||
final Collection<ChargeData> chargeOptions = this.chargeReadPlatformService.retrieveSharesApplicableCharges();
|
final Collection<ChargeData> chargeOptions = this.chargeReadPlatformService.retrieveSharesApplicableCharges();
|
||||||
data = ShareAccountData.template(data, productOptions, chargeOptions, clientSavingsAccounts, lockinPeriodFrequencyTypeOptions,
|
data = ShareAccountData.template(data, productOptions, chargeOptions, clientSavingsAccounts, lockinPeriodFrequencyTypeOptions,
|
||||||
@@ -224,11 +225,11 @@ public class ShareAccountReadPlatformServiceImpl implements ShareAccountReadPlat
|
|||||||
private final static class ShareAccountMapper implements RowMapper<ShareAccountData> {
|
private final static class ShareAccountMapper implements RowMapper<ShareAccountData> {
|
||||||
|
|
||||||
private final Collection<ShareAccountChargeData> charges;
|
private final Collection<ShareAccountChargeData> charges;
|
||||||
private final Collection<PurchasedSharesData> purchasedShares;
|
private final Collection<ShareAccountTransactionData> purchasedShares;
|
||||||
|
|
||||||
private final String schema;
|
private final String schema;
|
||||||
|
|
||||||
public ShareAccountMapper(final Collection<ShareAccountChargeData> charges, final Collection<PurchasedSharesData> purchasedShares) {
|
public ShareAccountMapper(final Collection<ShareAccountChargeData> charges, final Collection<ShareAccountTransactionData> purchasedShares) {
|
||||||
this.charges = charges;
|
this.charges = charges;
|
||||||
this.purchasedShares = purchasedShares;
|
this.purchasedShares = purchasedShares;
|
||||||
StringBuffer buff = new StringBuffer()
|
StringBuffer buff = new StringBuffer()
|
||||||
@@ -392,7 +393,7 @@ public class ShareAccountReadPlatformServiceImpl implements ShareAccountReadPlat
|
|||||||
final Boolean allowdividendsforinactiveclients = null;
|
final Boolean allowdividendsforinactiveclients = null;
|
||||||
|
|
||||||
final Collection<ShareAccountChargeData> charges = null;
|
final Collection<ShareAccountChargeData> charges = null;
|
||||||
final Collection<PurchasedSharesData> purchasedSharesData = new ArrayList<>();
|
final Collection<ShareAccountTransactionData> purchasedSharesData = new ArrayList<>();
|
||||||
final Integer lockinPeriod = null;
|
final Integer lockinPeriod = null;
|
||||||
final EnumOptionData lockPeriodTypeEnum = null;
|
final EnumOptionData lockPeriodTypeEnum = null;
|
||||||
final Integer minimumActivePeriod = null;
|
final Integer minimumActivePeriod = null;
|
||||||
@@ -418,19 +419,21 @@ public class ShareAccountReadPlatformServiceImpl implements ShareAccountReadPlat
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private final static class PurchasedSharesDataRowMapper implements RowMapper<PurchasedSharesData> {
|
private final static class PurchasedSharesDataRowMapper implements RowMapper<ShareAccountTransactionData> {
|
||||||
|
|
||||||
private final String schema;
|
private final String schema;
|
||||||
|
|
||||||
public PurchasedSharesDataRowMapper() {
|
public PurchasedSharesDataRowMapper() {
|
||||||
StringBuffer buff = new StringBuffer()
|
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.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 ");
|
.append("saps.status_enum as purchaseStatus, saps.type_enum as purchaseType, saps.amount as amount, saps.charge_amount as chargeamount, ")
|
||||||
|
.append("saps.amount_paid as amountPaid ");
|
||||||
|
|
||||||
schema = buff.toString();
|
schema = buff.toString();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public PurchasedSharesData mapRow(ResultSet rs, @SuppressWarnings("unused") int rowNum) throws SQLException {
|
public ShareAccountTransactionData mapRow(ResultSet rs, @SuppressWarnings("unused") int rowNum) throws SQLException {
|
||||||
final Long id = rs.getLong("purchasedId");
|
final Long id = rs.getLong("purchasedId");
|
||||||
final Long accountId = rs.getLong("accountId");
|
final Long accountId = rs.getLong("accountId");
|
||||||
final LocalDate transactionDate = new LocalDate(rs.getDate("transactionDate"));
|
final LocalDate transactionDate = new LocalDate(rs.getDate("transactionDate"));
|
||||||
@@ -442,8 +445,9 @@ public class ShareAccountReadPlatformServiceImpl implements ShareAccountReadPlat
|
|||||||
final EnumOptionData typeEnum = SharesEnumerations.purchasedSharesEnum(type);
|
final EnumOptionData typeEnum = SharesEnumerations.purchasedSharesEnum(type);
|
||||||
final BigDecimal amount = JdbcSupport.getBigDecimalDefaultToNullIfZero(rs, "amount");
|
final BigDecimal amount = JdbcSupport.getBigDecimalDefaultToNullIfZero(rs, "amount");
|
||||||
final BigDecimal chargeAmount = JdbcSupport.getBigDecimalDefaultToNullIfZero(rs, "chargeamount");
|
final BigDecimal chargeAmount = JdbcSupport.getBigDecimalDefaultToNullIfZero(rs, "chargeamount");
|
||||||
return new PurchasedSharesData(id, accountId, transactionDate, numberOfShares, purchasedPrice, statusEnum, typeEnum, amount,
|
final BigDecimal amountPaid = JdbcSupport.getBigDecimalDefaultToNullIfZero(rs, "amountPaid");
|
||||||
chargeAmount);
|
return new ShareAccountTransactionData(id, accountId, transactionDate, numberOfShares, purchasedPrice, statusEnum, typeEnum, amount,
|
||||||
|
chargeAmount, amountPaid);
|
||||||
}
|
}
|
||||||
|
|
||||||
public String schema() {
|
public String schema() {
|
||||||
|
|||||||
+89
-13
@@ -18,7 +18,9 @@
|
|||||||
*/
|
*/
|
||||||
package org.apache.fineract.portfolio.shareaccounts.service;
|
package org.apache.fineract.portfolio.shareaccounts.service;
|
||||||
|
|
||||||
|
import java.math.BigDecimal;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
|
import java.util.Date;
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
import java.util.HashSet;
|
import java.util.HashSet;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
@@ -32,6 +34,7 @@ import org.apache.fineract.infrastructure.accountnumberformat.domain.EntityAccou
|
|||||||
import org.apache.fineract.infrastructure.core.api.JsonCommand;
|
import org.apache.fineract.infrastructure.core.api.JsonCommand;
|
||||||
import org.apache.fineract.infrastructure.core.data.CommandProcessingResult;
|
import org.apache.fineract.infrastructure.core.data.CommandProcessingResult;
|
||||||
import org.apache.fineract.infrastructure.core.data.CommandProcessingResultBuilder;
|
import org.apache.fineract.infrastructure.core.data.CommandProcessingResultBuilder;
|
||||||
|
import org.apache.fineract.infrastructure.core.service.DateUtils;
|
||||||
import org.apache.fineract.organisation.monetary.data.CurrencyData;
|
import org.apache.fineract.organisation.monetary.data.CurrencyData;
|
||||||
import org.apache.fineract.organisation.monetary.domain.MonetaryCurrency;
|
import org.apache.fineract.organisation.monetary.domain.MonetaryCurrency;
|
||||||
import org.apache.fineract.portfolio.accounts.constants.ShareAccountApiConstants;
|
import org.apache.fineract.portfolio.accounts.constants.ShareAccountApiConstants;
|
||||||
@@ -42,6 +45,8 @@ import org.apache.fineract.portfolio.shareaccounts.domain.ShareAccountChargePaid
|
|||||||
import org.apache.fineract.portfolio.shareaccounts.domain.ShareAccountRepositoryWrapper;
|
import org.apache.fineract.portfolio.shareaccounts.domain.ShareAccountRepositoryWrapper;
|
||||||
import org.apache.fineract.portfolio.shareaccounts.domain.ShareAccountTransaction;
|
import org.apache.fineract.portfolio.shareaccounts.domain.ShareAccountTransaction;
|
||||||
import org.apache.fineract.portfolio.shareaccounts.serialization.ShareAccountDataSerializer;
|
import org.apache.fineract.portfolio.shareaccounts.serialization.ShareAccountDataSerializer;
|
||||||
|
import org.apache.fineract.portfolio.shareproducts.domain.ShareProduct;
|
||||||
|
import org.apache.fineract.portfolio.shareproducts.domain.ShareProductRepositoryWrapper;
|
||||||
import org.joda.time.LocalDate;
|
import org.joda.time.LocalDate;
|
||||||
import org.springframework.beans.factory.annotation.Autowired;
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
import org.springframework.dao.DataIntegrityViolationException;
|
import org.springframework.dao.DataIntegrityViolationException;
|
||||||
@@ -54,6 +59,8 @@ public class ShareAccountWritePlatformServiceJpaRepositoryImpl implements ShareA
|
|||||||
|
|
||||||
private final ShareAccountRepositoryWrapper shareAccountRepository;
|
private final ShareAccountRepositoryWrapper shareAccountRepository;
|
||||||
|
|
||||||
|
private final ShareProductRepositoryWrapper shareProductRepository ;
|
||||||
|
|
||||||
private final AccountNumberGenerator accountNumberGenerator;
|
private final AccountNumberGenerator accountNumberGenerator;
|
||||||
|
|
||||||
private final AccountNumberFormatRepositoryWrapper accountNumberFormatRepository;
|
private final AccountNumberFormatRepositoryWrapper accountNumberFormatRepository;
|
||||||
@@ -63,11 +70,13 @@ public class ShareAccountWritePlatformServiceJpaRepositoryImpl implements ShareA
|
|||||||
@Autowired
|
@Autowired
|
||||||
public ShareAccountWritePlatformServiceJpaRepositoryImpl(final ShareAccountDataSerializer accountDataSerializer,
|
public ShareAccountWritePlatformServiceJpaRepositoryImpl(final ShareAccountDataSerializer accountDataSerializer,
|
||||||
final ShareAccountRepositoryWrapper shareAccountRepository,
|
final ShareAccountRepositoryWrapper shareAccountRepository,
|
||||||
|
final ShareProductRepositoryWrapper shareProductRepository,
|
||||||
final AccountNumberGenerator accountNumberGenerator,
|
final AccountNumberGenerator accountNumberGenerator,
|
||||||
final AccountNumberFormatRepositoryWrapper accountNumberFormatRepository,
|
final AccountNumberFormatRepositoryWrapper accountNumberFormatRepository,
|
||||||
final JournalEntryWritePlatformService journalEntryWritePlatformService) {
|
final JournalEntryWritePlatformService journalEntryWritePlatformService) {
|
||||||
this.accountDataSerializer = accountDataSerializer;
|
this.accountDataSerializer = accountDataSerializer;
|
||||||
this.shareAccountRepository = shareAccountRepository;
|
this.shareAccountRepository = shareAccountRepository;
|
||||||
|
this.shareProductRepository = shareProductRepository ;
|
||||||
this.accountNumberGenerator = accountNumberGenerator;
|
this.accountNumberGenerator = accountNumberGenerator;
|
||||||
this.accountNumberFormatRepository = accountNumberFormatRepository;
|
this.accountNumberFormatRepository = accountNumberFormatRepository;
|
||||||
this.journalEntryWritePlatformService = journalEntryWritePlatformService;
|
this.journalEntryWritePlatformService = journalEntryWritePlatformService;
|
||||||
@@ -79,7 +88,6 @@ public class ShareAccountWritePlatformServiceJpaRepositoryImpl implements ShareA
|
|||||||
ShareAccount account = this.accountDataSerializer.validateAndCreate(jsonCommand);
|
ShareAccount account = this.accountDataSerializer.validateAndCreate(jsonCommand);
|
||||||
this.shareAccountRepository.save(account);
|
this.shareAccountRepository.save(account);
|
||||||
generateAccountNumber(account);
|
generateAccountNumber(account);
|
||||||
//this.shareProductRepository.save(account.getShareProduct()); //subscribed shares is increased
|
|
||||||
journalEntryWritePlatformService.createJournalEntriesForShares(populateJournalEntries(account,
|
journalEntryWritePlatformService.createJournalEntriesForShares(populateJournalEntries(account,
|
||||||
account.getPendingForApprovalSharePurchaseTransactions()));
|
account.getPendingForApprovalSharePurchaseTransactions()));
|
||||||
return new CommandProcessingResultBuilder() //
|
return new CommandProcessingResultBuilder() //
|
||||||
@@ -126,7 +134,16 @@ public class ShareAccountWritePlatformServiceJpaRepositoryImpl implements ShareA
|
|||||||
final ShareAccountTransactionEnumData typeEnum = new ShareAccountTransactionEnumData(type.longValue(), null, null);
|
final ShareAccountTransactionEnumData typeEnum = new ShareAccountTransactionEnumData(type.longValue(), null, null);
|
||||||
transactionDto.put("status", statusEnum);
|
transactionDto.put("status", statusEnum);
|
||||||
transactionDto.put("type", typeEnum);
|
transactionDto.put("type", typeEnum);
|
||||||
transactionDto.put("amount", transaction.amount());
|
if(transaction.isPurchaseRejectedTransaction() || transaction.isRedeemTransaction()) {
|
||||||
|
BigDecimal amount = transaction.amount() ;
|
||||||
|
if(transaction.chargeAmount() != null) {
|
||||||
|
amount = amount.add(transaction.chargeAmount()) ;
|
||||||
|
}
|
||||||
|
transactionDto.put("amount", amount);
|
||||||
|
}else {
|
||||||
|
transactionDto.put("amount", transaction.amount());
|
||||||
|
}
|
||||||
|
|
||||||
transactionDto.put("chargeAmount", transaction.chargeAmount());
|
transactionDto.put("chargeAmount", transaction.chargeAmount());
|
||||||
transactionDto.put("paymentTypeId", null); // FIXME::make it cash
|
transactionDto.put("paymentTypeId", null); // FIXME::make it cash
|
||||||
// payment
|
// payment
|
||||||
@@ -147,14 +164,24 @@ public class ShareAccountWritePlatformServiceJpaRepositoryImpl implements ShareA
|
|||||||
return accountingBridgeData;
|
return accountingBridgeData;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@SuppressWarnings("unchecked")
|
||||||
@Override
|
@Override
|
||||||
public CommandProcessingResult updateShareAccount(Long accountId, JsonCommand jsonCommand) {
|
public CommandProcessingResult updateShareAccount(Long accountId, JsonCommand jsonCommand) {
|
||||||
try {
|
try {
|
||||||
|
Date transactionDate = DateUtils.getDateOfTenant();
|
||||||
ShareAccount account = this.shareAccountRepository.findOneWithNotFoundDetection(accountId);
|
ShareAccount account = this.shareAccountRepository.findOneWithNotFoundDetection(accountId);
|
||||||
Map<String, Object> changes = this.accountDataSerializer.validateAndUpdate(jsonCommand, account);
|
Map<String, Object> changes = this.accountDataSerializer.validateAndUpdate(jsonCommand, account);
|
||||||
if (!changes.isEmpty()) {
|
if (!changes.isEmpty()) {
|
||||||
this.shareAccountRepository.save(account);
|
this.shareAccountRepository.save(account);
|
||||||
}
|
}
|
||||||
|
// since we are reverting all journal entries we need to add journal
|
||||||
|
// entries for application request
|
||||||
|
if (changes.containsKey("reversalIds")) {
|
||||||
|
ArrayList<Long> reversalIds = (ArrayList<Long>) changes.get("reversalIds");
|
||||||
|
this.journalEntryWritePlatformService.revertShareAccountJournalEntries(reversalIds, transactionDate);
|
||||||
|
journalEntryWritePlatformService.createJournalEntriesForShares(populateJournalEntries(account,
|
||||||
|
account.getPendingForApprovalSharePurchaseTransactions()));
|
||||||
|
}
|
||||||
return new CommandProcessingResultBuilder() //
|
return new CommandProcessingResultBuilder() //
|
||||||
.withCommandId(jsonCommand.commandId()) //
|
.withCommandId(jsonCommand.commandId()) //
|
||||||
.withEntityId(accountId) //
|
.withEntityId(accountId) //
|
||||||
@@ -205,8 +232,21 @@ public class ShareAccountWritePlatformServiceJpaRepositoryImpl implements ShareA
|
|||||||
if (!changes.isEmpty()) {
|
if (!changes.isEmpty()) {
|
||||||
this.shareAccountRepository.save(account);
|
this.shareAccountRepository.save(account);
|
||||||
}
|
}
|
||||||
this.journalEntryWritePlatformService.createJournalEntriesForShares(populateJournalEntries(account,
|
Set<ShareAccountTransaction> transactions = account.getShareAccountTransactions();
|
||||||
account.getShareAccountTransactions()));
|
Set<ShareAccountTransaction> journalTransactions = new HashSet<>();
|
||||||
|
Long totalSubsribedShares = new Long(0) ;
|
||||||
|
|
||||||
|
for (ShareAccountTransaction transaction : transactions) {
|
||||||
|
if (transaction.isActive() && transaction.isPurchasTransaction()) {
|
||||||
|
journalTransactions.add(transaction);
|
||||||
|
totalSubsribedShares += transaction.getTotalShares() ;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
ShareProduct shareProduct = account.getShareProduct() ;
|
||||||
|
shareProduct.addSubscribedShares(totalSubsribedShares);
|
||||||
|
this.shareProductRepository.save(shareProduct);
|
||||||
|
|
||||||
|
this.journalEntryWritePlatformService.createJournalEntriesForShares(populateJournalEntries(account, journalTransactions));
|
||||||
return new CommandProcessingResultBuilder() //
|
return new CommandProcessingResultBuilder() //
|
||||||
.withCommandId(jsonCommand.commandId()) //
|
.withCommandId(jsonCommand.commandId()) //
|
||||||
.withEntityId(accountId) //
|
.withEntityId(accountId) //
|
||||||
@@ -226,8 +266,14 @@ public class ShareAccountWritePlatformServiceJpaRepositoryImpl implements ShareA
|
|||||||
if (!changes.isEmpty()) {
|
if (!changes.isEmpty()) {
|
||||||
this.shareAccountRepository.save(account);
|
this.shareAccountRepository.save(account);
|
||||||
}
|
}
|
||||||
this.journalEntryWritePlatformService.createJournalEntriesForShares(populateJournalEntries(account,
|
Set<ShareAccountTransaction> transactions = account.getShareAccountTransactions();
|
||||||
account.getShareAccountTransactions()));
|
Set<ShareAccountTransaction> journalTransactions = new HashSet<>();
|
||||||
|
for (ShareAccountTransaction transaction : transactions) {
|
||||||
|
if (transaction.isActive() && !transaction.isChargeTransaction()) {
|
||||||
|
journalTransactions.add(transaction);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
this.journalEntryWritePlatformService.createJournalEntriesForShares(populateJournalEntries(account, journalTransactions));
|
||||||
return new CommandProcessingResultBuilder() //
|
return new CommandProcessingResultBuilder() //
|
||||||
.withCommandId(jsonCommand.commandId()) //
|
.withCommandId(jsonCommand.commandId()) //
|
||||||
.withEntityId(accountId) //
|
.withEntityId(accountId) //
|
||||||
@@ -247,11 +293,18 @@ public class ShareAccountWritePlatformServiceJpaRepositoryImpl implements ShareA
|
|||||||
if (!changes.isEmpty()) {
|
if (!changes.isEmpty()) {
|
||||||
this.shareAccountRepository.save(account);
|
this.shareAccountRepository.save(account);
|
||||||
}
|
}
|
||||||
/*
|
|
||||||
* this.journalEntryWritePlatformService.createJournalEntriesForShares
|
Set<ShareAccountTransaction> transactions = account.getShareAccountTransactions() ;
|
||||||
* (populateJournalEntries(account,
|
ArrayList<Long> journalEntryTransactions = new ArrayList<>() ;
|
||||||
* account.getShareAccountTransactions()));
|
for(ShareAccountTransaction transaction: transactions) {
|
||||||
*/
|
if(transaction.isActive() && !transaction.isChargeTransaction()){
|
||||||
|
journalEntryTransactions.add(transaction.getId()) ;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Date transactionDate = DateUtils.getDateOfTenant();
|
||||||
|
this.journalEntryWritePlatformService.revertShareAccountJournalEntries(journalEntryTransactions, transactionDate);
|
||||||
|
journalEntryWritePlatformService.createJournalEntriesForShares(populateJournalEntries(account,
|
||||||
|
account.getPendingForApprovalSharePurchaseTransactions()));
|
||||||
return new CommandProcessingResultBuilder() //
|
return new CommandProcessingResultBuilder() //
|
||||||
.withCommandId(jsonCommand.commandId()) //
|
.withCommandId(jsonCommand.commandId()) //
|
||||||
.withEntityId(accountId) //
|
.withEntityId(accountId) //
|
||||||
@@ -285,6 +338,7 @@ public class ShareAccountWritePlatformServiceJpaRepositoryImpl implements ShareA
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@SuppressWarnings("unchecked")
|
||||||
@Override
|
@Override
|
||||||
public CommandProcessingResult approveAdditionalShares(Long accountId, JsonCommand jsonCommand) {
|
public CommandProcessingResult approveAdditionalShares(Long accountId, JsonCommand jsonCommand) {
|
||||||
|
|
||||||
@@ -294,14 +348,21 @@ public class ShareAccountWritePlatformServiceJpaRepositoryImpl implements ShareA
|
|||||||
if (!changes.isEmpty()) {
|
if (!changes.isEmpty()) {
|
||||||
this.shareAccountRepository.save(account);
|
this.shareAccountRepository.save(account);
|
||||||
ArrayList<Long> transactionIds = (ArrayList<Long>) changes.get(ShareAccountApiConstants.requestedshares_paramname);
|
ArrayList<Long> transactionIds = (ArrayList<Long>) changes.get(ShareAccountApiConstants.requestedshares_paramname);
|
||||||
|
Long totalSubscribedShares = new Long(0) ;
|
||||||
if (transactionIds != null) {
|
if (transactionIds != null) {
|
||||||
Set<ShareAccountTransaction> transactions = new HashSet<>();
|
Set<ShareAccountTransaction> transactions = new HashSet<>();
|
||||||
for (Long id : transactionIds) {
|
for (Long id : transactionIds) {
|
||||||
ShareAccountTransaction transaction = account.retrievePurchasedShares(id);
|
ShareAccountTransaction transaction = account.retrievePurchasedShares(id);
|
||||||
transactions.add(transaction);
|
transactions.add(transaction);
|
||||||
|
totalSubscribedShares += transaction.getTotalShares() ;
|
||||||
}
|
}
|
||||||
this.journalEntryWritePlatformService.createJournalEntriesForShares(populateJournalEntries(account, transactions));
|
this.journalEntryWritePlatformService.createJournalEntriesForShares(populateJournalEntries(account, transactions));
|
||||||
}
|
}
|
||||||
|
if(!totalSubscribedShares.equals(new Long(0))) {
|
||||||
|
ShareProduct shareProduct = account.getShareProduct() ;
|
||||||
|
shareProduct.addSubscribedShares(totalSubscribedShares);
|
||||||
|
this.shareProductRepository.save(shareProduct);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
return new CommandProcessingResultBuilder() //
|
return new CommandProcessingResultBuilder() //
|
||||||
.withCommandId(jsonCommand.commandId()) //
|
.withCommandId(jsonCommand.commandId()) //
|
||||||
@@ -314,9 +375,9 @@ public class ShareAccountWritePlatformServiceJpaRepositoryImpl implements ShareA
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@SuppressWarnings("unchecked")
|
||||||
@Override
|
@Override
|
||||||
public CommandProcessingResult rejectAdditionalShares(Long accountId, JsonCommand jsonCommand) {
|
public CommandProcessingResult rejectAdditionalShares(Long accountId, JsonCommand jsonCommand) {
|
||||||
|
|
||||||
try {
|
try {
|
||||||
ShareAccount account = this.shareAccountRepository.findOneWithNotFoundDetection(accountId);
|
ShareAccount account = this.shareAccountRepository.findOneWithNotFoundDetection(accountId);
|
||||||
Map<String, Object> changes = this.accountDataSerializer.validateAndRejectAddtionalShares(jsonCommand, account);
|
Map<String, Object> changes = this.accountDataSerializer.validateAndRejectAddtionalShares(jsonCommand, account);
|
||||||
@@ -352,7 +413,21 @@ public class ShareAccountWritePlatformServiceJpaRepositoryImpl implements ShareA
|
|||||||
this.shareAccountRepository.save(account);
|
this.shareAccountRepository.save(account);
|
||||||
ShareAccountTransaction transaction = (ShareAccountTransaction) changes
|
ShareAccountTransaction transaction = (ShareAccountTransaction) changes
|
||||||
.get(ShareAccountApiConstants.requestedshares_paramname);
|
.get(ShareAccountApiConstants.requestedshares_paramname);
|
||||||
transaction = account.getShareAccountTransaction(transaction);
|
transaction = account.getShareAccountTransaction(transaction); // after
|
||||||
|
// saving,
|
||||||
|
// entity
|
||||||
|
// will
|
||||||
|
// have
|
||||||
|
// different
|
||||||
|
// object.
|
||||||
|
// So
|
||||||
|
// need
|
||||||
|
// to
|
||||||
|
// retrieve
|
||||||
|
// to
|
||||||
|
// get
|
||||||
|
// the
|
||||||
|
// id
|
||||||
Set<ShareAccountTransaction> transactions = new HashSet<>();
|
Set<ShareAccountTransaction> transactions = new HashSet<>();
|
||||||
transactions.add(transaction);
|
transactions.add(transaction);
|
||||||
this.journalEntryWritePlatformService.createJournalEntriesForShares(populateJournalEntries(account, transactions));
|
this.journalEntryWritePlatformService.createJournalEntriesForShares(populateJournalEntries(account, transactions));
|
||||||
@@ -398,6 +473,7 @@ public class ShareAccountWritePlatformServiceJpaRepositoryImpl implements ShareA
|
|||||||
return CommandProcessingResult.empty();
|
return CommandProcessingResult.empty();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void handleDataIntegrityIssues(final JsonCommand command, final DataIntegrityViolationException dve) {
|
private void handleDataIntegrityIssues(final JsonCommand command, final DataIntegrityViolationException dve) {
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
+15
-1
@@ -226,7 +226,10 @@ public class ShareProduct extends AbstractAuditableCustom<AppUser, Long> {
|
|||||||
|
|
||||||
public boolean setTotalIssuedShares(Long totalSharesIssued) {
|
public boolean setTotalIssuedShares(Long totalSharesIssued) {
|
||||||
boolean returnValue = false;
|
boolean returnValue = false;
|
||||||
if (!this.totalSharesIssued.equals(totalSharesIssued)) {
|
if(this.totalSharesIssued == null) {
|
||||||
|
this.totalSharesIssued = totalSharesIssued ;
|
||||||
|
returnValue = true ;
|
||||||
|
}else if (!this.totalSharesIssued.equals(totalSharesIssued)) {
|
||||||
this.totalSharesIssued = totalSharesIssued;
|
this.totalSharesIssued = totalSharesIssued;
|
||||||
returnValue = true;
|
returnValue = true;
|
||||||
}
|
}
|
||||||
@@ -431,4 +434,15 @@ public class ShareProduct extends AbstractAuditableCustom<AppUser, Long> {
|
|||||||
return this.totalSubscribedShares ;
|
return this.totalSubscribedShares ;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public Long getMinimumClientShares() {
|
||||||
|
return this.minimumShares ;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Long getMaximumClientShares() {
|
||||||
|
return this.maximumShares ;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Long getDefaultClientShares() {
|
||||||
|
return this.nominalShares ;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+29
@@ -0,0 +1,29 @@
|
|||||||
|
/**
|
||||||
|
* Licensed to the Apache Software Foundation (ASF) under one
|
||||||
|
* or more contributor license agreements. See the NOTICE file
|
||||||
|
* distributed with this work for additional information
|
||||||
|
* regarding copyright ownership. The ASF licenses this file
|
||||||
|
* to you under the Apache License, Version 2.0 (the
|
||||||
|
* "License"); you may not use this file except in compliance
|
||||||
|
* with the License. You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing,
|
||||||
|
* software distributed under the License is distributed on an
|
||||||
|
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||||
|
* KIND, either express or implied. See the License for the
|
||||||
|
* specific language governing permissions and limitations
|
||||||
|
* under the License.
|
||||||
|
*/
|
||||||
|
package org.apache.fineract.portfolio.shareproducts.exception;
|
||||||
|
|
||||||
|
import org.apache.fineract.infrastructure.core.exception.AbstractPlatformResourceNotFoundException;
|
||||||
|
|
||||||
|
|
||||||
|
public class ShareAccountsNotFoundException extends AbstractPlatformResourceNotFoundException{
|
||||||
|
|
||||||
|
public ShareAccountsNotFoundException(final Long productId) {
|
||||||
|
super("error.msg.shareproduct.shareaccounts.not.defined", " No Share Accounts found for this prodct " + productId, productId);
|
||||||
|
}
|
||||||
|
}
|
||||||
+21
-7
@@ -39,6 +39,7 @@ import org.apache.fineract.infrastructure.core.serialization.FromJsonHelper;
|
|||||||
import org.apache.fineract.infrastructure.core.service.DateUtils;
|
import org.apache.fineract.infrastructure.core.service.DateUtils;
|
||||||
import org.apache.fineract.infrastructure.security.service.PlatformSecurityContext;
|
import org.apache.fineract.infrastructure.security.service.PlatformSecurityContext;
|
||||||
import org.apache.fineract.organisation.monetary.domain.MonetaryCurrency;
|
import org.apache.fineract.organisation.monetary.domain.MonetaryCurrency;
|
||||||
|
import org.apache.fineract.portfolio.accounts.constants.ShareAccountApiConstants;
|
||||||
import org.apache.fineract.portfolio.charge.domain.Charge;
|
import org.apache.fineract.portfolio.charge.domain.Charge;
|
||||||
import org.apache.fineract.portfolio.charge.domain.ChargeRepositoryWrapper;
|
import org.apache.fineract.portfolio.charge.domain.ChargeRepositoryWrapper;
|
||||||
import org.apache.fineract.portfolio.common.domain.PeriodFrequencyType;
|
import org.apache.fineract.portfolio.common.domain.PeriodFrequencyType;
|
||||||
@@ -102,14 +103,18 @@ public class ShareProductDataSerializer {
|
|||||||
Long totalNumberOfShares = this.fromApiJsonHelper.extractLongNamed(ShareProductApiConstants.totalshares_paramname, element);
|
Long totalNumberOfShares = this.fromApiJsonHelper.extractLongNamed(ShareProductApiConstants.totalshares_paramname, element);
|
||||||
baseDataValidator.reset().parameter(ShareProductApiConstants.totalshares_paramname).value(totalNumberOfShares).notNull()
|
baseDataValidator.reset().parameter(ShareProductApiConstants.totalshares_paramname).value(totalNumberOfShares).notNull()
|
||||||
.longGreaterThanZero();
|
.longGreaterThanZero();
|
||||||
|
final Long sharesIssued = this.fromApiJsonHelper.extractLongNamed(ShareProductApiConstants.totalsharesissued_paramname, element);
|
||||||
|
if(sharesIssued != null && totalNumberOfShares != null && sharesIssued > totalNumberOfShares) {
|
||||||
|
baseDataValidator.reset().parameter(ShareProductApiConstants.totalsharesissued_paramname).value(sharesIssued)
|
||||||
|
.failWithCodeNoParameterAddedToErrorCode("sharesIssued.cannot.be.greater.than.totalNumberOfShares");
|
||||||
|
}
|
||||||
final String currencyCode = this.fromApiJsonHelper.extractStringNamed(ShareProductApiConstants.currency_paramname, element);
|
final String currencyCode = this.fromApiJsonHelper.extractStringNamed(ShareProductApiConstants.currency_paramname, element);
|
||||||
final Integer digitsAfterDecimal = this.fromApiJsonHelper.extractIntegerWithLocaleNamed(
|
final Integer digitsAfterDecimal = this.fromApiJsonHelper.extractIntegerWithLocaleNamed(
|
||||||
ShareProductApiConstants.digitsafterdecimal_paramname, element);
|
ShareProductApiConstants.digitsafterdecimal_paramname, element);
|
||||||
final Integer inMultiplesOf = this.fromApiJsonHelper.extractIntegerWithLocaleNamed(
|
final Integer inMultiplesOf = this.fromApiJsonHelper.extractIntegerWithLocaleNamed(
|
||||||
ShareProductApiConstants.inmultiplesof_paramname, element);
|
ShareProductApiConstants.inmultiplesof_paramname, element);
|
||||||
final MonetaryCurrency currency = new MonetaryCurrency(currencyCode, digitsAfterDecimal, inMultiplesOf);
|
final MonetaryCurrency currency = new MonetaryCurrency(currencyCode, digitsAfterDecimal, inMultiplesOf);
|
||||||
final Long sharesIssued = this.fromApiJsonHelper.extractLongNamed(ShareProductApiConstants.totalsharesissued_paramname, element);
|
|
||||||
final BigDecimal unitPrice = this.fromApiJsonHelper.extractBigDecimalNamed(ShareProductApiConstants.unitprice_paramname, element,
|
final BigDecimal unitPrice = this.fromApiJsonHelper.extractBigDecimalNamed(ShareProductApiConstants.unitprice_paramname, element,
|
||||||
locale);
|
locale);
|
||||||
baseDataValidator.reset().parameter(ShareProductApiConstants.unitprice_paramname).value(unitPrice).notNull().positiveAmount();
|
baseDataValidator.reset().parameter(ShareProductApiConstants.unitprice_paramname).value(unitPrice).notNull().positiveAmount();
|
||||||
@@ -132,12 +137,12 @@ public class ShareProductDataSerializer {
|
|||||||
Long nominalClientShares = this.fromApiJsonHelper.extractLongNamed(ShareProductApiConstants.nominaltshares_paramname, element);
|
Long nominalClientShares = this.fromApiJsonHelper.extractLongNamed(ShareProductApiConstants.nominaltshares_paramname, element);
|
||||||
baseDataValidator.reset().parameter(ShareProductApiConstants.nominaltshares_paramname).value(nominalClientShares).notNull()
|
baseDataValidator.reset().parameter(ShareProductApiConstants.nominaltshares_paramname).value(nominalClientShares).notNull()
|
||||||
.longGreaterThanZero();
|
.longGreaterThanZero();
|
||||||
if (minimumClientShares != null && nominalClientShares != null) {
|
if (minimumClientShares != null && nominalClientShares != null && !minimumClientShares.equals(nominalClientShares)) {
|
||||||
baseDataValidator.reset().parameter(ShareProductApiConstants.nominaltshares_paramname).value(nominalClientShares)
|
baseDataValidator.reset().parameter(ShareProductApiConstants.nominaltshares_paramname).value(nominalClientShares)
|
||||||
.longGreaterThanNumber(minimumClientShares);
|
.longGreaterThanNumber(minimumClientShares);
|
||||||
}
|
}
|
||||||
Long maximumClientShares = this.fromApiJsonHelper.extractLongNamed(ShareProductApiConstants.maximumshares_paramname, element);
|
Long maximumClientShares = this.fromApiJsonHelper.extractLongNamed(ShareProductApiConstants.maximumshares_paramname, element);
|
||||||
if (maximumClientShares != null && nominalClientShares != null) {
|
if (maximumClientShares != null && nominalClientShares != null && !maximumClientShares.equals(nominalClientShares)) {
|
||||||
baseDataValidator.reset().parameter(ShareProductApiConstants.maximumshares_paramname).value(maximumClientShares)
|
baseDataValidator.reset().parameter(ShareProductApiConstants.maximumshares_paramname).value(maximumClientShares)
|
||||||
.longGreaterThanNumber(nominalClientShares);
|
.longGreaterThanNumber(nominalClientShares);
|
||||||
}
|
}
|
||||||
@@ -294,8 +299,16 @@ public class ShareProductDataSerializer {
|
|||||||
if (product.setTotalIssuedShares(sharesIssued)) {
|
if (product.setTotalIssuedShares(sharesIssued)) {
|
||||||
actualChanges.put(ShareProductApiConstants.totalsharesissued_paramname, sharesIssued);
|
actualChanges.put(ShareProductApiConstants.totalsharesissued_paramname, sharesIssued);
|
||||||
}
|
}
|
||||||
|
}else {
|
||||||
|
product.setTotalIssuedShares(sharesIssued) ;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if(sharesIssued != null && product.getSubscribedShares() != null && sharesIssued < product.getSubscribedShares()) {
|
||||||
|
baseDataValidator.reset().parameter(ShareProductApiConstants.totalsharesissued_paramname).value(sharesIssued)
|
||||||
|
.failWithCodeNoParameterAddedToErrorCode("sharesissued.can.not.be.lessthan.accounts.subscribed.shares");
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
if (this.fromApiJsonHelper.parameterExists(ShareProductApiConstants.currency_paramname, element)
|
if (this.fromApiJsonHelper.parameterExists(ShareProductApiConstants.currency_paramname, element)
|
||||||
&& this.fromApiJsonHelper.parameterExists(ShareProductApiConstants.digitsafterdecimal_paramname, element)
|
&& this.fromApiJsonHelper.parameterExists(ShareProductApiConstants.digitsafterdecimal_paramname, element)
|
||||||
&& this.fromApiJsonHelper.parameterExists(ShareProductApiConstants.inmultiplesof_paramname, element)) {
|
&& this.fromApiJsonHelper.parameterExists(ShareProductApiConstants.inmultiplesof_paramname, element)) {
|
||||||
@@ -416,17 +429,17 @@ public class ShareProductDataSerializer {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (!dataValidationErrors.isEmpty()) { throw new PlatformApiDataValidationException(dataValidationErrors); }
|
||||||
|
|
||||||
BigDecimal shareCapitalValue;
|
BigDecimal shareCapitalValue;
|
||||||
if (sharesIssued != null || unitPrice != null) {
|
if (sharesIssued != null || unitPrice != null) {
|
||||||
if (sharesIssued == null) sharesIssued = product.getSharesIssued();
|
if (sharesIssued == null) sharesIssued = product.getTotalShares();
|
||||||
if (unitPrice == null) unitPrice = product.getUnitPrice();
|
if (unitPrice == null) unitPrice = product.getUnitPrice();
|
||||||
shareCapitalValue = BigDecimal.valueOf(sharesIssued).multiply(unitPrice);
|
shareCapitalValue = BigDecimal.valueOf(sharesIssued).multiply(unitPrice);
|
||||||
if (product.setshareCapitalValue(shareCapitalValue)) {
|
if (product.setshareCapitalValue(shareCapitalValue)) {
|
||||||
actualChanges.put(ShareProductApiConstants.sharecapital_paramname, shareCapitalValue);
|
actualChanges.put(ShareProductApiConstants.sharecapital_paramname, shareCapitalValue);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!dataValidationErrors.isEmpty()) { throw new PlatformApiDataValidationException(dataValidationErrors); }
|
|
||||||
return actualChanges;
|
return actualChanges;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -455,6 +468,7 @@ public class ShareProductDataSerializer {
|
|||||||
ShareProductApiConstants.dividendAmountParamName, element);
|
ShareProductApiConstants.dividendAmountParamName, element);
|
||||||
baseDataValidator.reset().parameter(ShareProductApiConstants.dividendAmountParamName).value(dividendAmount).notBlank()
|
baseDataValidator.reset().parameter(ShareProductApiConstants.dividendAmountParamName).value(dividendAmount).notBlank()
|
||||||
.positiveAmount();
|
.positiveAmount();
|
||||||
|
if (!dataValidationErrors.isEmpty()) { throw new PlatformApiDataValidationException(dataValidationErrors); }
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
+12
-4
@@ -26,13 +26,14 @@ import java.util.Map;
|
|||||||
import org.apache.fineract.organisation.monetary.domain.MonetaryCurrency;
|
import org.apache.fineract.organisation.monetary.domain.MonetaryCurrency;
|
||||||
import org.apache.fineract.organisation.monetary.domain.Money;
|
import org.apache.fineract.organisation.monetary.domain.Money;
|
||||||
import org.apache.fineract.portfolio.products.service.ProductReadPlatformService;
|
import org.apache.fineract.portfolio.products.service.ProductReadPlatformService;
|
||||||
import org.apache.fineract.portfolio.shareaccounts.data.PurchasedSharesData;
|
import org.apache.fineract.portfolio.shareaccounts.data.ShareAccountTransactionData;
|
||||||
import org.apache.fineract.portfolio.shareaccounts.data.ShareAccountData;
|
import org.apache.fineract.portfolio.shareaccounts.data.ShareAccountData;
|
||||||
import org.apache.fineract.portfolio.shareaccounts.domain.PurchasedSharesStatusType;
|
import org.apache.fineract.portfolio.shareaccounts.domain.PurchasedSharesStatusType;
|
||||||
import org.apache.fineract.portfolio.shareaccounts.domain.ShareAccountDividendDetails;
|
import org.apache.fineract.portfolio.shareaccounts.domain.ShareAccountDividendDetails;
|
||||||
import org.apache.fineract.portfolio.shareaccounts.service.ShareAccountReadPlatformService;
|
import org.apache.fineract.portfolio.shareaccounts.service.ShareAccountReadPlatformService;
|
||||||
import org.apache.fineract.portfolio.shareproducts.data.ShareProductData;
|
import org.apache.fineract.portfolio.shareproducts.data.ShareProductData;
|
||||||
import org.apache.fineract.portfolio.shareproducts.domain.ShareProductDividendPayOutDetails;
|
import org.apache.fineract.portfolio.shareproducts.domain.ShareProductDividendPayOutDetails;
|
||||||
|
import org.apache.fineract.portfolio.shareproducts.exception.ShareAccountsNotFoundException;
|
||||||
import org.joda.time.Days;
|
import org.joda.time.Days;
|
||||||
import org.joda.time.LocalDate;
|
import org.joda.time.LocalDate;
|
||||||
import org.springframework.beans.factory.annotation.Autowired;
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
@@ -59,8 +60,15 @@ public class ShareProductDividendAssembler {
|
|||||||
.getCurrency().currencyInMultiplesOf());
|
.getCurrency().currencyInMultiplesOf());
|
||||||
Collection<ShareAccountData> shareAccountDatas = this.ShareAccountReadPlatformService.retrieveAllShareAccountDataForDividends(
|
Collection<ShareAccountData> shareAccountDatas = this.ShareAccountReadPlatformService.retrieveAllShareAccountDataForDividends(
|
||||||
productId, product.getAllowDividendCalculationForInactiveClients(), dividendPeriodStartDate);
|
productId, product.getAllowDividendCalculationForInactiveClients(), dividendPeriodStartDate);
|
||||||
|
if(shareAccountDatas == null || shareAccountDatas.isEmpty()) {
|
||||||
|
throw new ShareAccountsNotFoundException(product.getId()) ;
|
||||||
|
}
|
||||||
|
|
||||||
ShareProductDividendPayOutDetails productDividendPayOutDetails = null;
|
ShareProductDividendPayOutDetails productDividendPayOutDetails = null;
|
||||||
final int minimumActivePeriod = product.getMinimumActivePeriod();
|
int minimumActivePeriod = 0 ;
|
||||||
|
if(product.getMinimumActivePeriod() != null) { //minimum active period may be null
|
||||||
|
minimumActivePeriod = product.getMinimumActivePeriod();
|
||||||
|
}
|
||||||
final Map<Long, Long> numberOfSharesdaysPerAccount = new HashMap<>();
|
final Map<Long, Long> numberOfSharesdaysPerAccount = new HashMap<>();
|
||||||
long numberOfShareDays = calculateNumberOfShareDays(dividendPeriodEndDate, dividendPeriodStartDate, minimumActivePeriod,
|
long numberOfShareDays = calculateNumberOfShareDays(dividendPeriodEndDate, dividendPeriodStartDate, minimumActivePeriod,
|
||||||
shareAccountDatas, numberOfSharesdaysPerAccount);
|
shareAccountDatas, numberOfSharesdaysPerAccount);
|
||||||
@@ -88,10 +96,10 @@ public class ShareProductDividendAssembler {
|
|||||||
long numberOfShareDays = 0;
|
long numberOfShareDays = 0;
|
||||||
for (ShareAccountData accountData : shareAccountDatas) {
|
for (ShareAccountData accountData : shareAccountDatas) {
|
||||||
long numberOfShareDaysPerAccount = 0;
|
long numberOfShareDaysPerAccount = 0;
|
||||||
Collection<PurchasedSharesData> purchasedShares = accountData.getPurchasedShares();
|
Collection<ShareAccountTransactionData> purchasedShares = accountData.getPurchasedShares();
|
||||||
long numberOfShares = 0;
|
long numberOfShares = 0;
|
||||||
LocalDate lastDividendAppliedDate = null;
|
LocalDate lastDividendAppliedDate = null;
|
||||||
for (PurchasedSharesData purchasedSharesData : purchasedShares) {
|
for (ShareAccountTransactionData purchasedSharesData : purchasedShares) {
|
||||||
final PurchasedSharesStatusType status = PurchasedSharesStatusType.fromInt(purchasedSharesData.getStatus().getId()
|
final PurchasedSharesStatusType status = PurchasedSharesStatusType.fromInt(purchasedSharesData.getStatus().getId()
|
||||||
.intValue());
|
.intValue());
|
||||||
final PurchasedSharesStatusType type = PurchasedSharesStatusType.fromInt(purchasedSharesData.getType().getId()
|
final PurchasedSharesStatusType type = PurchasedSharesStatusType.fromInt(purchasedSharesData.getType().getId()
|
||||||
|
|||||||
+1
-1
@@ -243,7 +243,7 @@ public class ShareProductReadPlatformServiceImpl implements ProductReadPlatformS
|
|||||||
currencyDisplaySymbol, currencyNameCode);
|
currencyDisplaySymbol, currencyNameCode);
|
||||||
|
|
||||||
final Long totalShares = rs.getLong("total_shares");
|
final Long totalShares = rs.getLong("total_shares");
|
||||||
final Long issuedShares = rs.getLong("issued_shares");
|
final Long issuedShares = JdbcSupport.getLongDefaultToNullIfZero(rs, "issued_shares");
|
||||||
final BigDecimal unitPrice = rs.getBigDecimal("unit_price");
|
final BigDecimal unitPrice = rs.getBigDecimal("unit_price");
|
||||||
final BigDecimal capitalAmount = rs.getBigDecimal("capital_amount");
|
final BigDecimal capitalAmount = rs.getBigDecimal("capital_amount");
|
||||||
final Long minimumClientShares = JdbcSupport.getLong(rs, "minimum_client_shares");
|
final Long minimumClientShares = JdbcSupport.getLong(rs, "minimum_client_shares");
|
||||||
|
|||||||
+4
-2
@@ -129,16 +129,18 @@ CREATE TABLE `m_share_account_transactions` (
|
|||||||
`unit_price` DECIMAL(10,2) NULL DEFAULT NULL,
|
`unit_price` DECIMAL(10,2) NULL DEFAULT NULL,
|
||||||
`amount` DECIMAL(20,2) NULL DEFAULT NULL,
|
`amount` DECIMAL(20,2) NULL DEFAULT NULL,
|
||||||
`charge_amount` DECIMAL(20,2) NULL DEFAULT NULL,
|
`charge_amount` DECIMAL(20,2) NULL DEFAULT NULL,
|
||||||
|
`amount_paid` DECIMAL(20,2) NULL DEFAULT NULL,
|
||||||
`status_enum` SMALLINT(5) NOT NULL DEFAULT '300',
|
`status_enum` SMALLINT(5) NOT NULL DEFAULT '300',
|
||||||
`type_enum` SMALLINT(5) NULL DEFAULT NULL,
|
`type_enum` SMALLINT(5) NULL DEFAULT NULL,
|
||||||
|
`is_active` TINYINT(1) NOT NULL DEFAULT '1',
|
||||||
PRIMARY KEY (`id`),
|
PRIMARY KEY (`id`),
|
||||||
CONSTRAINT `m_share_account_purchased_shares_ibfk_1` FOREIGN KEY (`account_id`) REFERENCES `m_share_account` (`id`)
|
CONSTRAINT `m_share_account_purchased_shares_ibfk_1` FOREIGN KEY (`account_id`) REFERENCES `m_share_account` (`id`)
|
||||||
) ;
|
) ;
|
||||||
|
|
||||||
CREATE TABLE `m_share_account_charge_paid_by` (
|
CREATE TABLE `m_share_account_charge_paid_by` (
|
||||||
`id` BIGINT(20) NOT NULL AUTO_INCREMENT,
|
`id` BIGINT(20) NOT NULL AUTO_INCREMENT,
|
||||||
`share_transaction_id` BIGINT(20) NOT NULL,
|
`share_transaction_id` BIGINT(20) NULL DEFAULT NULL,
|
||||||
`charge_transaction_id` BIGINT(20) NOT NULL,
|
`charge_transaction_id` BIGINT(20) NULL DEFAULT NULL,
|
||||||
`amount` DECIMAL(20,2) NOT NULL,
|
`amount` DECIMAL(20,2) NOT NULL,
|
||||||
PRIMARY KEY (`id`),
|
PRIMARY KEY (`id`),
|
||||||
CONSTRAINT `m_share_account_transactions_charge_mapping_ibfk1` FOREIGN KEY (`share_transaction_id`) REFERENCES `m_share_account_transactions` (`id`),
|
CONSTRAINT `m_share_account_transactions_charge_mapping_ibfk1` FOREIGN KEY (`share_transaction_id`) REFERENCES `m_share_account_transactions` (`id`),
|
||||||
|
|||||||
Reference in New Issue
Block a user