Skip to content
Permalink
Browse files
handling of loan repayment added
  • Loading branch information
mgeiss committed Aug 4, 2017
1 parent 5cf910b commit 11d8f58c0aa96cef6c614bdc16e6d9bb71261060
Show file tree
Hide file tree
Showing 7 changed files with 188 additions and 11 deletions.
@@ -21,9 +21,12 @@
import io.mifos.deposit.api.v1.instance.domain.ProductInstance;
import io.mifos.teller.api.v1.EventConstants;
import io.mifos.teller.api.v1.client.TellerNotFoundException;
import io.mifos.teller.api.v1.client.TellerTransactionValidationException;
import io.mifos.teller.api.v1.client.TransactionProcessingException;
import io.mifos.teller.api.v1.domain.*;
import io.mifos.teller.api.v1.domain.Teller;
import io.mifos.teller.api.v1.domain.TellerManagementCommand;
import io.mifos.teller.api.v1.domain.TellerTransaction;
import io.mifos.teller.api.v1.domain.TellerTransactionCosts;
import io.mifos.teller.api.v1.domain.UnlockDrawerCommand;
import io.mifos.teller.util.TellerGenerator;
import org.apache.commons.lang3.RandomStringUtils;
import org.junit.Assert;
@@ -465,4 +468,36 @@ public void shouldNotReopenAccountClosed() throws Exception {

super.testSubject.post(teller.getCode(), reopenAccountTransaction);
}

