This is an automated email from the ASF dual-hosted git repository. myrle pushed a commit to branch develop in repository https://gitbox.apache.org/repos/asf/fineract-cn-customer.git
commit aaa22f2a070e80613be5d69f05c67b0ddfffe14d Author: mgeiss <[email protected]> AuthorDate: Tue Sep 5 13:55:43 2017 +0200 added ability to manage payroll distribution per customer --- .../customer/api/v1/CustomerEventConstants.java | 3 + .../customer/api/v1/client/CustomerManager.java | 42 ++++++- ...=> PayrollDistributionValidationException.java} | 4 +- .../api/v1/client/ScanAlreadyExistsException.java | 2 +- .../api/v1/client/ScanNotFoundException.java | 2 +- .../api/v1/domain/IdentificationCardScan.java | 2 +- .../customer/api/v1/domain/PayrollAllocation.java | 58 ++++++++++ .../api/v1/domain/PayrollDistribution.java | 86 ++++++++++++++ .../io/mifos/customer/api/v1/events/ScanEvent.java | 2 +- .../main/java/io/mifos/customer/TestCustomer.java | 13 ++- .../io/mifos/customer/TestIdentificationCards.java | 2 +- .../io/mifos/customer/TestPayrollDistribution.java | 115 ++++++++++++++++++ .../io/mifos/customer/catalog/TestCatalog.java | 7 +- .../customer/listener/CustomerEventListener.java | 9 ++ .../java/io/mifos/customer/util/ScanGenerator.java | 2 +- .../resources/{logback.xml => logback-test.xml} | 0 .../internal/command/handler/CatalogAggregate.java | 4 +- .../internal/service/FieldValueValidator.java | 2 +- .../rest/controller/CatalogRestController.java | 2 +- .../CreateIdentificationCardScanCommand.java | 2 +- .../DeleteIdentificationCardScanCommand.java | 2 +- .../command/SetPayrollDistributionCommand.java | 38 ++++++ .../command/handler/CustomerAggregate.java | 111 +++++++++++++++++- .../mapper/IdentificationCardScanMapper.java | 2 +- .../internal/mapper/PayrollDistributionMapper.java | 55 +++++++++ .../internal/mapper/TaskInstanceMapper.java | 2 +- .../repository/IdentificationCardScanEntity.java | 15 ++- .../IdentificationCardScanRepository.java | 2 +- .../repository/PayrollAllocationEntity.java | 89 ++++++++++++++ .../repository/PayrollAllocationRepository.java | 9 +- .../repository/PayrollDistributionEntity.java | 128 +++++++++++++++++++++ .../repository/PayrollDistributionRepository.java | 11 +- .../internal/repository/PortraitEntity.java | 11 +- .../service/internal/service/CustomerService.java | 44 ++++++- .../service/internal/service/TaskService.java | 2 +- .../rest/controller/CustomerRestController.java | 75 +++++++++++- .../mariadb/V5__add_payroll_distributions.sql | 39 +++++++ 37 files changed, 948 insertions(+), 46 deletions(-) diff --git a/api/src/main/java/io/mifos/customer/api/v1/CustomerEventConstants.java b/api/src/main/java/io/mifos/customer/api/v1/CustomerEventConstants.java index ab5a9a3..21793b6 100644 --- a/api/src/main/java/io/mifos/customer/api/v1/CustomerEventConstants.java +++ b/api/src/main/java/io/mifos/customer/api/v1/CustomerEventConstants.java @@ -46,6 +46,7 @@ public interface CustomerEventConstants { String POST_PORTRAIT = "post-portrait"; String DELETE_PORTRAIT = "delete-portrait"; + String PUT_PAYROLL_DISTRIBUTION = "put-payroll-distribution"; String SELECTOR_INITIALIZE = SELECTOR_NAME + " = '" + INITIALIZE + "'"; @@ -72,4 +73,6 @@ public interface CustomerEventConstants { String SELECTOR_PUT_PORTRAIT = SELECTOR_NAME + " = '" + POST_PORTRAIT + "'"; String SELECTOR_DELETE_PORTRAIT = SELECTOR_NAME + " = '" + DELETE_PORTRAIT + "'"; + + String SELECTOR_PUT_PAYROLL_DISTRIBUTION = SELECTOR_NAME + " = '" + PUT_PAYROLL_DISTRIBUTION + "'"; } diff --git a/api/src/main/java/io/mifos/customer/api/v1/client/CustomerManager.java b/api/src/main/java/io/mifos/customer/api/v1/client/CustomerManager.java index a906755..67ef6c0 100644 --- a/api/src/main/java/io/mifos/customer/api/v1/client/CustomerManager.java +++ b/api/src/main/java/io/mifos/customer/api/v1/client/CustomerManager.java @@ -19,13 +19,27 @@ import io.mifos.core.api.annotation.ThrowsException; import io.mifos.core.api.annotation.ThrowsExceptions; import io.mifos.core.lang.validation.constraints.ValidIdentifier; import io.mifos.customer.api.v1.config.CustomerFeignClientConfig; -import io.mifos.customer.api.v1.domain.*; +import io.mifos.customer.api.v1.domain.Address; +import io.mifos.customer.api.v1.domain.Command; +import io.mifos.customer.api.v1.domain.ContactDetail; +import io.mifos.customer.api.v1.domain.Customer; +import io.mifos.customer.api.v1.domain.CustomerPage; +import io.mifos.customer.api.v1.domain.IdentificationCard; +import io.mifos.customer.api.v1.domain.IdentificationCardScan; +import io.mifos.customer.api.v1.domain.PayrollDistribution; +import io.mifos.customer.api.v1.domain.ProcessStep; +import io.mifos.customer.api.v1.domain.TaskDefinition; import org.springframework.cloud.netflix.feign.FeignClient; import org.springframework.http.HttpStatus; import org.springframework.http.MediaType; -import org.springframework.web.bind.annotation.*; +import org.springframework.web.bind.annotation.PathVariable; +import org.springframework.web.bind.annotation.RequestBody; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RequestMethod; +import org.springframework.web.bind.annotation.RequestParam; import org.springframework.web.multipart.MultipartFile; +import javax.validation.Valid; import javax.validation.constraints.Size; import java.util.List; @@ -379,4 +393,28 @@ public interface CustomerManager { ) @ThrowsException(status = HttpStatus.NOT_FOUND, exception = CustomerNotFoundException.class) List<ProcessStep> fetchProcessSteps(@PathVariable(value = "identifier") final String customerIdentifier); + + @RequestMapping( + value = "/customer/{identifier}/payroll", + method = RequestMethod.PUT, + produces = MediaType.APPLICATION_JSON_VALUE, + consumes = MediaType.APPLICATION_JSON_VALUE + ) + @ThrowsExceptions({ + @ThrowsException(status = HttpStatus.NOT_FOUND, exception = CustomerNotFoundException.class), + @ThrowsException(status = HttpStatus.BAD_REQUEST, exception = PayrollDistributionValidationException.class) + }) + void setPayrollDistribution(@PathVariable(value = "identifier") final String customerIdentifier, + @RequestBody @Valid final PayrollDistribution payrollDistribution); + + @RequestMapping( + value = "/customer/{identifier}/payroll", + method = RequestMethod.GET, + produces = MediaType.ALL_VALUE, + consumes = MediaType.APPLICATION_JSON_VALUE + ) + @ThrowsExceptions({ + @ThrowsException(status = HttpStatus.NOT_FOUND, exception = CustomerNotFoundException.class) + }) + PayrollDistribution getPayrollDistribution(@PathVariable(value = "identifier") final String customerIdentifier); } diff --git a/api/src/main/java/io/mifos/customer/api/v1/client/ScanAlreadyExistsException.java b/api/src/main/java/io/mifos/customer/api/v1/client/PayrollDistributionValidationException.java similarity index 83% copy from api/src/main/java/io/mifos/customer/api/v1/client/ScanAlreadyExistsException.java copy to api/src/main/java/io/mifos/customer/api/v1/client/PayrollDistributionValidationException.java index 45ef5a1..52caca1 100644 --- a/api/src/main/java/io/mifos/customer/api/v1/client/ScanAlreadyExistsException.java +++ b/api/src/main/java/io/mifos/customer/api/v1/client/PayrollDistributionValidationException.java @@ -1,5 +1,5 @@ /* - * Copyright 2016 The Mifos Initiative. + * 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. @@ -15,5 +15,5 @@ */ package io.mifos.customer.api.v1.client; -public final class ScanAlreadyExistsException extends RuntimeException { +public class PayrollDistributionValidationException extends RuntimeException { } diff --git a/api/src/main/java/io/mifos/customer/api/v1/client/ScanAlreadyExistsException.java b/api/src/main/java/io/mifos/customer/api/v1/client/ScanAlreadyExistsException.java index 45ef5a1..83682b1 100644 --- a/api/src/main/java/io/mifos/customer/api/v1/client/ScanAlreadyExistsException.java +++ b/api/src/main/java/io/mifos/customer/api/v1/client/ScanAlreadyExistsException.java @@ -1,5 +1,5 @@ /* - * Copyright 2016 The Mifos Initiative. + * 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. diff --git a/api/src/main/java/io/mifos/customer/api/v1/client/ScanNotFoundException.java b/api/src/main/java/io/mifos/customer/api/v1/client/ScanNotFoundException.java index 3f2ada1..178fd59 100644 --- a/api/src/main/java/io/mifos/customer/api/v1/client/ScanNotFoundException.java +++ b/api/src/main/java/io/mifos/customer/api/v1/client/ScanNotFoundException.java @@ -1,5 +1,5 @@ /* - * Copyright 2016 The Mifos Initiative. + * 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. diff --git a/api/src/main/java/io/mifos/customer/api/v1/domain/IdentificationCardScan.java b/api/src/main/java/io/mifos/customer/api/v1/domain/IdentificationCardScan.java index 462e4fe..ccbe68c 100644 --- a/api/src/main/java/io/mifos/customer/api/v1/domain/IdentificationCardScan.java +++ b/api/src/main/java/io/mifos/customer/api/v1/domain/IdentificationCardScan.java @@ -1,5 +1,5 @@ /* - * Copyright 2016 The Mifos Initiative. + * 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. diff --git a/api/src/main/java/io/mifos/customer/api/v1/domain/PayrollAllocation.java b/api/src/main/java/io/mifos/customer/api/v1/domain/PayrollAllocation.java new file mode 100644 index 0000000..10d49cd --- /dev/null +++ b/api/src/main/java/io/mifos/customer/api/v1/domain/PayrollAllocation.java @@ -0,0 +1,58 @@ +/* + * 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.customer.api.v1.domain; + +import io.mifos.core.lang.validation.constraints.ValidIdentifier; + +import javax.validation.constraints.DecimalMin; +import java.math.BigDecimal; + +public class PayrollAllocation { + + @ValidIdentifier + private String accountNumber; + @DecimalMin("0.001") + private BigDecimal amount; + private Boolean proportional = Boolean.FALSE; + + public PayrollAllocation() { + super(); + } + + public String getAccountNumber() { + return this.accountNumber; + } + + public void setAccountNumber(final String accountNumber) { + this.accountNumber = accountNumber; + } + + public BigDecimal getAmount() { + return this.amount; + } + + public void setAmount(final BigDecimal amount) { + this.amount = amount; + } + + public Boolean getProportional() { + return this.proportional; + } + + public void setProportional(final Boolean proportional) { + this.proportional = proportional; + } +} diff --git a/api/src/main/java/io/mifos/customer/api/v1/domain/PayrollDistribution.java b/api/src/main/java/io/mifos/customer/api/v1/domain/PayrollDistribution.java new file mode 100644 index 0000000..d905f11 --- /dev/null +++ b/api/src/main/java/io/mifos/customer/api/v1/domain/PayrollDistribution.java @@ -0,0 +1,86 @@ +/* + * 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.customer.api.v1.domain; + +import io.mifos.core.lang.validation.constraints.ValidIdentifier; + +import javax.validation.Valid; +import java.util.HashSet; +import java.util.Set; + +public class PayrollDistribution { + + @ValidIdentifier + private String mainAccountNumber; + @Valid + private Set<PayrollAllocation> payrollAllocations = new HashSet<>(); + private String createdBy; + private String createdOn; + private String lastModifiedBy; + private String lastModifiedOn; + + public PayrollDistribution() { + super(); + } + + public String getMainAccountNumber() { + return this.mainAccountNumber; + } + + public void setMainAccountNumber(final String mainAccountNumber) { + this.mainAccountNumber = mainAccountNumber; + } + + public Set<PayrollAllocation> getPayrollAllocations() { + return this.payrollAllocations; + } + + public void setPayrollAllocations(final Set<PayrollAllocation> payrollAllocations) { + this.payrollAllocations = payrollAllocations; + } + + public String getCreatedBy() { + return this.createdBy; + } + + public void setCreatedBy(final String createdBy) { + this.createdBy = createdBy; + } + + public String getCreatedOn() { + return this.createdOn; + } + + public void setCreatedOn(final String createdOn) { + this.createdOn = createdOn; + } + + public String getLastModifiedBy() { + return this.lastModifiedBy; + } + + public void setLastModifiedBy(final String lastModifiedBy) { + this.lastModifiedBy = lastModifiedBy; + } + + public String getLastModifiedOn() { + return this.lastModifiedOn; + } + + public void setLastModifiedOn(final String lastModifiedOn) { + this.lastModifiedOn = lastModifiedOn; + } +} diff --git a/api/src/main/java/io/mifos/customer/api/v1/events/ScanEvent.java b/api/src/main/java/io/mifos/customer/api/v1/events/ScanEvent.java index f4f8057..9ce809e 100644 --- a/api/src/main/java/io/mifos/customer/api/v1/events/ScanEvent.java +++ b/api/src/main/java/io/mifos/customer/api/v1/events/ScanEvent.java @@ -1,5 +1,5 @@ /* - * Copyright 2016 The Mifos Initiative. + * 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. diff --git a/component-test/src/main/java/io/mifos/customer/TestCustomer.java b/component-test/src/main/java/io/mifos/customer/TestCustomer.java index 4901dc7..36bf013 100644 --- a/component-test/src/main/java/io/mifos/customer/TestCustomer.java +++ b/component-test/src/main/java/io/mifos/customer/TestCustomer.java @@ -16,8 +16,17 @@ package io.mifos.customer; import io.mifos.customer.api.v1.CustomerEventConstants; -import io.mifos.customer.api.v1.client.*; -import io.mifos.customer.api.v1.domain.*; +import io.mifos.customer.api.v1.client.CustomerAlreadyExistsException; +import io.mifos.customer.api.v1.client.CustomerNotFoundException; +import io.mifos.customer.api.v1.client.CustomerValidationException; +import io.mifos.customer.api.v1.client.PortraitNotFoundException; +import io.mifos.customer.api.v1.client.PortraitValidationException; +import io.mifos.customer.api.v1.domain.Address; +import io.mifos.customer.api.v1.domain.Command; +import io.mifos.customer.api.v1.domain.ContactDetail; +import io.mifos.customer.api.v1.domain.Customer; +import io.mifos.customer.api.v1.domain.CustomerPage; +import io.mifos.customer.api.v1.domain.ProcessStep; import io.mifos.customer.util.AddressGenerator; import io.mifos.customer.util.CommandGenerator; import io.mifos.customer.util.ContactDetailGenerator; diff --git a/component-test/src/main/java/io/mifos/customer/TestIdentificationCards.java b/component-test/src/main/java/io/mifos/customer/TestIdentificationCards.java index 0740bba..b2d3c8b 100644 --- a/component-test/src/main/java/io/mifos/customer/TestIdentificationCards.java +++ b/component-test/src/main/java/io/mifos/customer/TestIdentificationCards.java @@ -1,5 +1,5 @@ /* - * Copyright 2016 The Mifos Initiative. + * 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. diff --git a/component-test/src/main/java/io/mifos/customer/TestPayrollDistribution.java b/component-test/src/main/java/io/mifos/customer/TestPayrollDistribution.java new file mode 100644 index 0000000..89f6da4 --- /dev/null +++ b/component-test/src/main/java/io/mifos/customer/TestPayrollDistribution.java @@ -0,0 +1,115 @@ +/* + * 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.customer; + +import com.google.common.collect.Sets; +import io.mifos.customer.api.v1.CustomerEventConstants; +import io.mifos.customer.api.v1.domain.Customer; +import io.mifos.customer.api.v1.domain.PayrollAllocation; +import io.mifos.customer.api.v1.domain.PayrollDistribution; +import io.mifos.customer.util.CustomerGenerator; +import org.junit.Assert; +import org.junit.Test; + +import java.math.BigDecimal; +import java.util.Optional; + +public class TestPayrollDistribution extends AbstractCustomerTest { + + @Test + public void shouldSetInitialPayrollDistribution() throws Exception { + final Customer customer = CustomerGenerator.createRandomCustomer(); + this.customerManager.createCustomer(customer); + + Assert.assertTrue(this.eventRecorder.wait(CustomerEventConstants.POST_CUSTOMER, customer.getIdentifier())); + + final PayrollAllocation firstPayrollAllocation = new PayrollAllocation(); + firstPayrollAllocation.setAccountNumber("08154712"); + firstPayrollAllocation.setAmount(BigDecimal.valueOf(234.56D)); + + final PayrollAllocation secondPayrollAllocation = new PayrollAllocation(); + secondPayrollAllocation.setAccountNumber("08154713"); + secondPayrollAllocation.setAmount(BigDecimal.valueOf(5.00D)); + secondPayrollAllocation.setProportional(Boolean.TRUE); + + final PayrollDistribution payrollDistribution = new PayrollDistribution(); + payrollDistribution.setMainAccountNumber("08154711"); + payrollDistribution.setPayrollAllocations(Sets.newHashSet(firstPayrollAllocation, secondPayrollAllocation)); + this.customerManager.setPayrollDistribution(customer.getIdentifier(), payrollDistribution); + + Assert.assertTrue(this.eventRecorder.wait(CustomerEventConstants.PUT_PAYROLL_DISTRIBUTION, customer.getIdentifier())); + + final PayrollDistribution fetchedPayrollDistribution = this.customerManager.getPayrollDistribution(customer.getIdentifier()); + + this.compare(payrollDistribution, fetchedPayrollDistribution); + } + + @Test + public void shouldUpdatePayrollDistribution() throws Exception { + final Customer customer = CustomerGenerator.createRandomCustomer(); + this.customerManager.createCustomer(customer); + + Assert.assertTrue(this.eventRecorder.wait(CustomerEventConstants.POST_CUSTOMER, customer.getIdentifier())); + + final PayrollAllocation firstPayrollAllocation = new PayrollAllocation(); + firstPayrollAllocation.setAccountNumber("08154712"); + firstPayrollAllocation.setAmount(BigDecimal.valueOf(234.56D)); + + final PayrollAllocation secondPayrollAllocation = new PayrollAllocation(); + secondPayrollAllocation.setAccountNumber("08154713"); + secondPayrollAllocation.setAmount(BigDecimal.valueOf(5.00D)); + secondPayrollAllocation.setProportional(Boolean.TRUE); + + final PayrollDistribution payrollDistribution = new PayrollDistribution(); + payrollDistribution.setMainAccountNumber("08154711"); + payrollDistribution.setPayrollAllocations(Sets.newHashSet(firstPayrollAllocation, secondPayrollAllocation)); + this.customerManager.setPayrollDistribution(customer.getIdentifier(), payrollDistribution); + + Assert.assertTrue(this.eventRecorder.wait(CustomerEventConstants.PUT_PAYROLL_DISTRIBUTION, customer.getIdentifier())); + this.eventRecorder.clear(); + + final PayrollDistribution fetchedPayrollDistribution = this.customerManager.getPayrollDistribution(customer.getIdentifier()); + + final PayrollAllocation replacedPayrollAllocation = new PayrollAllocation(); + replacedPayrollAllocation.setAccountNumber("08154714"); + replacedPayrollAllocation.setAmount(BigDecimal.valueOf(10.00D)); + replacedPayrollAllocation.setProportional(Boolean.TRUE); + + final PayrollDistribution replacedPayrollDistribution = new PayrollDistribution(); + replacedPayrollDistribution.setMainAccountNumber(fetchedPayrollDistribution.getMainAccountNumber()); + replacedPayrollDistribution.setPayrollAllocations(Sets.newHashSet(replacedPayrollAllocation)); + this.customerManager.setPayrollDistribution(customer.getIdentifier(), replacedPayrollDistribution); + + Assert.assertTrue(this.eventRecorder.wait(CustomerEventConstants.PUT_PAYROLL_DISTRIBUTION, customer.getIdentifier())); + + final PayrollDistribution updatedPayrollDistribution = this.customerManager.getPayrollDistribution(customer.getIdentifier()); + + this.compare(replacedPayrollDistribution, updatedPayrollDistribution); + + final Optional<PayrollAllocation> optionalPayrollAllocation = + updatedPayrollDistribution.getPayrollAllocations().stream().findFirst(); + + final PayrollAllocation payrollAllocation = optionalPayrollAllocation.orElseThrow(IllegalStateException::new); + Assert.assertEquals(replacedPayrollAllocation.getAccountNumber(), payrollAllocation.getAccountNumber()); + Assert.assertTrue(replacedPayrollAllocation.getAmount().compareTo(payrollAllocation.getAmount()) == 0); + Assert.assertEquals(replacedPayrollAllocation.getProportional(), payrollAllocation.getProportional()); + } + + private void compare(final PayrollDistribution payrollDistribution, final PayrollDistribution fetchedPayrollDistribution) { + Assert.assertEquals(payrollDistribution.getMainAccountNumber(), fetchedPayrollDistribution.getMainAccountNumber()); + Assert.assertTrue(payrollDistribution.getPayrollAllocations().size() == fetchedPayrollDistribution.getPayrollAllocations().size()); + } +} diff --git a/component-test/src/main/java/io/mifos/customer/catalog/TestCatalog.java b/component-test/src/main/java/io/mifos/customer/catalog/TestCatalog.java index e538822..2fe10c6 100644 --- a/component-test/src/main/java/io/mifos/customer/catalog/TestCatalog.java +++ b/component-test/src/main/java/io/mifos/customer/catalog/TestCatalog.java @@ -34,7 +34,12 @@ import io.mifos.customer.catalog.api.v1.domain.Value; import io.mifos.customer.catalog.util.CatalogGenerator; import io.mifos.customer.service.rest.config.CustomerRestConfiguration; import io.mifos.customer.util.CustomerGenerator; -import org.junit.*; +import org.junit.After; +import org.junit.Assert; +import org.junit.Before; +import org.junit.ClassRule; +import org.junit.Rule; +import org.junit.Test; import org.junit.rules.RuleChain; import org.junit.rules.TestRule; import org.junit.runner.RunWith; diff --git a/component-test/src/main/java/io/mifos/customer/listener/CustomerEventListener.java b/component-test/src/main/java/io/mifos/customer/listener/CustomerEventListener.java index 5c1d2e1..47ac0b5 100644 --- a/component-test/src/main/java/io/mifos/customer/listener/CustomerEventListener.java +++ b/component-test/src/main/java/io/mifos/customer/listener/CustomerEventListener.java @@ -178,4 +178,13 @@ public class CustomerEventListener { final String payload) { this.eventRecorder.event(tenant, CustomerEventConstants.DELETE_PORTRAIT, payload, String.class); } + + @JmsListener( + destination = CustomerEventConstants.DESTINATION, + selector = CustomerEventConstants.SELECTOR_PUT_PAYROLL_DISTRIBUTION + ) + public void onSetPayrollDistribution(@Header(TenantHeaderFilter.TENANT_HEADER) final String tenant, + final String payload) { + this.eventRecorder.event(tenant, CustomerEventConstants.PUT_PAYROLL_DISTRIBUTION, payload, String.class); + } } diff --git a/component-test/src/main/java/io/mifos/customer/util/ScanGenerator.java b/component-test/src/main/java/io/mifos/customer/util/ScanGenerator.java index b139623..b029496 100644 --- a/component-test/src/main/java/io/mifos/customer/util/ScanGenerator.java +++ b/component-test/src/main/java/io/mifos/customer/util/ScanGenerator.java @@ -1,5 +1,5 @@ /* - * Copyright 2016 The Mifos Initiative. + * 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. diff --git a/component-test/src/main/resources/logback.xml b/component-test/src/main/resources/logback-test.xml similarity index 100% rename from component-test/src/main/resources/logback.xml rename to component-test/src/main/resources/logback-test.xml diff --git a/service/src/main/java/io/mifos/customer/catalog/service/internal/command/handler/CatalogAggregate.java b/service/src/main/java/io/mifos/customer/catalog/service/internal/command/handler/CatalogAggregate.java index 31de88d..c464e3f 100644 --- a/service/src/main/java/io/mifos/customer/catalog/service/internal/command/handler/CatalogAggregate.java +++ b/service/src/main/java/io/mifos/customer/catalog/service/internal/command/handler/CatalogAggregate.java @@ -20,11 +20,11 @@ import io.mifos.core.command.annotation.CommandHandler; import io.mifos.core.command.annotation.EventEmitter; import io.mifos.customer.catalog.api.v1.CatalogEventConstants; import io.mifos.customer.catalog.api.v1.domain.Catalog; -import io.mifos.customer.catalog.service.internal.repository.CatalogEntity; -import io.mifos.customer.catalog.service.internal.repository.CatalogRepository; import io.mifos.customer.catalog.service.internal.command.CreateCatalogCommand; import io.mifos.customer.catalog.service.internal.mapper.CatalogMapper; import io.mifos.customer.catalog.service.internal.mapper.FieldMapper; +import io.mifos.customer.catalog.service.internal.repository.CatalogEntity; +import io.mifos.customer.catalog.service.internal.repository.CatalogRepository; import io.mifos.customer.service.ServiceConstants; import org.slf4j.Logger; import org.springframework.beans.factory.annotation.Autowired; diff --git a/service/src/main/java/io/mifos/customer/catalog/service/internal/service/FieldValueValidator.java b/service/src/main/java/io/mifos/customer/catalog/service/internal/service/FieldValueValidator.java index 35500f7..75c13d1 100644 --- a/service/src/main/java/io/mifos/customer/catalog/service/internal/service/FieldValueValidator.java +++ b/service/src/main/java/io/mifos/customer/catalog/service/internal/service/FieldValueValidator.java @@ -21,9 +21,9 @@ import io.mifos.customer.catalog.api.v1.domain.Field; import io.mifos.customer.catalog.api.v1.domain.Value; import io.mifos.customer.catalog.service.internal.repository.CatalogEntity; import io.mifos.customer.catalog.service.internal.repository.CatalogRepository; +import io.mifos.customer.catalog.service.internal.repository.FieldEntity; import io.mifos.customer.catalog.service.internal.repository.FieldRepository; import io.mifos.customer.catalog.service.internal.repository.OptionEntity; -import io.mifos.customer.catalog.service.internal.repository.FieldEntity; import io.mifos.customer.service.ServiceConstants; import org.slf4j.Logger; import org.springframework.beans.factory.annotation.Autowired; diff --git a/service/src/main/java/io/mifos/customer/catalog/service/rest/controller/CatalogRestController.java b/service/src/main/java/io/mifos/customer/catalog/service/rest/controller/CatalogRestController.java index 84a4a33..96fe00e 100644 --- a/service/src/main/java/io/mifos/customer/catalog/service/rest/controller/CatalogRestController.java +++ b/service/src/main/java/io/mifos/customer/catalog/service/rest/controller/CatalogRestController.java @@ -21,8 +21,8 @@ import io.mifos.core.command.gateway.CommandGateway; import io.mifos.core.lang.ServiceException; import io.mifos.customer.PermittableGroupIds; import io.mifos.customer.catalog.api.v1.domain.Catalog; -import io.mifos.customer.catalog.service.internal.service.CatalogService; import io.mifos.customer.catalog.service.internal.command.CreateCatalogCommand; +import io.mifos.customer.catalog.service.internal.service.CatalogService; import io.mifos.customer.service.ServiceConstants; import org.slf4j.Logger; import org.springframework.beans.factory.annotation.Autowired; diff --git a/service/src/main/java/io/mifos/customer/service/internal/command/CreateIdentificationCardScanCommand.java b/service/src/main/java/io/mifos/customer/service/internal/command/CreateIdentificationCardScanCommand.java index 166ba69..be9831b 100644 --- a/service/src/main/java/io/mifos/customer/service/internal/command/CreateIdentificationCardScanCommand.java +++ b/service/src/main/java/io/mifos/customer/service/internal/command/CreateIdentificationCardScanCommand.java @@ -1,5 +1,5 @@ /* - * Copyright 2016 The Mifos Initiative. + * 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. diff --git a/service/src/main/java/io/mifos/customer/service/internal/command/DeleteIdentificationCardScanCommand.java b/service/src/main/java/io/mifos/customer/service/internal/command/DeleteIdentificationCardScanCommand.java index 2240c0a..3961445 100644 --- a/service/src/main/java/io/mifos/customer/service/internal/command/DeleteIdentificationCardScanCommand.java +++ b/service/src/main/java/io/mifos/customer/service/internal/command/DeleteIdentificationCardScanCommand.java @@ -1,5 +1,5 @@ /* - * Copyright 2016 The Mifos Initiative. + * 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. diff --git a/service/src/main/java/io/mifos/customer/service/internal/command/SetPayrollDistributionCommand.java b/service/src/main/java/io/mifos/customer/service/internal/command/SetPayrollDistributionCommand.java new file mode 100644 index 0000000..9d456dd --- /dev/null +++ b/service/src/main/java/io/mifos/customer/service/internal/command/SetPayrollDistributionCommand.java @@ -0,0 +1,38 @@ +/* + * 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.customer.service.internal.command; + +import io.mifos.customer.api.v1.domain.PayrollDistribution; + +public class SetPayrollDistributionCommand { + private final String customerIdentifier; + private final PayrollDistribution payrollDistribution; + + public SetPayrollDistributionCommand(final String customerIdentifier, + final PayrollDistribution payrollDistribution) { + super(); + this.customerIdentifier = customerIdentifier; + this.payrollDistribution = payrollDistribution; + } + + public String customerIdentifier() { + return this.customerIdentifier; + } + + public PayrollDistribution payrollDistribution() { + return this.payrollDistribution; + } +} diff --git a/service/src/main/java/io/mifos/customer/service/internal/command/handler/CustomerAggregate.java b/service/src/main/java/io/mifos/customer/service/internal/command/handler/CustomerAggregate.java index 7ec7770..917b364 100644 --- a/service/src/main/java/io/mifos/customer/service/internal/command/handler/CustomerAggregate.java +++ b/service/src/main/java/io/mifos/customer/service/internal/command/handler/CustomerAggregate.java @@ -24,6 +24,7 @@ import io.mifos.core.lang.ServiceException; import io.mifos.customer.api.v1.CustomerEventConstants; import io.mifos.customer.api.v1.domain.Command; import io.mifos.customer.api.v1.domain.Customer; +import io.mifos.customer.api.v1.domain.PayrollDistribution; import io.mifos.customer.api.v1.events.ScanEvent; import io.mifos.customer.catalog.service.internal.repository.CatalogEntity; import io.mifos.customer.catalog.service.internal.repository.CatalogRepository; @@ -31,10 +32,52 @@ import io.mifos.customer.catalog.service.internal.repository.FieldEntity; import io.mifos.customer.catalog.service.internal.repository.FieldRepository; import io.mifos.customer.catalog.service.internal.repository.FieldValueEntity; import io.mifos.customer.catalog.service.internal.repository.FieldValueRepository; -import io.mifos.customer.service.internal.command.*; -import io.mifos.customer.service.internal.mapper.*; -import io.mifos.customer.service.internal.repository.*; +import io.mifos.customer.service.ServiceConstants; +import io.mifos.customer.service.internal.command.ActivateCustomerCommand; +import io.mifos.customer.service.internal.command.CloseCustomerCommand; +import io.mifos.customer.service.internal.command.CreateCustomerCommand; +import io.mifos.customer.service.internal.command.CreateIdentificationCardCommand; +import io.mifos.customer.service.internal.command.CreateIdentificationCardScanCommand; +import io.mifos.customer.service.internal.command.CreatePortraitCommand; +import io.mifos.customer.service.internal.command.DeleteIdentificationCardCommand; +import io.mifos.customer.service.internal.command.DeleteIdentificationCardScanCommand; +import io.mifos.customer.service.internal.command.DeletePortraitCommand; +import io.mifos.customer.service.internal.command.LockCustomerCommand; +import io.mifos.customer.service.internal.command.ReopenCustomerCommand; +import io.mifos.customer.service.internal.command.SetPayrollDistributionCommand; +import io.mifos.customer.service.internal.command.UnlockCustomerCommand; +import io.mifos.customer.service.internal.command.UpdateAddressCommand; +import io.mifos.customer.service.internal.command.UpdateContactDetailsCommand; +import io.mifos.customer.service.internal.command.UpdateCustomerCommand; +import io.mifos.customer.service.internal.command.UpdateIdentificationCardCommand; +import io.mifos.customer.service.internal.mapper.AddressMapper; +import io.mifos.customer.service.internal.mapper.CommandMapper; +import io.mifos.customer.service.internal.mapper.ContactDetailMapper; +import io.mifos.customer.service.internal.mapper.CustomerMapper; +import io.mifos.customer.service.internal.mapper.FieldValueMapper; +import io.mifos.customer.service.internal.mapper.IdentificationCardMapper; +import io.mifos.customer.service.internal.mapper.IdentificationCardScanMapper; +import io.mifos.customer.service.internal.mapper.PortraitMapper; +import io.mifos.customer.service.internal.repository.AddressEntity; +import io.mifos.customer.service.internal.repository.AddressRepository; +import io.mifos.customer.service.internal.repository.CommandRepository; +import io.mifos.customer.service.internal.repository.ContactDetailEntity; +import io.mifos.customer.service.internal.repository.ContactDetailRepository; +import io.mifos.customer.service.internal.repository.CustomerEntity; +import io.mifos.customer.service.internal.repository.CustomerRepository; +import io.mifos.customer.service.internal.repository.IdentificationCardEntity; +import io.mifos.customer.service.internal.repository.IdentificationCardRepository; +import io.mifos.customer.service.internal.repository.IdentificationCardScanEntity; +import io.mifos.customer.service.internal.repository.IdentificationCardScanRepository; +import io.mifos.customer.service.internal.repository.PayrollAllocationEntity; +import io.mifos.customer.service.internal.repository.PayrollAllocationRepository; +import io.mifos.customer.service.internal.repository.PayrollDistributionEntity; +import io.mifos.customer.service.internal.repository.PayrollDistributionRepository; +import io.mifos.customer.service.internal.repository.PortraitEntity; +import io.mifos.customer.service.internal.repository.PortraitRepository; +import org.slf4j.Logger; import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.beans.factory.annotation.Qualifier; import org.springframework.transaction.annotation.Transactional; import org.springframework.web.multipart.MultipartFile; @@ -51,6 +94,7 @@ import java.util.stream.Collectors; @Aggregate public class CustomerAggregate { + private final Logger logger; private final AddressRepository addressRepository; private final CustomerRepository customerRepository; private final IdentificationCardRepository identificationCardRepository; @@ -62,9 +106,12 @@ public class CustomerAggregate { private final FieldRepository fieldRepository; private final CommandRepository commandRepository; private final TaskAggregate taskAggregate; + private final PayrollDistributionRepository payrollDistributionRepository; + private final PayrollAllocationRepository payrollAllocationRepository; @Autowired - public CustomerAggregate(final AddressRepository addressRepository, + public CustomerAggregate(@Qualifier(ServiceConstants.LOGGER_NAME) final Logger logger, + final AddressRepository addressRepository, final CustomerRepository customerRepository, final IdentificationCardRepository identificationCardRepository, final IdentificationCardScanRepository identificationCardScanRepository, @@ -74,8 +121,11 @@ public class CustomerAggregate { final CatalogRepository catalogRepository, final FieldRepository fieldRepository, final CommandRepository commandRepository, - final TaskAggregate taskAggregate) { + final TaskAggregate taskAggregate, + final PayrollDistributionRepository payrollDistributionRepository, + final PayrollAllocationRepository payrollAllocationRepository) { super(); + this.logger = logger; this.addressRepository = addressRepository; this.customerRepository = customerRepository; this.identificationCardRepository = identificationCardRepository; @@ -87,6 +137,8 @@ public class CustomerAggregate { this.fieldRepository = fieldRepository; this.commandRepository = commandRepository; this.taskAggregate = taskAggregate; + this.payrollDistributionRepository = payrollDistributionRepository; + this.payrollAllocationRepository = payrollAllocationRepository; } @Transactional @@ -496,6 +548,55 @@ public class CustomerAggregate { return deletePortraitCommand.identifier(); } + @Transactional + @CommandHandler + @EventEmitter(selectorName = CustomerEventConstants.SELECTOR_NAME, selectorValue = CustomerEventConstants.PUT_PAYROLL_DISTRIBUTION) + public String setPayrollDistribution(final SetPayrollDistributionCommand setPayrollDistributionCommand) { + final CustomerEntity customerEntity = + this.customerRepository.findByIdentifier(setPayrollDistributionCommand.customerIdentifier()); + + final LocalDateTime now = LocalDateTime.now(Clock.systemUTC()); + + final PayrollDistributionEntity payrollDistributionEntity = + this.payrollDistributionRepository.findByCustomer(customerEntity).orElseGet(() -> { + final PayrollDistributionEntity newPayrollDistribution = new PayrollDistributionEntity(); + newPayrollDistribution.setCustomer(customerEntity); + newPayrollDistribution.setCreatedBy(UserContextHolder.checkedGetUser()); + newPayrollDistribution.setCreatedOn(now); + return newPayrollDistribution; + }); + + if (payrollDistributionEntity.getId() != null) { + this.payrollAllocationRepository.deleteByPayrollDistribution(payrollDistributionEntity); + this.payrollAllocationRepository.flush(); + + payrollDistributionEntity.setLastModifiedBy(UserContextHolder.checkedGetUser()); + payrollDistributionEntity.setLastModifiedOn(now); + payrollDistributionEntity.setPayrollAllocationEntities(null); + } + + final PayrollDistribution payrollDistribution = setPayrollDistributionCommand.payrollDistribution(); + payrollDistributionEntity.setMainAccountNumber(payrollDistribution.getMainAccountNumber()); + + final PayrollDistributionEntity savedPayrollDistributionEntity = + this.payrollDistributionRepository.save(payrollDistributionEntity); + + this.payrollAllocationRepository.save(payrollDistribution.getPayrollAllocations() + .stream() + .map(payrollAllocation -> { + final PayrollAllocationEntity payrollAllocationEntity = new PayrollAllocationEntity(); + payrollAllocationEntity.setPayrollDistribution(savedPayrollDistributionEntity); + payrollAllocationEntity.setAccountNumber(payrollAllocation.getAccountNumber()); + payrollAllocationEntity.setAmount(payrollAllocation.getAmount()); + payrollAllocationEntity.setProportional(payrollAllocation.getProportional()); + return payrollAllocationEntity; + }) + .collect(Collectors.toList()) + ); + + return setPayrollDistributionCommand.customerIdentifier(); + } + private void setCustomValues(final Customer customer, final CustomerEntity savedCustomerEntity) { this.fieldValueRepository.save( customer.getCustomValues() diff --git a/service/src/main/java/io/mifos/customer/service/internal/mapper/IdentificationCardScanMapper.java b/service/src/main/java/io/mifos/customer/service/internal/mapper/IdentificationCardScanMapper.java index 346adfb..e451d65 100644 --- a/service/src/main/java/io/mifos/customer/service/internal/mapper/IdentificationCardScanMapper.java +++ b/service/src/main/java/io/mifos/customer/service/internal/mapper/IdentificationCardScanMapper.java @@ -1,5 +1,5 @@ /* - * Copyright 2016 The Mifos Initiative. + * 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. diff --git a/service/src/main/java/io/mifos/customer/service/internal/mapper/PayrollDistributionMapper.java b/service/src/main/java/io/mifos/customer/service/internal/mapper/PayrollDistributionMapper.java new file mode 100644 index 0000000..c7cc514 --- /dev/null +++ b/service/src/main/java/io/mifos/customer/service/internal/mapper/PayrollDistributionMapper.java @@ -0,0 +1,55 @@ +/* + * 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.customer.service.internal.mapper; + +import io.mifos.core.lang.DateConverter; +import io.mifos.customer.api.v1.domain.PayrollAllocation; +import io.mifos.customer.api.v1.domain.PayrollDistribution; +import io.mifos.customer.service.internal.repository.PayrollDistributionEntity; + +import java.util.stream.Collectors; + +public class PayrollDistributionMapper { + + private PayrollDistributionMapper() { + super(); + } + + public static PayrollDistribution map(final PayrollDistributionEntity payrollDistributionEntity) { + final PayrollDistribution payrollDistribution = new PayrollDistribution(); + payrollDistribution.setMainAccountNumber(payrollDistributionEntity.getMainAccountNumber()); + payrollDistribution.setCreatedBy(payrollDistributionEntity.getCreatedBy()); + payrollDistribution.setCreatedOn(DateConverter.toIsoString(payrollDistributionEntity.getCreatedOn())); + if (payrollDistributionEntity.getLastModifiedBy() != null) { + payrollDistribution.setLastModifiedBy(payrollDistributionEntity.getLastModifiedBy()); + payrollDistribution.setLastModifiedOn(DateConverter.toIsoString(payrollDistributionEntity.getLastModifiedOn())); + } + + if (payrollDistributionEntity.getPayrollAllocationEntities() != null) { + payrollDistribution.setPayrollAllocations( + payrollDistributionEntity.getPayrollAllocationEntities().stream().map(payrollAllocationEntity -> { + final PayrollAllocation payrollAllocation = new PayrollAllocation(); + payrollAllocation.setAccountNumber(payrollAllocationEntity.getAccountNumber()); + payrollAllocation.setAmount(payrollAllocationEntity.getAmount()); + payrollAllocation.setProportional(payrollAllocationEntity.getProportional()); + return payrollAllocation; + }).collect(Collectors.toSet()) + ); + } + + return payrollDistribution; + } +} diff --git a/service/src/main/java/io/mifos/customer/service/internal/mapper/TaskInstanceMapper.java b/service/src/main/java/io/mifos/customer/service/internal/mapper/TaskInstanceMapper.java index 2ffbb1b..2b05865 100644 --- a/service/src/main/java/io/mifos/customer/service/internal/mapper/TaskInstanceMapper.java +++ b/service/src/main/java/io/mifos/customer/service/internal/mapper/TaskInstanceMapper.java @@ -18,8 +18,8 @@ package io.mifos.customer.service.internal.mapper; import io.mifos.core.lang.DateConverter; import io.mifos.customer.api.v1.domain.TaskInstance; import io.mifos.customer.service.internal.repository.CustomerEntity; -import io.mifos.customer.service.internal.repository.TaskInstanceEntity; import io.mifos.customer.service.internal.repository.TaskDefinitionEntity; +import io.mifos.customer.service.internal.repository.TaskInstanceEntity; public class TaskInstanceMapper { diff --git a/service/src/main/java/io/mifos/customer/service/internal/repository/IdentificationCardScanEntity.java b/service/src/main/java/io/mifos/customer/service/internal/repository/IdentificationCardScanEntity.java index acd9808..84c2e34 100644 --- a/service/src/main/java/io/mifos/customer/service/internal/repository/IdentificationCardScanEntity.java +++ b/service/src/main/java/io/mifos/customer/service/internal/repository/IdentificationCardScanEntity.java @@ -1,5 +1,5 @@ /* - * Copyright 2016 The Mifos Initiative. + * 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. @@ -16,9 +16,18 @@ package io.mifos.customer.service.internal.repository; import io.mifos.core.mariadb.util.LocalDateTimeConverter; -import io.mifos.customer.api.v1.domain.IdentificationCard; -import javax.persistence.*; +import javax.persistence.Column; +import javax.persistence.Convert; +import javax.persistence.Entity; +import javax.persistence.FetchType; +import javax.persistence.GeneratedValue; +import javax.persistence.GenerationType; +import javax.persistence.Id; +import javax.persistence.JoinColumn; +import javax.persistence.Lob; +import javax.persistence.ManyToOne; +import javax.persistence.Table; import java.time.LocalDateTime; @Entity diff --git a/service/src/main/java/io/mifos/customer/service/internal/repository/IdentificationCardScanRepository.java b/service/src/main/java/io/mifos/customer/service/internal/repository/IdentificationCardScanRepository.java index dded654..ce149cd 100644 --- a/service/src/main/java/io/mifos/customer/service/internal/repository/IdentificationCardScanRepository.java +++ b/service/src/main/java/io/mifos/customer/service/internal/repository/IdentificationCardScanRepository.java @@ -1,5 +1,5 @@ /* - * Copyright 2016 The Mifos Initiative. + * 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. diff --git a/service/src/main/java/io/mifos/customer/service/internal/repository/PayrollAllocationEntity.java b/service/src/main/java/io/mifos/customer/service/internal/repository/PayrollAllocationEntity.java new file mode 100644 index 0000000..a08907c --- /dev/null +++ b/service/src/main/java/io/mifos/customer/service/internal/repository/PayrollAllocationEntity.java @@ -0,0 +1,89 @@ +/* + * 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.customer.service.internal.repository; + +import javax.persistence.Column; +import javax.persistence.Entity; +import javax.persistence.GeneratedValue; +import javax.persistence.GenerationType; +import javax.persistence.Id; +import javax.persistence.JoinColumn; +import javax.persistence.ManyToOne; +import javax.persistence.Table; +import java.math.BigDecimal; + +@Entity +@Table(name = "maat_payroll_allocations") +public class PayrollAllocationEntity { + + @Id + @GeneratedValue(strategy = GenerationType.IDENTITY) + @Column(name = "id", nullable = false) + private Long id; + @ManyToOne + @JoinColumn(name = "payroll_distribution_id", nullable = false) + private PayrollDistributionEntity payrollDistribution; + @Column(name = "account_number", nullable = false, length = 34) + private String accountNumber; + @Column(name = "amount", nullable = false, precision = 15, scale = 5) + private BigDecimal amount; + @Column(name = "proportional", nullable = false) + private Boolean proportional = Boolean.FALSE; + + public PayrollAllocationEntity() { + super(); + } + + public Long getId() { + return this.id; + } + + public void setId(final Long id) { + this.id = id; + } + + public PayrollDistributionEntity getPayrollDistribution() { + return this.payrollDistribution; + } + + public void setPayrollDistribution(final PayrollDistributionEntity payrollDistribution) { + this.payrollDistribution = payrollDistribution; + } + + public String getAccountNumber() { + return this.accountNumber; + } + + public void setAccountNumber(final String accountNumber) { + this.accountNumber = accountNumber; + } + + public BigDecimal getAmount() { + return this.amount; + } + + public void setAmount(final BigDecimal amount) { + this.amount = amount; + } + + public Boolean getProportional() { + return this.proportional; + } + + public void setProportional(final Boolean proportional) { + this.proportional = proportional; + } +} diff --git a/api/src/main/java/io/mifos/customer/api/v1/client/ScanAlreadyExistsException.java b/service/src/main/java/io/mifos/customer/service/internal/repository/PayrollAllocationRepository.java similarity index 61% copy from api/src/main/java/io/mifos/customer/api/v1/client/ScanAlreadyExistsException.java copy to service/src/main/java/io/mifos/customer/service/internal/repository/PayrollAllocationRepository.java index 45ef5a1..9d418f3 100644 --- a/api/src/main/java/io/mifos/customer/api/v1/client/ScanAlreadyExistsException.java +++ b/service/src/main/java/io/mifos/customer/service/internal/repository/PayrollAllocationRepository.java @@ -1,5 +1,5 @@ /* - * Copyright 2016 The Mifos Initiative. + * 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. @@ -13,7 +13,10 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package io.mifos.customer.api.v1.client; +package io.mifos.customer.service.internal.repository; -public final class ScanAlreadyExistsException extends RuntimeException { +import org.springframework.data.jpa.repository.JpaRepository; + +public interface PayrollAllocationRepository extends JpaRepository<PayrollAllocationEntity, Long> { + void deleteByPayrollDistribution(final PayrollDistributionEntity payrollDistributionEntity); } diff --git a/service/src/main/java/io/mifos/customer/service/internal/repository/PayrollDistributionEntity.java b/service/src/main/java/io/mifos/customer/service/internal/repository/PayrollDistributionEntity.java new file mode 100644 index 0000000..5cb62b9 --- /dev/null +++ b/service/src/main/java/io/mifos/customer/service/internal/repository/PayrollDistributionEntity.java @@ -0,0 +1,128 @@ +/* + * 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.customer.service.internal.repository; + +import io.mifos.core.mariadb.util.LocalDateTimeConverter; + +import javax.persistence.CascadeType; +import javax.persistence.Column; +import javax.persistence.Convert; +import javax.persistence.Entity; +import javax.persistence.FetchType; +import javax.persistence.GeneratedValue; +import javax.persistence.GenerationType; +import javax.persistence.Id; +import javax.persistence.JoinColumn; +import javax.persistence.OneToMany; +import javax.persistence.OneToOne; +import javax.persistence.Table; +import java.time.LocalDateTime; +import java.util.List; + +@Entity +@Table(name = "maat_payroll_distributions") +public class PayrollDistributionEntity { + + @Id + @GeneratedValue(strategy = GenerationType.IDENTITY) + @Column(name = "id", nullable = false) + private Long id; + @OneToOne(cascade = CascadeType.ALL) + @JoinColumn(name = "customer_id", nullable = false) + private CustomerEntity customer; + @Column(name = "main_account_number", nullable = false, length = 34) + private String mainAccountNumber; + @OneToMany(fetch = FetchType.EAGER, mappedBy = "payrollDistribution") + private List<PayrollAllocationEntity> payrollAllocationEntities; + @Column(name = "created_by") + private String createdBy; + @Column(name = "created_on") + @Convert(converter = LocalDateTimeConverter.class) + private LocalDateTime createdOn; + @Column(name = "last_modified_by") + private String lastModifiedBy; + @Column(name = "last_modified_on") + @Convert(converter = LocalDateTimeConverter.class) + private LocalDateTime lastModifiedOn; + + public PayrollDistributionEntity() { + super(); + } + + public Long getId() { + return this.id; + } + + public void setId(final Long id) { + this.id = id; + } + + public CustomerEntity getCustomer() { + return this.customer; + } + + public void setCustomer(final CustomerEntity customer) { + this.customer = customer; + } + + public String getMainAccountNumber() { + return this.mainAccountNumber; + } + + public void setMainAccountNumber(final String mainAccountNumber) { + this.mainAccountNumber = mainAccountNumber; + } + + public List<PayrollAllocationEntity> getPayrollAllocationEntities() { + return this.payrollAllocationEntities; + } + + public void setPayrollAllocationEntities(final List<PayrollAllocationEntity> payrollAllocationEntities) { + this.payrollAllocationEntities = payrollAllocationEntities; + } + + public String getCreatedBy() { + return this.createdBy; + } + + public void setCreatedBy(final String createdBy) { + this.createdBy = createdBy; + } + + public LocalDateTime getCreatedOn() { + return this.createdOn; + } + + public void setCreatedOn(final LocalDateTime createdOn) { + this.createdOn = createdOn; + } + + public String getLastModifiedBy() { + return this.lastModifiedBy; + } + + public void setLastModifiedBy(final String lastModifiedBy) { + this.lastModifiedBy = lastModifiedBy; + } + + public LocalDateTime getLastModifiedOn() { + return this.lastModifiedOn; + } + + public void setLastModifiedOn(final LocalDateTime lastModifiedOn) { + this.lastModifiedOn = lastModifiedOn; + } +} diff --git a/api/src/main/java/io/mifos/customer/api/v1/client/ScanAlreadyExistsException.java b/service/src/main/java/io/mifos/customer/service/internal/repository/PayrollDistributionRepository.java similarity index 59% copy from api/src/main/java/io/mifos/customer/api/v1/client/ScanAlreadyExistsException.java copy to service/src/main/java/io/mifos/customer/service/internal/repository/PayrollDistributionRepository.java index 45ef5a1..f332432 100644 --- a/api/src/main/java/io/mifos/customer/api/v1/client/ScanAlreadyExistsException.java +++ b/service/src/main/java/io/mifos/customer/service/internal/repository/PayrollDistributionRepository.java @@ -1,5 +1,5 @@ /* - * Copyright 2016 The Mifos Initiative. + * 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. @@ -13,7 +13,12 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package io.mifos.customer.api.v1.client; +package io.mifos.customer.service.internal.repository; -public final class ScanAlreadyExistsException extends RuntimeException { +import org.springframework.data.jpa.repository.JpaRepository; + +import java.util.Optional; + +public interface PayrollDistributionRepository extends JpaRepository<PayrollDistributionEntity, Long> { + Optional<PayrollDistributionEntity> findByCustomer(final CustomerEntity customerEntity); } diff --git a/service/src/main/java/io/mifos/customer/service/internal/repository/PortraitEntity.java b/service/src/main/java/io/mifos/customer/service/internal/repository/PortraitEntity.java index 3d734b7..21231a7 100644 --- a/service/src/main/java/io/mifos/customer/service/internal/repository/PortraitEntity.java +++ b/service/src/main/java/io/mifos/customer/service/internal/repository/PortraitEntity.java @@ -15,7 +15,16 @@ */ package io.mifos.customer.service.internal.repository; -import javax.persistence.*; +import javax.persistence.Column; +import javax.persistence.Entity; +import javax.persistence.FetchType; +import javax.persistence.GeneratedValue; +import javax.persistence.GenerationType; +import javax.persistence.Id; +import javax.persistence.JoinColumn; +import javax.persistence.Lob; +import javax.persistence.OneToOne; +import javax.persistence.Table; @Entity @Table(name = "maat_portraits") diff --git a/service/src/main/java/io/mifos/customer/service/internal/service/CustomerService.java b/service/src/main/java/io/mifos/customer/service/internal/service/CustomerService.java index f7fd56f..3901f0d 100644 --- a/service/src/main/java/io/mifos/customer/service/internal/service/CustomerService.java +++ b/service/src/main/java/io/mifos/customer/service/internal/service/CustomerService.java @@ -15,14 +15,42 @@ */ package io.mifos.customer.service.internal.service; -import io.mifos.customer.api.v1.domain.*; +import io.mifos.customer.api.v1.domain.Command; +import io.mifos.customer.api.v1.domain.Customer; +import io.mifos.customer.api.v1.domain.CustomerPage; +import io.mifos.customer.api.v1.domain.IdentificationCard; +import io.mifos.customer.api.v1.domain.IdentificationCardScan; +import io.mifos.customer.api.v1.domain.PayrollDistribution; +import io.mifos.customer.api.v1.domain.ProcessStep; +import io.mifos.customer.api.v1.domain.TaskDefinition; import io.mifos.customer.catalog.api.v1.domain.Value; import io.mifos.customer.catalog.service.internal.repository.FieldEntity; import io.mifos.customer.catalog.service.internal.repository.FieldValueEntity; import io.mifos.customer.catalog.service.internal.repository.FieldValueRepository; import io.mifos.customer.service.ServiceConstants; -import io.mifos.customer.service.internal.mapper.*; -import io.mifos.customer.service.internal.repository.*; +import io.mifos.customer.service.internal.mapper.AddressMapper; +import io.mifos.customer.service.internal.mapper.CommandMapper; +import io.mifos.customer.service.internal.mapper.ContactDetailMapper; +import io.mifos.customer.service.internal.mapper.CustomerMapper; +import io.mifos.customer.service.internal.mapper.IdentificationCardMapper; +import io.mifos.customer.service.internal.mapper.IdentificationCardScanMapper; +import io.mifos.customer.service.internal.mapper.PayrollDistributionMapper; +import io.mifos.customer.service.internal.mapper.TaskDefinitionMapper; +import io.mifos.customer.service.internal.repository.CommandEntity; +import io.mifos.customer.service.internal.repository.CommandRepository; +import io.mifos.customer.service.internal.repository.ContactDetailEntity; +import io.mifos.customer.service.internal.repository.ContactDetailRepository; +import io.mifos.customer.service.internal.repository.CustomerEntity; +import io.mifos.customer.service.internal.repository.CustomerRepository; +import io.mifos.customer.service.internal.repository.IdentificationCardEntity; +import io.mifos.customer.service.internal.repository.IdentificationCardRepository; +import io.mifos.customer.service.internal.repository.IdentificationCardScanEntity; +import io.mifos.customer.service.internal.repository.IdentificationCardScanRepository; +import io.mifos.customer.service.internal.repository.PayrollDistributionRepository; +import io.mifos.customer.service.internal.repository.PortraitEntity; +import io.mifos.customer.service.internal.repository.PortraitRepository; +import io.mifos.customer.service.internal.repository.TaskDefinitionRepository; +import io.mifos.customer.service.internal.repository.TaskInstanceRepository; import org.slf4j.Logger; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Qualifier; @@ -49,6 +77,7 @@ public class CustomerService { private final CommandRepository commandRepository; private final TaskDefinitionRepository taskDefinitionRepository; private final TaskInstanceRepository taskInstanceRepository; + private final PayrollDistributionRepository payrollDistributionRepository; @Autowired public CustomerService(@Qualifier(ServiceConstants.LOGGER_NAME) final Logger logger, @@ -60,7 +89,8 @@ public class CustomerService { final FieldValueRepository fieldValueRepository, final CommandRepository commandRepository, final TaskDefinitionRepository taskDefinitionRepository, - final TaskInstanceRepository taskInstanceRepository) { + final TaskInstanceRepository taskInstanceRepository, + final PayrollDistributionRepository payrollDistributionRepository) { super(); this.logger = logger; this.customerRepository = customerRepository; @@ -72,6 +102,7 @@ public class CustomerService { this.commandRepository = commandRepository; this.taskDefinitionRepository = taskDefinitionRepository; this.taskInstanceRepository = taskInstanceRepository; + this.payrollDistributionRepository = payrollDistributionRepository; } public Boolean customerExists(final String identifier) { @@ -263,4 +294,9 @@ public class CustomerService { return processStep; } + + public Optional<PayrollDistribution> getPayrollDistribution(final String customerIdentifier) { + final CustomerEntity customerEntity = this.customerRepository.findByIdentifier(customerIdentifier); + return this.payrollDistributionRepository.findByCustomer(customerEntity).map(PayrollDistributionMapper::map); + } } diff --git a/service/src/main/java/io/mifos/customer/service/internal/service/TaskService.java b/service/src/main/java/io/mifos/customer/service/internal/service/TaskService.java index a6100f5..66132fc 100644 --- a/service/src/main/java/io/mifos/customer/service/internal/service/TaskService.java +++ b/service/src/main/java/io/mifos/customer/service/internal/service/TaskService.java @@ -19,9 +19,9 @@ import io.mifos.customer.api.v1.domain.TaskDefinition; import io.mifos.customer.service.internal.mapper.TaskDefinitionMapper; import io.mifos.customer.service.internal.repository.CustomerEntity; import io.mifos.customer.service.internal.repository.CustomerRepository; +import io.mifos.customer.service.internal.repository.TaskDefinitionEntity; import io.mifos.customer.service.internal.repository.TaskDefinitionRepository; import io.mifos.customer.service.internal.repository.TaskInstanceRepository; -import io.mifos.customer.service.internal.repository.TaskDefinitionEntity; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; diff --git a/service/src/main/java/io/mifos/customer/service/rest/controller/CustomerRestController.java b/service/src/main/java/io/mifos/customer/service/rest/controller/CustomerRestController.java index f68549e..401f1d9 100644 --- a/service/src/main/java/io/mifos/customer/service/rest/controller/CustomerRestController.java +++ b/service/src/main/java/io/mifos/customer/service/rest/controller/CustomerRestController.java @@ -22,14 +22,43 @@ import io.mifos.core.command.gateway.CommandGateway; import io.mifos.core.lang.ServiceException; import io.mifos.core.lang.validation.constraints.ValidIdentifier; import io.mifos.customer.PermittableGroupIds; -import io.mifos.customer.api.v1.domain.*; +import io.mifos.customer.api.v1.domain.Address; +import io.mifos.customer.api.v1.domain.Command; +import io.mifos.customer.api.v1.domain.ContactDetail; +import io.mifos.customer.api.v1.domain.Customer; +import io.mifos.customer.api.v1.domain.CustomerPage; +import io.mifos.customer.api.v1.domain.IdentificationCard; +import io.mifos.customer.api.v1.domain.IdentificationCardScan; +import io.mifos.customer.api.v1.domain.PayrollDistribution; +import io.mifos.customer.api.v1.domain.ProcessStep; +import io.mifos.customer.api.v1.domain.TaskDefinition; import io.mifos.customer.catalog.service.internal.service.FieldValueValidator; import io.mifos.customer.service.ServiceConstants; -import io.mifos.customer.service.internal.command.*; +import io.mifos.customer.service.internal.command.ActivateCustomerCommand; +import io.mifos.customer.service.internal.command.AddTaskDefinitionToCustomerCommand; +import io.mifos.customer.service.internal.command.CloseCustomerCommand; +import io.mifos.customer.service.internal.command.CreateCustomerCommand; +import io.mifos.customer.service.internal.command.CreateIdentificationCardCommand; +import io.mifos.customer.service.internal.command.CreateIdentificationCardScanCommand; +import io.mifos.customer.service.internal.command.CreatePortraitCommand; +import io.mifos.customer.service.internal.command.CreateTaskDefinitionCommand; +import io.mifos.customer.service.internal.command.DeleteIdentificationCardCommand; +import io.mifos.customer.service.internal.command.DeleteIdentificationCardScanCommand; +import io.mifos.customer.service.internal.command.DeletePortraitCommand; +import io.mifos.customer.service.internal.command.ExecuteTaskForCustomerCommand; +import io.mifos.customer.service.internal.command.InitializeServiceCommand; +import io.mifos.customer.service.internal.command.LockCustomerCommand; +import io.mifos.customer.service.internal.command.ReopenCustomerCommand; +import io.mifos.customer.service.internal.command.SetPayrollDistributionCommand; +import io.mifos.customer.service.internal.command.UnlockCustomerCommand; +import io.mifos.customer.service.internal.command.UpdateAddressCommand; +import io.mifos.customer.service.internal.command.UpdateContactDetailsCommand; +import io.mifos.customer.service.internal.command.UpdateCustomerCommand; +import io.mifos.customer.service.internal.command.UpdateIdentificationCardCommand; +import io.mifos.customer.service.internal.command.UpdateTaskDefinitionCommand; import io.mifos.customer.service.internal.repository.PortraitEntity; import io.mifos.customer.service.internal.service.CustomerService; import io.mifos.customer.service.internal.service.TaskService; -import org.apache.commons.lang.RandomStringUtils; import org.slf4j.Logger; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Qualifier; @@ -39,7 +68,13 @@ import org.springframework.data.domain.Pageable; import org.springframework.data.domain.Sort; import org.springframework.http.MediaType; import org.springframework.http.ResponseEntity; -import org.springframework.web.bind.annotation.*; +import org.springframework.web.bind.annotation.PathVariable; +import org.springframework.web.bind.annotation.RequestBody; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RequestMethod; +import org.springframework.web.bind.annotation.RequestParam; +import org.springframework.web.bind.annotation.ResponseBody; +import org.springframework.web.bind.annotation.RestController; import org.springframework.web.multipart.MultipartFile; import javax.validation.Valid; @@ -711,6 +746,38 @@ public class CustomerRestController { return ResponseEntity.ok(this.customerService.getProcessSteps(customerIdentifier)); } + @Permittable(value = AcceptedTokenType.TENANT, groupId = PermittableGroupIds.CUSTOMER) + @RequestMapping( + value = "customer/{identifier}/payroll", + method = RequestMethod.PUT, + produces = MediaType.APPLICATION_JSON_VALUE, + consumes = MediaType.APPLICATION_JSON_VALUE + ) + public + @ResponseBody + ResponseEntity<Void> setPayrollDistribution(@PathVariable(value = "identifier") final String customerIdentifier, + @RequestBody @Valid final PayrollDistribution payrollDistribution) { + this.throwIfCustomerNotExists(customerIdentifier); + this.commandGateway.process(new SetPayrollDistributionCommand(customerIdentifier, payrollDistribution)); + return ResponseEntity.accepted().build(); + } + + @Permittable(value = AcceptedTokenType.TENANT, groupId = PermittableGroupIds.CUSTOMER) + @RequestMapping( + value = "customer/{identifier}/payroll", + method = RequestMethod.GET, + produces = MediaType.APPLICATION_JSON_VALUE, + consumes = MediaType.ALL_VALUE + ) + public + @ResponseBody + ResponseEntity<PayrollDistribution> getPayrollDistribution(@PathVariable(value = "identifier") final String customerIdentifier) { + this.throwIfCustomerNotExists(customerIdentifier); + return ResponseEntity.ok( + this.customerService.getPayrollDistribution(customerIdentifier).orElse(null) + ); + } + private Pageable createPageRequest(final Integer pageIndex, final Integer size, final String sortColumn, final String sortDirection) { final Integer pageIndexToUse = pageIndex != null ? pageIndex : 0; final Integer sizeToUse = size != null ? size : 20; diff --git a/service/src/main/resources/db/migrations/mariadb/V5__add_payroll_distributions.sql b/service/src/main/resources/db/migrations/mariadb/V5__add_payroll_distributions.sql new file mode 100644 index 0000000..1a50ac1 --- /dev/null +++ b/service/src/main/resources/db/migrations/mariadb/V5__add_payroll_distributions.sql @@ -0,0 +1,39 @@ +-- +-- 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. +-- + +CREATE TABLE maat_payroll_distributions ( + id BIGINT NOT NULL AUTO_INCREMENT, + customer_id BIGINT NOT NULL, + main_account_number VARCHAR(34) NOT NULL, + created_by VARCHAR(32) NOT NULL, + created_on TIMESTAMP(3) NOT NULL, + last_modified_by VARCHAR(32) NULL, + last_modified_on TIMESTAMP(3) NULL, + CONSTRAINT maat_payroll_distributions_pk PRIMARY KEY (id), + CONSTRAINT maat_payroll_dist_main_acct_uq UNIQUE (customer_id, main_account_number), + CONSTRAINT maat_payroll_dist_customers_fk FOREIGN KEY (customer_id) REFERENCES maat_customers (id) +); + +CREATE TABLE maat_payroll_allocations ( + id BIGINT NOT NULL AUTO_INCREMENT, + payroll_distribution_id BIGINT NOT NULL, + account_number VARCHAR(34) NOT NULL, + amount NUMERIC(15,5) NOT NULL, + proportional BOOLEAN NOT NULL, + CONSTRAINT maat_payroll_allocations_pk PRIMARY KEY (id), + CONSTRAINT maat_payroll_alloc_acct_uq UNIQUE (payroll_distribution_id, account_number), + CONSTRAINT maat_payroll_alloc_dist_fk FOREIGN KEY (payroll_distribution_id) REFERENCES maat_payroll_distributions (id) +); \ No newline at end of file -- To stop receiving notification emails like this one, please contact [email protected].
