You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@fineract.apache.org by aw...@apache.org on 2019/06/03 19:02:53 UTC
[fineract-cn-payroll] 18/50: added validation for accounts and
customers
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 d04212776bf9840307dc04c170312ceb2eb738ae
Author: mgeiss <mg...@mifos.org>
AuthorDate: Wed Sep 20 10:47:12 2017 +0200
added validation for accounts and customers
---
.../api/v1/domain/PayrollCollectionSheet.java | 4 +--
.../payroll/api/v1/domain/PayrollPayment.java | 18 +++++++++++++
.../io/mifos/payroll/TestPayrollDistribution.java | 12 +++++++++
.../handler/PayrollConfigurationAggregate.java | 1 -
.../handler/PayrollDistributionAggregate.java | 25 ++++++++++-------
.../internal/mapper/PayrollPaymentMapper.java | 2 ++
.../internal/repository/PayrollPaymentEntity.java | 20 ++++++++++++++
.../service/adaptor/AccountingAdaptor.java | 31 ++++++++++++++++------
.../internal/service/adaptor/CustomerAdaptor.java | 7 +++--
.../rest/PayrollConfigurationRestController.java | 26 +++++++++++-------
.../rest/PayrollDistributionRestController.java | 13 +++------
.../V2__add_distribution_processing_behavior.sql | 18 +++++++++++++
12 files changed, 137 insertions(+), 40 deletions(-)
diff --git a/api/src/main/java/io/mifos/payroll/api/v1/domain/PayrollCollectionSheet.java b/api/src/main/java/io/mifos/payroll/api/v1/domain/PayrollCollectionSheet.java
index 99f2f78..043ca02 100644
--- a/api/src/main/java/io/mifos/payroll/api/v1/domain/PayrollCollectionSheet.java
+++ b/api/src/main/java/io/mifos/payroll/api/v1/domain/PayrollCollectionSheet.java
@@ -16,16 +16,16 @@
package io.mifos.payroll.api.v1.domain;
import io.mifos.core.lang.validation.constraints.ValidIdentifier;
+import org.hibernate.validator.constraints.NotEmpty;
import javax.validation.Valid;
-import javax.validation.constraints.NotNull;
import java.util.List;
public class PayrollCollectionSheet {
@ValidIdentifier(maxLength = 34)
private String sourceAccountNumber;
- @NotNull
+ @NotEmpty
@Valid
private List<PayrollPayment> payrollPayments;
diff --git a/api/src/main/java/io/mifos/payroll/api/v1/domain/PayrollPayment.java b/api/src/main/java/io/mifos/payroll/api/v1/domain/PayrollPayment.java
index 50daa4b..dbee945 100644
--- a/api/src/main/java/io/mifos/payroll/api/v1/domain/PayrollPayment.java
+++ b/api/src/main/java/io/mifos/payroll/api/v1/domain/PayrollPayment.java
@@ -32,6 +32,8 @@ public class PayrollPayment {
@DecimalMin("0.001")
@DecimalMax("9999999999.99999")
private BigDecimal salary;
+ private Boolean processed;
+ private String message;
public PayrollPayment() {
super();
@@ -60,4 +62,20 @@ public class PayrollPayment {
public void setSalary(final BigDecimal salary) {
this.salary = salary;
}
+
+ public Boolean getProcessed() {
+ return this.processed;
+ }
+
+ public void setProcessed(final Boolean processed) {
+ this.processed = processed;
+ }
+
+ public String getMessage() {
+ return this.message;
+ }
+
+ public void setMessage(final String message) {
+ this.message = message;
+ }
}
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 0bcae44..661b586 100644
--- a/component-test/src/main/java/io/mifos/payroll/TestPayrollDistribution.java
+++ b/component-test/src/main/java/io/mifos/payroll/TestPayrollDistribution.java
@@ -25,6 +25,7 @@ import io.mifos.payroll.api.v1.domain.PayrollConfiguration;
import io.mifos.payroll.api.v1.domain.PayrollPayment;
import io.mifos.payroll.api.v1.domain.PayrollPaymentPage;
import io.mifos.payroll.domain.DomainObjectGenerator;
+import io.mifos.payroll.service.internal.repository.PayrollCollectionEntity;
import io.mifos.payroll.service.internal.service.adaptor.AccountingAdaptor;
import io.mifos.payroll.service.internal.service.adaptor.CustomerAdaptor;
import org.apache.commons.lang3.RandomStringUtils;
@@ -70,6 +71,14 @@ public class TestPayrollDistribution extends AbstractPayrollTest {
.doAnswer(invocation -> Optional.of(new Account()))
.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);
Assert.assertTrue(super.eventRecorder.wait(EventConstants.POST_DISTRIBUTION, payrollCollectionSheet.getSourceAccountNumber()));
@@ -80,6 +89,9 @@ public class TestPayrollDistribution extends AbstractPayrollTest {
final PayrollPaymentPage payrollPaymentPage =
super.testSubject.fetchPayments(payrollCollectionHistory.getIdentifier(), 0, 10, null, null);
Assert.assertEquals(Long.valueOf(1L), payrollPaymentPage.getTotalElements());
+
+ final PayrollPayment fetchedPayrollPayment = payrollPaymentPage.getPayrollPayments().get(0);
+ Assert.assertTrue(fetchedPayrollPayment.getProcessed());
}
private void prepareMocks(final String customerIdentifier, final PayrollConfiguration payrollConfiguration) {
diff --git a/service/src/main/java/io/mifos/payroll/service/internal/command/handler/PayrollConfigurationAggregate.java b/service/src/main/java/io/mifos/payroll/service/internal/command/handler/PayrollConfigurationAggregate.java
index 43e954d..b5383bd 100644
--- a/service/src/main/java/io/mifos/payroll/service/internal/command/handler/PayrollConfigurationAggregate.java
+++ b/service/src/main/java/io/mifos/payroll/service/internal/command/handler/PayrollConfigurationAggregate.java
@@ -72,7 +72,6 @@ public class PayrollConfigurationAggregate {
if (optionalPayrollConfiguration.isPresent()) {
payrollConfigurationEntity = optionalPayrollConfiguration.get();
this.payrollAllocationRepository.deleteByPayrollConfiguration(payrollConfigurationEntity);
-
this.payrollAllocationRepository.flush();
payrollConfigurationEntity.setLastModifiedBy(UserContextHolder.checkedGetUser());
diff --git a/service/src/main/java/io/mifos/payroll/service/internal/command/handler/PayrollDistributionAggregate.java b/service/src/main/java/io/mifos/payroll/service/internal/command/handler/PayrollDistributionAggregate.java
index 86f4aae..93f9596 100644
--- a/service/src/main/java/io/mifos/payroll/service/internal/command/handler/PayrollDistributionAggregate.java
+++ b/service/src/main/java/io/mifos/payroll/service/internal/command/handler/PayrollDistributionAggregate.java
@@ -37,6 +37,7 @@ import org.springframework.transaction.annotation.Transactional;
import java.time.Clock;
import java.time.LocalDateTime;
+import java.util.Optional;
@Aggregate
public class PayrollDistributionAggregate {
@@ -79,16 +80,22 @@ public class PayrollDistributionAggregate {
this.payrollConfigurationService
.findPayrollConfiguration(payrollPayment.getCustomerIdentifier())
.ifPresent(payrollConfiguration -> {
- final PayrollPaymentEntity payrollPaymentEntity = new PayrollPaymentEntity();
- payrollPaymentEntity.setPayrollCollection(savedPayrollCollectionEntity);
- payrollPaymentEntity.setCustomerIdentifier(payrollPayment.getCustomerIdentifier());
- payrollPaymentEntity.setEmployer(payrollPayment.getEmployer());
- payrollPaymentEntity.setSalary(payrollPayment.getSalary());
+ final PayrollPaymentEntity payrollPaymentEntity = new PayrollPaymentEntity();
+ payrollPaymentEntity.setPayrollCollection(savedPayrollCollectionEntity);
+ payrollPaymentEntity.setCustomerIdentifier(payrollPayment.getCustomerIdentifier());
+ payrollPaymentEntity.setEmployer(payrollPayment.getEmployer());
+ payrollPaymentEntity.setSalary(payrollPayment.getSalary());
- this.payrollPaymentRepository.save(payrollPaymentEntity);
-
- this.accountingAdaptor.postPayrollPayment(savedPayrollCollectionEntity, payrollPayment, payrollConfiguration);
- })
+ final Optional<String> optionalErrorMessage =
+ this.accountingAdaptor.postPayrollPayment(savedPayrollCollectionEntity, payrollPayment, payrollConfiguration);
+ if (optionalErrorMessage.isPresent()) {
+ payrollPaymentEntity.setMessage(optionalErrorMessage.get());
+ payrollPaymentEntity.setProcessed(Boolean.FALSE);
+ } else {
+ payrollPaymentEntity.setProcessed(Boolean.TRUE);
+ }
+ this.payrollPaymentRepository.save(payrollPaymentEntity);
+ })
);
return payrollCollectionSheet.getSourceAccountNumber();
diff --git a/service/src/main/java/io/mifos/payroll/service/internal/mapper/PayrollPaymentMapper.java b/service/src/main/java/io/mifos/payroll/service/internal/mapper/PayrollPaymentMapper.java
index fd7538a..738d8ed 100644
--- a/service/src/main/java/io/mifos/payroll/service/internal/mapper/PayrollPaymentMapper.java
+++ b/service/src/main/java/io/mifos/payroll/service/internal/mapper/PayrollPaymentMapper.java
@@ -29,6 +29,8 @@ public class PayrollPaymentMapper {
payrollPayment.setCustomerIdentifier(payrollPaymentEntity.getCustomerIdentifier());
payrollPayment.setEmployer(payrollPaymentEntity.getEmployer());
payrollPayment.setSalary(payrollPaymentEntity.getSalary());
+ payrollPayment.setProcessed(payrollPaymentEntity.getProcessed());
+ payrollPayment.setMessage(payrollPaymentEntity.getMessage());
return payrollPayment;
}
}
diff --git a/service/src/main/java/io/mifos/payroll/service/internal/repository/PayrollPaymentEntity.java b/service/src/main/java/io/mifos/payroll/service/internal/repository/PayrollPaymentEntity.java
index 3b782ed..c04dc8d 100644
--- a/service/src/main/java/io/mifos/payroll/service/internal/repository/PayrollPaymentEntity.java
+++ b/service/src/main/java/io/mifos/payroll/service/internal/repository/PayrollPaymentEntity.java
@@ -42,6 +42,10 @@ public class PayrollPaymentEntity {
private String employer;
@Column(name = "salary", nullable = false, precision = 15, scale = 5)
private BigDecimal salary;
+ @Column(name = "processed", nullable = false)
+ private Boolean processed;
+ @Column(name = "message", nullable = true)
+ private String message;
public PayrollPaymentEntity() {
super();
@@ -86,4 +90,20 @@ public class PayrollPaymentEntity {
public void setSalary(final BigDecimal salary) {
this.salary = salary;
}
+
+ public Boolean getProcessed() {
+ return this.processed;
+ }
+
+ public void setProcessed(final Boolean processed) {
+ this.processed = processed;
+ }
+
+ public String getMessage() {
+ return this.message;
+ }
+
+ public void setMessage(final String message) {
+ this.message = message;
+ }
}
diff --git a/service/src/main/java/io/mifos/payroll/service/internal/service/adaptor/AccountingAdaptor.java b/service/src/main/java/io/mifos/payroll/service/internal/service/adaptor/AccountingAdaptor.java
index 41f19df..14aa326 100644
--- a/service/src/main/java/io/mifos/payroll/service/internal/service/adaptor/AccountingAdaptor.java
+++ b/service/src/main/java/io/mifos/payroll/service/internal/service/adaptor/AccountingAdaptor.java
@@ -57,14 +57,17 @@ public class AccountingAdaptor {
public Optional<Account> findAccount(final String accountIdentifier) {
try {
- return Optional.of(this.ledgerManager.findAccount(accountIdentifier));
+ final Account account = this.ledgerManager.findAccount(accountIdentifier);
+ if (account.getState().equals(Account.State.OPEN.name())) {
+ return Optional.of(account);
+ }
} catch (final AccountNotFoundException anfex) {
this.logger.warn("Account {} not found.", accountIdentifier);
- return Optional.empty();
}
+ return Optional.empty();
}
- public void postPayrollPayment(final PayrollCollectionEntity payrollCollectionEntity,
+ public Optional<String> postPayrollPayment(final PayrollCollectionEntity payrollCollectionEntity,
final PayrollPayment payrollPayment,
final PayrollConfiguration payrollConfiguration) {
@@ -102,11 +105,23 @@ public class AccountingAdaptor {
final BigDecimal currentCreditorSum =
BigDecimal.valueOf(creditors.stream().mapToDouble(value -> Double.valueOf(value.getAmount())).sum());
- final Creditor mainCreditor = new Creditor();
- mainCreditor.setAccountNumber(payrollConfiguration.getMainAccountNumber());
- mainCreditor.setAmount(payrollPayment.getSalary().subtract(currentCreditorSum).toString());
- creditors.add(mainCreditor);
+ final int comparedValue = currentCreditorSum.compareTo(payrollPayment.getSalary());
+ if (comparedValue > 0) {
+ return Optional.of("Allocated amount would exceed posted salary.");
+ }
+ if (comparedValue < 0) {
+ final Creditor mainCreditor = new Creditor();
+ mainCreditor.setAccountNumber(payrollConfiguration.getMainAccountNumber());
+ mainCreditor.setAmount(payrollPayment.getSalary().subtract(currentCreditorSum).toString());
+ creditors.add(mainCreditor);
+ }
- this.ledgerManager.createJournalEntry(journalEntry);
+ try {
+ this.ledgerManager.createJournalEntry(journalEntry);
+ return Optional.empty();
+ } catch (final Throwable th) {
+ this.logger.warn("Could not process journal entry for customer {}.", payrollPayment.getCustomerIdentifier(), th);
+ return Optional.of("Error while processing journal entry.");
+ }
}
}
diff --git a/service/src/main/java/io/mifos/payroll/service/internal/service/adaptor/CustomerAdaptor.java b/service/src/main/java/io/mifos/payroll/service/internal/service/adaptor/CustomerAdaptor.java
index 9fd9d0c..dde236f 100644
--- a/service/src/main/java/io/mifos/payroll/service/internal/service/adaptor/CustomerAdaptor.java
+++ b/service/src/main/java/io/mifos/payroll/service/internal/service/adaptor/CustomerAdaptor.java
@@ -42,10 +42,13 @@ public class CustomerAdaptor {
public Optional<Customer> findCustomer(final String customerIdentifier) {
try {
- return Optional.of(this.customerManager.findCustomer(customerIdentifier));
+ final Customer customer = this.customerManager.findCustomer(customerIdentifier);
+ if (customer.getCurrentState().equals(Customer.State.ACTIVE.name())) {
+ return Optional.of(customer);
+ }
} catch (final CustomerNotFoundException cnfex) {
this.logger.warn("Customer {} not found.", customerIdentifier);
- return Optional.empty();
}
+ return Optional.empty();
}
}
diff --git a/service/src/main/java/io/mifos/payroll/service/rest/PayrollConfigurationRestController.java b/service/src/main/java/io/mifos/payroll/service/rest/PayrollConfigurationRestController.java
index 100319d..70e3221 100644
--- a/service/src/main/java/io/mifos/payroll/service/rest/PayrollConfigurationRestController.java
+++ b/service/src/main/java/io/mifos/payroll/service/rest/PayrollConfigurationRestController.java
@@ -21,6 +21,7 @@ import io.mifos.anubis.annotation.Permittables;
import io.mifos.core.command.gateway.CommandGateway;
import io.mifos.core.lang.ServiceException;
import io.mifos.payroll.api.v1.PermittableGroupIds;
+import io.mifos.payroll.api.v1.domain.PayrollAllocation;
import io.mifos.payroll.api.v1.domain.PayrollConfiguration;
import io.mifos.payroll.service.ServiceConstants;
import io.mifos.payroll.service.internal.command.PutPayrollConfigurationCommand;
@@ -38,6 +39,7 @@ import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.bind.annotation.RestController;
import javax.validation.Valid;
+import java.util.Set;
@RestController
@RequestMapping("/customers/{identifier}/payroll")
@@ -73,19 +75,25 @@ public class PayrollConfigurationRestController {
public ResponseEntity<Void> setPayrollConfiguration(@PathVariable(value = "identifier") final String customerIdentifier,
@RequestBody @Valid final PayrollConfiguration payrollConfiguration) {
this.payrollConfigurationService.findCustomer(customerIdentifier)
- .orElseThrow(() -> ServiceException.notFound("Customer {0} not found.", customerIdentifier)
+ .orElseThrow(() -> ServiceException.notFound("Customer {0} not available.", customerIdentifier)
);
this.payrollConfigurationService.findAccount(payrollConfiguration.getMainAccountNumber())
- .orElseThrow(() -> ServiceException.notFound("Main account {0} not found.", payrollConfiguration.getMainAccountNumber()));
+ .orElseThrow(() -> ServiceException.notFound("Main account {0} not available.", payrollConfiguration.getMainAccountNumber()));
- if (payrollConfiguration.getPayrollAllocations() != null
- && payrollConfiguration.getPayrollAllocations()
- .stream()
- .filter(payrollAllocation ->
- !this.payrollConfigurationService.findAccount(payrollAllocation.getAccountNumber()).isPresent()
- ).count() > 0L) {
- throw ServiceException.notFound("Certain allocated accounts not found.");
+ if (payrollConfiguration.getPayrollAllocations() != null) {
+
+ final Set<PayrollAllocation> payrollAllocations = payrollConfiguration.getPayrollAllocations();
+
+ if (payrollAllocations.stream().anyMatch(payrollAllocation ->
+ payrollAllocation.getAccountNumber().equals(payrollConfiguration.getMainAccountNumber()))) {
+ throw ServiceException.conflict("Main account should not be used in allocations.");
+ }
+
+ if (payrollAllocations.stream().anyMatch(payrollAllocation ->
+ !this.payrollConfigurationService.findAccount(payrollAllocation.getAccountNumber()).isPresent())) {
+ throw ServiceException.notFound("Certain allocated accounts not available.");
+ }
}
this.commandGateway.process(new PutPayrollConfigurationCommand(customerIdentifier, payrollConfiguration));
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 86d3203..7a2a8ea 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
@@ -82,17 +82,12 @@ public class PayrollDistributionRestController {
public ResponseEntity<Void> distribute(@RequestBody @Valid final PayrollCollectionSheet payrollCollectionSheet) {
this.payrollConfigurationService.findAccount(payrollCollectionSheet.getSourceAccountNumber())
- .orElseThrow(() -> ServiceException.notFound("Account {0} not found.", payrollCollectionSheet.getSourceAccountNumber()));
+ .orElseThrow(() -> ServiceException.notFound("Account {0} not available.", payrollCollectionSheet.getSourceAccountNumber()));
if (payrollCollectionSheet.getPayrollPayments()
- .stream()
- .filter(
- payrollPayment -> !this.payrollConfigurationService
- .findPayrollConfiguration(payrollPayment.getCustomerIdentifier())
- .isPresent()
- )
- .count() > 0L) {
- throw ServiceException.conflict("Missing payroll configuration for certain customers.");
+ .stream().anyMatch(payrollPayment ->
+ !this.payrollConfigurationService.findPayrollConfiguration(payrollPayment.getCustomerIdentifier()).isPresent())) {
+ throw ServiceException.conflict("Payroll configuration for certain customers not available.");
}
this.commandGateway.process(new DistributePayrollCommand(payrollCollectionSheet));
diff --git a/service/src/main/resources/db/migrations/mariadb/V2__add_distribution_processing_behavior.sql b/service/src/main/resources/db/migrations/mariadb/V2__add_distribution_processing_behavior.sql
new file mode 100644
index 0000000..c7d1ab3
--- /dev/null
+++ b/service/src/main/resources/db/migrations/mariadb/V2__add_distribution_processing_behavior.sql
@@ -0,0 +1,18 @@
+--
+-- 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.
+--
+
+ALTER TABLE meketre_payroll_payments ADD processed BOOLEAN NOT NULL;
+ALTER TABLE meketre_payroll_payments ADD message VARCHAR(256) NULL;
\ No newline at end of file