From 4a90cb091a2b72ecaf33ac29203f8fb0b98cf774 Mon Sep 17 00:00:00 2001 From: Madhukar Date: Wed, 5 Sep 2012 18:26:36 +0530 Subject: [PATCH] Transactions for DepositAccounts --- .../saving/domain/DepositAccount.java | 27 +++- .../domain/DepositAccountTransaction.java | 133 ++++++++++++++++++ .../saving/domain/DepositTransactionType.java | 53 +++++++ ...WritePlatformServiceJpaRepositoryImpl.java | 5 +- ...ateTransitionApprovalCommandValidator.java | 2 +- 5 files changed, 216 insertions(+), 4 deletions(-) create mode 100644 mifosng-provider/src/main/java/org/mifosng/platform/saving/domain/DepositAccountTransaction.java create mode 100644 mifosng-provider/src/main/java/org/mifosng/platform/saving/domain/DepositTransactionType.java diff --git a/mifosng-provider/src/main/java/org/mifosng/platform/saving/domain/DepositAccount.java b/mifosng-provider/src/main/java/org/mifosng/platform/saving/domain/DepositAccount.java index 095b08e24..774a84168 100644 --- a/mifosng-provider/src/main/java/org/mifosng/platform/saving/domain/DepositAccount.java +++ b/mifosng-provider/src/main/java/org/mifosng/platform/saving/domain/DepositAccount.java @@ -1,18 +1,25 @@ package org.mifosng.platform.saving.domain; import java.math.BigDecimal; +import java.util.ArrayList; import java.util.Date; +import java.util.List; +import javax.persistence.CascadeType; import javax.persistence.Column; import javax.persistence.Embedded; import javax.persistence.Entity; import javax.persistence.JoinColumn; import javax.persistence.ManyToOne; +import javax.persistence.OneToMany; +import javax.persistence.OrderBy; import javax.persistence.Table; import javax.persistence.Temporal; import javax.persistence.TemporalType; import javax.persistence.UniqueConstraint; +import org.hibernate.annotations.LazyCollection; +import org.hibernate.annotations.LazyCollectionOption; import org.joda.time.LocalDate; import org.mifosng.platform.api.commands.DepositAccountCommand; import org.mifosng.platform.api.commands.DepositStateTransitionApprovalCommand; @@ -126,6 +133,14 @@ public class DepositAccount extends AbstractAuditableCustom { @Temporal(TemporalType.DATE) @Column(name = "withdrawnon_date") 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 depositaccountTransactions = new ArrayList(); public DepositAccount openNew( final Client client, final DepositProduct product, @@ -241,8 +256,13 @@ public class DepositAccount extends AbstractAuditableCustom { Money futureValueOnMaturity = calculator.calculateInterestOnMaturityFor(getDeposit(), this.tenureInMonths, this.interestRate, this.interestCompoundedEvery, getInterestCompoundedFrequencyType()); - this.projectedInterestAccruedOnMaturity = futureValueOnMaturity.minus(getDeposit()).getAmount(); - this.projectedTotalOnMaturity = futureValueOnMaturity.getAmount(); + this.interestAccrued = futureValueOnMaturity.minus(getDeposit()).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); if (actualCommencementDate.isBefore(submittalDate)) { @@ -339,6 +359,9 @@ public class DepositAccount extends AbstractAuditableCustom { this.actualCommencementDate = null; this.actualMaturityDate = null; + this.total=null; + this.interestAccrued=null; + this.depositaccountTransactions.clear(); } public PeriodFrequencyType getInterestCompoundedFrequencyType() { diff --git a/mifosng-provider/src/main/java/org/mifosng/platform/saving/domain/DepositAccountTransaction.java b/mifosng-provider/src/main/java/org/mifosng/platform/saving/domain/DepositAccountTransaction.java new file mode 100644 index 000000000..c9f74c151 --- /dev/null +++ b/mifosng-provider/src/main/java/org/mifosng/platform/saving/domain/DepositAccountTransaction.java @@ -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 { + + @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; + + } + +} diff --git a/mifosng-provider/src/main/java/org/mifosng/platform/saving/domain/DepositTransactionType.java b/mifosng-provider/src/main/java/org/mifosng/platform/saving/domain/DepositTransactionType.java new file mode 100644 index 000000000..6645d73d5 --- /dev/null +++ b/mifosng-provider/src/main/java/org/mifosng/platform/saving/domain/DepositTransactionType.java @@ -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; + } + +} diff --git a/mifosng-provider/src/main/java/org/mifosng/platform/saving/service/DepositAccountWritePlatformServiceJpaRepositoryImpl.java b/mifosng-provider/src/main/java/org/mifosng/platform/saving/service/DepositAccountWritePlatformServiceJpaRepositoryImpl.java index c7093f332..b2995deef 100644 --- a/mifosng-provider/src/main/java/org/mifosng/platform/saving/service/DepositAccountWritePlatformServiceJpaRepositoryImpl.java +++ b/mifosng-provider/src/main/java/org/mifosng/platform/saving/service/DepositAccountWritePlatformServiceJpaRepositoryImpl.java @@ -43,7 +43,8 @@ public class DepositAccountWritePlatformServiceJpaRepositoryImpl implements Depo final PlatformSecurityContext context, final DepositAccountRepository depositAccountRepository, final DepositAccountAssembler depositAccountAssembler, - final FixedTermDepositInterestCalculator fixedTermDepositInterestCalculator) { + final FixedTermDepositInterestCalculator fixedTermDepositInterestCalculator + ) { this.context=context; this.depositAccountRepository = depositAccountRepository; this.depositAccountAssembler = depositAccountAssembler; @@ -149,7 +150,9 @@ public class DepositAccountWritePlatformServiceJpaRepositoryImpl implements Depo } account.approve(eventDate, defaultDepositLifecycleStateMachine(), command, this.fixedTermDepositInterestCalculator); + this.depositAccountRepository.save(account); + return new EntityIdentifier(account.getId()); diff --git a/mifosng-provider/src/main/java/org/mifosng/platform/saving/service/DepositStateTransitionApprovalCommandValidator.java b/mifosng-provider/src/main/java/org/mifosng/platform/saving/service/DepositStateTransitionApprovalCommandValidator.java index cc5b96212..35291184e 100644 --- a/mifosng-provider/src/main/java/org/mifosng/platform/saving/service/DepositStateTransitionApprovalCommandValidator.java +++ b/mifosng-provider/src/main/java/org/mifosng/platform/saving/service/DepositStateTransitionApprovalCommandValidator.java @@ -25,7 +25,7 @@ public class DepositStateTransitionApprovalCommandValidator { baseDataValidator.reset().parameter("accountId").value(command.getAccountId()).notNull().integerGreaterThanZero(); 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("interestCompoundedEveryPeriodType").value(command.getInterestCompoundedEveryPeriodType()).ignoreIfNull().inMinMaxRange(2, 2);