wip:enabling transfer of saving accounts

This commit is contained in:
Vishwas Babu A J
2013-09-10 17:13:53 +05:30
parent b9f929aec2
commit 190b9a58b3
22 changed files with 333 additions and 48 deletions
@@ -108,7 +108,7 @@ public class AccountingConstants {
/*** Accounting placeholders for cash based accounting for savings products ***/ /*** Accounting placeholders for cash based accounting for savings products ***/
public static enum CASH_ACCOUNTS_FOR_SAVINGS { public static enum CASH_ACCOUNTS_FOR_SAVINGS {
SAVINGS_REFERENCE(1), SAVINGS_CONTROL(2), INTEREST_ON_SAVINGS(3), INCOME_FROM_FEES(4); SAVINGS_REFERENCE(1), SAVINGS_CONTROL(2), INTEREST_ON_SAVINGS(3), INCOME_FROM_FEES(4), TRANSFERS_SUSPENSE(10);
private final Integer value; private final Integer value;
@@ -145,7 +145,8 @@ public class AccountingConstants {
public static enum SAVINGS_PRODUCT_ACCOUNTING_PARAMS { public static enum SAVINGS_PRODUCT_ACCOUNTING_PARAMS {
SAVINGS_REFERENCE("savingsReferenceAccountId"), SAVINGS_CONTROL("savingsControlAccountId"), INCOME_FROM_FEES( SAVINGS_REFERENCE("savingsReferenceAccountId"), SAVINGS_CONTROL("savingsControlAccountId"), INCOME_FROM_FEES(
"incomeFromFeeAccountId"), INTEREST_ON_SAVINGS("interestOnSavingsAccountId"), PAYMENT_CHANNEL_FUND_SOURCE_MAPPING( "incomeFromFeeAccountId"), INTEREST_ON_SAVINGS("interestOnSavingsAccountId"), PAYMENT_CHANNEL_FUND_SOURCE_MAPPING(
"paymentChannelToFundSourceMappings"), PAYMENT_TYPE("paymentTypeId"), FUND_SOURCE("fundSourceAccountId"); "paymentChannelToFundSourceMappings"), PAYMENT_TYPE("paymentTypeId"), FUND_SOURCE("fundSourceAccountId"), TRANSFERS_SUSPENSE(
"transfersInSuspenseAccountId");
private final String value; private final String value;
@@ -72,6 +72,21 @@ public class CashBasedAccountingProcessorForSavings implements AccountingProcess
transactionDate, amount, isReversal); transactionDate, amount, isReversal);
} }
/** Handle Transfers proposal **/
else if (savingsTransactionDTO.getTransactionType().isInitiateTransfer()) {
helper.createCashBasedJournalEntriesAndReversalsForSavings(office, CASH_ACCOUNTS_FOR_SAVINGS.SAVINGS_CONTROL,
CASH_ACCOUNTS_FOR_SAVINGS.TRANSFERS_SUSPENSE, savingsProductId, paymentTypeId, savingsId, transactionId,
transactionDate, amount, isReversal);
}
/** Handle Transfer Withdrawal or Acceptance **/
else if (savingsTransactionDTO.getTransactionType().isWithdrawTransfer()
|| savingsTransactionDTO.getTransactionType().isApproveTransfer()) {
helper.createCashBasedJournalEntriesAndReversalsForSavings(office, CASH_ACCOUNTS_FOR_SAVINGS.TRANSFERS_SUSPENSE,
CASH_ACCOUNTS_FOR_SAVINGS.SAVINGS_CONTROL, savingsProductId, paymentTypeId, savingsId, transactionId,
transactionDate, amount, isReversal);
}
} }
} }
} }
@@ -156,6 +156,11 @@ public final class ProductToGLAccountMappingFromApiJsonDeserializer {
baseDataValidator.reset().parameter(SAVINGS_PRODUCT_ACCOUNTING_PARAMS.SAVINGS_REFERENCE.getValue()) baseDataValidator.reset().parameter(SAVINGS_PRODUCT_ACCOUNTING_PARAMS.SAVINGS_REFERENCE.getValue())
.value(savingsReferenceAccountId).notNull().integerGreaterThanZero(); .value(savingsReferenceAccountId).notNull().integerGreaterThanZero();
final Long transfersInSuspenseAccountId = fromApiJsonHelper.extractLongNamed(
SAVINGS_PRODUCT_ACCOUNTING_PARAMS.TRANSFERS_SUSPENSE.getValue(), element);
baseDataValidator.reset().parameter(SAVINGS_PRODUCT_ACCOUNTING_PARAMS.TRANSFERS_SUSPENSE.getValue())
.value(transfersInSuspenseAccountId).notNull().integerGreaterThanZero();
final Long interestOnSavingsAccountId = fromApiJsonHelper.extractLongNamed( final Long interestOnSavingsAccountId = fromApiJsonHelper.extractLongNamed(
SAVINGS_PRODUCT_ACCOUNTING_PARAMS.INTEREST_ON_SAVINGS.getValue(), element); SAVINGS_PRODUCT_ACCOUNTING_PARAMS.INTEREST_ON_SAVINGS.getValue(), element);
baseDataValidator.reset().parameter(SAVINGS_PRODUCT_ACCOUNTING_PARAMS.INTEREST_ON_SAVINGS.getValue()) baseDataValidator.reset().parameter(SAVINGS_PRODUCT_ACCOUNTING_PARAMS.INTEREST_ON_SAVINGS.getValue())
@@ -169,6 +169,8 @@ public class ProductToGLAccountMappingReadPlatformServiceImpl implements Product
accountMappingDetails.put(SAVINGS_PRODUCT_ACCOUNTING_PARAMS.SAVINGS_CONTROL.getValue(), glAccountId); accountMappingDetails.put(SAVINGS_PRODUCT_ACCOUNTING_PARAMS.SAVINGS_CONTROL.getValue(), glAccountId);
} else if (glAccountForSavings.equals(CASH_ACCOUNTS_FOR_SAVINGS.INCOME_FROM_FEES)) { } else if (glAccountForSavings.equals(CASH_ACCOUNTS_FOR_SAVINGS.INCOME_FROM_FEES)) {
accountMappingDetails.put(SAVINGS_PRODUCT_ACCOUNTING_PARAMS.INCOME_FROM_FEES.getValue(), glAccountId); accountMappingDetails.put(SAVINGS_PRODUCT_ACCOUNTING_PARAMS.INCOME_FROM_FEES.getValue(), glAccountId);
} else if (glAccountForSavings.equals(CASH_ACCOUNTS_FOR_SAVINGS.TRANSFERS_SUSPENSE)) {
accountMappingDetails.put(SAVINGS_PRODUCT_ACCOUNTING_PARAMS.TRANSFERS_SUSPENSE.getValue(), glAccountId);
} else if (glAccountForSavings.equals(CASH_ACCOUNTS_FOR_SAVINGS.INTEREST_ON_SAVINGS)) { } else if (glAccountForSavings.equals(CASH_ACCOUNTS_FOR_SAVINGS.INTEREST_ON_SAVINGS)) {
accountMappingDetails.put(SAVINGS_PRODUCT_ACCOUNTING_PARAMS.INTEREST_ON_SAVINGS.getValue(), glAccountId); accountMappingDetails.put(SAVINGS_PRODUCT_ACCOUNTING_PARAMS.INTEREST_ON_SAVINGS.getValue(), glAccountId);
} }
@@ -163,6 +163,9 @@ public class ProductToGLAccountMappingWritePlatformServiceImpl implements Produc
savingsProductToGLAccountMappingHelper.saveSavingsToLiabilityAccountMapping(element, savingsProductToGLAccountMappingHelper.saveSavingsToLiabilityAccountMapping(element,
SAVINGS_PRODUCT_ACCOUNTING_PARAMS.SAVINGS_CONTROL.getValue(), savingProductId, SAVINGS_PRODUCT_ACCOUNTING_PARAMS.SAVINGS_CONTROL.getValue(), savingProductId,
CASH_ACCOUNTS_FOR_SAVINGS.SAVINGS_CONTROL.getValue()); CASH_ACCOUNTS_FOR_SAVINGS.SAVINGS_CONTROL.getValue());
savingsProductToGLAccountMappingHelper.saveSavingsToLiabilityAccountMapping(element,
SAVINGS_PRODUCT_ACCOUNTING_PARAMS.TRANSFERS_SUSPENSE.getValue(), savingProductId,
CASH_ACCOUNTS_FOR_SAVINGS.TRANSFERS_SUSPENSE.getValue());
// advanced accounting mappings // advanced accounting mappings
savingsProductToGLAccountMappingHelper.savePaymentChannelToFundSourceMappings(command, element, savingProductId, null); savingsProductToGLAccountMappingHelper.savePaymentChannelToFundSourceMappings(command, element, savingProductId, null);
@@ -106,6 +106,8 @@ public class SavingsProductToGLAccountMappingHelper extends ProductToGLAccountMa
SAVINGS_PRODUCT_ACCOUNTING_PARAMS.INTEREST_ON_SAVINGS.getValue(), element); SAVINGS_PRODUCT_ACCOUNTING_PARAMS.INTEREST_ON_SAVINGS.getValue(), element);
final Long savingsControlId = this.fromApiJsonHelper.extractLongNamed(SAVINGS_PRODUCT_ACCOUNTING_PARAMS.SAVINGS_CONTROL.getValue(), final Long savingsControlId = this.fromApiJsonHelper.extractLongNamed(SAVINGS_PRODUCT_ACCOUNTING_PARAMS.SAVINGS_CONTROL.getValue(),
element); element);
final Long transfersInSuspenseAccountId = this.fromApiJsonHelper.extractLongNamed(
SAVINGS_PRODUCT_ACCOUNTING_PARAMS.TRANSFERS_SUSPENSE.getValue(), element);
switch (accountingRuleType) { switch (accountingRuleType) {
case NONE: case NONE:
@@ -115,6 +117,7 @@ public class SavingsProductToGLAccountMappingHelper extends ProductToGLAccountMa
changes.put(SAVINGS_PRODUCT_ACCOUNTING_PARAMS.SAVINGS_REFERENCE.getValue(), savingsReferenceId); changes.put(SAVINGS_PRODUCT_ACCOUNTING_PARAMS.SAVINGS_REFERENCE.getValue(), savingsReferenceId);
changes.put(SAVINGS_PRODUCT_ACCOUNTING_PARAMS.INTEREST_ON_SAVINGS.getValue(), interestOnSavingsId); changes.put(SAVINGS_PRODUCT_ACCOUNTING_PARAMS.INTEREST_ON_SAVINGS.getValue(), interestOnSavingsId);
changes.put(SAVINGS_PRODUCT_ACCOUNTING_PARAMS.INCOME_FROM_FEES.getValue(), incomeFromFeesId); changes.put(SAVINGS_PRODUCT_ACCOUNTING_PARAMS.INCOME_FROM_FEES.getValue(), incomeFromFeesId);
changes.put(SAVINGS_PRODUCT_ACCOUNTING_PARAMS.TRANSFERS_SUSPENSE.getValue(), transfersInSuspenseAccountId);
break; break;
case ACCRUAL_BASED: case ACCRUAL_BASED:
break; break;
@@ -156,6 +159,9 @@ public class SavingsProductToGLAccountMappingHelper extends ProductToGLAccountMa
mergeSavingsToLiabilityAccountMappingChanges(element, SAVINGS_PRODUCT_ACCOUNTING_PARAMS.SAVINGS_CONTROL.getValue(), mergeSavingsToLiabilityAccountMappingChanges(element, SAVINGS_PRODUCT_ACCOUNTING_PARAMS.SAVINGS_CONTROL.getValue(),
savingsProductId, CASH_ACCOUNTS_FOR_SAVINGS.SAVINGS_CONTROL.getValue(), savingsProductId, CASH_ACCOUNTS_FOR_SAVINGS.SAVINGS_CONTROL.getValue(),
CASH_ACCOUNTS_FOR_SAVINGS.SAVINGS_CONTROL.toString(), changes); CASH_ACCOUNTS_FOR_SAVINGS.SAVINGS_CONTROL.toString(), changes);
mergeSavingsToLiabilityAccountMappingChanges(element, SAVINGS_PRODUCT_ACCOUNTING_PARAMS.TRANSFERS_SUSPENSE.getValue(),
savingsProductId, CASH_ACCOUNTS_FOR_SAVINGS.TRANSFERS_SUSPENSE.getValue(),
CASH_ACCOUNTS_FOR_SAVINGS.TRANSFERS_SUSPENSE.toString(), changes);
break; break;
case ACCRUAL_BASED: case ACCRUAL_BASED:
break; break;
@@ -125,18 +125,18 @@ public enum LoanStatus {
} }
public boolean isTransferInProgress() { public boolean isTransferInProgress() {
return this.isTransferInProgress(); return this.value.equals(LoanStatus.TRANSFER_IN_PROGRESS.getValue());
} }
public boolean isTransferOnHold() { public boolean isTransferOnHold() {
return this.isTransferOnHold(); return this.value.equals(LoanStatus.TRANSFER_ON_HOLD.getValue());
} }
public boolean isUnderTransfer() { public boolean isUnderTransfer() {
return isTransferInProgress() || isTransferOnHold(); return isTransferInProgress() || isTransferOnHold();
} }
public boolean isOverpaid(){ public boolean isOverpaid() {
return this.value.equals(LoanStatus.OVERPAID.getValue()); return this.value.equals(LoanStatus.OVERPAID.getValue());
} }
} }
@@ -138,7 +138,7 @@ public final class LoanTransaction extends AbstractPersistable<Long> {
} }
public static LoanTransaction withdrawTransfer(final Office office, final Loan loan, final LocalDate transferDate) { public static LoanTransaction withdrawTransfer(final Office office, final Loan loan, final LocalDate transferDate) {
return new LoanTransaction(loan, office, LoanTransactionType.APPROVE_TRANSFER.getValue(), transferDate.toDateMidnight().toDate(), return new LoanTransaction(loan, office, LoanTransactionType.WITHDRAW_TRANSFER.getValue(), transferDate.toDateMidnight().toDate(),
loan.getSummary().getTotalOutstanding(), loan.getSummary().getTotalPrincipalOutstanding(), loan.getSummary() loan.getSummary().getTotalOutstanding(), loan.getSummary().getTotalPrincipalOutstanding(), loan.getSummary()
.getTotalInterestOutstanding(), loan.getSummary().getTotalFeeChargesOutstanding(), loan.getSummary() .getTotalInterestOutstanding(), loan.getSummary().getTotalFeeChargesOutstanding(), loan.getSummary()
.getTotalPenaltyChargesOutstanding(), false, null); .getTotalPenaltyChargesOutstanding(), false, null);
@@ -357,7 +357,7 @@ public class LoanEnumerations {
break; break;
case TRANSFER_ON_HOLD: case TRANSFER_ON_HOLD:
optionData = new LoanStatusEnumData(LoanStatus.TRANSFER_ON_HOLD.getValue().longValue(), optionData = new LoanStatusEnumData(LoanStatus.TRANSFER_ON_HOLD.getValue().longValue(),
LoanStatus.TRANSFER_ON_HOLD.getCode(), "Transfer in hold"); LoanStatus.TRANSFER_ON_HOLD.getCode(), "Transfer on hold");
break; break;
default: default:
break; break;
@@ -18,7 +18,11 @@ public enum SavingsAccountTransactionType {
WITHDRAWAL(2, "savingsAccountTransactionType.withdrawal"), // WITHDRAWAL(2, "savingsAccountTransactionType.withdrawal"), //
INTEREST_POSTING(3, "savingsAccountTransactionType.interestPosting"), // INTEREST_POSTING(3, "savingsAccountTransactionType.interestPosting"), //
WITHDRAWAL_FEE(4, "savingsAccountTransactionType.withdrawalFee"), // WITHDRAWAL_FEE(4, "savingsAccountTransactionType.withdrawalFee"), //
ANNUAL_FEE(5, "savingsAccountTransactionType.annualFee"); ANNUAL_FEE(5, "savingsAccountTransactionType.annualFee"), //
INITIATE_TRANSFER(12, "savingsAccountTransactionType.initiateTransfer"), //
APPROVE_TRANSFER(13, "savingsAccountTransactionType.approveTransfer"), //
WITHDRAW_TRANSFER(14, "savingsAccountTransactionType.withdrawTransfer"), //
REJECT_TRANSFER(15, "savingsAccountTransactionType.rejectTransfer");
private final Integer value; private final Integer value;
private final String code; private final String code;
@@ -57,6 +61,18 @@ public enum SavingsAccountTransactionType {
case 5: case 5:
loanTransactionType = SavingsAccountTransactionType.ANNUAL_FEE; loanTransactionType = SavingsAccountTransactionType.ANNUAL_FEE;
break; break;
case 12:
loanTransactionType = SavingsAccountTransactionType.INITIATE_TRANSFER;
break;
case 13:
loanTransactionType = SavingsAccountTransactionType.APPROVE_TRANSFER;
break;
case 14:
loanTransactionType = SavingsAccountTransactionType.WITHDRAW_TRANSFER;
break;
case 15:
loanTransactionType = SavingsAccountTransactionType.REJECT_TRANSFER;
break;
} }
return loanTransactionType; return loanTransactionType;
} }
@@ -105,7 +105,8 @@ public class SavingsApiConstants {
annualFeeOnMonthDayParamName, accountingRuleParamName, SAVINGS_PRODUCT_ACCOUNTING_PARAMS.INCOME_FROM_FEES.getValue(), annualFeeOnMonthDayParamName, accountingRuleParamName, SAVINGS_PRODUCT_ACCOUNTING_PARAMS.INCOME_FROM_FEES.getValue(),
SAVINGS_PRODUCT_ACCOUNTING_PARAMS.INTEREST_ON_SAVINGS.getValue(), SAVINGS_PRODUCT_ACCOUNTING_PARAMS.INTEREST_ON_SAVINGS.getValue(),
SAVINGS_PRODUCT_ACCOUNTING_PARAMS.PAYMENT_CHANNEL_FUND_SOURCE_MAPPING.getValue(), SAVINGS_PRODUCT_ACCOUNTING_PARAMS.PAYMENT_CHANNEL_FUND_SOURCE_MAPPING.getValue(),
SAVINGS_PRODUCT_ACCOUNTING_PARAMS.SAVINGS_CONTROL.getValue(), SAVINGS_PRODUCT_ACCOUNTING_PARAMS.SAVINGS_REFERENCE.getValue())); SAVINGS_PRODUCT_ACCOUNTING_PARAMS.SAVINGS_CONTROL.getValue(), SAVINGS_PRODUCT_ACCOUNTING_PARAMS.TRANSFERS_SUSPENSE.getValue(),
SAVINGS_PRODUCT_ACCOUNTING_PARAMS.SAVINGS_REFERENCE.getValue()));
/** /**
* These parameters will match the class level parameters of * These parameters will match the class level parameters of
@@ -27,9 +27,14 @@ public class SavingsAccountStatusEnumData {
private final boolean active; private final boolean active;
@SuppressWarnings("unused") @SuppressWarnings("unused")
private final boolean closed; private final boolean closed;
@SuppressWarnings("unused")
private final boolean transferInProgress;
@SuppressWarnings("unused")
private final boolean transferOnHold;
public SavingsAccountStatusEnumData(final Long id, final String code, final String value, final boolean submittedAndPendingApproval, public SavingsAccountStatusEnumData(final Long id, final String code, final String value, final boolean submittedAndPendingApproval,
final boolean approved, final boolean rejected, final boolean withdrawnByApplicant, final boolean active, final boolean closed) { final boolean approved, final boolean rejected, final boolean withdrawnByApplicant, final boolean active, final boolean closed,
final boolean transferInProgress, final boolean transferOnHold) {
this.id = id; this.id = id;
this.code = code; this.code = code;
this.value = value; this.value = value;
@@ -39,6 +44,8 @@ public class SavingsAccountStatusEnumData {
this.withdrawnByApplicant = withdrawnByApplicant; this.withdrawnByApplicant = withdrawnByApplicant;
this.active = active; this.active = active;
this.closed = closed; this.closed = closed;
this.transferInProgress = transferInProgress;
this.transferOnHold = transferOnHold;
} }
public Long id() { public Long id() {
@@ -22,6 +22,10 @@ public class SavingsAccountTransactionEnumData {
private final boolean withdrawal; private final boolean withdrawal;
private final boolean interestPosting; private final boolean interestPosting;
private final boolean feeDeduction; private final boolean feeDeduction;
private final boolean initiateTransfer;
private final boolean approveTransfer;
private final boolean withdrawTransfer;
private final boolean rejectTransfer;
public SavingsAccountTransactionEnumData(final Long id, final String code, final String value) { public SavingsAccountTransactionEnumData(final Long id, final String code, final String value) {
this.id = id; this.id = id;
@@ -32,6 +36,10 @@ public class SavingsAccountTransactionEnumData {
this.interestPosting = Long.valueOf(SavingsAccountTransactionType.INTEREST_POSTING.getValue()).equals(this.id); this.interestPosting = Long.valueOf(SavingsAccountTransactionType.INTEREST_POSTING.getValue()).equals(this.id);
this.feeDeduction = Long.valueOf(SavingsAccountTransactionType.ANNUAL_FEE.getValue()).equals(this.id) this.feeDeduction = Long.valueOf(SavingsAccountTransactionType.ANNUAL_FEE.getValue()).equals(this.id)
|| Long.valueOf(SavingsAccountTransactionType.WITHDRAWAL_FEE.getValue()).equals(this.id); || Long.valueOf(SavingsAccountTransactionType.WITHDRAWAL_FEE.getValue()).equals(this.id);
this.initiateTransfer = Long.valueOf(SavingsAccountTransactionType.INITIATE_TRANSFER.getValue()).equals(this.id);
this.approveTransfer = Long.valueOf(SavingsAccountTransactionType.APPROVE_TRANSFER.getValue()).equals(this.id);
this.withdrawTransfer = Long.valueOf(SavingsAccountTransactionType.WITHDRAW_TRANSFER.getValue()).equals(this.id);
this.rejectTransfer = Long.valueOf(SavingsAccountTransactionType.REJECT_TRANSFER.getValue()).equals(this.id);
} }
public boolean isDeposit() { public boolean isDeposit() {
@@ -54,4 +62,20 @@ public class SavingsAccountTransactionEnumData {
return this.feeDeduction; return this.feeDeduction;
} }
public boolean isInitiateTransfer() {
return this.initiateTransfer;
}
public boolean isApproveTransfer() {
return this.approveTransfer;
}
public boolean isWithdrawTransfer() {
return this.withdrawTransfer;
}
public boolean isRejectTransfer() {
return this.rejectTransfer;
}
} }
@@ -174,11 +174,12 @@ public class SavingsProductDataValidator {
.zeroOrPositiveAmount(); .zeroOrPositiveAmount();
} }
} }
if(this.fromApiJsonHelper.parameterExists(withdrawalFeeForTransfersParamName, element)) { if (this.fromApiJsonHelper.parameterExists(withdrawalFeeForTransfersParamName, element)) {
final Boolean isWithdrawalFeeApplicableForTransfers = fromApiJsonHelper.extractBooleanNamed(withdrawalFeeForTransfersParamName, element); final Boolean isWithdrawalFeeApplicableForTransfers = fromApiJsonHelper.extractBooleanNamed(withdrawalFeeForTransfersParamName,
baseDataValidator.reset().parameter(withdrawalFeeForTransfersParamName).value(isWithdrawalFeeApplicableForTransfers).ignoreIfNull() element);
.validateForBooleanValue(); baseDataValidator.reset().parameter(withdrawalFeeForTransfersParamName).value(isWithdrawalFeeApplicableForTransfers)
.ignoreIfNull().validateForBooleanValue();
} }
if (this.fromApiJsonHelper.parameterExists(annualFeeAmountParamName, element)) { if (this.fromApiJsonHelper.parameterExists(annualFeeAmountParamName, element)) {
@@ -216,6 +217,11 @@ public class SavingsProductDataValidator {
baseDataValidator.reset().parameter(SAVINGS_PRODUCT_ACCOUNTING_PARAMS.SAVINGS_REFERENCE.getValue()) baseDataValidator.reset().parameter(SAVINGS_PRODUCT_ACCOUNTING_PARAMS.SAVINGS_REFERENCE.getValue())
.value(savingsReferenceAccountId).notNull().integerGreaterThanZero(); .value(savingsReferenceAccountId).notNull().integerGreaterThanZero();
final Long transfersInSuspenseAccountId = fromApiJsonHelper.extractLongNamed(
SAVINGS_PRODUCT_ACCOUNTING_PARAMS.TRANSFERS_SUSPENSE.getValue(), element);
baseDataValidator.reset().parameter(SAVINGS_PRODUCT_ACCOUNTING_PARAMS.TRANSFERS_SUSPENSE.getValue())
.value(transfersInSuspenseAccountId).notNull().integerGreaterThanZero();
final Long interestOnSavingsAccountId = fromApiJsonHelper.extractLongNamed( final Long interestOnSavingsAccountId = fromApiJsonHelper.extractLongNamed(
SAVINGS_PRODUCT_ACCOUNTING_PARAMS.INTEREST_ON_SAVINGS.getValue(), element); SAVINGS_PRODUCT_ACCOUNTING_PARAMS.INTEREST_ON_SAVINGS.getValue(), element);
baseDataValidator.reset().parameter(SAVINGS_PRODUCT_ACCOUNTING_PARAMS.INTEREST_ON_SAVINGS.getValue()) baseDataValidator.reset().parameter(SAVINGS_PRODUCT_ACCOUNTING_PARAMS.INTEREST_ON_SAVINGS.getValue())
@@ -326,11 +332,12 @@ public class SavingsProductDataValidator {
baseDataValidator.reset().parameter(withdrawalFeeTypeParamName).value(withdrawalFeeType).ignoreIfNull() baseDataValidator.reset().parameter(withdrawalFeeTypeParamName).value(withdrawalFeeType).ignoreIfNull()
.isOneOfTheseValues(1, 2); .isOneOfTheseValues(1, 2);
} }
if(this.fromApiJsonHelper.parameterExists(withdrawalFeeForTransfersParamName, element)) { if (this.fromApiJsonHelper.parameterExists(withdrawalFeeForTransfersParamName, element)) {
final Boolean isWithdrawalFeeApplicableForTransfers = fromApiJsonHelper.extractBooleanNamed(withdrawalFeeForTransfersParamName, element); final Boolean isWithdrawalFeeApplicableForTransfers = fromApiJsonHelper.extractBooleanNamed(withdrawalFeeForTransfersParamName,
baseDataValidator.reset().parameter(withdrawalFeeForTransfersParamName).value(isWithdrawalFeeApplicableForTransfers).ignoreIfNull() element);
.validateForBooleanValue(); baseDataValidator.reset().parameter(withdrawalFeeForTransfersParamName).value(isWithdrawalFeeApplicableForTransfers)
.ignoreIfNull().validateForBooleanValue();
} }
if (this.fromApiJsonHelper.parameterExists(annualFeeAmountParamName, element)) { if (this.fromApiJsonHelper.parameterExists(annualFeeAmountParamName, element)) {
@@ -353,6 +360,11 @@ public class SavingsProductDataValidator {
baseDataValidator.reset().parameter(SAVINGS_PRODUCT_ACCOUNTING_PARAMS.SAVINGS_REFERENCE.getValue()) baseDataValidator.reset().parameter(SAVINGS_PRODUCT_ACCOUNTING_PARAMS.SAVINGS_REFERENCE.getValue())
.value(savingsReferenceAccountId).ignoreIfNull().integerGreaterThanZero(); .value(savingsReferenceAccountId).ignoreIfNull().integerGreaterThanZero();
final Long transfersInSuspenseAccountId = fromApiJsonHelper.extractLongNamed(
SAVINGS_PRODUCT_ACCOUNTING_PARAMS.TRANSFERS_SUSPENSE.getValue(), element);
baseDataValidator.reset().parameter(SAVINGS_PRODUCT_ACCOUNTING_PARAMS.TRANSFERS_SUSPENSE.getValue())
.value(transfersInSuspenseAccountId).ignoreIfNull().integerGreaterThanZero();
final Long interestOnSavingsAccountId = fromApiJsonHelper.extractLongNamed( final Long interestOnSavingsAccountId = fromApiJsonHelper.extractLongNamed(
SAVINGS_PRODUCT_ACCOUNTING_PARAMS.INTEREST_ON_SAVINGS.getValue(), element); SAVINGS_PRODUCT_ACCOUNTING_PARAMS.INTEREST_ON_SAVINGS.getValue(), element);
baseDataValidator.reset().parameter(SAVINGS_PRODUCT_ACCOUNTING_PARAMS.INTEREST_ON_SAVINGS.getValue()) baseDataValidator.reset().parameter(SAVINGS_PRODUCT_ACCOUNTING_PARAMS.INTEREST_ON_SAVINGS.getValue())
@@ -1178,7 +1178,7 @@ public class SavingsAccount extends AbstractPersistable<Long> {
return accountingBridgeData; return accountingBridgeData;
} }
private Collection<Long> findExistingTransactionIds() { public Collection<Long> findExistingTransactionIds() {
final Collection<Long> ids = new ArrayList<Long>(); final Collection<Long> ids = new ArrayList<Long>();
@@ -1189,7 +1189,7 @@ public class SavingsAccount extends AbstractPersistable<Long> {
return ids; return ids;
} }
private Collection<Long> findExistingReversedTransactionIds() { public Collection<Long> findExistingReversedTransactionIds() {
final Collection<Long> ids = new ArrayList<Long>(); final Collection<Long> ids = new ArrayList<Long>();
@@ -1787,4 +1787,17 @@ public class SavingsAccount extends AbstractPersistable<Long> {
public LocalDate getClosedOnDate() { public LocalDate getClosedOnDate() {
return (LocalDate) ObjectUtils.defaultIfNull(new LocalDate(this.closedOnDate), null); return (LocalDate) ObjectUtils.defaultIfNull(new LocalDate(this.closedOnDate), null);
} }
public SavingsAccountSummary getSummary() {
return this.summary;
}
public List<SavingsAccountTransaction> getTransactions() {
return this.transactions;
}
public void setStatus(Integer status) {
this.status = status;
}
} }
@@ -14,6 +14,8 @@ public enum SavingsAccountStatusType {
SUBMITTED_AND_PENDING_APPROVAL(100, "savingsAccountStatusType.submitted.and.pending.approval"), // SUBMITTED_AND_PENDING_APPROVAL(100, "savingsAccountStatusType.submitted.and.pending.approval"), //
APPROVED(200, "savingsAccountStatusType.approved"), // APPROVED(200, "savingsAccountStatusType.approved"), //
ACTIVE(300, "savingsAccountStatusType.active"), // ACTIVE(300, "savingsAccountStatusType.active"), //
TRANSFER_IN_PROGRESS(303, "savingsAccountStatusType.transfer.in.progress"), //
TRANSFER_ON_HOLD(304, "savingsAccountStatusType.transfer.on.hold"), //
WITHDRAWN_BY_APPLICANT(400, "savingsAccountStatusType.withdrawn.by.applicant"), // WITHDRAWN_BY_APPLICANT(400, "savingsAccountStatusType.withdrawn.by.applicant"), //
REJECTED(500, "savingsAccountStatusType.rejected"), // REJECTED(500, "savingsAccountStatusType.rejected"), //
CLOSED(600, "savingsAccountStatusType.closed"); CLOSED(600, "savingsAccountStatusType.closed");
@@ -34,6 +36,12 @@ public enum SavingsAccountStatusType {
case 300: case 300:
enumeration = SavingsAccountStatusType.ACTIVE; enumeration = SavingsAccountStatusType.ACTIVE;
break; break;
case 303:
enumeration = SavingsAccountStatusType.TRANSFER_IN_PROGRESS;
break;
case 304:
enumeration = SavingsAccountStatusType.TRANSFER_ON_HOLD;
break;
case 400: case 400:
enumeration = SavingsAccountStatusType.WITHDRAWN_BY_APPLICANT; enumeration = SavingsAccountStatusType.WITHDRAWN_BY_APPLICANT;
break; break;
@@ -87,4 +95,16 @@ public enum SavingsAccountStatusType {
public boolean isClosed() { public boolean isClosed() {
return this.value.equals(SavingsAccountStatusType.CLOSED.getValue()) || isRejected() || isApplicationWithdrawnByApplicant(); return this.value.equals(SavingsAccountStatusType.CLOSED.getValue()) || isRejected() || isApplicationWithdrawnByApplicant();
} }
public boolean isTransferInProgress() {
return this.value.equals(SavingsAccountStatusType.TRANSFER_IN_PROGRESS.getValue());
}
public boolean isTransferOnHold() {
return this.value.equals(SavingsAccountStatusType.TRANSFER_ON_HOLD.getValue());
}
public boolean isUnderTransfer() {
return isTransferInProgress() || isTransferOnHold();
}
} }
@@ -79,4 +79,9 @@ public final class SavingsAccountSummary {
public Money getAccountBalance(final MonetaryCurrency currency) { public Money getAccountBalance(final MonetaryCurrency currency) {
return Money.of(currency, this.accountBalance); return Money.of(currency, this.accountBalance);
} }
public BigDecimal getAccountBalance() {
return this.accountBalance;
}
} }
@@ -117,6 +117,30 @@ public final class SavingsAccountTransaction extends AbstractPersistable<Long> {
isReversed); isReversed);
} }
public static SavingsAccountTransaction initiateTransfer(final SavingsAccount savingsAccount, final Office office, final LocalDate date) {
final boolean isReversed = false;
final PaymentDetail paymentDetail = null;
return new SavingsAccountTransaction(savingsAccount, office, paymentDetail,
SavingsAccountTransactionType.INITIATE_TRANSFER.getValue(), date, savingsAccount.getSummary().getAccountBalance(),
isReversed);
}
public static SavingsAccountTransaction approveTransfer(final SavingsAccount savingsAccount, final Office office, final LocalDate date) {
final boolean isReversed = false;
final PaymentDetail paymentDetail = null;
return new SavingsAccountTransaction(savingsAccount, office, paymentDetail,
SavingsAccountTransactionType.APPROVE_TRANSFER.getValue(), date, savingsAccount.getSummary().getAccountBalance(),
isReversed);
}
public static SavingsAccountTransaction withdrawTransfer(final SavingsAccount savingsAccount, final Office office, final LocalDate date) {
final boolean isReversed = false;
final PaymentDetail paymentDetail = null;
return new SavingsAccountTransaction(savingsAccount, office, paymentDetail,
SavingsAccountTransactionType.WITHDRAW_TRANSFER.getValue(), date, savingsAccount.getSummary().getAccountBalance(),
isReversed);
}
private SavingsAccountTransaction(final SavingsAccount savingsAccount, final Office office, final Integer typeOf, private SavingsAccountTransaction(final SavingsAccount savingsAccount, final Office office, final Integer typeOf,
final LocalDate transactionLocalDate, final Money amount, final boolean isReversed) { final LocalDate transactionLocalDate, final Money amount, final boolean isReversed) {
this(savingsAccount, office, null, typeOf, transactionLocalDate, amount, isReversed); this(savingsAccount, office, null, typeOf, transactionLocalDate, amount, isReversed);
@@ -124,11 +148,16 @@ public final class SavingsAccountTransaction extends AbstractPersistable<Long> {
private SavingsAccountTransaction(final SavingsAccount savingsAccount, final Office office, final PaymentDetail paymentDetail, private SavingsAccountTransaction(final SavingsAccount savingsAccount, final Office office, final PaymentDetail paymentDetail,
final Integer typeOf, final LocalDate transactionLocalDate, final Money amount, final boolean isReversed) { final Integer typeOf, final LocalDate transactionLocalDate, final Money amount, final boolean isReversed) {
this(savingsAccount, office, paymentDetail, typeOf, transactionLocalDate, amount.getAmount(), isReversed);
}
private SavingsAccountTransaction(final SavingsAccount savingsAccount, final Office office, final PaymentDetail paymentDetail,
final Integer typeOf, final LocalDate transactionLocalDate, final BigDecimal amount, final boolean isReversed) {
this.savingsAccount = savingsAccount; this.savingsAccount = savingsAccount;
this.office = office; this.office = office;
this.typeOf = typeOf; this.typeOf = typeOf;
this.dateOf = transactionLocalDate.toDate(); this.dateOf = transactionLocalDate.toDate();
this.amount = amount.getAmount(); this.amount = amount;
this.reversed = isReversed; this.reversed = isReversed;
this.paymentDetail = paymentDetail; this.paymentDetail = paymentDetail;
@@ -8,6 +8,9 @@ package org.mifosplatform.portfolio.savings.service;
import org.joda.time.LocalDate; import org.joda.time.LocalDate;
import org.mifosplatform.infrastructure.core.api.JsonCommand; import org.mifosplatform.infrastructure.core.api.JsonCommand;
import org.mifosplatform.infrastructure.core.data.CommandProcessingResult; import org.mifosplatform.infrastructure.core.data.CommandProcessingResult;
import org.mifosplatform.organisation.office.domain.Office;
import org.mifosplatform.organisation.staff.domain.Staff;
import org.mifosplatform.portfolio.savings.domain.SavingsAccountTransaction;
public interface SavingsAccountWritePlatformService { public interface SavingsAccountWritePlatformService {
@@ -28,6 +31,14 @@ public interface SavingsAccountWritePlatformService {
void postInterestForAccounts(); void postInterestForAccounts();
CommandProcessingResult adjustSavingsTransaction(Long savingsId, Long transactionId, JsonCommand command); CommandProcessingResult adjustSavingsTransaction(Long savingsId, Long transactionId, JsonCommand command);
CommandProcessingResult close(Long savingsId, JsonCommand command); CommandProcessingResult close(Long savingsId, JsonCommand command);
SavingsAccountTransaction initiateSavingsTransfer(Long accountId, LocalDate transferDate);
SavingsAccountTransaction withdrawSavingsTransfer(Long accountId, LocalDate transferDate);
void rejectSavingsTransfer(Long accountId);
SavingsAccountTransaction acceptSavingsTransfer(Long accountId, LocalDate transferDate, Office acceptedInOffice, Staff staff);
} }
@@ -34,6 +34,8 @@ import org.mifosplatform.infrastructure.security.service.PlatformSecurityContext
import org.mifosplatform.organisation.monetary.domain.ApplicationCurrency; import org.mifosplatform.organisation.monetary.domain.ApplicationCurrency;
import org.mifosplatform.organisation.monetary.domain.ApplicationCurrencyRepositoryWrapper; import org.mifosplatform.organisation.monetary.domain.ApplicationCurrencyRepositoryWrapper;
import org.mifosplatform.organisation.monetary.domain.MonetaryCurrency; import org.mifosplatform.organisation.monetary.domain.MonetaryCurrency;
import org.mifosplatform.organisation.office.domain.Office;
import org.mifosplatform.organisation.staff.domain.Staff;
import org.mifosplatform.portfolio.client.domain.Client; import org.mifosplatform.portfolio.client.domain.Client;
import org.mifosplatform.portfolio.client.exception.ClientNotActiveException; import org.mifosplatform.portfolio.client.exception.ClientNotActiveException;
import org.mifosplatform.portfolio.group.domain.Group; import org.mifosplatform.portfolio.group.domain.Group;
@@ -304,7 +306,7 @@ public class SavingsAccountWritePlatformServiceJpaRepositoryImpl implements Savi
final MathContext mc = new MathContext(15, RoundingMode.HALF_EVEN); final MathContext mc = new MathContext(15, RoundingMode.HALF_EVEN);
final SavingsAccount account = this.savingAccountAssembler.assembleFrom(savingsId); final SavingsAccount account = this.savingAccountAssembler.assembleFrom(savingsId);
if(account.isNotActive()){ if (account.isNotActive()) {
throwValidationForActiveStatus(SavingsApiConstants.undoTransactionAction); throwValidationForActiveStatus(SavingsApiConstants.undoTransactionAction);
} }
account.undoTransaction(transactionId, reversedTransactionIds); account.undoTransaction(transactionId, reversedTransactionIds);
@@ -342,7 +344,7 @@ public class SavingsAccountWritePlatformServiceJpaRepositoryImpl implements Savi
final LocalDate today = DateUtils.getLocalDateOfTenant(); final LocalDate today = DateUtils.getLocalDateOfTenant();
final SavingsAccount account = this.savingAccountAssembler.assembleFrom(savingsId); final SavingsAccount account = this.savingAccountAssembler.assembleFrom(savingsId);
if(account.isNotActive()){ if (account.isNotActive()) {
throwValidationForActiveStatus(SavingsApiConstants.adjustTransactionAction); throwValidationForActiveStatus(SavingsApiConstants.adjustTransactionAction);
} }
@@ -357,23 +359,23 @@ public class SavingsAccountWritePlatformServiceJpaRepositoryImpl implements Savi
final MathContext mc = new MathContext(10, RoundingMode.HALF_EVEN); final MathContext mc = new MathContext(10, RoundingMode.HALF_EVEN);
account.undoTransaction(transactionId, existingReversedTransactionIds); account.undoTransaction(transactionId, existingReversedTransactionIds);
//for undo withdrawal fee // for undo withdrawal fee
SavingsAccountTransaction nextSavingsAccountTransaction = this.savingsAccountTransactionRepository.findOneByIdAndSavingsAccountId( SavingsAccountTransaction nextSavingsAccountTransaction = this.savingsAccountTransactionRepository.findOneByIdAndSavingsAccountId(
transactionId+1, savingsId); transactionId + 1, savingsId);
if(nextSavingsAccountTransaction.isWithdrawalFeeAndNotReversed()){ if (nextSavingsAccountTransaction.isWithdrawalFeeAndNotReversed()) {
account.undoTransaction(transactionId+1, existingReversedTransactionIds); account.undoTransaction(transactionId + 1, existingReversedTransactionIds);
} }
SavingsAccountTransaction transaction = null; SavingsAccountTransaction transaction = null;
if (savingsAccountTransaction.isDeposit()) { if (savingsAccountTransaction.isDeposit()) {
SavingsAccountTransactionDTO transactionDTO = new SavingsAccountTransactionDTO(fmt, transactionDate, transactionAmount, SavingsAccountTransactionDTO transactionDTO = new SavingsAccountTransactionDTO(fmt, transactionDate, transactionAmount,
existingTransactionIds, existingReversedTransactionIds,paymentDetail); existingTransactionIds, existingReversedTransactionIds, paymentDetail);
transaction = account.deposit(transactionDTO); transaction = account.deposit(transactionDTO);
} else { } else {
SavingsAccountTransactionDTO transactionDTO = new SavingsAccountTransactionDTO(fmt, transactionDate, transactionAmount, SavingsAccountTransactionDTO transactionDTO = new SavingsAccountTransactionDTO(fmt, transactionDate, transactionAmount,
existingTransactionIds, existingReversedTransactionIds, paymentDetail); existingTransactionIds, existingReversedTransactionIds, paymentDetail);
transaction = account.withdraw(transactionDTO , true); transaction = account.withdraw(transactionDTO, true);
} }
final Long newtransactionId = saveTransactionToGenerateTransactionId(transaction); final Long newtransactionId = saveTransactionToGenerateTransactionId(transaction);
@@ -455,4 +457,75 @@ public class SavingsAccountWritePlatformServiceJpaRepositoryImpl implements Savi
.with(changes) // .with(changes) //
.build(); .build();
} }
@Override
public SavingsAccountTransaction initiateSavingsTransfer(Long accountId, LocalDate transferDate) {
final SavingsAccount savingsAccount = this.savingAccountAssembler.assembleFrom(accountId);
final List<Long> existingTransactionIds = new ArrayList<Long>(savingsAccount.findExistingTransactionIds());
final List<Long> existingReversedTransactionIds = new ArrayList<Long>(savingsAccount.findExistingReversedTransactionIds());
final SavingsAccountTransaction newTransferTransaction = SavingsAccountTransaction.initiateTransfer(savingsAccount,
savingsAccount.office(), transferDate);
savingsAccount.getTransactions().add(newTransferTransaction);
savingsAccount.setStatus(SavingsAccountStatusType.TRANSFER_IN_PROGRESS.getValue());
this.savingsAccountTransactionRepository.save(newTransferTransaction);
this.savingAccountRepository.save(savingsAccount);
postJournalEntries(savingsAccount, existingTransactionIds, existingReversedTransactionIds);
return newTransferTransaction;
}
@Override
public SavingsAccountTransaction withdrawSavingsTransfer(Long accountId, LocalDate transferDate) {
final SavingsAccount savingsAccount = this.savingAccountAssembler.assembleFrom(accountId);
final List<Long> existingTransactionIds = new ArrayList<Long>(savingsAccount.findExistingTransactionIds());
final List<Long> existingReversedTransactionIds = new ArrayList<Long>(savingsAccount.findExistingReversedTransactionIds());
final SavingsAccountTransaction withdrawtransferTransaction = SavingsAccountTransaction.withdrawTransfer(savingsAccount,
savingsAccount.office(), transferDate);
savingsAccount.getTransactions().add(withdrawtransferTransaction);
savingsAccount.setStatus(SavingsAccountStatusType.ACTIVE.getValue());
this.savingsAccountTransactionRepository.save(withdrawtransferTransaction);
this.savingAccountRepository.save(savingsAccount);
postJournalEntries(savingsAccount, existingTransactionIds, existingReversedTransactionIds);
return withdrawtransferTransaction;
}
@Override
public void rejectSavingsTransfer(Long accountId) {
final SavingsAccount savingsAccount = this.savingAccountAssembler.assembleFrom(accountId);
savingsAccount.setStatus(SavingsAccountStatusType.TRANSFER_ON_HOLD.getValue());
this.savingAccountRepository.save(savingsAccount);
}
@Override
public SavingsAccountTransaction acceptSavingsTransfer(Long accountId, LocalDate transferDate, Office acceptedInOffice,
Staff fieldOfficer) {
final SavingsAccount savingsAccount = this.savingAccountAssembler.assembleFrom(accountId);
final List<Long> existingTransactionIds = new ArrayList<Long>(savingsAccount.findExistingTransactionIds());
final List<Long> existingReversedTransactionIds = new ArrayList<Long>(savingsAccount.findExistingReversedTransactionIds());
final SavingsAccountTransaction acceptTransferTransaction = SavingsAccountTransaction.approveTransfer(savingsAccount,
acceptedInOffice, transferDate);
savingsAccount.getTransactions().add(acceptTransferTransaction);
savingsAccount.setStatus(SavingsAccountStatusType.ACTIVE.getValue());
if (fieldOfficer != null) {
savingsAccount.update(fieldOfficer);
}
this.savingsAccountTransactionRepository.save(acceptTransferTransaction);
this.savingAccountRepository.save(savingsAccount);
postJournalEntries(savingsAccount, existingTransactionIds, existingReversedTransactionIds);
return acceptTransferTransaction;
}
} }
@@ -100,46 +100,61 @@ public class SavingsEnumerations {
final boolean isWithdrawnByApplicant = type.isApplicationWithdrawnByApplicant(); final boolean isWithdrawnByApplicant = type.isApplicationWithdrawnByApplicant();
final boolean isActive = type.isActive(); final boolean isActive = type.isActive();
final boolean isClosed = type.isClosed(); final boolean isClosed = type.isClosed();
final boolean isTransferInProgress = type.isTransferInProgress();
final boolean isTransferOnHold = type.isTransferOnHold();
SavingsAccountStatusEnumData optionData = new SavingsAccountStatusEnumData(SavingsAccountStatusType.INVALID.getValue().longValue(), SavingsAccountStatusEnumData optionData = new SavingsAccountStatusEnumData(SavingsAccountStatusType.INVALID.getValue().longValue(),
SavingsAccountStatusType.INVALID.getCode(), "Invalid", submittedAndPendingApproval, isApproved, isRejected, SavingsAccountStatusType.INVALID.getCode(), "Invalid", submittedAndPendingApproval, isApproved, isRejected,
isWithdrawnByApplicant, isActive, isClosed); isWithdrawnByApplicant, isActive, isClosed, isTransferInProgress, isTransferOnHold);
switch (type) { switch (type) {
case INVALID: case INVALID:
optionData = new SavingsAccountStatusEnumData(SavingsAccountStatusType.INVALID.getValue().longValue(), optionData = new SavingsAccountStatusEnumData(SavingsAccountStatusType.INVALID.getValue().longValue(),
SavingsAccountStatusType.INVALID.getCode(), "Invalid", submittedAndPendingApproval, isApproved, isRejected, SavingsAccountStatusType.INVALID.getCode(), "Invalid", submittedAndPendingApproval, isApproved, isRejected,
isWithdrawnByApplicant, isActive, isClosed); isWithdrawnByApplicant, isActive, isClosed, isTransferInProgress, isTransferOnHold);
break; break;
case SUBMITTED_AND_PENDING_APPROVAL: case SUBMITTED_AND_PENDING_APPROVAL:
optionData = new SavingsAccountStatusEnumData(SavingsAccountStatusType.SUBMITTED_AND_PENDING_APPROVAL.getValue() optionData = new SavingsAccountStatusEnumData(SavingsAccountStatusType.SUBMITTED_AND_PENDING_APPROVAL.getValue()
.longValue(), SavingsAccountStatusType.SUBMITTED_AND_PENDING_APPROVAL.getCode(), "Submitted and pending approval", .longValue(), SavingsAccountStatusType.SUBMITTED_AND_PENDING_APPROVAL.getCode(), "Submitted and pending approval",
submittedAndPendingApproval, isApproved, isRejected, isWithdrawnByApplicant, isActive, isClosed); submittedAndPendingApproval, isApproved, isRejected, isWithdrawnByApplicant, isActive, isClosed,
isTransferInProgress, isTransferOnHold);
break; break;
case REJECTED: case REJECTED:
optionData = new SavingsAccountStatusEnumData(SavingsAccountStatusType.REJECTED.getValue().longValue(), optionData = new SavingsAccountStatusEnumData(SavingsAccountStatusType.REJECTED.getValue().longValue(),
SavingsAccountStatusType.REJECTED.getCode(), "Rejected", submittedAndPendingApproval, isApproved, isRejected, SavingsAccountStatusType.REJECTED.getCode(), "Rejected", submittedAndPendingApproval, isApproved, isRejected,
isWithdrawnByApplicant, isActive, isClosed); isWithdrawnByApplicant, isActive, isClosed, isTransferInProgress, isTransferOnHold);
break; break;
case WITHDRAWN_BY_APPLICANT: case WITHDRAWN_BY_APPLICANT:
optionData = new SavingsAccountStatusEnumData(SavingsAccountStatusType.WITHDRAWN_BY_APPLICANT.getValue().longValue(), optionData = new SavingsAccountStatusEnumData(SavingsAccountStatusType.WITHDRAWN_BY_APPLICANT.getValue().longValue(),
SavingsAccountStatusType.WITHDRAWN_BY_APPLICANT.getCode(), "Withdrawn by applicant", submittedAndPendingApproval, SavingsAccountStatusType.WITHDRAWN_BY_APPLICANT.getCode(), "Withdrawn by applicant", submittedAndPendingApproval,
isApproved, isRejected, isWithdrawnByApplicant, isActive, isClosed); isApproved, isRejected, isWithdrawnByApplicant, isActive, isClosed, isTransferInProgress, isTransferOnHold);
break; break;
case APPROVED: case APPROVED:
optionData = new SavingsAccountStatusEnumData(SavingsAccountStatusType.APPROVED.getValue().longValue(), optionData = new SavingsAccountStatusEnumData(SavingsAccountStatusType.APPROVED.getValue().longValue(),
SavingsAccountStatusType.APPROVED.getCode(), "Approved", submittedAndPendingApproval, isApproved, isRejected, SavingsAccountStatusType.APPROVED.getCode(), "Approved", submittedAndPendingApproval, isApproved, isRejected,
isWithdrawnByApplicant, isActive, isClosed); isWithdrawnByApplicant, isActive, isClosed, isTransferInProgress, isTransferOnHold);
break; break;
case ACTIVE: case ACTIVE:
optionData = new SavingsAccountStatusEnumData(SavingsAccountStatusType.ACTIVE.getValue().longValue(), optionData = new SavingsAccountStatusEnumData(SavingsAccountStatusType.ACTIVE.getValue().longValue(),
SavingsAccountStatusType.ACTIVE.getCode(), "Active", submittedAndPendingApproval, isApproved, isRejected, SavingsAccountStatusType.ACTIVE.getCode(), "Active", submittedAndPendingApproval, isApproved, isRejected,
isWithdrawnByApplicant, isActive, isClosed); isWithdrawnByApplicant, isActive, isClosed, isTransferInProgress, isTransferOnHold);
break; break;
case CLOSED: case CLOSED:
optionData = new SavingsAccountStatusEnumData(SavingsAccountStatusType.CLOSED.getValue().longValue(), optionData = new SavingsAccountStatusEnumData(SavingsAccountStatusType.CLOSED.getValue().longValue(),
SavingsAccountStatusType.CLOSED.getCode(), "Closed", submittedAndPendingApproval, isApproved, isRejected, SavingsAccountStatusType.CLOSED.getCode(), "Closed", submittedAndPendingApproval, isApproved, isRejected,
isWithdrawnByApplicant, isActive, isClosed); isWithdrawnByApplicant, isActive, isClosed, isTransferInProgress, isTransferOnHold);
break;
case TRANSFER_IN_PROGRESS:
optionData = new SavingsAccountStatusEnumData(SavingsAccountStatusType.TRANSFER_IN_PROGRESS.getValue().longValue(),
SavingsAccountStatusType.TRANSFER_IN_PROGRESS.getCode(), "Transfer in progress", submittedAndPendingApproval,
isApproved, isRejected, isWithdrawnByApplicant, isActive, isClosed, isTransferInProgress, isTransferOnHold);
break;
case TRANSFER_ON_HOLD:
optionData = new SavingsAccountStatusEnumData(SavingsAccountStatusType.TRANSFER_IN_PROGRESS.getValue().longValue(),
SavingsAccountStatusType.TRANSFER_ON_HOLD.getCode(), "Transfer in progress", submittedAndPendingApproval,
isApproved, isRejected, isWithdrawnByApplicant, isActive, isClosed, isTransferInProgress, isTransferOnHold);
break;
default:
break; break;
} }
return optionData; return optionData;
@@ -35,7 +35,9 @@ import org.mifosplatform.portfolio.loanaccount.domain.Loan;
import org.mifosplatform.portfolio.loanaccount.domain.LoanRepository; import org.mifosplatform.portfolio.loanaccount.domain.LoanRepository;
import org.mifosplatform.portfolio.loanaccount.service.LoanWritePlatformService; import org.mifosplatform.portfolio.loanaccount.service.LoanWritePlatformService;
import org.mifosplatform.portfolio.note.service.NoteWritePlatformService; import org.mifosplatform.portfolio.note.service.NoteWritePlatformService;
import org.mifosplatform.portfolio.savings.domain.SavingsAccount;
import org.mifosplatform.portfolio.savings.domain.SavingsAccountRepository; import org.mifosplatform.portfolio.savings.domain.SavingsAccountRepository;
import org.mifosplatform.portfolio.savings.service.SavingsAccountWritePlatformService;
import org.mifosplatform.portfolio.transfer.api.TransferApiConstants; import org.mifosplatform.portfolio.transfer.api.TransferApiConstants;
import org.mifosplatform.portfolio.transfer.data.TransfersDataValidator; import org.mifosplatform.portfolio.transfer.data.TransfersDataValidator;
import org.mifosplatform.portfolio.transfer.exception.ClientNotAwaitingTransferApprovalException; import org.mifosplatform.portfolio.transfer.exception.ClientNotAwaitingTransferApprovalException;
@@ -58,6 +60,7 @@ public class TransferWritePlatformServiceJpaRepositoryImpl implements TransferWr
private final CalendarInstanceRepository calendarInstanceRepository; private final CalendarInstanceRepository calendarInstanceRepository;
private final GroupRepositoryWrapper groupRepository; private final GroupRepositoryWrapper groupRepository;
private final LoanWritePlatformService loanWritePlatformService; private final LoanWritePlatformService loanWritePlatformService;
private final SavingsAccountWritePlatformService savingsAccountWritePlatformService;
private final LoanRepository loanRepository; private final LoanRepository loanRepository;
private final SavingsAccountRepository savingsAccountRepository; private final SavingsAccountRepository savingsAccountRepository;
private final TransfersDataValidator transfersDataValidator; private final TransfersDataValidator transfersDataValidator;
@@ -70,7 +73,8 @@ public class TransferWritePlatformServiceJpaRepositoryImpl implements TransferWr
final LoanWritePlatformService loanWritePlatformService, final GroupRepositoryWrapper groupRepository, final LoanWritePlatformService loanWritePlatformService, final GroupRepositoryWrapper groupRepository,
final LoanRepository loanRepository, final TransfersDataValidator transfersDataValidator, final LoanRepository loanRepository, final TransfersDataValidator transfersDataValidator,
final NoteWritePlatformService noteWritePlatformService, final StaffRepositoryWrapper staffRepositoryWrapper, final NoteWritePlatformService noteWritePlatformService, final StaffRepositoryWrapper staffRepositoryWrapper,
final SavingsAccountRepository savingsAccountRepository) { final SavingsAccountRepository savingsAccountRepository,
final SavingsAccountWritePlatformService savingsAccountWritePlatformService) {
this.clientRepository = clientRepository; this.clientRepository = clientRepository;
this.officeRepository = officeRepository; this.officeRepository = officeRepository;
this.calendarInstanceRepository = calendarInstanceRepository; this.calendarInstanceRepository = calendarInstanceRepository;
@@ -81,6 +85,7 @@ public class TransferWritePlatformServiceJpaRepositoryImpl implements TransferWr
this.noteWritePlatformService = noteWritePlatformService; this.noteWritePlatformService = noteWritePlatformService;
this.staffRepositoryWrapper = staffRepositoryWrapper; this.staffRepositoryWrapper = staffRepositoryWrapper;
this.savingsAccountRepository = savingsAccountRepository; this.savingsAccountRepository = savingsAccountRepository;
this.savingsAccountWritePlatformService = savingsAccountWritePlatformService;
} }
@Override @Override
@@ -345,8 +350,30 @@ public class TransferWritePlatformServiceJpaRepositoryImpl implements TransferWr
} }
/*** Handle Active Savings (Currently throw and exception) ***/ /*** Handle Active Savings (Currently throw and exception) ***/
if (savingsAccountRepository.doNonClosedSavingAccountsExistForClient(client.getId())) { throw new TransferNotSupportedException( if (savingsAccountRepository.doNonClosedSavingAccountsExistForClient(client.getId())) {
TRANSFER_NOT_SUPPORTED_REASON.ACTIVE_SAVINGS_ACCOUNT, client.getId()); } // get each individual saving account for the client
for (SavingsAccount savingsAccount : savingsAccountRepository.findSavingAccountByClientId(client.getId())) {
if (!savingsAccount.isClosed()) {
switch (transferEventType) {
case ACCEPTANCE:
this.savingsAccountWritePlatformService.acceptSavingsTransfer(savingsAccount.getId(),
DateUtils.getLocalDateOfTenant(), destinationOffice, staff);
break;
case PROPOSAL:
this.savingsAccountWritePlatformService.initiateSavingsTransfer(savingsAccount.getId(),
DateUtils.getLocalDateOfTenant());
break;
case REJECTION:
this.savingsAccountWritePlatformService.withdrawSavingsTransfer(savingsAccount.getId(),
DateUtils.getLocalDateOfTenant());
break;
case WITHDRAWAL:
this.savingsAccountWritePlatformService.withdrawSavingsTransfer(savingsAccount.getId(),
DateUtils.getLocalDateOfTenant());
}
}
}
}
switch (transferEventType) { switch (transferEventType) {
case ACCEPTANCE: case ACCEPTANCE: