Skip to content
Permalink
Browse files
Merge pull request #12 from markusgeiss/develop
fixes and ability to delete teller
  • Loading branch information
markusgeiss committed Sep 14, 2017
2 parents 5cb363f + 7d89a3e commit fd0d1bf67dad7ed8e74f890f58bccdb504538cbe
Showing 16 changed files with 379 additions and 64 deletions.
@@ -2,7 +2,7 @@
.idea
build/
target/

out/
# Ignore Gradle GUI config
gradle-app.setting

@@ -37,6 +37,8 @@ public interface EventConstants {
String SELECTOR_ACTIVATE_TELLER = SELECTOR_NAME + " = '" + ACTIVATE_TELLER + "'";
String PAUSE_TELLER = "pause-teller";
String SELECTOR_PAUSE_TELLER = SELECTOR_NAME + " = '" + PAUSE_TELLER + "'";
String DELETE_TELLER = "delete-teller";
String SELECTOR_DELETE_TELLER = SELECTOR_NAME + " = '" + DELETE_TELLER + "'";

String INIT_TRANSACTION = "init-transaction";
String SELECTOR_INIT_TRANSACTION = SELECTOR_NAME + " = '" + INIT_TRANSACTION + "'";
@@ -165,7 +165,8 @@ TellerTransactionCosts post(@PathVariable("tellerCode") final String tellerCode,
produces = MediaType.APPLICATION_JSON_VALUE
)
@ThrowsExceptions({
@ThrowsException(status = HttpStatus.NOT_FOUND, exception = TellerNotFoundException.class)
@ThrowsException(status = HttpStatus.NOT_FOUND, exception = TellerNotFoundException.class),
@ThrowsException(status = HttpStatus.CONFLICT, exception = TransactionProcessingException.class)
})
void confirm(@PathVariable("tellerCode") final String tellerCode,
@PathVariable("identifier") final String tellerTransactionIdentifier,
@@ -183,4 +184,17 @@ void confirm(@PathVariable("tellerCode") final String tellerCode,
})
List<TellerTransaction> fetch(@PathVariable("tellerCode") final String tellerCode,
@RequestParam(value = "status", required = false) final String status);

@RequestMapping(
value = "/offices/{officeIdentifier}/teller/{tellerCode}",
method = RequestMethod.DELETE,
consumes = MediaType.APPLICATION_JSON_VALUE,
produces = MediaType.ALL_VALUE
)
@ThrowsExceptions({
@ThrowsException(status = HttpStatus.NOT_FOUND, exception = TellerNotFoundException.class),
@ThrowsException(status = HttpStatus.CONFLICT, exception = TellerValidationException.class)
})
void deleteTeller(@PathVariable("officeIdentifier") final String officeIdentifier,
@PathVariable("tellerCode") final String tellerCode);
}
@@ -50,6 +50,8 @@ public enum State {
private String createdOn;
private String lastModifiedBy;
private String lastModifiedOn;
private String lastOpenedBy;
private String lastOpenedOn;

public Teller() {
super();
@@ -154,4 +156,20 @@ public String getLastModifiedOn() {
public void setLastModifiedOn(final String lastModifiedOn) {
this.lastModifiedOn = lastModifiedOn;
}

public String getLastOpenedBy() {
return this.lastOpenedBy;
}

public void setLastOpenedBy(final String lastOpenedBy) {
this.lastOpenedBy = lastOpenedBy;
}

public String getLastOpenedOn() {
return this.lastOpenedOn;
}

public void setLastOpenedOn(final String lastOpenedOn) {
this.lastOpenedOn = lastOpenedOn;
}
}
@@ -538,6 +538,64 @@ public void shouldCloseTellerEvenCashDrawLimitExceeding() throws Exception {
Assert.assertTrue(super.eventRecorder.wait(EventConstants.CLOSE_TELLER, teller.getCode()));
}

@Test
public void shouldDeleteTeller() throws Exception {
final String officeIdentifier = RandomStringUtils.randomAlphabetic(32);
final Teller teller = TellerGenerator.createRandomTeller();
teller.setCashdrawLimit(BigDecimal.valueOf(10000.00D));

Mockito.doAnswer(invocation -> true)
.when(super.organizationServiceSpy).officeExists(Matchers.eq(officeIdentifier));

Mockito.doAnswer(invocation -> Optional.of(new Account()))
.when(super.accountingServiceSpy).findAccount(Matchers.eq(teller.getTellerAccountIdentifier()));

Mockito.doAnswer(invocation -> Optional.of(new Account()))
.when(super.accountingServiceSpy).findAccount(Matchers.eq(teller.getVaultAccountIdentifier()));

super.testSubject.create(officeIdentifier, teller);
Assert.assertTrue(super.eventRecorder.wait(EventConstants.POST_TELLER, teller.getCode()));

final Teller fetchedTeller = this.testSubject.find(officeIdentifier, teller.getCode());
Assert.assertTrue(fetchedTeller.getLastOpenedBy() == null);

super.testSubject.deleteTeller(officeIdentifier, teller.getCode());
Assert.assertTrue(super.eventRecorder.wait(EventConstants.DELETE_TELLER, teller.getCode()));
}

@Test(expected = TellerValidationException.class)
public void shouldNotDeleteTeller() throws Exception {
final String officeIdentifier = RandomStringUtils.randomAlphabetic(32);
final Teller teller = TellerGenerator.createRandomTeller();
teller.setCashdrawLimit(BigDecimal.valueOf(10000.00D));

Mockito.doAnswer(invocation -> true)
.when(super.organizationServiceSpy).officeExists(Matchers.eq(officeIdentifier));

Mockito.doAnswer(invocation -> Optional.of(new Account()))
.when(super.accountingServiceSpy).findAccount(Matchers.eq(teller.getTellerAccountIdentifier()));

Mockito.doAnswer(invocation -> Optional.of(new Account()))
.when(super.accountingServiceSpy).findAccount(Matchers.eq(teller.getVaultAccountIdentifier()));

super.testSubject.create(officeIdentifier, teller);
Assert.assertTrue(super.eventRecorder.wait(EventConstants.POST_TELLER, teller.getCode()));

final TellerManagementCommand openCommand = new TellerManagementCommand();
openCommand.setAction(TellerManagementCommand.Action.OPEN.name());
openCommand.setAdjustment(TellerManagementCommand.Adjustment.NONE.name());
openCommand.setAssignedEmployeeIdentifier(RandomStringUtils.randomAlphanumeric(32));

this.testSubject.post(officeIdentifier, teller.getCode(), openCommand);
Assert.assertTrue(super.eventRecorder.wait(EventConstants.OPEN_TELLER, teller.getCode()));

final Teller fetchedTeller = this.testSubject.find(officeIdentifier, teller.getCode());
Assert.assertTrue(fetchedTeller.getLastOpenedBy() != null);

super.testSubject.deleteTeller(officeIdentifier, teller.getCode());
Assert.assertTrue(super.eventRecorder.wait(EventConstants.DELETE_TELLER, teller.getCode()));
}

private void compareTeller(final Teller expected, final Teller actual) {
Assert.assertEquals(expected.getCode(), actual.getCode());
Assert.assertEquals(expected.getTellerAccountIdentifier(), actual.getTellerAccountIdentifier());
@@ -241,7 +241,9 @@ public void shouldNotCloseAccountRemainingBalance() throws Exception {
Mockito.doAnswer(invocation -> Collections.emptyList())
.when(super.depositAccountManagementServiceSpy).fetchProductInstances(tellerTransaction.getCustomerIdentifier());

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

super.testSubject.confirm(teller.getCode(), tellerTransactionCosts.getTellerTransactionIdentifier(), "CONFIRM", null);
}

@Test
@@ -266,13 +268,18 @@ public void shouldTransferAccountToAccount() throws Exception {
tellerTransaction.setClerk(AbstractTellerTest.TEST_USER);
tellerTransaction.setAmount(commonAmount);

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

final Account targetAccount = new Account();
targetAccount.setBalance(2000.00D);
targetAccount.setState(Account.State.OPEN.name());
Mockito.doAnswer(invocation -> Optional.of(targetAccount))
.when(super.accountingServiceSpy).findAccount(tellerTransaction.getTargetAccountIdentifier());

Mockito.doAnswer(invocation -> Collections.emptyList())
.when(super.depositAccountManagementServiceSpy).getCharges(Matchers.eq(tellerTransaction));
Mockito.doAnswer(invocation -> Collections.emptyList())
@@ -379,7 +386,9 @@ public void shouldNotWithdrawLackingBalance() throws Exception {
Mockito.doAnswer(invocation -> Collections.emptyList())
.when(super.depositAccountManagementServiceSpy).fetchProductInstances(tellerTransaction.getCustomerIdentifier());

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

super.testSubject.confirm(teller.getCode(), tellerTransactionCosts.getTellerTransactionIdentifier(), "CONFIRM", null);
}

@Test(expected = TransactionProcessingException.class)
@@ -609,6 +618,14 @@ public void shouldProcessCheque() throws Exception {
micr.setBranchSortCode("08154711");
micr.setAccountNumber("4711");

Mockito
.doAnswer(invocation -> {
final Account mockedAccount = new Account();
mockedAccount.setState(Account.State.OPEN.name());
return Optional.of(mockedAccount);
})
.when(super.accountingServiceSpy).findAccount(Matchers.eq(micr.getAccountNumber()));

final Cheque cheque = new Cheque();
cheque.setMicr(micr);
cheque.setDrawee("whatever Bank");
@@ -665,6 +682,14 @@ public void shouldNotProcessChequeAlreadyUsed() throws Exception {
micr.setBranchSortCode("08154711");
micr.setAccountNumber("4711");

Mockito
.doAnswer(invocation -> {
final Account mockedAccount = new Account();
mockedAccount.setState(Account.State.OPEN.name());
return Optional.of(mockedAccount);
})
.when(super.accountingServiceSpy).findAccount(Matchers.eq(micr.getAccountNumber()));

final Cheque cheque = new Cheque();
cheque.setMicr(micr);
cheque.setDrawee("whatever Bank");
@@ -114,4 +114,14 @@ public void confirmTransaction(@Header(TenantHeaderFilter.TENANT_HEADER) final S
this.logger.debug("Teller {} created.", payload);
this.eventRecorder.event(tenant, EventConstants.CONFIRM_TRANSACTION, payload, String.class);
}
}

@JmsListener(
destination = EventConstants.DESTINATION,
selector = EventConstants.SELECTOR_DELETE_TELLER,
subscription = EventConstants.DESTINATION
)
public void onDeleteTeller(@Header(TenantHeaderFilter.TENANT_HEADER) final String tenant,
final String payload) {
this.logger.debug("Teller {} created.", payload);
this.eventRecorder.event(tenant, EventConstants.DELETE_TELLER, payload, String.class);
}}
@@ -0,0 +1,29 @@
/*
* 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.command;

public class DeleteTellerCommand {
private final String tellerCode;

public DeleteTellerCommand(final String tellerCode) {
super();
this.tellerCode = tellerCode;
}

public String tellerCode() {
return this.tellerCode;
}
}
@@ -33,6 +33,7 @@
import io.mifos.teller.service.internal.command.ChangeTellerCommand;
import io.mifos.teller.service.internal.command.CloseTellerCommand;
import io.mifos.teller.service.internal.command.CreateTellerCommand;
import io.mifos.teller.service.internal.command.DeleteTellerCommand;
import io.mifos.teller.service.internal.command.DrawerUnlockCommand;
import io.mifos.teller.service.internal.command.OpenTellerCommand;
import io.mifos.teller.service.internal.command.PauseTellerCommand;
@@ -165,6 +166,8 @@ public String process(final OpenTellerCommand openTellerCommand) {
tellerEntity.setState(Teller.State.OPEN.name());
tellerEntity.setLastModifiedBy(UserContextHolder.checkedGetUser());
tellerEntity.setLastModifiedOn(LocalDateTime.now(Clock.systemUTC()));
tellerEntity.setLastOpenedBy(tellerEntity.getLastModifiedBy());
tellerEntity.setLastOpenedOn(tellerEntity.getLastModifiedOn());

this.tellerRepository.save(tellerEntity);
return tellerCode;
@@ -271,6 +274,27 @@ public String process(final PauseTellerCommand pauseTellerCommand) {
return null;
}

@Transactional
@CommandHandler
@EventEmitter(selectorName = EventConstants.SELECTOR_NAME, selectorValue = EventConstants.DELETE_TELLER)
public String process(final DeleteTellerCommand deleteTellerCommand) {
final String tellerCode = deleteTellerCommand.tellerCode();

final Optional<TellerEntity> optionalTeller = this.tellerRepository.findByIdentifier(tellerCode);
if (optionalTeller.isPresent()) {
final TellerEntity tellerEntity = optionalTeller.get();
if (tellerEntity.getLastOpenedBy() == null) {
this.tellerRepository.delete(tellerEntity);
return tellerCode;
} else {
this.logger.warn("Could not close teller {}, already used.", tellerCode);
}
} else {
this.logger.warn("Teller {} not found.", tellerCode);
}
return null;
}

private boolean checkPreconditions(final String officeIdentifier, final Teller teller) {
boolean pass = true;

@@ -42,6 +42,10 @@ public static Teller map(final TellerEntity tellerEntity) {
teller.setLastModifiedBy(tellerEntity.getLastModifiedBy());
teller.setLastModifiedOn(DateConverter.toIsoString(tellerEntity.getLastModifiedOn()));
}
if (tellerEntity.getLastOpenedBy() != null) {
teller.setLastOpenedBy(tellerEntity.getLastOpenedBy());
teller.setLastOpenedOn(DateConverter.toIsoString(tellerEntity.getLastOpenedOn()));
}

return teller;
}
@@ -67,6 +71,11 @@ public static TellerEntity map(final String officeIdentifier, final Teller telle
tellerEntity.setLastModifiedBy(teller.getLastModifiedBy());
tellerEntity.setLastModifiedOn(DateConverter.fromIsoString(teller.getLastModifiedOn()));
}
if (teller.getLastOpenedBy() != null) {
tellerEntity.setLastOpenedBy(teller.getLastOpenedBy());
tellerEntity.setLastOpenedOn(DateConverter.fromIsoString(teller.getLastOpenedOn()));
}

return tellerEntity;
}
}
@@ -167,13 +167,24 @@ public void processCashWithdrawal(final String tellerCode, final TellerTransacti
}

final JournalEntry journalEntry = this.prepareJournalEntry(tellerTransaction);

final HashSet<Debtor> debtors = new HashSet<>();
journalEntry.setDebtors(debtors);

final Debtor customerDebtor = new Debtor();
customerDebtor.setAccountNumber(tellerTransaction.getCustomerAccountIdentifier());
customerDebtor.setAmount(tellerTransaction.getAmount().toString());
debtors.add(customerDebtor);
final HashSet<Creditor> creditors = new HashSet<>();
journalEntry.setCreditors(creditors);

if (tellerTransaction.getAmount().compareTo(BigDecimal.ZERO) > 0) {
final Debtor customerDebtor = new Debtor();
customerDebtor.setAccountNumber(tellerTransaction.getCustomerAccountIdentifier());
customerDebtor.setAmount(tellerTransaction.getAmount().toString());
debtors.add(customerDebtor);

final Creditor tellerCreditor = new Creditor();
tellerCreditor.setAccountNumber(tellerEntity.getTellerAccountIdentifier());
tellerCreditor.setAmount(tellerTransaction.getAmount().toString());
creditors.add(tellerCreditor);
}

if (!tellerTransactionCosts.getCharges().isEmpty()) {
if (chargesIncluded) {
@@ -183,14 +194,6 @@ public void processCashWithdrawal(final String tellerCode, final TellerTransacti
}
}

final HashSet<Creditor> creditors = new HashSet<>();
journalEntry.setCreditors(creditors);

final Creditor tellerCreditor = new Creditor();
tellerCreditor.setAccountNumber(tellerEntity.getTellerAccountIdentifier());
tellerCreditor.setAmount(tellerTransaction.getAmount().toString());
creditors.add(tellerCreditor);

creditors.addAll(this.createChargeCreditors(tellerTransactionCosts));

this.accountingService.postJournalEntry(journalEntry);

0 comments on commit fd0d1bf

Please sign in to comment.