Transactions for DepositAccounts

This commit is contained in:
Madhukar
2012-09-05 18:29:04 +05:30
parent 464f146a7c
commit 4a90cb091a
5 changed files with 216 additions and 4 deletions
@@ -1,18 +1,25 @@
package org.mifosng.platform.saving.domain; package org.mifosng.platform.saving.domain;
import java.math.BigDecimal; import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.Date; import java.util.Date;
import java.util.List;
import javax.persistence.CascadeType;
import javax.persistence.Column; import javax.persistence.Column;
import javax.persistence.Embedded; import javax.persistence.Embedded;
import javax.persistence.Entity; import javax.persistence.Entity;
import javax.persistence.JoinColumn; import javax.persistence.JoinColumn;
import javax.persistence.ManyToOne; import javax.persistence.ManyToOne;
import javax.persistence.OneToMany;
import javax.persistence.OrderBy;
import javax.persistence.Table; import javax.persistence.Table;
import javax.persistence.Temporal; import javax.persistence.Temporal;
import javax.persistence.TemporalType; import javax.persistence.TemporalType;
import javax.persistence.UniqueConstraint; import javax.persistence.UniqueConstraint;
import org.hibernate.annotations.LazyCollection;
import org.hibernate.annotations.LazyCollectionOption;
import org.joda.time.LocalDate; import org.joda.time.LocalDate;
import org.mifosng.platform.api.commands.DepositAccountCommand; import org.mifosng.platform.api.commands.DepositAccountCommand;
import org.mifosng.platform.api.commands.DepositStateTransitionApprovalCommand; import org.mifosng.platform.api.commands.DepositStateTransitionApprovalCommand;
@@ -127,6 +134,14 @@ public class DepositAccount extends AbstractAuditableCustom<AppUser, Long> {
@Column(name = "withdrawnon_date") @Column(name = "withdrawnon_date")
private Date withdrawnOnDate; private Date withdrawnOnDate;
// see
// http://stackoverflow.com/questions/4334970/hibernate-cannot-simultaneously-fetch-multiple-bags
@OrderBy(value = "id")
@LazyCollection(LazyCollectionOption.FALSE)
@OneToMany(cascade = CascadeType.ALL, mappedBy = "depositAccount", orphanRemoval = true)
private final List<DepositAccountTransaction> depositaccountTransactions = new ArrayList<DepositAccountTransaction>();
public DepositAccount openNew( public DepositAccount openNew(
final Client client, final DepositProduct product, final Client client, final DepositProduct product,
final String externalId, final Money deposit, final BigDecimal maturityInterestRate, final Integer tenureInMonths, final String externalId, final Money deposit, final BigDecimal maturityInterestRate, final Integer tenureInMonths,
@@ -241,8 +256,13 @@ public class DepositAccount extends AbstractAuditableCustom<AppUser, Long> {
Money futureValueOnMaturity = calculator.calculateInterestOnMaturityFor(getDeposit(), this.tenureInMonths, Money futureValueOnMaturity = calculator.calculateInterestOnMaturityFor(getDeposit(), this.tenureInMonths,
this.interestRate, this.interestCompoundedEvery, getInterestCompoundedFrequencyType()); this.interestRate, this.interestCompoundedEvery, getInterestCompoundedFrequencyType());
this.projectedInterestAccruedOnMaturity = futureValueOnMaturity.minus(getDeposit()).getAmount(); this.interestAccrued = futureValueOnMaturity.minus(getDeposit()).getAmount();
this.projectedTotalOnMaturity = futureValueOnMaturity.getAmount(); this.total = futureValueOnMaturity.getAmount();
DepositAccountTransaction depositaccountTransaction = DepositAccountTransaction.deposit(futureValueOnMaturity,new LocalDate(this.actualCommencementDate));
this.depositaccountTransactions.add(depositaccountTransaction);
depositaccountTransaction.updateAccount(this);
LocalDate submittalDate = new LocalDate(this.projectedCommencementDate); LocalDate submittalDate = new LocalDate(this.projectedCommencementDate);
if (actualCommencementDate.isBefore(submittalDate)) { if (actualCommencementDate.isBefore(submittalDate)) {
@@ -339,6 +359,9 @@ public class DepositAccount extends AbstractAuditableCustom<AppUser, Long> {
this.actualCommencementDate = null; this.actualCommencementDate = null;
this.actualMaturityDate = null; this.actualMaturityDate = null;
this.total=null;
this.interestAccrued=null;
this.depositaccountTransactions.clear();
} }
public PeriodFrequencyType getInterestCompoundedFrequencyType() { public PeriodFrequencyType getInterestCompoundedFrequencyType() {
@@ -0,0 +1,133 @@
package org.mifosng.platform.saving.domain;
import java.math.BigDecimal;
import java.util.Date;
import javax.persistence.CascadeType;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.EnumType;
import javax.persistence.Enumerated;
import javax.persistence.JoinColumn;
import javax.persistence.ManyToOne;
import javax.persistence.OneToOne;
import javax.persistence.Table;
import javax.persistence.Temporal;
import javax.persistence.TemporalType;
import org.joda.time.LocalDate;
import org.mifosng.platform.currency.domain.MonetaryCurrency;
import org.mifosng.platform.currency.domain.Money;
import org.springframework.data.jpa.domain.AbstractPersistable;
import org.springframework.format.annotation.DateTimeFormat;
@Entity
@Table(name="m_deposit_account_transaction")
public class DepositAccountTransaction extends AbstractPersistable<Long> {
@ManyToOne(optional = false)
@JoinColumn(name = "deposit_account_id", nullable=false)
private DepositAccount depositAccount;
@Enumerated(EnumType.ORDINAL)
@Column(name = "transaction_type_enum", nullable = false)
private DepositTransactionType typeOf;
@OneToOne(optional=true, cascade={CascadeType.PERSIST})
@JoinColumn(name="contra_id")
private DepositAccountTransaction contra;
@Temporal(TemporalType.DATE)
@Column(name = "transaction_date", nullable=false)
private final Date dateOf;
@Column(name = "amount", scale = 6, precision = 19, nullable = false)
private final BigDecimal amount;
protected DepositAccountTransaction(){
this.depositAccount=null;
this.typeOf=null;
this.amount=null;
this.dateOf=null;
}
private DepositAccountTransaction(DepositTransactionType type, final BigDecimal amount, final LocalDate date) {
this.typeOf = type;
this.amount = amount;
this.dateOf = date.toDateMidnight().toDate();
}
public Date getDateOf() {
return dateOf;
}
public BigDecimal getAmount() {
return amount;
}
public DepositTransactionType getTypeOf() {
return typeOf;
}
public Money getAmount(MonetaryCurrency currency) {
return Money.of(currency, this.amount);
}
@DateTimeFormat(style="-M")
public LocalDate getTransactionDate() {
return new LocalDate(this.dateOf);
}
public DepositAccountTransaction getContra() {
return contra;
}
public boolean isNotContra() {
return this.contra == null;
}
public boolean isDeposit(){
return DepositTransactionType.DEPOSIT.equals(typeOf) && isNotContra();
}
public static DepositAccountTransaction deposit(Money amount, LocalDate paymentDate) {
return new DepositAccountTransaction(DepositTransactionType.DEPOSIT, amount.getAmount(), paymentDate);
}
public static DepositAccountTransaction withdraw(Money amount, LocalDate paymentDate) {
return new DepositAccountTransaction(DepositTransactionType.WITHDRAW, amount.getAmount(), paymentDate);
}
private static DepositAccountTransaction contra(DepositAccountTransaction originalTransaction) {
DepositAccountTransaction contra = new DepositAccountTransaction(DepositTransactionType.REVERSAL, originalTransaction.getAmount().negate(), new LocalDate(originalTransaction.getDateOf()));
contra.updateContra(originalTransaction);
return contra;
}
public void updateContra(DepositAccountTransaction transaction) {
this.contra = transaction;
}
public DepositAccount getDepositAccount() {
return depositAccount;
}
public void setDepositAccount(DepositAccount depositAccount) {
this.depositAccount = depositAccount;
}
public void updateAccount(DepositAccount depositAccount) {
this.depositAccount=depositAccount;
}
}
@@ -0,0 +1,53 @@
package org.mifosng.platform.saving.domain;
public enum DepositTransactionType {
INVALID(0, "depositTransactionType.invalid"), DEPOSIT(1, "depositTransactionType.deposit"), WITHDRAW(2, "depositTransactionType.withdraw"), REVERSAL(3, "depositTransactionType.reversal");
private final Integer value;
private final String code;
private DepositTransactionType(final Integer value, final String code) {
this.value=value;
this.code=code;
}
public Integer getValue() {
return value;
}
public String getCode() {
return code;
}
public static DepositTransactionType fromInt(final Integer transactionType){
if (transactionType == null) {
return DepositTransactionType.INVALID;
}
DepositTransactionType depositTransactionType=null;
switch (transactionType) {
case 1:
depositTransactionType=DepositTransactionType.DEPOSIT;
break;
case 2:
depositTransactionType=DepositTransactionType.WITHDRAW;
break;
case 3:
depositTransactionType=DepositTransactionType.REVERSAL;
break;
default :
depositTransactionType=DepositTransactionType.INVALID;
break;
}
return depositTransactionType;
}
}
@@ -43,7 +43,8 @@ public class DepositAccountWritePlatformServiceJpaRepositoryImpl implements Depo
final PlatformSecurityContext context, final PlatformSecurityContext context,
final DepositAccountRepository depositAccountRepository, final DepositAccountRepository depositAccountRepository,
final DepositAccountAssembler depositAccountAssembler, final DepositAccountAssembler depositAccountAssembler,
final FixedTermDepositInterestCalculator fixedTermDepositInterestCalculator) { final FixedTermDepositInterestCalculator fixedTermDepositInterestCalculator
) {
this.context=context; this.context=context;
this.depositAccountRepository = depositAccountRepository; this.depositAccountRepository = depositAccountRepository;
this.depositAccountAssembler = depositAccountAssembler; this.depositAccountAssembler = depositAccountAssembler;
@@ -149,8 +150,10 @@ public class DepositAccountWritePlatformServiceJpaRepositoryImpl implements Depo
} }
account.approve(eventDate, defaultDepositLifecycleStateMachine(), command, this.fixedTermDepositInterestCalculator); account.approve(eventDate, defaultDepositLifecycleStateMachine(), command, this.fixedTermDepositInterestCalculator);
this.depositAccountRepository.save(account); this.depositAccountRepository.save(account);
return new EntityIdentifier(account.getId()); return new EntityIdentifier(account.getId());
} }
@@ -25,7 +25,7 @@ public class DepositStateTransitionApprovalCommandValidator {
baseDataValidator.reset().parameter("accountId").value(command.getAccountId()).notNull().integerGreaterThanZero(); baseDataValidator.reset().parameter("accountId").value(command.getAccountId()).notNull().integerGreaterThanZero();
baseDataValidator.reset().parameter("eventDate").value(command.getEventDate()).notNull(); baseDataValidator.reset().parameter("eventDate").value(command.getEventDate()).notNull();
baseDataValidator.reset().parameter("depositAmount").value(command.getDepositAmount()).notNull().zeroOrPositiveAmount(); baseDataValidator.reset().parameter("depositAmount").value(command.getDepositAmount()).ignoreIfNull().zeroOrPositiveAmount();
baseDataValidator.reset().parameter("tenureInMonths").value(command.getTenureInMonths()).ignoreIfNull().integerGreaterThanZero(); baseDataValidator.reset().parameter("tenureInMonths").value(command.getTenureInMonths()).ignoreIfNull().integerGreaterThanZero();
baseDataValidator.reset().parameter("interestCompoundedEveryPeriodType").value(command.getInterestCompoundedEveryPeriodType()).ignoreIfNull().inMinMaxRange(2, 2); baseDataValidator.reset().parameter("interestCompoundedEveryPeriodType").value(command.getInterestCompoundedEveryPeriodType()).ignoreIfNull().inMinMaxRange(2, 2);