@Test
public void shouldProcessRepayment() throws Exception {
final Teller teller = this.prepareTeller();

final UnlockDrawerCommand unlockDrawerCommand = new UnlockDrawerCommand();
unlockDrawerCommand.setEmployeeIdentifier(AbstractTellerTest.TEST_USER);
unlockDrawerCommand.setPassword(teller.getPassword());

super.testSubject.unlockDrawer(teller.getCode(), unlockDrawerCommand);

super.eventRecorder.wait(EventConstants.AUTHENTICATE_TELLER, teller.getCode());

final TellerTransaction repaymentTransaction = new TellerTransaction();
repaymentTransaction.setTransactionType(ServiceConstants.TX_REPAYMENT);
repaymentTransaction.setTransactionDate(DateConverter.toIsoString(LocalDateTime.now(Clock.systemUTC())));
repaymentTransaction.setProductIdentifier(RandomStringUtils.randomAlphanumeric(32));
repaymentTransaction.setProductCaseIdentifier(RandomStringUtils.randomAlphanumeric(32));
repaymentTransaction.setCustomerAccountIdentifier(RandomStringUtils.randomAlphanumeric(32));
repaymentTransaction.setCustomerIdentifier(RandomStringUtils.randomAlphanumeric(32));
repaymentTransaction.setClerk(AbstractTellerTest.TEST_USER);
repaymentTransaction.setAmount(246.80D);

final Account account = new Account();
account.setState(Account.State.OPEN.name());
Mockito.doAnswer(invocation -> Optional.of(account))
.when(super.accountingServiceSpy).findAccount(repaymentTransaction.getCustomerAccountIdentifier());

final TellerTransactionCosts tellerTransactionCosts = super.testSubject.post(teller.getCode(), repaymentTransaction);

super.testSubject.confirm(teller.getCode(), tellerTransactionCosts.getTellerTransactionIdentifier(), "CONFIRM", null);
}
}
@@ -1,6 +1,6 @@
#Fri Mar 17 17:54:20 CET 2017
#Fri Aug 04 10:46:39 CEST 2017
distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists
zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists
distributionUrl=https\://services.gradle.org/distributions/gradle-3.4.1-bin.zip
distributionUrl=https\://services.gradle.org/distributions/gradle-3.4.1-all.zip
@@ -26,6 +26,7 @@ public interface ServiceConstants {
String TX_ACCOUNT_TRANSFER = "ACCT";
String TX_CASH_DEPOSIT = "CDPT";
String TX_CASH_WITHDRAWAL = "CWDL";
String TX_REPAYMENT = "PPAY";

String TX_DEPOSIT_ADJUSTMENT = "DAJT";
String TX_CREDIT_ADJUSTMENT = "CAJT";
@@ -60,7 +60,7 @@ public DepositTransactionHandler(@Qualifier(ServiceConstants.LOGGER_NAME) final
this.tellerRepository = tellerRepository;
}

public TellerTransactionCosts getDepositTransactionCosts(final TellerTransaction tellerTransaction) {
public TellerTransactionCosts getTellerTransactionCosts(final TellerTransaction tellerTransaction) {
final List<Charge> charges = this.depositAccountManagementService.getCharges(tellerTransaction);

final TellerTransactionCosts tellerTransactionCosts = new TellerTransactionCosts();
@@ -74,11 +74,11 @@ public TellerTransactionCosts getDepositTransactionCosts(final TellerTransaction
}

public void processTransfer(final String tellerCode, final TellerTransaction tellerTransaction,
final boolean chargesIncluded) {
final boolean chargesIncluded) {
final TellerEntity tellerEntity = getTellerEntity(tellerCode);
final JournalEntry journalEntry = this.prepareJournalEntry(tellerTransaction);

final TellerTransactionCosts tellerTransactionCosts = this.getDepositTransactionCosts(tellerTransaction);
final TellerTransactionCosts tellerTransactionCosts = this.getTellerTransactionCosts(tellerTransaction);

final HashSet<Debtor> debtors = new HashSet<>();
journalEntry.setDebtors(debtors);
@@ -112,7 +112,7 @@ public void processTransfer(final String tellerCode, final TellerTransaction tel
public void processCashDeposit(final String tellerCode, final TellerTransaction tellerTransaction, final boolean chargesIncluded) {
final TellerEntity tellerEntity = getTellerEntity(tellerCode);
final JournalEntry journalEntry = this.prepareJournalEntry(tellerTransaction);
final TellerTransactionCosts tellerTransactionCosts = this.getDepositTransactionCosts(tellerTransaction);
final TellerTransactionCosts tellerTransactionCosts = this.getTellerTransactionCosts(tellerTransaction);

final HashSet<Debtor> debtors = new HashSet<>();
journalEntry.setDebtors(debtors);
@@ -146,7 +146,7 @@ public void processCashWithdrawal(final String tellerCode, final TellerTransacti
final boolean chargesIncluded) {
final TellerEntity tellerEntity = getTellerEntity(tellerCode);
final JournalEntry journalEntry = this.prepareJournalEntry(tellerTransaction);
final TellerTransactionCosts tellerTransactionCosts = this.getDepositTransactionCosts(tellerTransaction);
final TellerTransactionCosts tellerTransactionCosts = this.getTellerTransactionCosts(tellerTransaction);

final HashSet<Debtor> debtors = new HashSet<>();
journalEntry.setDebtors(debtors);
@@ -0,0 +1,81 @@
/*
* Copyright 2017 The Mifos Initiative.
*
* Licensed 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 io.mifos.teller.service.internal.processor;

import io.mifos.core.lang.ServiceException;
import io.mifos.teller.ServiceConstants;
import io.mifos.teller.api.v1.domain.Charge;
import io.mifos.teller.api.v1.domain.TellerTransaction;
import io.mifos.teller.api.v1.domain.TellerTransactionCosts;
import io.mifos.teller.service.internal.repository.TellerEntity;
import io.mifos.teller.service.internal.repository.TellerRepository;
import io.mifos.teller.service.internal.service.helper.PortfolioService;
import org.slf4j.Logger;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.stereotype.Component;

import java.util.List;
import java.util.Optional;

@Component
public class PortfolioTransactionHandler {

private final Logger logger;
private final PortfolioService portfolioService;
private final TellerRepository tellerRepository;

public PortfolioTransactionHandler(@Qualifier(ServiceConstants.LOGGER_NAME) final Logger logger,
final PortfolioService portfolioService,
final TellerRepository tellerRepository) {
super();
this.logger = logger;
this.portfolioService = portfolioService;
this.tellerRepository = tellerRepository;
}

public TellerTransactionCosts getTellerTransactionCosts(final TellerTransaction tellerTransaction) {
final List<Charge> charges =
this.portfolioService.getCharges(
tellerTransaction.getProductIdentifier(), tellerTransaction.getProductCaseIdentifier()
);

final TellerTransactionCosts tellerTransactionCosts = new TellerTransactionCosts();
tellerTransactionCosts.setCharges(charges);
tellerTransactionCosts.setTellerTransactionIdentifier(tellerTransaction.getIdentifier());
tellerTransactionCosts.setTotalAmount(
charges.stream().mapToDouble(Charge::getAmount).sum()
);

return tellerTransactionCosts;
}

public void processRepayment(final String tellerCode, final TellerTransaction tellerTransaction) {
final Optional<TellerEntity> optionalTellerEntity = this.tellerRepository.findByIdentifier(tellerCode);
if (optionalTellerEntity.isPresent()) {
final TellerEntity tellerEntity = optionalTellerEntity.get();

this.portfolioService.processRepayment(
tellerTransaction.getProductIdentifier(),
tellerTransaction.getProductCaseIdentifier(),
tellerEntity.getTellerAccountIdentifier()
);

} else {
throw ServiceException.notFound("Teller {0} not found." , tellerCode);
}

}
}
@@ -28,13 +28,16 @@ public class TellerTransactionProcessor {

private final Logger logger;
private final DepositTransactionHandler depositTransactionHandler;
private final PortfolioTransactionHandler portfolioTransactionHandler;

@Autowired
public TellerTransactionProcessor(@Qualifier(ServiceConstants.LOGGER_NAME) final Logger logger,
final DepositTransactionHandler depositTransactionHandler) {
final DepositTransactionHandler depositTransactionHandler,
final PortfolioTransactionHandler portfolioTransactionHandler) {
super();
this.logger = logger;
this.depositTransactionHandler = depositTransactionHandler;
this.portfolioTransactionHandler = portfolioTransactionHandler;
}

public void process(final String tellerCode, final TellerTransaction tellerTransaction, final Boolean chargesIncluded) {
@@ -54,6 +57,9 @@ public void process(final String tellerCode, final TellerTransaction tellerTrans
case ServiceConstants.TX_CASH_WITHDRAWAL:
this.depositTransactionHandler.processCashWithdrawal(tellerCode, tellerTransaction, chargesIncluded);
break;
case ServiceConstants.TX_REPAYMENT:
this.portfolioTransactionHandler.processRepayment(tellerCode, tellerTransaction);
break;
default:
throw new IllegalArgumentException("Unsupported TX type " + tellerTransaction.getTransactionType());
}
@@ -66,7 +72,9 @@ public TellerTransactionCosts getCosts(final TellerTransaction tellerTransaction
case ServiceConstants.TX_ACCOUNT_TRANSFER:
case ServiceConstants.TX_CASH_DEPOSIT:
case ServiceConstants.TX_CASH_WITHDRAWAL:
return this.depositTransactionHandler.getDepositTransactionCosts(tellerTransaction);
return this.depositTransactionHandler.getTellerTransactionCosts(tellerTransaction);
case ServiceConstants.TX_REPAYMENT:
return this.portfolioTransactionHandler.getTellerTransactionCosts(tellerTransaction);
default:
throw new IllegalArgumentException("Unsupported TX type " + tellerTransaction.getTransactionType());
}
@@ -15,13 +15,25 @@
*/
package io.mifos.teller.service.internal.service.helper;

import io.mifos.individuallending.api.v1.domain.product.AccountDesignators;
import io.mifos.individuallending.api.v1.domain.workflow.Action;
import io.mifos.portfolio.api.v1.client.PortfolioManager;
import io.mifos.portfolio.api.v1.domain.AccountAssignment;
import io.mifos.portfolio.api.v1.domain.ChargeDefinition;
import io.mifos.portfolio.api.v1.domain.Command;
import io.mifos.portfolio.api.v1.domain.CostComponent;
import io.mifos.teller.ServiceConstants;
import io.mifos.teller.api.v1.domain.Charge;
import org.slf4j.Logger;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.stereotype.Service;

import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;

@Service
public class PortfolioService {

@@ -36,5 +48,45 @@ public PortfolioService(@Qualifier(ServiceConstants.LOGGER_NAME) final Logger lo
this.portfolioManager = portfolioManager;
}

public List<Charge> getCharges(final String productIdentifier, final String caseIdentifier) {

final List<Charge> charges = new ArrayList<>();

final List<CostComponent> costComponentsForAction =
this.portfolioManager.getCostComponentsForAction(productIdentifier, caseIdentifier, Action.ACCEPT_PAYMENT.name());

costComponentsForAction.forEach(costComponent -> {
final ChargeDefinition chargeDefinition =
this.portfolioManager.getChargeDefinition(productIdentifier, costComponent.getChargeIdentifier());

final Charge charge = new Charge();
charge.setCode(chargeDefinition.getIdentifier());
charge.setName(chargeDefinition.getName());
charge.setAmount(costComponent.getAmount().doubleValue());
charges.add(charge);
});

return charges;
}

public void processRepayment(final String productIdentifier, final String caseIdentifier, final String tellerAccount) {

final List<CostComponent> costComponentsForAction =
this.portfolioManager.getCostComponentsForAction(productIdentifier, caseIdentifier, Action.ACCEPT_PAYMENT.name());

final Command repaymentCommand = new Command();
repaymentCommand.setOneTimeAccountAssignments(this.getAccountAssignments(tellerAccount));
repaymentCommand.setPaymentSize(BigDecimal.valueOf(
costComponentsForAction.stream().mapToDouble(value -> value.getAmount().doubleValue()).sum())
);

portfolioManager.executeCaseCommand(productIdentifier, caseIdentifier, Action.ACCEPT_PAYMENT.name(), repaymentCommand);
}

private List<AccountAssignment> getAccountAssignments(final String tellerAccount) {
final AccountAssignment accountAssignment = new AccountAssignment();
accountAssignment.setAccountIdentifier(tellerAccount);
accountAssignment.setDesignator(AccountDesignators.ENTRY);
return Collections.singletonList(accountAssignment);
}
}

0 comments on commit 11d8f58

Please sign in to comment.