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")
|
||||
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"); }
|
||||
}
|
||||
|
||||
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,
|
||||
final Long shareAccountId, final String transactionId, final Date transactionDate, final BigDecimal amount) {
|
||||
final boolean manualEntry = false;
|
||||
|
||||
+2
@@ -119,6 +119,8 @@ public class CashBasedAccountingProcessorForShares implements AccountingProcesso
|
||||
BigDecimal amountForJE = amount;
|
||||
if (chargeAmount != null && chargeAmount.compareTo(BigDecimal.ZERO) == 1) {
|
||||
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(),
|
||||
CASH_ACCOUNTS_FOR_SHARES.SHARES_REFERENCE.getValue(), shareProductId, paymentTypeId, shareAccountId, transactionId,
|
||||
|
||||
+3
@@ -18,6 +18,7 @@
|
||||
*/
|
||||
package org.apache.fineract.accounting.journalentry.service;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Date;
|
||||
import java.util.Map;
|
||||
|
||||
@@ -44,4 +45,6 @@ public interface JournalEntryWritePlatformService {
|
||||
public String createProvisioningJournalEntries(ProvisioningEntry entry) ;
|
||||
|
||||
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.GL_JOURNAL_ENTRY_INVALID_REASON;
|
||||
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.ProvisioningEntry;
|
||||
import org.apache.fineract.accounting.rule.domain.AccountingRule;
|
||||
@@ -383,6 +384,7 @@ public class JournalEntryWritePlatformServiceJpaRepositoryImpl implements Journa
|
||||
// save the reversal entry
|
||||
this.glJournalEntryRepository.save(reversalJournalEntry);
|
||||
journalEntry.setReversalJournalEntry(reversalJournalEntry);
|
||||
journalEntry.setReversed(true);
|
||||
// save the updated journal entry
|
||||
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) {
|
||||
/** check if date of Journal entry is valid ***/
|
||||
final LocalDate entryLocalDate = command.getTransactionDate();
|
||||
|
||||
+3
-1
@@ -290,9 +290,11 @@ public class ChargeData implements Comparable<ChargeData>, Serializable {
|
||||
final BigDecimal amountPercentageAppliedTo = BigDecimal.ZERO;
|
||||
final Collection<ChargeData> chargeOptions = null;
|
||||
final Boolean isActive = null;
|
||||
final BigDecimal chargeAmountOrPercentage = BigDecimal.ZERO ;
|
||||
|
||||
return new ShareAccountChargeData(shareChargeId, this.id, shareAccountId, this.name, this.currency, this.amount, amountPaid,
|
||||
amountWaived, amountWrittenOff, amountOutstanding, this.chargeTimeType, this.chargeCalculationType, percentage,
|
||||
amountPercentageAppliedTo, chargeOptions, isActive);
|
||||
amountPercentageAppliedTo, chargeOptions, isActive, chargeAmountOrPercentage);
|
||||
}
|
||||
|
||||
public boolean isPenalty() {
|
||||
|
||||
+2
@@ -34,6 +34,8 @@ public interface SavingsAccountReadPlatformService {
|
||||
|
||||
Collection<SavingsAccountData> retrieveActiveForLookup(Long clientId, DepositAccountType depositAccountType);
|
||||
|
||||
public Collection<SavingsAccountData> retrieveActiveForLookup(final Long clientId, DepositAccountType depositAccountType, String currencyCode) ;
|
||||
|
||||
SavingsAccountData retrieveOne(Long savingsId);
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
@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
|
||||
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 BigDecimal amountWrittenOff, final BigDecimal amountOutstanding, final EnumOptionData chargeTimeType,
|
||||
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.chargeId = chargeId;
|
||||
this.accountId = accountId;
|
||||
@@ -84,11 +84,12 @@ public class ShareAccountChargeData {
|
||||
this.amountWaived = amountWaived;
|
||||
this.amountWrittenOff = amountWrittenOff;
|
||||
this.amountOutstanding = amountOutstanding;
|
||||
this.amountOrPercentage = getAmountOrPercentage();
|
||||
this.amountOrPercentage = chargeamountorpercentage;
|
||||
this.chargeOptions = chargeOptions;
|
||||
this.isActive = isActive;
|
||||
}
|
||||
|
||||
|
||||
private BigDecimal getAmountOrPercentage() {
|
||||
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 Collection<PurchasedSharesData> purchasedShares;
|
||||
private Collection<ShareAccountTransactionData> purchasedShares;
|
||||
|
||||
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 productName, final ShareAccountStatusEnumData status, final ShareAccountApplicationTimelineData timeline,
|
||||
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) {
|
||||
this.id = id;
|
||||
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 productName, final ShareAccountStatusEnumData status, final ShareAccountApplicationTimelineData timeline,
|
||||
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 Boolean allowDividendCalculationForInactiveClients, final Collection<ProductData> productOptions,
|
||||
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) {
|
||||
String externalId = null;
|
||||
ShareAccountSummaryData summaryData = null;
|
||||
Collection<PurchasedSharesData> purchasedSharesData = null;
|
||||
Collection<ShareAccountTransactionData> purchasedSharesData = null;
|
||||
GLAccountData suspenseAccount = null;
|
||||
Integer lockinPeriod = null;
|
||||
EnumOptionData lockPeriodTypeEnum = null;
|
||||
@@ -233,7 +233,7 @@ public class ShareAccountData implements AccountData {
|
||||
return this.id;
|
||||
}
|
||||
|
||||
public Collection<PurchasedSharesData> getPurchasedShares() {
|
||||
public Collection<ShareAccountTransactionData> getPurchasedShares() {
|
||||
return this.purchasedShares;
|
||||
}
|
||||
|
||||
|
||||
+8
-3
@@ -23,7 +23,8 @@ import java.math.BigDecimal;
|
||||
import org.apache.fineract.infrastructure.core.data.EnumOptionData;
|
||||
import org.joda.time.LocalDate;
|
||||
|
||||
public class PurchasedSharesData {
|
||||
@SuppressWarnings("unused")
|
||||
public class ShareAccountTransactionData {
|
||||
|
||||
private final Long id;
|
||||
|
||||
@@ -43,8 +44,11 @@ public class PurchasedSharesData {
|
||||
|
||||
private final BigDecimal chargeAmount ;
|
||||
|
||||
public PurchasedSharesData(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) {
|
||||
private final BigDecimal amountPaid ;
|
||||
|
||||
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.accountId = accountId;
|
||||
this.purchasedDate = purchasedDate;
|
||||
@@ -54,6 +58,7 @@ public class PurchasedSharesData {
|
||||
this.type = type;
|
||||
this.amount = amount ;
|
||||
this.chargeAmount = chargeAmount ;
|
||||
this.amountPaid = amountPaid ;
|
||||
}
|
||||
|
||||
public LocalDate getPurchasedDate() {
|
||||
+52
-23
@@ -18,10 +18,8 @@
|
||||
*/
|
||||
package org.apache.fineract.portfolio.shareaccounts.domain;
|
||||
|
||||
import java.math.BigDecimal;
|
||||
import java.util.Date;
|
||||
import java.util.HashSet;
|
||||
import java.util.Iterator;
|
||||
import java.util.Set;
|
||||
|
||||
import javax.persistence.CascadeType;
|
||||
@@ -261,6 +259,17 @@ public class ShareAccount extends AbstractPersistable<Long> {
|
||||
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) {
|
||||
boolean returnValue = false;
|
||||
if (this.allowDividendCalculationForInactiveClients == null) {
|
||||
@@ -346,7 +355,7 @@ public class ShareAccount extends AbstractPersistable<Long> {
|
||||
public Set<ShareAccountTransaction> getChargeTransactions() {
|
||||
Set<ShareAccountTransaction> chargeTransactions = new HashSet<>();
|
||||
for (ShareAccountTransaction transaction : this.shareAccountTransactions) {
|
||||
if (transaction.isChargeTransaction()) {
|
||||
if (transaction.isActive() && transaction.isChargeTransaction()) {
|
||||
chargeTransactions.add(transaction);
|
||||
}
|
||||
}
|
||||
@@ -380,18 +389,6 @@ public class ShareAccount extends AbstractPersistable<Long> {
|
||||
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) {
|
||||
this.approvedDate = approvedDate;
|
||||
this.approvedBy = approvedUser;
|
||||
@@ -418,10 +415,14 @@ public class ShareAccount extends AbstractPersistable<Long> {
|
||||
this.closedDate = null;
|
||||
this.closedBy = null;
|
||||
this.totalSharesApproved = null;
|
||||
Iterator<ShareAccountTransaction> iter = this.shareAccountTransactions.iterator();
|
||||
ShareAccountTransaction share = iter.next();
|
||||
share.undoApprove();
|
||||
this.totalSharesPending = share.getTotalShares();
|
||||
Long tempTotalShares = new Long(0);
|
||||
for (ShareAccountTransaction transaction : this.shareAccountTransactions) {
|
||||
if(transaction.isPurchasTransaction()) {
|
||||
transaction.undoApprove();
|
||||
tempTotalShares += transaction.getTotalShares() ;
|
||||
}
|
||||
}
|
||||
this.totalSharesPending = tempTotalShares;
|
||||
}
|
||||
|
||||
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.totalSharesPending = null;
|
||||
this.totalSharesApproved = null;
|
||||
Iterator<ShareAccountTransaction> iter = this.shareAccountTransactions.iterator();
|
||||
ShareAccountTransaction share = iter.next();
|
||||
share.reject();
|
||||
for (ShareAccountTransaction transaction : this.shareAccountTransactions) {
|
||||
if(transaction.isPurchasTransaction()) {
|
||||
transaction.reject();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void close(final Date closedDate, final AppUser closedBy) {
|
||||
@@ -469,7 +472,7 @@ public class ShareAccount extends AbstractPersistable<Long> {
|
||||
public Set<ShareAccountTransaction> getPendingForApprovalSharePurchaseTransactions() {
|
||||
Set<ShareAccountTransaction> purchaseTransactions = new HashSet<>();
|
||||
for (ShareAccountTransaction transaction : this.shareAccountTransactions) {
|
||||
if (transaction.isPendingForApprovalTransaction()) {
|
||||
if (transaction.isActive() && transaction.isPendingForApprovalTransaction()) {
|
||||
purchaseTransactions.add(transaction);
|
||||
}
|
||||
}
|
||||
@@ -523,4 +526,30 @@ public class ShareAccount extends AbstractPersistable<Long> {
|
||||
public Date getApprovedDate() {
|
||||
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;
|
||||
|
||||
@Column(name = "is_active", nullable = false)
|
||||
private boolean status = true;
|
||||
private boolean active = true;
|
||||
|
||||
@Column(name = "charge_amount_or_percentage")
|
||||
private BigDecimal amountOrPercentage;
|
||||
@@ -118,13 +118,13 @@ public class ShareAccountCharge extends AbstractPersistable<Long> {
|
||||
|
||||
populateDerivedFields(transactionAmount, chargeAmount);
|
||||
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())) {
|
||||
this.percentage = null;
|
||||
this.amountOrPercentage = chargeAmount ;
|
||||
this.amount = BigDecimal.ZERO;
|
||||
this.amountPercentageAppliedTo = null;
|
||||
this.amountPaid = null;
|
||||
@@ -149,6 +149,7 @@ public class ShareAccountCharge extends AbstractPersistable<Long> {
|
||||
}
|
||||
|
||||
public void resetToOriginal(final MonetaryCurrency currency) {
|
||||
this.amount = BigDecimal.ZERO ;
|
||||
this.amountPaid = BigDecimal.ZERO;
|
||||
this.amountWaived = BigDecimal.ZERO;
|
||||
this.amountWrittenOff = BigDecimal.ZERO;
|
||||
@@ -163,7 +164,7 @@ public class ShareAccountCharge extends AbstractPersistable<Long> {
|
||||
this.amountPaid = amountPaid.getAmount();
|
||||
this.amountOutstanding = calculateAmountOutstanding(currency);
|
||||
this.paid = false;
|
||||
this.status = true;
|
||||
this.active = true;
|
||||
}
|
||||
|
||||
public Money waive(final MonetaryCurrency currency) {
|
||||
@@ -181,7 +182,7 @@ public class ShareAccountCharge extends AbstractPersistable<Long> {
|
||||
this.amountWaived = amountWaived.getAmount();
|
||||
this.amountOutstanding = calculateAmountOutstanding(currency);
|
||||
this.waived = false;
|
||||
this.status = true;
|
||||
this.active = true;
|
||||
}
|
||||
|
||||
public Money pay(final MonetaryCurrency currency, final Money amountPaid) {
|
||||
@@ -203,17 +204,8 @@ public class ShareAccountCharge extends AbstractPersistable<Long> {
|
||||
this.shareAccount = shareAccount;
|
||||
}
|
||||
|
||||
public void update(final BigDecimal amount) {
|
||||
final BigDecimal transactionAmount = BigDecimal.ZERO;
|
||||
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();
|
||||
}
|
||||
public void update(final BigDecimal transactionAmount, final BigDecimal amount) {
|
||||
populateDerivedFields(transactionAmount, amount);
|
||||
}
|
||||
|
||||
private boolean isGreaterThanZero(final BigDecimal value) {
|
||||
@@ -360,7 +352,7 @@ public class ShareAccountCharge extends AbstractPersistable<Long> {
|
||||
}
|
||||
|
||||
public boolean isActive() {
|
||||
return this.status;
|
||||
return this.active;
|
||||
}
|
||||
|
||||
public boolean isNotActive() {
|
||||
@@ -420,6 +412,10 @@ public class ShareAccountCharge extends AbstractPersistable<Long> {
|
||||
return toReturnAmount;
|
||||
}
|
||||
|
||||
public void setActive(boolean active) {
|
||||
this.active = active ;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(final Object obj) {
|
||||
if (obj == null) { return false; }
|
||||
|
||||
+5
@@ -74,4 +74,9 @@ public class ShareAccountChargePaidBy extends AbstractPersistable<Long>{
|
||||
public Long getShareChargeId() {
|
||||
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")
|
||||
private BigDecimal amount ;
|
||||
|
||||
@Column(name = "amount_paid")
|
||||
private BigDecimal amountPaid ;
|
||||
|
||||
@Column(name = "charge_amount")
|
||||
private BigDecimal totalChargeAmount ;
|
||||
private BigDecimal chargeAmount ;
|
||||
|
||||
@Column(name = "status_enum", nullable = true)
|
||||
private Integer status;
|
||||
@@ -67,6 +70,9 @@ public class ShareAccountTransaction extends AbstractPersistable<Long> {
|
||||
@Column(name = "type_enum", nullable = true)
|
||||
private Integer type ;
|
||||
|
||||
@Column(name = "is_active", nullable = false)
|
||||
private boolean active = true ;
|
||||
|
||||
@LazyCollection(LazyCollectionOption.FALSE)
|
||||
@OneToMany(cascade = CascadeType.ALL, mappedBy = "shareAccountTransaction", orphanRemoval = true)
|
||||
private final Set<ShareAccountChargePaidBy> shareAccountChargesPaid = new HashSet<>();
|
||||
@@ -86,24 +92,27 @@ public class ShareAccountTransaction extends AbstractPersistable<Long> {
|
||||
this.status = PurchasedSharesStatusType.APPLIED.getValue();
|
||||
this.type = PurchasedSharesStatusType.PURCHASED.getValue() ;
|
||||
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,
|
||||
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.totalShares = totalShares;
|
||||
this.shareValue = shareValue;
|
||||
this.status = status ;
|
||||
this.type = type ;
|
||||
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) {
|
||||
final Integer status = PurchasedSharesStatusType.APPROVED.getValue() ;
|
||||
final Integer type = PurchasedSharesStatusType.REDEEMED.getValue() ;
|
||||
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) {
|
||||
@@ -113,7 +122,8 @@ public class ShareAccountTransaction extends AbstractPersistable<Long> {
|
||||
final Integer type = PurchasedSharesStatusType.CHARGE_PAYMENT.getValue() ;
|
||||
BigDecimal amount = charge.percentageOrAmount() ;
|
||||
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() {
|
||||
@@ -133,6 +143,7 @@ public class ShareAccountTransaction extends AbstractPersistable<Long> {
|
||||
this.totalShares = totalShares;
|
||||
this.shareValue = shareValue;
|
||||
this.amount = shareValue.multiply(BigDecimal.valueOf(totalShares)) ;
|
||||
this.chargeAmount = BigDecimal.ZERO ;
|
||||
this.status = PurchasedSharesStatusType.APPLIED.getValue();
|
||||
}
|
||||
|
||||
@@ -146,8 +157,8 @@ public class ShareAccountTransaction extends AbstractPersistable<Long> {
|
||||
|
||||
public void reject() {
|
||||
this.status = PurchasedSharesStatusType.REJECTED.getValue() ;
|
||||
if(this.totalChargeAmount != null) {
|
||||
this.amount = this.amount.subtract(totalChargeAmount) ;
|
||||
if(this.chargeAmount != null) {
|
||||
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()) ;
|
||||
}
|
||||
|
||||
public boolean isPurchaseRejectedTransaction() {
|
||||
return this.status.equals(PurchasedSharesStatusType.REJECTED.getValue()) && this.type.equals(PurchasedSharesStatusType.PURCHASED.getValue()) ;
|
||||
}
|
||||
|
||||
public void addShareAccountChargePaidBy(final ShareAccountChargePaidBy chargePaidBy) {
|
||||
this.shareAccountChargesPaid.add(chargePaidBy) ;
|
||||
}
|
||||
@@ -176,17 +191,17 @@ public class ShareAccountTransaction extends AbstractPersistable<Long> {
|
||||
}
|
||||
|
||||
public BigDecimal chargeAmount() {
|
||||
return this.totalChargeAmount ;
|
||||
return this.chargeAmount ;
|
||||
}
|
||||
|
||||
public void updateChargeAmount(BigDecimal totalChargeAmount) {
|
||||
this.amount = this.amount.add(totalChargeAmount);
|
||||
this.totalChargeAmount = totalChargeAmount ;
|
||||
this.chargeAmount = totalChargeAmount ;
|
||||
}
|
||||
|
||||
public void deductChargesFromTotalAmount(BigDecimal totalChargeAmount) {
|
||||
this.amount = this.amount.subtract(totalChargeAmount);
|
||||
this.totalChargeAmount = totalChargeAmount ;
|
||||
this.chargeAmount = totalChargeAmount ;
|
||||
}
|
||||
|
||||
public Set<ShareAccountChargePaidBy> getChargesPaidBy() {
|
||||
@@ -201,9 +216,32 @@ public class ShareAccountTransaction extends AbstractPersistable<Long> {
|
||||
return this.type ;
|
||||
}
|
||||
|
||||
public void adjustRedeemAmount() {
|
||||
if(this.totalChargeAmount != null) {
|
||||
this.amount = this.amount.subtract(totalChargeAmount) ;
|
||||
public void updateAmountPaid(final BigDecimal amountPaid) {
|
||||
this.amountPaid = amountPaid ;
|
||||
}
|
||||
|
||||
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 ;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
+325
-137
@@ -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.common.domain.PeriodFrequencyType;
|
||||
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.SavingsAccountRepositoryWrapper;
|
||||
import org.apache.fineract.portfolio.shareaccounts.domain.ShareAccount;
|
||||
@@ -87,9 +86,8 @@ public class ShareAccountDataSerializer {
|
||||
|
||||
@Autowired
|
||||
public ShareAccountDataSerializer(final PlatformSecurityContext platformSecurityContext, final FromJsonHelper fromApiJsonHelper,
|
||||
final ChargeRepositoryWrapper chargeRepository,
|
||||
final SavingsAccountRepositoryWrapper savingsAccountRepositoryWrapper, final ClientRepositoryWrapper clientRepositoryWrapper,
|
||||
final ShareProductRepositoryWrapper shareProductRepository) {
|
||||
final ChargeRepositoryWrapper chargeRepository, final SavingsAccountRepositoryWrapper savingsAccountRepositoryWrapper,
|
||||
final ClientRepositoryWrapper clientRepositoryWrapper, final ShareProductRepositoryWrapper shareProductRepository) {
|
||||
this.platformSecurityContext = platformSecurityContext;
|
||||
this.fromApiJsonHelper = fromApiJsonHelper;
|
||||
this.chargeRepository = chargeRepository;
|
||||
@@ -117,7 +115,7 @@ public class ShareAccountDataSerializer {
|
||||
baseDataValidator.reset().parameter(ShareAccountApiConstants.submitteddate_paramname).value(submittedDate).notNull();
|
||||
|
||||
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);
|
||||
baseDataValidator.reset().parameter(ShareAccountApiConstants.savingsaccountid_paramname).value(savingsAccountId).notNull()
|
||||
@@ -126,25 +124,16 @@ public class ShareAccountDataSerializer {
|
||||
final Long requestedShares = this.fromApiJsonHelper.extractLongNamed(ShareAccountApiConstants.requestedshares_paramname, element);
|
||||
baseDataValidator.reset().parameter(ShareAccountApiConstants.requestedshares_paramname).value(requestedShares).notNull()
|
||||
.longGreaterThanZero();
|
||||
boolean allowed = shareProduct.isSharesAllowed(requestedShares) ;
|
||||
if(!allowed) {
|
||||
baseDataValidator.reset().parameter(ShareAccountApiConstants.requestedshares_paramname).value(requestedShares).failWithCode("differ.from.productdefinition", "Out of range");;
|
||||
if(requestedShares < shareProduct.getMinimumClientShares()) {
|
||||
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");
|
||||
}
|
||||
|
||||
/*Long subscribedShares = shareProduct.getSubscribedShares() ;
|
||||
if(subscribedShares == null) subscribedShares = new Long(0) ;
|
||||
Long totalShares = shareProduct.getTotalShares() ;
|
||||
Long issuedShares = shareProduct.getSharesIssued() ;
|
||||
if(issuedShares == null) issuedShares = totalShares ;
|
||||
if((subscribedShares+requestedShares) > issuedShares) {
|
||||
throw new IssueableSharesExceededException() ;
|
||||
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");
|
||||
}
|
||||
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);
|
||||
baseDataValidator.reset().parameter(ShareAccountApiConstants.applicationdate_param).value(applicationDate).notNull();
|
||||
|
||||
@@ -185,7 +174,7 @@ public class ShareAccountDataSerializer {
|
||||
String accountNo = null;
|
||||
Long approvedShares = null;
|
||||
Long pendingShares = requestedShares;
|
||||
BigDecimal unitPrice = shareProduct.deriveMarketPrice(applicationDate.toDate()) ;
|
||||
BigDecimal unitPrice = shareProduct.deriveMarketPrice(applicationDate.toDate());
|
||||
ShareAccountTransaction transaction = new ShareAccountTransaction(applicationDate.toDate(), requestedShares, unitPrice);
|
||||
Set<ShareAccountTransaction> sharesPurchased = new HashSet<>();
|
||||
sharesPurchased.add(transaction);
|
||||
@@ -204,28 +193,28 @@ public class ShareAccountDataSerializer {
|
||||
charge.update(account);
|
||||
}
|
||||
}
|
||||
createChargeTransaction(account, transaction);
|
||||
createChargeTransaction(account);
|
||||
return account;
|
||||
}
|
||||
|
||||
private void createChargeTransaction(ShareAccount account, final ShareAccountTransaction transaction) {
|
||||
private void createChargeTransaction(ShareAccount account) {
|
||||
BigDecimal totalChargeAmount = BigDecimal.ZERO;
|
||||
Set<ShareAccountCharge> charges = account.getCharges();
|
||||
Date currentDate = DateUtils.getLocalDateOfTenant().toDate();
|
||||
for (ShareAccountCharge charge : charges) {
|
||||
if (charge.isShareAccountActivation()) {
|
||||
charge.deriveChargeAmount(totalChargeAmount) ;
|
||||
if (charge.isActive() && charge.isShareAccountActivation()) {
|
||||
charge.deriveChargeAmount(totalChargeAmount);
|
||||
ShareAccountTransaction chargeTransaction = ShareAccountTransaction.createChargeTransaction(currentDate, charge);
|
||||
ShareAccountChargePaidBy paidBy = new ShareAccountChargePaidBy(chargeTransaction, charge, charge.percentageOrAmount());
|
||||
chargeTransaction.addShareAccountChargePaidBy(paidBy);
|
||||
account.addChargeTransaction(chargeTransaction);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Set<ShareAccountTransaction> pendingApprovalTransaction = account.getPendingForApprovalSharePurchaseTransactions();
|
||||
for (ShareAccountTransaction pending : pendingApprovalTransaction) {
|
||||
for (ShareAccountCharge charge : charges) {
|
||||
if (charge.isSharesPurchaseCharge()) {
|
||||
if (charge.isActive() && charge.isSharesPurchaseCharge()) {
|
||||
BigDecimal amount = charge.deriveChargeAmount(pending.amount());
|
||||
ShareAccountChargePaidBy paidBy = new ShareAccountChargePaidBy(pending, charge, amount);
|
||||
pending.addShareAccountChargePaidBy(paidBy);
|
||||
@@ -245,7 +234,7 @@ public class ShareAccountDataSerializer {
|
||||
final List<ApiParameterError> dataValidationErrors = new ArrayList<>();
|
||||
final DataValidatorBuilder baseDataValidator = new DataValidatorBuilder(dataValidationErrors).resource("sharesaccount");
|
||||
JsonElement element = jsonCommand.parsedJson();
|
||||
ShareProduct shareProduct = account.getShareProduct() ;
|
||||
ShareProduct shareProduct = account.getShareProduct();
|
||||
final Locale locale = this.fromApiJsonHelper.extractLocaleParameter(element.getAsJsonObject());
|
||||
if (this.fromApiJsonHelper.parameterExists(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)) {
|
||||
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)) {
|
||||
actualChanges.put(ShareAccountApiConstants.externalid_paramname, externalId);
|
||||
}
|
||||
@@ -274,25 +263,51 @@ public class ShareAccountDataSerializer {
|
||||
|
||||
if (this.fromApiJsonHelper.parameterExists(ShareAccountApiConstants.savingsaccountid_paramname, element)) {
|
||||
Long savingsAccountId = this.fromApiJsonHelper.extractLongNamed(ShareAccountApiConstants.savingsaccountid_paramname, element);
|
||||
SavingsAccount savingsAccount = this.savingsAccountRepositoryWrapper.findOneWithNotFoundDetection(savingsAccountId);
|
||||
if (account.setSavingsAccount(savingsAccount)) {
|
||||
actualChanges.put(ShareAccountApiConstants.savingsaccountid_paramname, savingsAccount);
|
||||
baseDataValidator.reset().parameter(ShareAccountApiConstants.savingsaccountid_paramname).value(savingsAccountId).notNull()
|
||||
.longGreaterThanZero();
|
||||
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)) {
|
||||
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)
|
||||
.toDate();
|
||||
BigDecimal unitPrice = shareProduct.deriveMarketPrice(applicationDate) ;
|
||||
ShareAccountTransaction purchased = new ShareAccountTransaction(applicationDate, requestedShares, unitPrice);
|
||||
account.updateRequestedShares(purchased);
|
||||
actualChanges.put(ShareAccountApiConstants.requestedshares_paramname, purchased);
|
||||
boolean allowed = shareProduct.isSharesAllowed(requestedShares) ;
|
||||
if(!allowed) {
|
||||
baseDataValidator.reset().parameter(ShareAccountApiConstants.requestedshares_paramname).value(requestedShares).failWithCode("differ.from.productdefinition", "Out of range");;
|
||||
BigDecimal unitPrice = shareProduct.deriveMarketPrice(applicationDate);
|
||||
ShareAccountTransaction transaction = new ShareAccountTransaction(applicationDate, requestedShares, unitPrice);
|
||||
account.addTransaction(transaction);
|
||||
actualChanges.put(ShareAccountApiConstants.requestedshares_paramname, "Transaction");
|
||||
|
||||
if(requestedShares < shareProduct.getMinimumClientShares()) {
|
||||
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)) {
|
||||
shareProduct = account.getShareProduct();
|
||||
Set<ShareAccountCharge> updatedCharges = assembleListOfAccountChargesforUpdate(account, element, shareProduct.getCurrency()
|
||||
.getCode());
|
||||
if (!updatedCharges.isEmpty()) {
|
||||
actualChanges.put(ShareAccountApiConstants.charges_paramname, new HashSet<ShareAccountCharge>());
|
||||
final MonetaryCurrency currency = shareProduct.getCurrency();
|
||||
Set<ShareAccountCharge> charges = assembleListOfAccountCharges(element, currency.getCode());
|
||||
if (charges != null) {
|
||||
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); }
|
||||
return actualChanges;
|
||||
}
|
||||
@@ -366,30 +387,57 @@ public class ShareAccountDataSerializer {
|
||||
final DateTimeFormatter formatter = DateTimeFormat.forPattern(jsonCommand.dateFormat()).withLocale(jsonCommand.extractLocale());
|
||||
final String submittalDateAsString = formatter.print(submittalDate);
|
||||
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); }
|
||||
|
||||
AppUser approvedUser = this.platformSecurityContext.authenticatedUser();
|
||||
account.approve(approvedDate.toDate(), approvedUser);
|
||||
account.approve(approvedDate.toDate(), approvedUser);
|
||||
actualChanges.put(ShareAccountApiConstants.id_paramname, account.getId());
|
||||
updateTotalChargeDerived(account);
|
||||
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) {
|
||||
// Set<ShareAccountCharge> charges = shareAccount.getCharges() ;
|
||||
Set<ShareAccountTransaction> transactions = shareAccount.getShareAccountTransactions();
|
||||
for (ShareAccountTransaction transaction : transactions) {
|
||||
Set<ShareAccountChargePaidBy> paidBySet = transaction.getChargesPaidBy();
|
||||
if (paidBySet != null && !paidBySet.isEmpty()) {
|
||||
for (ShareAccountChargePaidBy chargePaidBy : paidBySet) {
|
||||
ShareAccountCharge charge = chargePaidBy.getCharge();
|
||||
if (charge.isSharesPurchaseCharge()) {
|
||||
Money money = Money.of(shareAccount.getCurrency(), chargePaidBy.getAmount());
|
||||
charge.updatePaidAmountBy(money);
|
||||
if (transaction.isActive()) {
|
||||
Set<ShareAccountChargePaidBy> paidBySet = transaction.getChargesPaidBy();
|
||||
if (paidBySet != null && !paidBySet.isEmpty()) {
|
||||
for (ShareAccountChargePaidBy chargePaidBy : paidBySet) {
|
||||
ShareAccountCharge charge = chargePaidBy.getCharge();
|
||||
if (charge.isActive() && charge.isSharesPurchaseCharge()) {
|
||||
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) {
|
||||
Map<String, Object> actualChanges = new HashMap<>();
|
||||
if (StringUtils.isBlank(jsonCommand.json())) { throw new InvalidJsonException(); }
|
||||
//final Type typeOfMap = new TypeToken<Map<String, Object>>() {}.getType();
|
||||
//this.fromApiJsonHelper.checkForUnsupportedParameters(typeOfMap, jsonCommand.json(), ShareAccountApiConstants.activateParameters);
|
||||
//final List<ApiParameterError> dataValidationErrors = new ArrayList<>();
|
||||
//final DataValidatorBuilder baseDataValidator = new DataValidatorBuilder(dataValidationErrors).resource("sharesaccount");
|
||||
//JsonElement element = jsonCommand.parsedJson();
|
||||
//String notes = this.fromApiJsonHelper.extractStringNamed(ShareAccountApiConstants.note_paramname, element);
|
||||
// final Type typeOfMap = new TypeToken<Map<String, Object>>()
|
||||
// {}.getType();
|
||||
// this.fromApiJsonHelper.checkForUnsupportedParameters(typeOfMap,
|
||||
// jsonCommand.json(), ShareAccountApiConstants.activateParameters);
|
||||
// final List<ApiParameterError> dataValidationErrors = new
|
||||
// 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)
|
||||
//AppUser approvedUser = this.platformSecurityContext.authenticatedUser();
|
||||
// AppUser approvedUser =
|
||||
// this.platformSecurityContext.authenticatedUser();
|
||||
account.undoApprove();
|
||||
updateTotalChargeDerivedForUndoApproval(account) ;
|
||||
actualChanges.put(ShareAccountApiConstants.charges_paramname, Boolean.TRUE);
|
||||
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")
|
||||
public Map<String, Object> validateAndReject(JsonCommand jsonCommand, ShareAccount account) {
|
||||
Map<String, Object> actualChanges = new HashMap<>();
|
||||
@@ -449,10 +532,17 @@ public class ShareAccountDataSerializer {
|
||||
private void handlechargesOnActivation(final ShareAccount account) {
|
||||
Set<ShareAccountCharge> charges = account.getCharges();
|
||||
for (ShareAccountCharge charge : charges) {
|
||||
if (charge.isShareAccountActivation()) {
|
||||
if (charge.isActive() && charge.isShareAccountActivation()) {
|
||||
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) {
|
||||
@@ -484,49 +574,6 @@ public class ShareAccountDataSerializer {
|
||||
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) {
|
||||
PeriodFrequencyType frequencyType = PeriodFrequencyType.INVALID;
|
||||
frequencyType = PeriodFrequencyType.fromInt(this.fromApiJsonHelper.extractIntegerWithLocaleNamed(paramName, element));
|
||||
@@ -546,15 +593,33 @@ public class ShareAccountDataSerializer {
|
||||
baseDataValidator.reset().parameter(ShareAccountApiConstants.requesteddate_paramname).value(requestedDate).notNull();
|
||||
final Long sharesRequested = this.fromApiJsonHelper.extractLongNamed(ShareAccountApiConstants.requestedshares_paramname, element);
|
||||
baseDataValidator.reset().parameter(ShareAccountApiConstants.requestedshares_paramname).value(sharesRequested).notNull();
|
||||
ShareProduct shareProduct = account.getShareProduct() ;
|
||||
if(sharesRequested != null) {
|
||||
boolean allowed = shareProduct.isSharesAllowed(sharesRequested) ;
|
||||
if(!allowed) {
|
||||
baseDataValidator.reset().parameter(ShareAccountApiConstants.requestedshares_paramname).value(sharesRequested).failWithCode("differ.from.productdefinition", "Out of range");;
|
||||
}
|
||||
ShareProduct shareProduct = account.getShareProduct();
|
||||
if (sharesRequested != null) {
|
||||
Long totalSharesAfterapproval = account.getTotalApprovedShares() + sharesRequested;
|
||||
if(totalSharesAfterapproval > shareProduct.getMaximumClientShares()) {
|
||||
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); }
|
||||
final BigDecimal unitPrice = shareProduct.deriveMarketPrice(requestedDate.toDate()) ;
|
||||
final BigDecimal unitPrice = shareProduct.deriveMarketPrice(requestedDate.toDate());
|
||||
ShareAccountTransaction purchaseTransaction = new ShareAccountTransaction(requestedDate.toDate(), sharesRequested, unitPrice);
|
||||
account.addAdditionalPurchasedShares(purchaseTransaction);
|
||||
handleAdditionalSharesChargeTransactions(account, purchaseTransaction);
|
||||
@@ -566,7 +631,7 @@ public class ShareAccountDataSerializer {
|
||||
Set<ShareAccountCharge> charges = account.getCharges();
|
||||
BigDecimal totalChargeAmount = BigDecimal.ZERO;
|
||||
for (ShareAccountCharge charge : charges) {
|
||||
if (charge.isSharesPurchaseCharge()) {
|
||||
if (charge.isActive() && charge.isSharesPurchaseCharge()) {
|
||||
BigDecimal amount = charge.updateChargeDetailsForAdditionalSharesRequest(purchaseTransaction.amount());
|
||||
ShareAccountChargePaidBy paidBy = new ShareAccountChargePaidBy(purchaseTransaction, charge, amount);
|
||||
purchaseTransaction.addShareAccountChargePaidBy(paidBy);
|
||||
@@ -588,20 +653,21 @@ public class ShareAccountDataSerializer {
|
||||
final ArrayList<Long> purchasedShares = new ArrayList<>();
|
||||
if (this.fromApiJsonHelper.parameterExists(ShareAccountApiConstants.requestedshares_paramname, element)) {
|
||||
JsonArray array = this.fromApiJsonHelper.extractJsonArrayNamed(ShareAccountApiConstants.requestedshares_paramname, element);
|
||||
long totalShares = 0 ;
|
||||
long totalShares = 0;
|
||||
for (JsonElement arrayElement : array) {
|
||||
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);
|
||||
if (transaction != null) {
|
||||
totalShares+=transaction.getTotalShares().longValue() ;
|
||||
validateTotalSubsribedShares(account, transaction, baseDataValidator) ;
|
||||
totalShares += transaction.getTotalShares().longValue();
|
||||
transaction.approve();
|
||||
updateTotalChargeDerivedForAdditonalShares(account, transaction);
|
||||
}
|
||||
purchasedShares.add(purchasedSharesId);
|
||||
}
|
||||
if(totalShares > 0) {
|
||||
account.updateApprovedShares(new Long(totalShares)) ;
|
||||
if (totalShares > 0) {
|
||||
account.updateApprovedShares(new Long(totalShares));
|
||||
}
|
||||
}
|
||||
if (!dataValidationErrors.isEmpty()) { throw new PlatformApiDataValidationException(dataValidationErrors); }
|
||||
@@ -614,11 +680,14 @@ public class ShareAccountDataSerializer {
|
||||
if (paidBySet != null && !paidBySet.isEmpty()) {
|
||||
for (ShareAccountChargePaidBy chargePaidBy : paidBySet) {
|
||||
ShareAccountCharge charge = chargePaidBy.getCharge();
|
||||
if (charge.isSharesPurchaseCharge()) {
|
||||
if (charge.isActive() && charge.isSharesPurchaseCharge()) {
|
||||
Money money = Money.of(shareAccount.getCurrency(), chargePaidBy.getAmount());
|
||||
charge.updatePaidAmountBy(money);
|
||||
}
|
||||
}
|
||||
if (!transaction.isChargeTransaction()) {
|
||||
transaction.addAmountPaid(transaction.chargeAmount());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -631,20 +700,20 @@ public class ShareAccountDataSerializer {
|
||||
JsonElement element = jsonCommand.parsedJson();
|
||||
final ArrayList<Long> purchasedShares = new ArrayList<>();
|
||||
if (this.fromApiJsonHelper.parameterExists(ShareAccountApiConstants.requestedshares_paramname, element)) {
|
||||
long totalShares = 0 ;
|
||||
long totalShares = 0;
|
||||
JsonArray array = this.fromApiJsonHelper.extractJsonArrayNamed(ShareAccountApiConstants.requestedshares_paramname, element);
|
||||
for (JsonElement arrayElement : array) {
|
||||
final Long purchasedSharesId = this.fromApiJsonHelper.extractLongNamed(ShareAccountApiConstants.id_paramname, arrayElement);
|
||||
ShareAccountTransaction shares = account.retrievePurchasedShares(purchasedSharesId);
|
||||
if (shares != null) {
|
||||
shares.reject();
|
||||
updateTotalChargeDerivedForAdditonalSharesReject(account, shares) ;
|
||||
totalShares +=shares.getTotalShares().longValue() ;
|
||||
updateTotalChargeDerivedForAdditonalSharesReject(account, shares);
|
||||
totalShares += shares.getTotalShares().longValue();
|
||||
}
|
||||
purchasedShares.add(purchasedSharesId);
|
||||
}
|
||||
if(totalShares > 0) {
|
||||
account.removePendingShares(new Long(totalShares)) ;
|
||||
if (totalShares > 0) {
|
||||
account.removePendingShares(new Long(totalShares));
|
||||
}
|
||||
}
|
||||
actualChanges.put(ShareAccountApiConstants.requestedshares_paramname, purchasedShares);
|
||||
@@ -656,14 +725,17 @@ public class ShareAccountDataSerializer {
|
||||
if (paidBySet != null && !paidBySet.isEmpty()) {
|
||||
for (ShareAccountChargePaidBy chargePaidBy : paidBySet) {
|
||||
ShareAccountCharge charge = chargePaidBy.getCharge();
|
||||
if (charge.isSharesPurchaseCharge()) {
|
||||
if (charge.isActive() && charge.isSharesPurchaseCharge()) {
|
||||
Money money = Money.of(shareAccount.getCurrency(), chargePaidBy.getAmount());
|
||||
charge.updatePaidAmountBy(money);
|
||||
}
|
||||
}
|
||||
if (!transaction.isChargeTransaction()) {
|
||||
transaction.addAmountPaid(transaction.chargeAmount());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public Map<String, Object> validateAndRedeemShares(JsonCommand jsonCommand, ShareAccount account) {
|
||||
Map<String, Object> actualChanges = new HashMap<>();
|
||||
if (StringUtils.isBlank(jsonCommand.json())) { throw new InvalidJsonException(); }
|
||||
@@ -683,19 +755,116 @@ public class ShareAccountDataSerializer {
|
||||
final BigDecimal unitPrice = this.fromApiJsonHelper.extractBigDecimalNamed(ShareAccountApiConstants.purchasedprice_paramname,
|
||||
element, locale);
|
||||
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,
|
||||
unitPrice);
|
||||
account.addAdditionalPurchasedShares(transaction);
|
||||
actualChanges.put(ShareAccountApiConstants.requestedshares_paramname, transaction);
|
||||
validateRedeemRequest(account, transaction, baseDataValidator, dataValidationErrors) ;
|
||||
handleRedeemSharesChargeTransactions(account, transaction);
|
||||
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) {
|
||||
Set<ShareAccountCharge> charges = account.getCharges();
|
||||
BigDecimal totalChargeAmount = BigDecimal.ZERO;
|
||||
for (ShareAccountCharge charge : charges) {
|
||||
if (charge.isSharesRedeemCharge()) {
|
||||
if (charge.isActive() && charge.isSharesRedeemCharge()) {
|
||||
BigDecimal amount = charge.updateChargeDetailsForAdditionalSharesRequest(transaction.amount());
|
||||
ShareAccountChargePaidBy paidBy = new ShareAccountChargePaidBy(transaction, charge, amount);
|
||||
transaction.addShareAccountChargePaidBy(paidBy);
|
||||
@@ -707,16 +876,15 @@ public class ShareAccountDataSerializer {
|
||||
if (paidBySet != null && !paidBySet.isEmpty()) {
|
||||
for (ShareAccountChargePaidBy chargePaidBy : paidBySet) {
|
||||
ShareAccountCharge charge = chargePaidBy.getCharge();
|
||||
if (charge.isSharesRedeemCharge()) {
|
||||
if (charge.isActive() && charge.isSharesRedeemCharge()) {
|
||||
Money money = Money.of(account.getCurrency(), chargePaidBy.getAmount());
|
||||
charge.updatePaidAmountBy(money);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// transaction.adjustRedeemAmount();
|
||||
transaction.addAmountPaid(transaction.chargeAmount());
|
||||
}
|
||||
|
||||
|
||||
public Map<String, Object> validateAndClose(JsonCommand jsonCommand, ShareAccount account) {
|
||||
Map<String, Object> actualChanges = new HashMap<>();
|
||||
if (StringUtils.isBlank(jsonCommand.json())) { throw new InvalidJsonException(); }
|
||||
@@ -727,15 +895,35 @@ public class ShareAccountDataSerializer {
|
||||
JsonElement element = jsonCommand.parsedJson();
|
||||
LocalDate closedDate = this.fromApiJsonHelper.extractLocalDateNamed(ShareAccountApiConstants.closeddate_paramname, element);
|
||||
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();
|
||||
final BigDecimal unitPrice = account.getShareProduct().deriveMarketPrice(DateUtils.getDateOfTenant()) ;
|
||||
ShareAccountTransaction transaction = ShareAccountTransaction.createRedeemTransaction(closedDate.toDate(), account.getTotalApprovedShares(), unitPrice) ;
|
||||
final BigDecimal unitPrice = account.getShareProduct().deriveMarketPrice(DateUtils.getDateOfTenant());
|
||||
ShareAccountTransaction transaction = ShareAccountTransaction.createRedeemTransaction(closedDate.toDate(),
|
||||
account.getTotalApprovedShares(), unitPrice);
|
||||
account.addAdditionalPurchasedShares(transaction);
|
||||
account.close(closedDate.toDate(), approvedUser);
|
||||
handleRedeemSharesChargeTransactions(account, transaction) ;
|
||||
handleRedeemSharesChargeTransactions(account, transaction);
|
||||
actualChanges.put(ShareAccountApiConstants.requestedshares_paramname, transaction);
|
||||
updateTotalChargeDerived(account);
|
||||
if (!dataValidationErrors.isEmpty()) { throw new PlatformApiDataValidationException(dataValidationErrors); }
|
||||
|
||||
return actualChanges;
|
||||
}
|
||||
}
|
||||
|
||||
+2
-2
@@ -20,9 +20,9 @@ package org.apache.fineract.portfolio.shareaccounts.service;
|
||||
|
||||
import java.util.Collection;
|
||||
|
||||
import org.apache.fineract.portfolio.shareaccounts.data.PurchasedSharesData;
|
||||
import org.apache.fineract.portfolio.shareaccounts.data.ShareAccountTransactionData;
|
||||
|
||||
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.domain.JdbcSupport;
|
||||
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.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.jdbc.core.JdbcTemplate;
|
||||
@@ -44,26 +44,27 @@ public class PurchasedSharesReadPlatformServiceImpl implements
|
||||
this.jdbcTemplate = new JdbcTemplate(dataSource) ;
|
||||
}
|
||||
@Override
|
||||
public Collection<PurchasedSharesData> retrievePurchasedShares(
|
||||
public Collection<ShareAccountTransactionData> retrievePurchasedShares(
|
||||
Long accountId) {
|
||||
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});
|
||||
}
|
||||
|
||||
private final static class PurchasedSharesDataRowMapper implements RowMapper<PurchasedSharesData> {
|
||||
private final static class PurchasedSharesDataRowMapper implements RowMapper<ShareAccountTransactionData> {
|
||||
|
||||
private final String schema ;
|
||||
|
||||
public PurchasedSharesDataRowMapper() {
|
||||
StringBuffer buff = new StringBuffer()
|
||||
.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 ");
|
||||
schema = buff.toString() ;
|
||||
}
|
||||
@Override
|
||||
public PurchasedSharesData mapRow(ResultSet rs, int rowNum)
|
||||
public ShareAccountTransactionData mapRow(ResultSet rs, int rowNum)
|
||||
throws SQLException {
|
||||
final Long id = rs.getLong("id") ;
|
||||
final Long accountId = rs.getLong("account_id") ;
|
||||
@@ -76,7 +77,9 @@ public class PurchasedSharesReadPlatformServiceImpl implements
|
||||
final EnumOptionData typeEnum = SharesEnumerations.purchasedSharesEnum(type) ;
|
||||
final BigDecimal amount = JdbcSupport.getBigDecimalDefaultToZeroIfNull(rs, "amount") ;
|
||||
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() {
|
||||
|
||||
+4
-2
@@ -80,6 +80,7 @@ public class ShareAccountChargeReadPlatformServiceImpl implements
|
||||
.append("sc.charge_calculation_enum as chargeCalculation, c.is_active as isActive, ")
|
||||
.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("sc.charge_amount_or_percentage, ")
|
||||
.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_share_account_charge sc on sc.charge_id = c.id ");
|
||||
@@ -132,13 +133,14 @@ public class ShareAccountChargeReadPlatformServiceImpl implements
|
||||
final EnumOptionData chargeCalculationType = ChargeEnumerations
|
||||
.chargeCalculationType(chargeCalculation);
|
||||
final Boolean isActive = rs.getBoolean("isActive");
|
||||
|
||||
final BigDecimal chargeamountorpercentage = rs.getBigDecimal("charge_amount_or_percentage") ;
|
||||
|
||||
final Collection<ChargeData> chargeOptions = null;
|
||||
return new ShareAccountChargeData(id, chargeId, accountId, name,
|
||||
currency, amount, amountPaid, amountWaived,
|
||||
amountWrittenOff, amountOutstanding, chargeTimeType,
|
||||
chargeCalculationType, percentageOf,
|
||||
amountPercentageAppliedTo, chargeOptions, isActive);
|
||||
amountPercentageAppliedTo, chargeOptions, isActive, chargeamountorpercentage);
|
||||
}
|
||||
|
||||
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.data.ProductData;
|
||||
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.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.ShareAccountDividendData;
|
||||
import org.apache.fineract.portfolio.shareaccounts.data.ShareAccountStatusEnumData;
|
||||
@@ -114,7 +115,7 @@ public class ShareAccountReadPlatformServiceImpl implements ShareAccountReadPlat
|
||||
final Collection<EnumOptionData> minimumActivePeriodFrequencyTypeOptions = this.shareProductDropdownReadPlatformService
|
||||
.retrieveMinimumActivePeriodFrequencyTypeOptions();
|
||||
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,
|
||||
minimumActivePeriodFrequencyTypeOptions, lockinPeriodFrequencyTypeOptions, clientSavingsAccounts, productData.getNominaltShares());
|
||||
} else {
|
||||
@@ -143,7 +144,7 @@ public class ShareAccountReadPlatformServiceImpl implements ShareAccountReadPlat
|
||||
@Override
|
||||
public ShareAccountData retrieveOne(final Long id, final boolean includeTemplate) {
|
||||
Collection<ShareAccountChargeData> charges = this.shareAccountChargeReadPlatformService.retrieveAccountCharges(id, "active");
|
||||
Collection<PurchasedSharesData> purchasedShares = this.purchasedSharesReadPlatformService.retrievePurchasedShares(id);
|
||||
Collection<ShareAccountTransactionData> purchasedShares = this.purchasedSharesReadPlatformService.retrievePurchasedShares(id);
|
||||
|
||||
ShareAccountMapper mapper = new ShareAccountMapper(charges, purchasedShares);
|
||||
String query = "select " + mapper.schema() + "where sa.id=?";
|
||||
@@ -161,8 +162,8 @@ public class ShareAccountReadPlatformServiceImpl implements ShareAccountReadPlat
|
||||
final Collection<EnumOptionData> lockinPeriodFrequencyTypeOptions = this.shareProductDropdownReadPlatformService
|
||||
.retrieveLockinPeriodFrequencyTypeOptions();
|
||||
final Collection<EnumOptionData> minimumActivePeriodFrequencyTypeOptions = lockinPeriodFrequencyTypeOptions;
|
||||
final Collection<SavingsAccountData> clientSavingsAccounts = this.savingsAccountReadPlatformService.retrieveAllForLookup(data
|
||||
.getClientId());
|
||||
final Collection<SavingsAccountData> clientSavingsAccounts = this.savingsAccountReadPlatformService
|
||||
.retrieveActiveForLookup(data.getClientId(), DepositAccountType.SAVINGS_DEPOSIT, productData.getCurrency().code());
|
||||
Collection<ProductData> productOptions = service.retrieveAllForLookup();
|
||||
final Collection<ChargeData> chargeOptions = this.chargeReadPlatformService.retrieveSharesApplicableCharges();
|
||||
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 Collection<ShareAccountChargeData> charges;
|
||||
private final Collection<PurchasedSharesData> purchasedShares;
|
||||
private final Collection<ShareAccountTransactionData> purchasedShares;
|
||||
|
||||
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.purchasedShares = purchasedShares;
|
||||
StringBuffer buff = new StringBuffer()
|
||||
@@ -392,7 +393,7 @@ public class ShareAccountReadPlatformServiceImpl implements ShareAccountReadPlat
|
||||
final Boolean allowdividendsforinactiveclients = null;
|
||||
|
||||
final Collection<ShareAccountChargeData> charges = null;
|
||||
final Collection<PurchasedSharesData> purchasedSharesData = new ArrayList<>();
|
||||
final Collection<ShareAccountTransactionData> purchasedSharesData = new ArrayList<>();
|
||||
final Integer lockinPeriod = null;
|
||||
final EnumOptionData lockPeriodTypeEnum = 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;
|
||||
|
||||
public PurchasedSharesDataRowMapper() {
|
||||
StringBuffer buff = new StringBuffer()
|
||||
.append("saps.id as purchasedId, saps.account_id as accountId, saps.transaction_date as transactionDate, saps.total_shares as purchasedShares, saps.unit_price as unitPrice, ")
|
||||
.append("saps.status_enum as purchaseStatus, saps.type_enum as purchaseType, saps.amount as amount, saps.charge_amount as chargeamount ");
|
||||
.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();
|
||||
}
|
||||
|
||||
@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 accountId = rs.getLong("accountId");
|
||||
final LocalDate transactionDate = new LocalDate(rs.getDate("transactionDate"));
|
||||
@@ -442,8 +445,9 @@ public class ShareAccountReadPlatformServiceImpl implements ShareAccountReadPlat
|
||||
final EnumOptionData typeEnum = SharesEnumerations.purchasedSharesEnum(type);
|
||||
final BigDecimal amount = JdbcSupport.getBigDecimalDefaultToNullIfZero(rs, "amount");
|
||||
final BigDecimal chargeAmount = JdbcSupport.getBigDecimalDefaultToNullIfZero(rs, "chargeamount");
|
||||
return new PurchasedSharesData(id, accountId, transactionDate, numberOfShares, purchasedPrice, statusEnum, typeEnum, amount,
|
||||
chargeAmount);
|
||||
final BigDecimal amountPaid = JdbcSupport.getBigDecimalDefaultToNullIfZero(rs, "amountPaid");
|
||||
return new ShareAccountTransactionData(id, accountId, transactionDate, numberOfShares, purchasedPrice, statusEnum, typeEnum, amount,
|
||||
chargeAmount, amountPaid);
|
||||
}
|
||||
|
||||
public String schema() {
|
||||
|
||||
+90
-14
@@ -18,7 +18,9 @@
|
||||
*/
|
||||
package org.apache.fineract.portfolio.shareaccounts.service;
|
||||
|
||||
import java.math.BigDecimal;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Date;
|
||||
import java.util.HashMap;
|
||||
import java.util.HashSet;
|
||||
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.data.CommandProcessingResult;
|
||||
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.domain.MonetaryCurrency;
|
||||
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.ShareAccountTransaction;
|
||||
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.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.dao.DataIntegrityViolationException;
|
||||
@@ -54,6 +59,8 @@ public class ShareAccountWritePlatformServiceJpaRepositoryImpl implements ShareA
|
||||
|
||||
private final ShareAccountRepositoryWrapper shareAccountRepository;
|
||||
|
||||
private final ShareProductRepositoryWrapper shareProductRepository ;
|
||||
|
||||
private final AccountNumberGenerator accountNumberGenerator;
|
||||
|
||||
private final AccountNumberFormatRepositoryWrapper accountNumberFormatRepository;
|
||||
@@ -62,12 +69,14 @@ public class ShareAccountWritePlatformServiceJpaRepositoryImpl implements ShareA
|
||||
|
||||
@Autowired
|
||||
public ShareAccountWritePlatformServiceJpaRepositoryImpl(final ShareAccountDataSerializer accountDataSerializer,
|
||||
final ShareAccountRepositoryWrapper shareAccountRepository,
|
||||
final ShareAccountRepositoryWrapper shareAccountRepository,
|
||||
final ShareProductRepositoryWrapper shareProductRepository,
|
||||
final AccountNumberGenerator accountNumberGenerator,
|
||||
final AccountNumberFormatRepositoryWrapper accountNumberFormatRepository,
|
||||
final JournalEntryWritePlatformService journalEntryWritePlatformService) {
|
||||
this.accountDataSerializer = accountDataSerializer;
|
||||
this.shareAccountRepository = shareAccountRepository;
|
||||
this.shareProductRepository = shareProductRepository ;
|
||||
this.accountNumberGenerator = accountNumberGenerator;
|
||||
this.accountNumberFormatRepository = accountNumberFormatRepository;
|
||||
this.journalEntryWritePlatformService = journalEntryWritePlatformService;
|
||||
@@ -79,7 +88,6 @@ public class ShareAccountWritePlatformServiceJpaRepositoryImpl implements ShareA
|
||||
ShareAccount account = this.accountDataSerializer.validateAndCreate(jsonCommand);
|
||||
this.shareAccountRepository.save(account);
|
||||
generateAccountNumber(account);
|
||||
//this.shareProductRepository.save(account.getShareProduct()); //subscribed shares is increased
|
||||
journalEntryWritePlatformService.createJournalEntriesForShares(populateJournalEntries(account,
|
||||
account.getPendingForApprovalSharePurchaseTransactions()));
|
||||
return new CommandProcessingResultBuilder() //
|
||||
@@ -126,7 +134,16 @@ public class ShareAccountWritePlatformServiceJpaRepositoryImpl implements ShareA
|
||||
final ShareAccountTransactionEnumData typeEnum = new ShareAccountTransactionEnumData(type.longValue(), null, null);
|
||||
transactionDto.put("status", statusEnum);
|
||||
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("paymentTypeId", null); // FIXME::make it cash
|
||||
// payment
|
||||
@@ -147,14 +164,24 @@ public class ShareAccountWritePlatformServiceJpaRepositoryImpl implements ShareA
|
||||
return accountingBridgeData;
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
@Override
|
||||
public CommandProcessingResult updateShareAccount(Long accountId, JsonCommand jsonCommand) {
|
||||
try {
|
||||
Date transactionDate = DateUtils.getDateOfTenant();
|
||||
ShareAccount account = this.shareAccountRepository.findOneWithNotFoundDetection(accountId);
|
||||
Map<String, Object> changes = this.accountDataSerializer.validateAndUpdate(jsonCommand, account);
|
||||
if (!changes.isEmpty()) {
|
||||
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() //
|
||||
.withCommandId(jsonCommand.commandId()) //
|
||||
.withEntityId(accountId) //
|
||||
@@ -205,8 +232,21 @@ public class ShareAccountWritePlatformServiceJpaRepositoryImpl implements ShareA
|
||||
if (!changes.isEmpty()) {
|
||||
this.shareAccountRepository.save(account);
|
||||
}
|
||||
this.journalEntryWritePlatformService.createJournalEntriesForShares(populateJournalEntries(account,
|
||||
account.getShareAccountTransactions()));
|
||||
Set<ShareAccountTransaction> transactions = 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() //
|
||||
.withCommandId(jsonCommand.commandId()) //
|
||||
.withEntityId(accountId) //
|
||||
@@ -226,8 +266,14 @@ public class ShareAccountWritePlatformServiceJpaRepositoryImpl implements ShareA
|
||||
if (!changes.isEmpty()) {
|
||||
this.shareAccountRepository.save(account);
|
||||
}
|
||||
this.journalEntryWritePlatformService.createJournalEntriesForShares(populateJournalEntries(account,
|
||||
account.getShareAccountTransactions()));
|
||||
Set<ShareAccountTransaction> transactions = 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() //
|
||||
.withCommandId(jsonCommand.commandId()) //
|
||||
.withEntityId(accountId) //
|
||||
@@ -247,11 +293,18 @@ public class ShareAccountWritePlatformServiceJpaRepositoryImpl implements ShareA
|
||||
if (!changes.isEmpty()) {
|
||||
this.shareAccountRepository.save(account);
|
||||
}
|
||||
/*
|
||||
* this.journalEntryWritePlatformService.createJournalEntriesForShares
|
||||
* (populateJournalEntries(account,
|
||||
* account.getShareAccountTransactions()));
|
||||
*/
|
||||
|
||||
Set<ShareAccountTransaction> transactions = account.getShareAccountTransactions() ;
|
||||
ArrayList<Long> journalEntryTransactions = new ArrayList<>() ;
|
||||
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() //
|
||||
.withCommandId(jsonCommand.commandId()) //
|
||||
.withEntityId(accountId) //
|
||||
@@ -285,6 +338,7 @@ public class ShareAccountWritePlatformServiceJpaRepositoryImpl implements ShareA
|
||||
}
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
@Override
|
||||
public CommandProcessingResult approveAdditionalShares(Long accountId, JsonCommand jsonCommand) {
|
||||
|
||||
@@ -294,14 +348,21 @@ public class ShareAccountWritePlatformServiceJpaRepositoryImpl implements ShareA
|
||||
if (!changes.isEmpty()) {
|
||||
this.shareAccountRepository.save(account);
|
||||
ArrayList<Long> transactionIds = (ArrayList<Long>) changes.get(ShareAccountApiConstants.requestedshares_paramname);
|
||||
Long totalSubscribedShares = new Long(0) ;
|
||||
if (transactionIds != null) {
|
||||
Set<ShareAccountTransaction> transactions = new HashSet<>();
|
||||
for (Long id : transactionIds) {
|
||||
ShareAccountTransaction transaction = account.retrievePurchasedShares(id);
|
||||
transactions.add(transaction);
|
||||
totalSubscribedShares += transaction.getTotalShares() ;
|
||||
}
|
||||
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() //
|
||||
.withCommandId(jsonCommand.commandId()) //
|
||||
@@ -314,9 +375,9 @@ public class ShareAccountWritePlatformServiceJpaRepositoryImpl implements ShareA
|
||||
}
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
@Override
|
||||
public CommandProcessingResult rejectAdditionalShares(Long accountId, JsonCommand jsonCommand) {
|
||||
|
||||
try {
|
||||
ShareAccount account = this.shareAccountRepository.findOneWithNotFoundDetection(accountId);
|
||||
Map<String, Object> changes = this.accountDataSerializer.validateAndRejectAddtionalShares(jsonCommand, account);
|
||||
@@ -352,7 +413,21 @@ public class ShareAccountWritePlatformServiceJpaRepositoryImpl implements ShareA
|
||||
this.shareAccountRepository.save(account);
|
||||
ShareAccountTransaction transaction = (ShareAccountTransaction) changes
|
||||
.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<>();
|
||||
transactions.add(transaction);
|
||||
this.journalEntryWritePlatformService.createJournalEntriesForShares(populateJournalEntries(account, transactions));
|
||||
@@ -398,6 +473,7 @@ public class ShareAccountWritePlatformServiceJpaRepositoryImpl implements ShareA
|
||||
return CommandProcessingResult.empty();
|
||||
}
|
||||
}
|
||||
|
||||
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) {
|
||||
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;
|
||||
returnValue = true;
|
||||
}
|
||||
@@ -430,5 +433,16 @@ public class ShareProduct extends AbstractAuditableCustom<AppUser, Long> {
|
||||
public Long getSubscribedShares() {
|
||||
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);
|
||||
}
|
||||
}
|
||||
+22
-8
@@ -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.security.service.PlatformSecurityContext;
|
||||
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.ChargeRepositoryWrapper;
|
||||
import org.apache.fineract.portfolio.common.domain.PeriodFrequencyType;
|
||||
@@ -102,14 +103,18 @@ public class ShareProductDataSerializer {
|
||||
Long totalNumberOfShares = this.fromApiJsonHelper.extractLongNamed(ShareProductApiConstants.totalshares_paramname, element);
|
||||
baseDataValidator.reset().parameter(ShareProductApiConstants.totalshares_paramname).value(totalNumberOfShares).notNull()
|
||||
.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 Integer digitsAfterDecimal = this.fromApiJsonHelper.extractIntegerWithLocaleNamed(
|
||||
ShareProductApiConstants.digitsafterdecimal_paramname, element);
|
||||
final Integer inMultiplesOf = this.fromApiJsonHelper.extractIntegerWithLocaleNamed(
|
||||
ShareProductApiConstants.inmultiplesof_paramname, element);
|
||||
final MonetaryCurrency currency = new MonetaryCurrency(currencyCode, digitsAfterDecimal, inMultiplesOf);
|
||||
final Long sharesIssued = this.fromApiJsonHelper.extractLongNamed(ShareProductApiConstants.totalsharesissued_paramname, element);
|
||||
|
||||
final BigDecimal unitPrice = this.fromApiJsonHelper.extractBigDecimalNamed(ShareProductApiConstants.unitprice_paramname, element,
|
||||
locale);
|
||||
baseDataValidator.reset().parameter(ShareProductApiConstants.unitprice_paramname).value(unitPrice).notNull().positiveAmount();
|
||||
@@ -132,12 +137,12 @@ public class ShareProductDataSerializer {
|
||||
Long nominalClientShares = this.fromApiJsonHelper.extractLongNamed(ShareProductApiConstants.nominaltshares_paramname, element);
|
||||
baseDataValidator.reset().parameter(ShareProductApiConstants.nominaltshares_paramname).value(nominalClientShares).notNull()
|
||||
.longGreaterThanZero();
|
||||
if (minimumClientShares != null && nominalClientShares != null) {
|
||||
if (minimumClientShares != null && nominalClientShares != null && !minimumClientShares.equals(nominalClientShares)) {
|
||||
baseDataValidator.reset().parameter(ShareProductApiConstants.nominaltshares_paramname).value(nominalClientShares)
|
||||
.longGreaterThanNumber(minimumClientShares);
|
||||
}
|
||||
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)
|
||||
.longGreaterThanNumber(nominalClientShares);
|
||||
}
|
||||
@@ -294,8 +299,16 @@ public class ShareProductDataSerializer {
|
||||
if (product.setTotalIssuedShares(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)
|
||||
&& this.fromApiJsonHelper.parameterExists(ShareProductApiConstants.digitsafterdecimal_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;
|
||||
if (sharesIssued != null || unitPrice != null) {
|
||||
if (sharesIssued == null) sharesIssued = product.getSharesIssued();
|
||||
if (sharesIssued == null) sharesIssued = product.getTotalShares();
|
||||
if (unitPrice == null) unitPrice = product.getUnitPrice();
|
||||
shareCapitalValue = BigDecimal.valueOf(sharesIssued).multiply(unitPrice);
|
||||
if (product.setshareCapitalValue(shareCapitalValue)) {
|
||||
actualChanges.put(ShareProductApiConstants.sharecapital_paramname, shareCapitalValue);
|
||||
}
|
||||
}
|
||||
|
||||
if (!dataValidationErrors.isEmpty()) { throw new PlatformApiDataValidationException(dataValidationErrors); }
|
||||
return actualChanges;
|
||||
}
|
||||
|
||||
@@ -455,6 +468,7 @@ public class ShareProductDataSerializer {
|
||||
ShareProductApiConstants.dividendAmountParamName, element);
|
||||
baseDataValidator.reset().parameter(ShareProductApiConstants.dividendAmountParamName).value(dividendAmount).notBlank()
|
||||
.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.Money;
|
||||
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.domain.PurchasedSharesStatusType;
|
||||
import org.apache.fineract.portfolio.shareaccounts.domain.ShareAccountDividendDetails;
|
||||
import org.apache.fineract.portfolio.shareaccounts.service.ShareAccountReadPlatformService;
|
||||
import org.apache.fineract.portfolio.shareproducts.data.ShareProductData;
|
||||
import org.apache.fineract.portfolio.shareproducts.domain.ShareProductDividendPayOutDetails;
|
||||
import org.apache.fineract.portfolio.shareproducts.exception.ShareAccountsNotFoundException;
|
||||
import org.joda.time.Days;
|
||||
import org.joda.time.LocalDate;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
@@ -59,8 +60,15 @@ public class ShareProductDividendAssembler {
|
||||
.getCurrency().currencyInMultiplesOf());
|
||||
Collection<ShareAccountData> shareAccountDatas = this.ShareAccountReadPlatformService.retrieveAllShareAccountDataForDividends(
|
||||
productId, product.getAllowDividendCalculationForInactiveClients(), dividendPeriodStartDate);
|
||||
if(shareAccountDatas == null || shareAccountDatas.isEmpty()) {
|
||||
throw new ShareAccountsNotFoundException(product.getId()) ;
|
||||
}
|
||||
|
||||
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<>();
|
||||
long numberOfShareDays = calculateNumberOfShareDays(dividendPeriodEndDate, dividendPeriodStartDate, minimumActivePeriod,
|
||||
shareAccountDatas, numberOfSharesdaysPerAccount);
|
||||
@@ -88,10 +96,10 @@ public class ShareProductDividendAssembler {
|
||||
long numberOfShareDays = 0;
|
||||
for (ShareAccountData accountData : shareAccountDatas) {
|
||||
long numberOfShareDaysPerAccount = 0;
|
||||
Collection<PurchasedSharesData> purchasedShares = accountData.getPurchasedShares();
|
||||
Collection<ShareAccountTransactionData> purchasedShares = accountData.getPurchasedShares();
|
||||
long numberOfShares = 0;
|
||||
LocalDate lastDividendAppliedDate = null;
|
||||
for (PurchasedSharesData purchasedSharesData : purchasedShares) {
|
||||
for (ShareAccountTransactionData purchasedSharesData : purchasedShares) {
|
||||
final PurchasedSharesStatusType status = PurchasedSharesStatusType.fromInt(purchasedSharesData.getStatus().getId()
|
||||
.intValue());
|
||||
final PurchasedSharesStatusType type = PurchasedSharesStatusType.fromInt(purchasedSharesData.getType().getId()
|
||||
|
||||
+1
-1
@@ -243,7 +243,7 @@ public class ShareProductReadPlatformServiceImpl implements ProductReadPlatformS
|
||||
currencyDisplaySymbol, currencyNameCode);
|
||||
|
||||
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 capitalAmount = rs.getBigDecimal("capital_amount");
|
||||
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,
|
||||
`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',
|
||||
`type_enum` SMALLINT(5) NULL DEFAULT NULL,
|
||||
`is_active` TINYINT(1) NOT NULL DEFAULT '1',
|
||||
PRIMARY KEY (`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` (
|
||||
`id` BIGINT(20) NOT NULL AUTO_INCREMENT,
|
||||
`share_transaction_id` BIGINT(20) NOT NULL,
|
||||
`charge_transaction_id` BIGINT(20) NOT NULL,
|
||||
`share_transaction_id` BIGINT(20) NULL DEFAULT NULL,
|
||||
`charge_transaction_id` BIGINT(20) NULL DEFAULT NULL,
|
||||
`amount` DECIMAL(20,2) NOT NULL,
|
||||
PRIMARY KEY (`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