blob: c8d2bc89cd67b4acdf05f00f4091439e55657341 [file] [log] [blame]
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you 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 org.apache.fineract.cn.teller;
import com.google.common.collect.Lists;
import org.apache.commons.lang3.RandomStringUtils;
import org.apache.fineract.cn.accounting.api.v1.domain.Account;
import org.apache.fineract.cn.accounting.api.v1.domain.AccountEntry;
import org.apache.fineract.cn.accounting.api.v1.domain.AccountEntryPage;
import org.apache.fineract.cn.accounting.api.v1.domain.JournalEntry;
import org.apache.fineract.cn.lang.DateRange;
import org.apache.fineract.cn.teller.api.v1.EventConstants;
import org.apache.fineract.cn.teller.api.v1.client.TellerValidationException;
import org.apache.fineract.cn.teller.api.v1.domain.Teller;
import org.apache.fineract.cn.teller.api.v1.domain.TellerDenomination;
import org.apache.fineract.cn.teller.api.v1.domain.TellerManagementCommand;
import org.apache.fineract.cn.teller.api.v1.domain.UnlockDrawerCommand;
import org.apache.fineract.cn.teller.util.TellerGenerator;
import org.junit.Assert;
import org.junit.Test;
import org.mockito.Matchers;
import org.mockito.Mockito;
import java.math.BigDecimal;
import java.time.Clock;
import java.time.LocalDate;
import java.util.List;
import java.util.Optional;
public class TestTellerDenomination extends AbstractTellerTest {
public TestTellerDenomination() {
super();
}
@Test
public void shouldProcessDenomination() throws Exception {
final String officeIdentifier = RandomStringUtils.randomAlphabetic(32);
final BigDecimal openingAmount = BigDecimal.valueOf(20000.00D);
final Teller teller = this.prepareTeller(officeIdentifier, openingAmount);
super.testSubject.post(teller.getCode(), "PAUSE");
Assert.assertTrue(super.eventRecorder.wait(EventConstants.PAUSE_TELLER, teller.getCode()));
final AccountEntry openingAmountEntry = new AccountEntry();
openingAmountEntry.setType(AccountEntry.Type.DEBIT.name());
openingAmountEntry.setMessage(ServiceConstants.TX_REPAYMENT);
openingAmountEntry.setAmount(openingAmount.doubleValue());
final AccountEntryPage accountEntryPage = new AccountEntryPage();
accountEntryPage.setAccountEntries(Lists.newArrayList(openingAmountEntry));
accountEntryPage.setTotalPages(1);
accountEntryPage.setTotalElements(Integer.valueOf(accountEntryPage.getAccountEntries().size()).longValue());
Mockito
.doAnswer(invocation -> accountEntryPage)
.when(super.accountingServiceSpy)
.fetchAccountEntries(Matchers.eq(teller.getTellerAccountIdentifier()), Matchers.anyString(),
Matchers.eq(0), Matchers.anyInt());
final TellerDenomination tellerDenomination = new TellerDenomination();
tellerDenomination.setCountedTotal(openingAmount);
tellerDenomination.setNote("Nothing has happened.");
super.testSubject.saveTellerDenomination(officeIdentifier, teller.getCode(), tellerDenomination);
Assert.assertTrue(super.eventRecorder.wait(EventConstants.SAVE_DENOMINATION, teller.getCode()));
Mockito
.verify(super.accountingServiceSpy, Mockito.atMost(1))
.postJournalEntry(Matchers.any(JournalEntry.class));
final LocalDate now = LocalDate.now(Clock.systemUTC());
final DateRange dateRange = new DateRange(now, now);
final List<TellerDenomination> tellerDenominations =
super.testSubject.fetchTellerDenominations(officeIdentifier, teller.getCode(), dateRange.toString());
Assert.assertEquals(1, tellerDenominations.size());
Assert.assertNull(tellerDenominations.get(0).getAdjustingJournalEntry());
this.closeTeller(officeIdentifier, teller.getCode());
}
@Test
public void shouldProcessDenominationOver() throws Exception {
final String officeIdentifier = RandomStringUtils.randomAlphabetic(32);
final BigDecimal openingAmount = BigDecimal.valueOf(20000.00D);
final Teller teller = this.prepareTeller(officeIdentifier, openingAmount);
super.testSubject.post(teller.getCode(), "PAUSE");
Assert.assertTrue(super.eventRecorder.wait(EventConstants.PAUSE_TELLER, teller.getCode()));
final AccountEntry openingAmountEntry = new AccountEntry();
openingAmountEntry.setType(AccountEntry.Type.DEBIT.name());
openingAmountEntry.setMessage(ServiceConstants.TX_REPAYMENT);
openingAmountEntry.setAmount(openingAmount.doubleValue());
final AccountEntryPage accountEntryPage = new AccountEntryPage();
accountEntryPage.setAccountEntries(Lists.newArrayList(openingAmountEntry));
accountEntryPage.setTotalPages(1);
accountEntryPage.setTotalElements(Integer.valueOf(accountEntryPage.getAccountEntries().size()).longValue());
Mockito
.doAnswer(invocation -> accountEntryPage)
.when(super.accountingServiceSpy)
.fetchAccountEntries(Matchers.eq(teller.getTellerAccountIdentifier()), Matchers.anyString(),
Matchers.eq(0), Matchers.anyInt());
final TellerDenomination tellerDenomination = new TellerDenomination();
tellerDenomination.setCountedTotal(openingAmount.add(BigDecimal.valueOf(1000.00D)));
tellerDenomination.setNote("Teller is over.");
super.testSubject.saveTellerDenomination(officeIdentifier, teller.getCode(), tellerDenomination);
Assert.assertTrue(super.eventRecorder.wait(EventConstants.SAVE_DENOMINATION, teller.getCode()));
Mockito
.verify(super.accountingServiceSpy, Mockito.atMost(2))
.postJournalEntry(Matchers.any(JournalEntry.class));
final LocalDate now = LocalDate.now(Clock.systemUTC());
final DateRange dateRange = new DateRange(now, now);
final List<TellerDenomination> tellerDenominations =
super.testSubject.fetchTellerDenominations(officeIdentifier, teller.getCode(), dateRange.toString());
Assert.assertEquals(1, tellerDenominations.size());
Assert.assertNotNull(tellerDenominations.get(0).getAdjustingJournalEntry());
this.closeTeller(officeIdentifier, teller.getCode());
}
@Test
public void shouldProcessDenominationShort() throws Exception {
final String officeIdentifier = RandomStringUtils.randomAlphabetic(32);
final BigDecimal openingAmount = BigDecimal.valueOf(20000.00D);
final Teller teller = this.prepareTeller(officeIdentifier, openingAmount);
super.testSubject.post(teller.getCode(), "PAUSE");
Assert.assertTrue(super.eventRecorder.wait(EventConstants.PAUSE_TELLER, teller.getCode()));
final AccountEntry openingAmountEntry = new AccountEntry();
openingAmountEntry.setType(AccountEntry.Type.DEBIT.name());
openingAmountEntry.setMessage(ServiceConstants.TX_REPAYMENT);
openingAmountEntry.setAmount(openingAmount.doubleValue());
final AccountEntryPage accountEntryPage = new AccountEntryPage();
accountEntryPage.setAccountEntries(Lists.newArrayList(openingAmountEntry));
accountEntryPage.setTotalPages(1);
accountEntryPage.setTotalElements(Integer.valueOf(accountEntryPage.getAccountEntries().size()).longValue());
Mockito
.doAnswer(invocation -> accountEntryPage)
.when(super.accountingServiceSpy)
.fetchAccountEntries(Matchers.eq(teller.getTellerAccountIdentifier()), Matchers.anyString(),
Matchers.eq(0), Matchers.anyInt());
final TellerDenomination tellerDenomination = new TellerDenomination();
tellerDenomination.setCountedTotal(openingAmount.subtract(BigDecimal.valueOf(1000.00D)));
tellerDenomination.setNote("Teller is short.");
super.testSubject.saveTellerDenomination(officeIdentifier, teller.getCode(), tellerDenomination);
Assert.assertTrue(super.eventRecorder.wait(EventConstants.SAVE_DENOMINATION, teller.getCode()));
Mockito
.verify(super.accountingServiceSpy, Mockito.atMost(2))
.postJournalEntry(Matchers.any(JournalEntry.class));
final LocalDate now = LocalDate.now(Clock.systemUTC());
final DateRange dateRange = new DateRange(now, now);
final List<TellerDenomination> tellerDenominations =
super.testSubject.fetchTellerDenominations(officeIdentifier, teller.getCode(), dateRange.toString());
Assert.assertEquals(1, tellerDenominations.size());
Assert.assertNotNull(tellerDenominations.get(0).getAdjustingJournalEntry());
this.closeTeller(officeIdentifier, teller.getCode());
}
@Test
public void shouldNotProcessDenominationIsActive() throws Exception {
final String officeIdentifier = RandomStringUtils.randomAlphabetic(32);
final BigDecimal openingAmount = BigDecimal.valueOf(20000.00D);
final Teller teller = this.prepareTeller(officeIdentifier, openingAmount);
final TellerDenomination tellerDenomination = new TellerDenomination();
tellerDenomination.setCountedTotal(openingAmount.subtract(BigDecimal.valueOf(1000.00D)));
try {
super.testSubject.saveTellerDenomination(officeIdentifier, teller.getCode(), tellerDenomination);
Assert.fail();
} catch (final TellerValidationException tvex) {
// do nothing ... expected
}
this.closeTeller(officeIdentifier, teller.getCode());
}
private Teller prepareTeller(final String officeIdentifier, BigDecimal openingAmount) throws Exception {
final Teller teller = TellerGenerator.createRandomTeller();
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()));
Mockito.doAnswer(invocation -> Optional.of(new Account()))
.when(super.accountingServiceSpy).findAccount(Matchers.eq(teller.getChequesReceivableAccount()));
Mockito.doAnswer(invocation -> Optional.of(new Account()))
.when(super.accountingServiceSpy).findAccount(Matchers.eq(teller.getCashOverShortAccount()));
super.testSubject.create(officeIdentifier, teller);
Assert.assertTrue(super.eventRecorder.wait(EventConstants.POST_TELLER, teller.getCode()));
final TellerManagementCommand command = new TellerManagementCommand();
command.setAction(TellerManagementCommand.Action.OPEN.name());
command.setAdjustment(TellerManagementCommand.Adjustment.DEBIT.name());
command.setAmount(openingAmount);
command.setAssignedEmployeeIdentifier(AbstractTellerTest.TEST_USER);
Mockito.doAnswer(invocation -> true)
.when(super.organizationServiceSpy).employeeExists(Matchers.eq(command.getAssignedEmployeeIdentifier()));
super.testSubject.post(officeIdentifier, teller.getCode(), command);
Assert.assertTrue(super.eventRecorder.wait(EventConstants.OPEN_TELLER, teller.getCode()));
final UnlockDrawerCommand unlockDrawerCommand = new UnlockDrawerCommand();
unlockDrawerCommand.setEmployeeIdentifier(AbstractTellerTest.TEST_USER);
unlockDrawerCommand.setPassword(teller.getPassword());
super.testSubject.unlockDrawer(teller.getCode(), unlockDrawerCommand);
Assert.assertTrue(super.eventRecorder.wait(EventConstants.AUTHENTICATE_TELLER, teller.getCode()));
return teller;
}
private void closeTeller(final String officeIdentifier, final String tellerCode) throws Exception {
final TellerManagementCommand closeTellerCommand = new TellerManagementCommand();
closeTellerCommand.setAction(TellerManagementCommand.Action.CLOSE.name());
closeTellerCommand.setAmount(BigDecimal.ZERO);
closeTellerCommand.setAdjustment(TellerManagementCommand.Adjustment.NONE.name());
super.testSubject.post(officeIdentifier, tellerCode, closeTellerCommand);
Assert.assertTrue(super.eventRecorder.wait(EventConstants.CLOSE_TELLER, tellerCode));
}
}