This is an automated email from the ASF dual-hosted git repository. awasum pushed a commit to branch develop in repository https://gitbox.apache.org/repos/asf/fineract-cn-payroll.git
commit 23bd6e3446df127f93d248987ec864eff7215c94 Author: mgeiss <[email protected]> AuthorDate: Fri Oct 6 16:22:07 2017 +0200 added account validation before initializing payroll transaction --- .../payroll/api/v1/client/PayrollManager.java | 3 +- .../io/mifos/payroll/TestPayrollDistribution.java | 111 ++++++++++++++++++--- .../rest/PayrollDistributionRestController.java | 35 +++++-- 3 files changed, 128 insertions(+), 21 deletions(-) diff --git a/api/src/main/java/io/mifos/payroll/api/v1/client/PayrollManager.java b/api/src/main/java/io/mifos/payroll/api/v1/client/PayrollManager.java index 5c232c0..d9235cf 100644 --- a/api/src/main/java/io/mifos/payroll/api/v1/client/PayrollManager.java +++ b/api/src/main/java/io/mifos/payroll/api/v1/client/PayrollManager.java @@ -69,7 +69,8 @@ public interface PayrollManager { consumes = MediaType.APPLICATION_JSON_VALUE ) @ThrowsExceptions({ - @ThrowsException(status = HttpStatus.BAD_REQUEST, exception = PayrollPaymentValidationException.class) + @ThrowsException(status = HttpStatus.BAD_REQUEST, exception = PayrollPaymentValidationException.class), + @ThrowsException(status = HttpStatus.CONFLICT, exception = PayrollPaymentValidationException.class) }) void distribute(@RequestBody @Valid final PayrollCollectionSheet payrollCollectionSheet); diff --git a/component-test/src/main/java/io/mifos/payroll/TestPayrollDistribution.java b/component-test/src/main/java/io/mifos/payroll/TestPayrollDistribution.java index 661b586..cca752c 100644 --- a/component-test/src/main/java/io/mifos/payroll/TestPayrollDistribution.java +++ b/component-test/src/main/java/io/mifos/payroll/TestPayrollDistribution.java @@ -19,6 +19,8 @@ import com.google.common.collect.Lists; import io.mifos.accounting.api.v1.domain.Account; import io.mifos.customer.api.v1.domain.Customer; import io.mifos.payroll.api.v1.EventConstants; +import io.mifos.payroll.api.v1.client.PayrollPaymentValidationException; +import io.mifos.payroll.api.v1.domain.PayrollAllocation; import io.mifos.payroll.api.v1.domain.PayrollCollectionHistory; import io.mifos.payroll.api.v1.domain.PayrollCollectionSheet; import io.mifos.payroll.api.v1.domain.PayrollConfiguration; @@ -67,17 +69,19 @@ public class TestPayrollDistribution extends AbstractPayrollTest { payrollPayment.setSalary(BigDecimal.valueOf(1234.56D)); payrollCollectionSheet.setPayrollPayments(Lists.newArrayList(payrollPayment)); + final Account sourceAccount = new Account(); + sourceAccount.setState(Account.State.OPEN.name()); Mockito - .doAnswer(invocation -> Optional.of(new Account())) + .doAnswer(invocation -> Optional.of(sourceAccount)) .when(this.accountingAdaptorSpy).findAccount(Matchers.eq(payrollCollectionSheet.getSourceAccountNumber())); Mockito .doAnswer(invocation -> Optional.empty()) .when(this.accountingAdaptorSpy).postPayrollPayment( - Matchers.any(PayrollCollectionEntity.class), - Matchers.refEq(payrollPayment), - Matchers.any(PayrollConfiguration.class) - ); + Matchers.any(PayrollCollectionEntity.class), + Matchers.refEq(payrollPayment), + Matchers.any(PayrollConfiguration.class) + ); super.testSubject.distribute(payrollCollectionSheet); Assert.assertTrue(super.eventRecorder.wait(EventConstants.POST_DISTRIBUTION, payrollCollectionSheet.getSourceAccountNumber())); @@ -94,20 +98,103 @@ public class TestPayrollDistribution extends AbstractPayrollTest { Assert.assertTrue(fetchedPayrollPayment.getProcessed()); } + @Test(expected = PayrollPaymentValidationException.class) + public void shouldNotDistributePaymentsAllocatedAccountClosed() throws Exception { + final String customerIdentifier = RandomStringUtils.randomAlphanumeric(32); + final PayrollConfiguration payrollConfiguration = DomainObjectGenerator.getPayrollConfiguration(); + this.prepareMocks(customerIdentifier, payrollConfiguration); + + final PayrollAllocation invalidPayrollAllocation = new PayrollAllocation(); + invalidPayrollAllocation.setAccountNumber(RandomStringUtils.randomAlphanumeric(34)); + invalidPayrollAllocation.setProportional(Boolean.FALSE); + invalidPayrollAllocation.setAmount(BigDecimal.valueOf(200.00D)); + payrollConfiguration.getPayrollAllocations().add(invalidPayrollAllocation); + + final Account invalidPayrollAccount = new Account(); + invalidPayrollAccount.setState(Account.State.CLOSED.name()); + Mockito + .doAnswer(invocation -> Optional.of(invalidPayrollAccount)) + .when(this.accountingAdaptorSpy).findAccount(Matchers.eq(invalidPayrollAllocation.getAccountNumber())); + + super.testSubject.setPayrollConfiguration(customerIdentifier, payrollConfiguration); + Assert.assertTrue(super.eventRecorder.wait(EventConstants.PUT_CONFIGURATION, customerIdentifier)); + + final PayrollCollectionSheet payrollCollectionSheet = new PayrollCollectionSheet(); + payrollCollectionSheet.setSourceAccountNumber(RandomStringUtils.randomAlphanumeric(34)); + final PayrollPayment payrollPayment = new PayrollPayment(); + payrollPayment.setCustomerIdentifier(customerIdentifier); + payrollPayment.setEmployer("ACME, Inc."); + payrollPayment.setSalary(BigDecimal.valueOf(1234.56D)); + payrollCollectionSheet.setPayrollPayments(Lists.newArrayList(payrollPayment)); + + final Account sourceAccount = new Account(); + sourceAccount.setState(Account.State.OPEN.name()); + Mockito + .doAnswer(invocation -> Optional.of(sourceAccount)) + .when(this.accountingAdaptorSpy).findAccount(Matchers.eq(payrollCollectionSheet.getSourceAccountNumber())); + + Mockito + .doAnswer(invocation -> Optional.empty()) + .when(this.accountingAdaptorSpy).postPayrollPayment( + Matchers.any(PayrollCollectionEntity.class), + Matchers.refEq(payrollPayment), + Matchers.any(PayrollConfiguration.class) + ); + + super.testSubject.distribute(payrollCollectionSheet); + } + + @Test(expected = PayrollPaymentValidationException.class) + public void shouldNotDistributePaymentsSourceAccountClosed() throws Exception { + final String customerIdentifier = RandomStringUtils.randomAlphanumeric(32); + final PayrollConfiguration payrollConfiguration = DomainObjectGenerator.getPayrollConfiguration(); + this.prepareMocks(customerIdentifier, payrollConfiguration); + + super.testSubject.setPayrollConfiguration(customerIdentifier, payrollConfiguration); + Assert.assertTrue(super.eventRecorder.wait(EventConstants.PUT_CONFIGURATION, customerIdentifier)); + + final PayrollCollectionSheet payrollCollectionSheet = new PayrollCollectionSheet(); + payrollCollectionSheet.setSourceAccountNumber(RandomStringUtils.randomAlphanumeric(34)); + final PayrollPayment payrollPayment = new PayrollPayment(); + payrollPayment.setCustomerIdentifier(customerIdentifier); + payrollPayment.setEmployer("ACME, Inc."); + payrollPayment.setSalary(BigDecimal.valueOf(1234.56D)); + payrollCollectionSheet.setPayrollPayments(Lists.newArrayList(payrollPayment)); + + final Account sourceAccount = new Account(); + sourceAccount.setState(Account.State.CLOSED.name()); + Mockito + .doAnswer(invocation -> Optional.of(sourceAccount)) + .when(this.accountingAdaptorSpy).findAccount(Matchers.eq(payrollCollectionSheet.getSourceAccountNumber())); + + Mockito + .doAnswer(invocation -> Optional.empty()) + .when(this.accountingAdaptorSpy).postPayrollPayment( + Matchers.any(PayrollCollectionEntity.class), + Matchers.refEq(payrollPayment), + Matchers.any(PayrollConfiguration.class) + ); + + super.testSubject.distribute(payrollCollectionSheet); + } + private void prepareMocks(final String customerIdentifier, final PayrollConfiguration payrollConfiguration) { Mockito .doAnswer(invocation -> Optional.of(new Customer())) .when(this.customerAdaptorSpy).findCustomer(Matchers.eq(customerIdentifier)); + final Account mainAccount = new Account(); + mainAccount.setState(Account.State.OPEN.name()); Mockito - .doAnswer(invocation -> Optional.of(new Account())) + .doAnswer(invocation -> Optional.of(mainAccount)) .when(this.accountingAdaptorSpy).findAccount(Matchers.eq(payrollConfiguration.getMainAccountNumber())); - payrollConfiguration.getPayrollAllocations().forEach(payrollAllocation -> - Mockito - .doAnswer(invocation -> Optional.of(new Account())) - .when(this.accountingAdaptorSpy).findAccount(Matchers.eq(payrollAllocation.getAccountNumber())) - ); + payrollConfiguration.getPayrollAllocations().forEach(payrollAllocation -> { + final Account allocatedAccount = new Account(); + allocatedAccount.setState(Account.State.OPEN.name()); + Mockito + .doAnswer(invocation -> Optional.of(allocatedAccount)) + .when(this.accountingAdaptorSpy).findAccount(Matchers.eq(payrollAllocation.getAccountNumber())); + }); } - } diff --git a/service/src/main/java/io/mifos/payroll/service/rest/PayrollDistributionRestController.java b/service/src/main/java/io/mifos/payroll/service/rest/PayrollDistributionRestController.java index 7a2a8ea..681c48f 100644 --- a/service/src/main/java/io/mifos/payroll/service/rest/PayrollDistributionRestController.java +++ b/service/src/main/java/io/mifos/payroll/service/rest/PayrollDistributionRestController.java @@ -15,6 +15,7 @@ */ package io.mifos.payroll.service.rest; +import io.mifos.accounting.api.v1.domain.Account; import io.mifos.anubis.annotation.AcceptedTokenType; import io.mifos.anubis.annotation.Permittable; import io.mifos.anubis.annotation.Permittables; @@ -23,11 +24,13 @@ import io.mifos.core.lang.ServiceException; import io.mifos.payroll.api.v1.PermittableGroupIds; import io.mifos.payroll.api.v1.domain.PayrollCollectionHistory; import io.mifos.payroll.api.v1.domain.PayrollCollectionSheet; +import io.mifos.payroll.api.v1.domain.PayrollConfiguration; import io.mifos.payroll.api.v1.domain.PayrollPaymentPage; import io.mifos.payroll.service.ServiceConstants; import io.mifos.payroll.service.internal.command.DistributePayrollCommand; import io.mifos.payroll.service.internal.service.PayrollConfigurationService; import io.mifos.payroll.service.internal.service.PayrollDistributionService; +import io.mifos.payroll.service.internal.service.adaptor.AccountingAdaptor; import io.mifos.payroll.service.rest.util.PageableBuilder; import org.slf4j.Logger; import org.springframework.beans.factory.annotation.Autowired; @@ -53,17 +56,20 @@ public class PayrollDistributionRestController { private final CommandGateway commandGateway; private final PayrollDistributionService payrollDistributionService; private final PayrollConfigurationService payrollConfigurationService; + private final AccountingAdaptor accountingAdaptor; @Autowired public PayrollDistributionRestController(@Qualifier(ServiceConstants.LOGGER_NAME) final Logger logger, final CommandGateway commandGateway, final PayrollDistributionService payrollDistributionService, - final PayrollConfigurationService payrollConfigurationService) { + final PayrollConfigurationService payrollConfigurationService, + final AccountingAdaptor accountingAdaptor) { super(); this.logger = logger; this.commandGateway = commandGateway; this.payrollDistributionService = payrollDistributionService; this.payrollConfigurationService = payrollConfigurationService; + this.accountingAdaptor = accountingAdaptor; } @Permittables({ @@ -81,14 +87,17 @@ public class PayrollDistributionRestController { @ResponseBody public ResponseEntity<Void> distribute(@RequestBody @Valid final PayrollCollectionSheet payrollCollectionSheet) { - this.payrollConfigurationService.findAccount(payrollCollectionSheet.getSourceAccountNumber()) - .orElseThrow(() -> ServiceException.notFound("Account {0} not available.", payrollCollectionSheet.getSourceAccountNumber())); + this.verifyAccount(payrollCollectionSheet.getSourceAccountNumber()); + payrollCollectionSheet.getPayrollPayments() + .forEach(payrollPayment -> { + final PayrollConfiguration payrollConfiguration = + this.payrollConfigurationService.findPayrollConfiguration(payrollPayment.getCustomerIdentifier()) + .orElseThrow(() -> ServiceException.conflict("Payroll configuration for certain customers not available.")); - if (payrollCollectionSheet.getPayrollPayments() - .stream().anyMatch(payrollPayment -> - !this.payrollConfigurationService.findPayrollConfiguration(payrollPayment.getCustomerIdentifier()).isPresent())) { - throw ServiceException.conflict("Payroll configuration for certain customers not available."); - } + this.verifyAccount(payrollConfiguration.getMainAccountNumber()); + payrollConfiguration.getPayrollAllocations() + .forEach(payrollAllocation -> this.verifyAccount(payrollAllocation.getAccountNumber())); + }); this.commandGateway.process(new DistributePayrollCommand(payrollCollectionSheet)); @@ -138,4 +147,14 @@ public class PayrollDistributionRestController { return ResponseEntity.ok(this.payrollDistributionService .fetchPayments(identifier, PageableBuilder.create(pageIndex, size, sortColumn, sortDirection))); } + + private void verifyAccount(final String accountIdentifier) { + final Account account = this.accountingAdaptor.findAccount(accountIdentifier).orElseThrow( + () -> ServiceException.conflict("Account {0} not found.") + ); + + if (!account.getState().equals(Account.State.OPEN.name())) { + throw ServiceException.conflict("Account {0} must be open.", accountIdentifier); + } + } }
