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:50 UTC

[fineract-cn-payroll] 15/50: initial commit

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 118dd1df0e001f35cdbc3889f07915c5b60491b3
Author: mgeiss <mg...@mifos.org>
AuthorDate: Mon Sep 18 16:36:23 2017 +0200

    initial commit
---
 .gitignore                                         |   1 +
 README.md                                          |  47 +------
 .../events => payroll/api/v1}/EventConstants.java  |  16 ++-
 .../api/v1/PermittableGroupIds.java                |   6 +-
 .../api/v1/client/CustomerNotFoundException.java}  |   5 +-
 .../PayrollConfigurationNotFoundException.java     |   5 +-
 .../PayrollDistributionValidationException.java    |   5 +-
 .../payroll/api/v1/client/PayrollManager.java      |  96 ++++++++++++++
 .../client/PayrollPaymentValidationException.java  |   5 +-
 .../payroll/api/v1/domain/PayrollAllocation.java   |  62 +++++++++
 .../api/v1/domain/PayrollCollectionHistory.java    |  68 ++++++++++
 .../api/v1/domain/PayrollCollectionSheet.java      |  51 +++++++
 .../api/v1/domain/PayrollConfiguration.java        |  86 ++++++++++++
 .../payroll/api/v1/domain/PayrollPayment.java      |  63 +++++++++
 .../payroll/api/v1/domain/PayrollPaymentPage.java  |  61 +++++++++
 .../template/api/v1/client/TemplateManager.java    |  57 --------
 .../io/mifos/template/api/v1/domain/Sample.java    |  70 ----------
 .../mifos/template/api/v1/domain/SampleTest.java   |  55 --------
 component-test/build.gradle                        |   4 +-
 .../java/io/mifos/payroll/AbstractPayrollTest.java | 111 ++++++++++++++++
 .../SuiteTestEnvironment.java                      |   4 +-
 .../io/mifos/payroll/TestPayrollConfiguration.java | 118 +++++++++++++++++
 .../io/mifos/payroll/TestPayrollDistribution.java  | 101 ++++++++++++++
 .../io/mifos/{template => payroll}/TestSuite.java  |   6 +-
 .../payroll/domain/DomainObjectGenerator.java      |  46 +++++++
 .../listener/MigrationEventListener.java           |   4 +-
 .../listener/PayrollConfigurationListener.java}    |  24 ++--
 .../listener/PayrollDistributionListener.java}     |  22 ++--
 .../main/java/io/mifos/template/TestSample.java    | 130 ------------------
 component-test/src/main/resources/logback-test.xml |  34 +++++
 gradle/wrapper/gradle-wrapper.properties           |   4 +-
 service/build.gradle                               |   4 +-
 .../service/PayrollApplication.java}               |   8 +-
 .../service/PayrollServiceConfiguration.java}      |  23 ++--
 .../service/ServiceConstants.java                  |   4 +-
 .../command/DistributePayrollCommand.java}         |  24 ++--
 .../internal/command/MigrateServiceCommand.java}   |  12 +-
 .../command/PutPayrollConfigurationCommand.java    |  38 ++++++
 .../command/handler/MigrationAggregate.java        |  26 ++--
 .../handler/PayrollConfigurationAggregate.java     |  99 ++++++++++++++
 .../handler/PayrollDistributionAggregate.java      |  96 ++++++++++++++
 .../internal/mapper/PayrollAllocationMapper.java   |  42 ++++++
 .../mapper/PayrollConfigurationMapper.java         |  39 ++++++
 .../internal/mapper/PayrollPaymentMapper.java      |  34 +++++
 .../repository/PayrollAllocationEntity.java        |  89 +++++++++++++
 .../repository/PayrollAllocationRepository.java}   |  14 +-
 .../repository/PayrollCollectionEntity.java        |  89 +++++++++++++
 .../repository/PayrollCollectionRepository.java}   |   9 +-
 .../repository/PayrollConfigurationEntity.java     | 111 ++++++++++++++++
 .../PayrollConfigurationRepository.java}           |   6 +-
 .../internal/repository/PayrollPaymentEntity.java  |  89 +++++++++++++
 .../repository/PayrollPaymentRepository.java}      |  11 +-
 .../service/PayrollConfigurationService.java       |  83 ++++++++++++
 .../service/PayrollDistributionService.java        | 100 ++++++++++++++
 .../service/adaptor/AccountingAdaptor.java         | 112 ++++++++++++++++
 .../internal/service/adaptor/CustomerAdaptor.java  |  51 +++++++
 .../service/rest/MigrationRestController.java      |  56 ++++++++
 .../rest/PayrollConfigurationRestController.java   | 113 ++++++++++++++++
 .../rest/PayrollDistributionRestController.java    | 146 +++++++++++++++++++++
 .../payroll/service/rest/util/PageableBuilder.java |  41 ++++++
 .../internal/command/handler/SampleAggregate.java  |  65 ---------
 .../service/internal/mapper/SampleMapper.java      |  43 ------
 .../internal/repository/SampleJpaEntity.java       |  61 ---------
 .../service/internal/service/SampleService.java    |  45 -------
 .../service/rest/SampleRestController.java         | 112 ----------------
 service/src/main/resources/application.yml         |   2 +-
 service/src/main/resources/bootstrap.yml           |   2 +-
 .../db/migrations/mariadb/V1__initial_setup.sql    |  46 ++++++-
 service/src/main/resources/logback.xml             |  55 ++++++++
 settings.gradle                                    |   2 +-
 shared.gradle                                      |   4 +-
 71 files changed, 2561 insertions(+), 812 deletions(-)

diff --git a/.gitignore b/.gitignore
index f9d7cba..1d62734 100644
--- a/.gitignore
+++ b/.gitignore
@@ -2,6 +2,7 @@
 .idea
 build/
 target/
+out/
 
 # Ignore Gradle GUI config
 gradle-app.setting
diff --git a/README.md b/README.md
index 1839633..8636dff 100644
--- a/README.md
+++ b/README.md
@@ -1,49 +1,6 @@
-# Mifos I/O Template
+# Mifos I/O Payroll
 
-[![Join the chat at https://gitter.im/mifos-initiative/mifos.io](https://badges.gitter.im/Join%20Chat.svg)](https://gitter.im/mifos-initiative/mifos.io?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge)
-
-This project provides a template layout for all Mifos I/O microservices.
-
-## Abstract
-Mifos I/O is an application framework for digital financial services, a system to support nationwide and cross-national financial transactions and help to level and speed the creation of an inclusive, interconnected digital economy for every nation in the world.
-
-## Steps needed to turn the template project into a real project
-
-1.  Git clone template into {project name} folder
-
-        git clone https://github.com/mifosio/template.git {project name}
-
-2.  Delete _.git_
-
-        rm -rf .git
-    
-3.  Open settings.gradle and replace value of _rootProject.name_ with {project name}
-
-4.  Open root build.gradle and replace value of _version_ with 0.1.0-snapshot
-
-6.  Create Gradle wrapper
-
-        gradle wrapper
-
-6.  Open all module specific build.gradle files (api, service, and component-test) and replace value of _group_ with io.mifos.{project name}
-
-7.  Import project into IDE
-
-8.  Rename all io.mifos.template packages to io.mifos.{project name}
-
-9.  Open _SampleRestConfiguration_ and _SampleServiceConfiguration_, adjust @ComponentScan to reflect the new package name
-
-10. Open _application.yml_ and replace _server.contextPath_ with /{project name}/v1/*
-
-11. Open _bootstrap.yml_ and replace _spring.application.name_ with {project name}/v1/
-
-12. Open _SampleTest_ and replace constructor argument of TestEnvironment in line 80 with {project name}/v1/
-
-13. Run _SampleTest_
-
-14. Replace the contents of the README with text describing your new project.
-
-15. Happy coding! ; o) 
+This project provides functionality to configure payroll allocations and distribute payroll payments for customers.
 
 ## Versioning
 The version numbers follow the [Semantic Versioning](http://semver.org/) scheme.
diff --git a/api/src/main/java/io/mifos/template/api/v1/events/EventConstants.java b/api/src/main/java/io/mifos/payroll/api/v1/EventConstants.java
similarity index 67%
rename from api/src/main/java/io/mifos/template/api/v1/events/EventConstants.java
rename to api/src/main/java/io/mifos/payroll/api/v1/EventConstants.java
index 6207c03..72e925b 100644
--- a/api/src/main/java/io/mifos/template/api/v1/events/EventConstants.java
+++ b/api/src/main/java/io/mifos/payroll/api/v1/EventConstants.java
@@ -13,14 +13,26 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-package io.mifos.template.api.v1.events;
+package io.mifos.payroll.api.v1;
 
 @SuppressWarnings("unused")
 public interface EventConstants {
 
-  String DESTINATION = "template-v1";
+  String DESTINATION = "payroll-v1";
   String SELECTOR_NAME = "action";
+
+  // Migration events
   String INITIALIZE = "initialize";
+
+  // Payroll configuration events
+  String PUT_CONFIGURATION = "put-configuration";
+  String SELECTOR_PUT_CONFIGURATION = SELECTOR_NAME + " = '" + PUT_CONFIGURATION + "'";
+
+  // Payroll distribution events
+  String POST_DISTRIBUTION = "post-distribution";
+  String SELECTOR_POST_DISTRIBUTION = SELECTOR_NAME + " = '" + POST_DISTRIBUTION + "'";
+
+
   String POST_SAMPLE = "post-sample";
   String SELECTOR_INITIALIZE = SELECTOR_NAME + " = '" + INITIALIZE + "'";
   String SELECTOR_POST_SAMPLE = SELECTOR_NAME + " = '" + POST_SAMPLE + "'";
diff --git a/api/src/main/java/io/mifos/template/api/v1/PermittableGroupIds.java b/api/src/main/java/io/mifos/payroll/api/v1/PermittableGroupIds.java
similarity index 82%
rename from api/src/main/java/io/mifos/template/api/v1/PermittableGroupIds.java
rename to api/src/main/java/io/mifos/payroll/api/v1/PermittableGroupIds.java
index 239e2ac..f925986 100644
--- a/api/src/main/java/io/mifos/template/api/v1/PermittableGroupIds.java
+++ b/api/src/main/java/io/mifos/payroll/api/v1/PermittableGroupIds.java
@@ -13,10 +13,10 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-package io.mifos.template.api.v1;
+package io.mifos.payroll.api.v1;
 
 @SuppressWarnings("unused")
 public interface PermittableGroupIds {
-  String SAMPLE_MANAGEMENT = "template__v1__samples";
-  String SELF_MANAGEMENT = "template__v1__self";
+  String CONFIGURATION = "payroll__v1__configuration";
+  String DISTRIBUTION = "payroll__v1__distribution";
 }
diff --git a/api/src/main/java/io/mifos/template/api/v1/client/IamATeapotException.java b/api/src/main/java/io/mifos/payroll/api/v1/client/CustomerNotFoundException.java
similarity index 81%
rename from api/src/main/java/io/mifos/template/api/v1/client/IamATeapotException.java
rename to api/src/main/java/io/mifos/payroll/api/v1/client/CustomerNotFoundException.java
index ec4383c..ca8d1c8 100644
--- a/api/src/main/java/io/mifos/template/api/v1/client/IamATeapotException.java
+++ b/api/src/main/java/io/mifos/payroll/api/v1/client/CustomerNotFoundException.java
@@ -13,8 +13,7 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-package io.mifos.template.api.v1.client;
+package io.mifos.payroll.api.v1.client;
 
-@SuppressWarnings("WeakerAccess")
-public class IamATeapotException extends RuntimeException {
+public class CustomerNotFoundException extends RuntimeException {
 }
diff --git a/service/src/main/java/io/mifos/template/service/ServiceConstants.java b/api/src/main/java/io/mifos/payroll/api/v1/client/PayrollConfigurationNotFoundException.java
similarity index 83%
copy from service/src/main/java/io/mifos/template/service/ServiceConstants.java
copy to api/src/main/java/io/mifos/payroll/api/v1/client/PayrollConfigurationNotFoundException.java
index e9e0623..0c39d16 100644
--- a/service/src/main/java/io/mifos/template/service/ServiceConstants.java
+++ b/api/src/main/java/io/mifos/payroll/api/v1/client/PayrollConfigurationNotFoundException.java
@@ -13,8 +13,7 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-package io.mifos.template.service;
+package io.mifos.payroll.api.v1.client;
 
-public interface ServiceConstants {
-  String LOGGER_NAME = "rest-logger";
+public class PayrollConfigurationNotFoundException extends RuntimeException {
 }
diff --git a/service/src/main/java/io/mifos/template/service/ServiceConstants.java b/api/src/main/java/io/mifos/payroll/api/v1/client/PayrollDistributionValidationException.java
similarity index 83%
copy from service/src/main/java/io/mifos/template/service/ServiceConstants.java
copy to api/src/main/java/io/mifos/payroll/api/v1/client/PayrollDistributionValidationException.java
index e9e0623..2f330f2 100644
--- a/service/src/main/java/io/mifos/template/service/ServiceConstants.java
+++ b/api/src/main/java/io/mifos/payroll/api/v1/client/PayrollDistributionValidationException.java
@@ -13,8 +13,7 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-package io.mifos.template.service;
+package io.mifos.payroll.api.v1.client;
 
-public interface ServiceConstants {
-  String LOGGER_NAME = "rest-logger";
+public class PayrollDistributionValidationException extends RuntimeException {
 }
diff --git a/api/src/main/java/io/mifos/payroll/api/v1/client/PayrollManager.java b/api/src/main/java/io/mifos/payroll/api/v1/client/PayrollManager.java
new file mode 100644
index 0000000..5c232c0
--- /dev/null
+++ b/api/src/main/java/io/mifos/payroll/api/v1/client/PayrollManager.java
@@ -0,0 +1,96 @@
+/*
+ * 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.payroll.api.v1.client;
+
+import io.mifos.core.api.annotation.ThrowsException;
+import io.mifos.core.api.annotation.ThrowsExceptions;
+import io.mifos.core.api.util.CustomFeignClientsConfiguration;
+import io.mifos.payroll.api.v1.domain.PayrollCollectionHistory;
+import io.mifos.payroll.api.v1.domain.PayrollCollectionSheet;
+import io.mifos.payroll.api.v1.domain.PayrollConfiguration;
+import io.mifos.payroll.api.v1.domain.PayrollPaymentPage;
+import org.springframework.cloud.netflix.feign.FeignClient;
+import org.springframework.http.HttpStatus;
+import org.springframework.http.MediaType;
+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 javax.validation.Valid;
+import java.util.List;
+
+@SuppressWarnings("unused")
+@FeignClient(name="payroll-v1", path="/payroll/v1", configuration = CustomFeignClientsConfiguration.class)
+public interface PayrollManager {
+
+  @RequestMapping(
+      value = "/customers/{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 setPayrollConfiguration(@PathVariable(value = "identifier") final String customerIdentifier,
+                               @RequestBody @Valid final PayrollConfiguration payrollConfiguration);
+
+  @RequestMapping(
+      value = "/customers/{identifier}/payroll",
+      method = RequestMethod.GET,
+      produces = MediaType.ALL_VALUE,
+      consumes = MediaType.APPLICATION_JSON_VALUE
+  )
+  @ThrowsExceptions({
+      @ThrowsException(status = HttpStatus.NOT_FOUND, exception = PayrollConfigurationNotFoundException.class)
+  })
+  PayrollConfiguration findPayrollConfiguration(@PathVariable(value = "identifier") final String customerIdentifier);
+
+  @RequestMapping(
+      value = "/distribution",
+      method = RequestMethod.POST,
+      produces = MediaType.APPLICATION_JSON_VALUE,
+      consumes = MediaType.APPLICATION_JSON_VALUE
+  )
+  @ThrowsExceptions({
+      @ThrowsException(status = HttpStatus.BAD_REQUEST, exception = PayrollPaymentValidationException.class)
+  })
+  void distribute(@RequestBody @Valid final PayrollCollectionSheet payrollCollectionSheet);
+
+  @RequestMapping(
+      value = "/distribution",
+      method = RequestMethod.GET,
+      produces = MediaType.ALL_VALUE,
+      consumes = MediaType.APPLICATION_JSON_VALUE
+  )
+  List<PayrollCollectionHistory> fetchDistributionHistory();
+
+  @RequestMapping(
+      value = "/distribution/{identifier}/payments",
+      method = RequestMethod.GET,
+      produces = MediaType.ALL_VALUE,
+      consumes = MediaType.APPLICATION_JSON_VALUE
+  )
+  PayrollPaymentPage fetchPayments(@PathVariable("identifier") final String identifier,
+                                   @RequestParam(value = "pageIndex", required = false) final Integer pageIndex,
+                                   @RequestParam(value = "size", required = false) final Integer size,
+                                   @RequestParam(value = "sortColumn", required = false) final String sortColumn,
+                                   @RequestParam(value = "sortDirection", required = false) final String sortDirection);
+
+}
diff --git a/service/src/main/java/io/mifos/template/service/ServiceConstants.java b/api/src/main/java/io/mifos/payroll/api/v1/client/PayrollPaymentValidationException.java
similarity index 84%
copy from service/src/main/java/io/mifos/template/service/ServiceConstants.java
copy to api/src/main/java/io/mifos/payroll/api/v1/client/PayrollPaymentValidationException.java
index e9e0623..90ee5e5 100644
--- a/service/src/main/java/io/mifos/template/service/ServiceConstants.java
+++ b/api/src/main/java/io/mifos/payroll/api/v1/client/PayrollPaymentValidationException.java
@@ -13,8 +13,7 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-package io.mifos.template.service;
+package io.mifos.payroll.api.v1.client;
 
-public interface ServiceConstants {
-  String LOGGER_NAME = "rest-logger";
+public class PayrollPaymentValidationException extends RuntimeException {
 }
diff --git a/api/src/main/java/io/mifos/payroll/api/v1/domain/PayrollAllocation.java b/api/src/main/java/io/mifos/payroll/api/v1/domain/PayrollAllocation.java
new file mode 100644
index 0000000..3a4d42c
--- /dev/null
+++ b/api/src/main/java/io/mifos/payroll/api/v1/domain/PayrollAllocation.java
@@ -0,0 +1,62 @@
+/*
+ * 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.payroll.api.v1.domain;
+
+import io.mifos.core.lang.validation.constraints.ValidIdentifier;
+
+import javax.validation.constraints.DecimalMax;
+import javax.validation.constraints.DecimalMin;
+import javax.validation.constraints.NotNull;
+import java.math.BigDecimal;
+
+public class PayrollAllocation {
+
+  @ValidIdentifier(maxLength = 34)
+  private String accountNumber;
+  @NotNull
+  @DecimalMin("0.001")
+  @DecimalMax("9999999999.99999")
+  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/payroll/api/v1/domain/PayrollCollectionHistory.java b/api/src/main/java/io/mifos/payroll/api/v1/domain/PayrollCollectionHistory.java
new file mode 100644
index 0000000..b0b5f77
--- /dev/null
+++ b/api/src/main/java/io/mifos/payroll/api/v1/domain/PayrollCollectionHistory.java
@@ -0,0 +1,68 @@
+/*
+ * 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.payroll.api.v1.domain;
+
+import io.mifos.core.lang.validation.constraints.ValidIdentifier;
+
+import javax.validation.constraints.NotNull;
+
+public class PayrollCollectionHistory {
+
+  @ValidIdentifier
+  private String identifier;
+  @ValidIdentifier(maxLength = 34)
+  private String sourceAccountNumber;
+  @ValidIdentifier
+  private String createdBy;
+  @NotNull
+  private String createdOn;
+
+  public PayrollCollectionHistory() {
+    super();
+  }
+
+  public String getIdentifier() {
+    return this.identifier;
+  }
+
+  public void setIdentifier(final String identifier) {
+    this.identifier = identifier;
+  }
+
+  public String getSourceAccountNumber() {
+    return this.sourceAccountNumber;
+  }
+
+  public void setSourceAccountNumber(final String sourceAccountNumber) {
+    this.sourceAccountNumber = sourceAccountNumber;
+  }
+
+  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;
+  }
+}
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
new file mode 100644
index 0000000..99f2f78
--- /dev/null
+++ b/api/src/main/java/io/mifos/payroll/api/v1/domain/PayrollCollectionSheet.java
@@ -0,0 +1,51 @@
+/*
+ * 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.payroll.api.v1.domain;
+
+import io.mifos.core.lang.validation.constraints.ValidIdentifier;
+
+import javax.validation.Valid;
+import javax.validation.constraints.NotNull;
+import java.util.List;
+
+public class PayrollCollectionSheet {
+
+  @ValidIdentifier(maxLength = 34)
+  private String sourceAccountNumber;
+  @NotNull
+  @Valid
+  private List<PayrollPayment> payrollPayments;
+
+  public PayrollCollectionSheet() {
+    super();
+  }
+
+  public String getSourceAccountNumber() {
+    return this.sourceAccountNumber;
+  }
+
+  public void setSourceAccountNumber(final String sourceAccountNumber) {
+    this.sourceAccountNumber = sourceAccountNumber;
+  }
+
+  public List<PayrollPayment> getPayrollPayments() {
+    return this.payrollPayments;
+  }
+
+  public void setPayrollPayments(final List<PayrollPayment> payrollPayments) {
+    this.payrollPayments = payrollPayments;
+  }
+}
diff --git a/api/src/main/java/io/mifos/payroll/api/v1/domain/PayrollConfiguration.java b/api/src/main/java/io/mifos/payroll/api/v1/domain/PayrollConfiguration.java
new file mode 100644
index 0000000..5375a9a
--- /dev/null
+++ b/api/src/main/java/io/mifos/payroll/api/v1/domain/PayrollConfiguration.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.payroll.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 PayrollConfiguration {
+
+  @ValidIdentifier(maxLength = 34)
+  private String mainAccountNumber;
+  @Valid
+  private Set<PayrollAllocation> payrollAllocations = new HashSet<>();
+  private String createdBy;
+  private String createdOn;
+  private String lastModifiedBy;
+  private String lastModifiedOn;
+
+  public PayrollConfiguration() {
+    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/payroll/api/v1/domain/PayrollPayment.java b/api/src/main/java/io/mifos/payroll/api/v1/domain/PayrollPayment.java
new file mode 100644
index 0000000..50daa4b
--- /dev/null
+++ b/api/src/main/java/io/mifos/payroll/api/v1/domain/PayrollPayment.java
@@ -0,0 +1,63 @@
+/*
+ * 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.payroll.api.v1.domain;
+
+import io.mifos.core.lang.validation.constraints.ValidIdentifier;
+
+import javax.validation.constraints.DecimalMax;
+import javax.validation.constraints.DecimalMin;
+import javax.validation.constraints.NotNull;
+import java.math.BigDecimal;
+
+public class PayrollPayment {
+
+  @ValidIdentifier
+  private String customerIdentifier;
+  @NotNull
+  private String employer;
+  @NotNull
+  @DecimalMin("0.001")
+  @DecimalMax("9999999999.99999")
+  private BigDecimal salary;
+
+  public PayrollPayment() {
+    super();
+  }
+
+  public String getCustomerIdentifier() {
+    return this.customerIdentifier;
+  }
+
+  public void setCustomerIdentifier(final String customerIdentifier) {
+    this.customerIdentifier = customerIdentifier;
+  }
+
+  public String getEmployer() {
+    return this.employer;
+  }
+
+  public void setEmployer(final String employer) {
+    this.employer = employer;
+  }
+
+  public BigDecimal getSalary() {
+    return this.salary;
+  }
+
+  public void setSalary(final BigDecimal salary) {
+    this.salary = salary;
+  }
+}
diff --git a/api/src/main/java/io/mifos/payroll/api/v1/domain/PayrollPaymentPage.java b/api/src/main/java/io/mifos/payroll/api/v1/domain/PayrollPaymentPage.java
new file mode 100644
index 0000000..2e28399
--- /dev/null
+++ b/api/src/main/java/io/mifos/payroll/api/v1/domain/PayrollPaymentPage.java
@@ -0,0 +1,61 @@
+/*
+ * 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.payroll.api.v1.domain;
+
+import java.util.ArrayList;
+import java.util.List;
+
+public class PayrollPaymentPage {
+
+  private List<PayrollPayment> payrollPayments;
+  private Integer totalPages;
+  private Long totalElements;
+
+  public PayrollPaymentPage() {
+    super();
+  }
+
+  public List<PayrollPayment> getPayrollPayments() {
+    return this.payrollPayments;
+  }
+
+  public void setPayrollPayments(final List<PayrollPayment> payrollPayments) {
+    this.payrollPayments = payrollPayments;
+  }
+
+  public Integer getTotalPages() {
+    return this.totalPages;
+  }
+
+  public void setTotalPages(final Integer totalPages) {
+    this.totalPages = totalPages;
+  }
+
+  public Long getTotalElements() {
+    return this.totalElements;
+  }
+
+  public void setTotalElements(final Long totalElements) {
+    this.totalElements = totalElements;
+  }
+
+  public void add(final PayrollPayment payrollPayment) {
+    if (this.payrollPayments == null) {
+      this.payrollPayments = new ArrayList<>();
+    }
+    this.payrollPayments.add(payrollPayment);
+  }
+}
diff --git a/api/src/main/java/io/mifos/template/api/v1/client/TemplateManager.java b/api/src/main/java/io/mifos/template/api/v1/client/TemplateManager.java
deleted file mode 100644
index 9914e36..0000000
--- a/api/src/main/java/io/mifos/template/api/v1/client/TemplateManager.java
+++ /dev/null
@@ -1,57 +0,0 @@
-/*
- * 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.template.api.v1.client;
-
-import io.mifos.core.api.annotation.ThrowsException;
-import io.mifos.core.api.util.CustomFeignClientsConfiguration;
-import io.mifos.template.api.v1.domain.Sample;
-import org.springframework.cloud.netflix.feign.FeignClient;
-import org.springframework.http.HttpStatus;
-import org.springframework.http.MediaType;
-import org.springframework.web.bind.annotation.PathVariable;
-import org.springframework.web.bind.annotation.RequestMapping;
-import org.springframework.web.bind.annotation.RequestMethod;
-
-import java.util.List;
-
-@SuppressWarnings("unused")
-@FeignClient(value="template-v1", path="/template/v1", configuration = CustomFeignClientsConfiguration.class)
-public interface TemplateManager {
-
-  @RequestMapping(
-          value = "/sample",
-          method = RequestMethod.GET,
-          produces = MediaType.ALL_VALUE,
-          consumes = MediaType.APPLICATION_JSON_VALUE
-  )
-  List<Sample> findAllEntities();
-
-  @RequestMapping(
-          value = "/sample/{identifier}",
-          method = RequestMethod.GET,
-          produces = MediaType.ALL_VALUE,
-          consumes = MediaType.APPLICATION_JSON_VALUE)
-  Sample getEntity(@PathVariable("identifier") final String identifier);
-
-  @RequestMapping(
-      value = "/sample",
-      method = RequestMethod.POST,
-      produces = MediaType.APPLICATION_JSON_VALUE,
-      consumes = MediaType.APPLICATION_JSON_VALUE
-  )
-  @ThrowsException(status = HttpStatus.I_AM_A_TEAPOT, exception = IamATeapotException.class)
-  void createEntity(final Sample sample);
-}
diff --git a/api/src/main/java/io/mifos/template/api/v1/domain/Sample.java b/api/src/main/java/io/mifos/template/api/v1/domain/Sample.java
deleted file mode 100644
index 6f25719..0000000
--- a/api/src/main/java/io/mifos/template/api/v1/domain/Sample.java
+++ /dev/null
@@ -1,70 +0,0 @@
-/*
- * 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.template.api.v1.domain;
-
-import io.mifos.core.lang.validation.constraints.ValidIdentifier;
-import org.hibernate.validator.constraints.Length;
-
-import java.util.Objects;
-
-@SuppressWarnings({"WeakerAccess", "unused"})
-public class Sample {
-  @ValidIdentifier
-  private String identifier;
-  @Length(max = 512)
-  private String payload;
-
-  public Sample() {
-    super();
-  }
-
-  public static Sample create(final String identifier, final String payload) {
-    final Sample sample = new Sample();
-    sample.setIdentifier(identifier);
-    sample.setPayload(payload);
-    return sample;
-  }
-
-  public String getIdentifier() {
-    return this.identifier;
-  }
-
-  public void setIdentifier(final String identifier) {
-    this.identifier = identifier;
-  }
-
-  public String getPayload() {
-    return payload;
-  }
-
-  public void setPayload(String payload) {
-    this.payload = payload;
-  }
-
-  @Override
-  public boolean equals(Object o) {
-    if (this == o) return true;
-    if (o == null || getClass() != o.getClass()) return false;
-    Sample sample = (Sample) o;
-    return Objects.equals(identifier, sample.identifier) &&
-            Objects.equals(payload, sample.payload);
-  }
-
-  @Override
-  public int hashCode() {
-    return Objects.hash(identifier, payload);
-  }
-}
diff --git a/api/src/test/java/io/mifos/template/api/v1/domain/SampleTest.java b/api/src/test/java/io/mifos/template/api/v1/domain/SampleTest.java
deleted file mode 100644
index acf33cb..0000000
--- a/api/src/test/java/io/mifos/template/api/v1/domain/SampleTest.java
+++ /dev/null
@@ -1,55 +0,0 @@
-/*
- * 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.template.api.v1.domain;
-
-import io.mifos.core.test.domain.ValidationTest;
-import io.mifos.core.test.domain.ValidationTestCase;
-import org.apache.commons.lang.RandomStringUtils;
-import org.junit.runners.Parameterized;
-
-import java.util.ArrayList;
-import java.util.Collection;
-
-public class SampleTest extends ValidationTest<Sample> {
-
-  public SampleTest(ValidationTestCase<Sample> testCase) {
-    super(testCase);
-  }
-
-  @Override
-  protected Sample createValidTestSubject() {
-    return Sample.create("xxxx", "yyy");
-  }
-
-  @Parameterized.Parameters
-  public static Collection testCases() {
-    final Collection<ValidationTestCase> ret = new ArrayList<>();
-    ret.add(new ValidationTestCase<Sample>("basicCase")
-            .adjustment(x -> {})
-            .valid(true));
-    ret.add(new ValidationTestCase<Sample>("nullIdentifier")
-            .adjustment(x -> x.setIdentifier(null))
-            .valid(false));
-    ret.add(new ValidationTestCase<Sample>("tooShortIdentifier")
-            .adjustment(x -> x.setIdentifier("z"))
-            .valid(false));
-    ret.add(new ValidationTestCase<Sample>("tooLongPayload")
-            .adjustment(x -> x.setPayload(RandomStringUtils.randomAlphanumeric(513)))
-            .valid(false));
-    return ret;
-  }
-
-}
\ No newline at end of file
diff --git a/component-test/build.gradle b/component-test/build.gradle
index 7818273..4e0cc53 100644
--- a/component-test/build.gradle
+++ b/component-test/build.gradle
@@ -19,8 +19,8 @@ apply from: '../shared.gradle'
 
 dependencies {
     compile(
-            [group: 'io.mifos.template', name: 'api', version: project.version],
-            [group: 'io.mifos.template', name: 'service', version: project.version],
+            [group: 'io.mifos.payroll', name: 'api', version: project.version],
+            [group: 'io.mifos.payroll', name: 'service', version: project.version],
             [group: 'io.mifos.anubis', name: 'test', version: versions.frameworkanubis],
             [group: 'io.mifos.core', name: 'api', version: versions.frameworkapi],
             [group: 'io.mifos.core', name: 'test', version: versions.frameworktest],
diff --git a/component-test/src/main/java/io/mifos/payroll/AbstractPayrollTest.java b/component-test/src/main/java/io/mifos/payroll/AbstractPayrollTest.java
new file mode 100644
index 0000000..a995040
--- /dev/null
+++ b/component-test/src/main/java/io/mifos/payroll/AbstractPayrollTest.java
@@ -0,0 +1,111 @@
+/*
+ * 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.payroll;
+
+
+import io.mifos.anubis.test.v1.TenantApplicationSecurityEnvironmentTestRule;
+import io.mifos.core.api.context.AutoUserContext;
+import io.mifos.core.test.fixture.TenantDataStoreContextTestRule;
+import io.mifos.core.test.listener.EnableEventRecording;
+import io.mifos.core.test.listener.EventRecorder;
+import io.mifos.payroll.api.v1.EventConstants;
+import io.mifos.payroll.api.v1.client.PayrollManager;
+import io.mifos.payroll.service.PayrollServiceConfiguration;
+import org.junit.After;
+import org.junit.Before;
+import org.junit.ClassRule;
+import org.junit.Rule;
+import org.junit.runner.RunWith;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.boot.test.context.SpringBootTest;
+import org.springframework.cloud.netflix.feign.EnableFeignClients;
+import org.springframework.cloud.netflix.ribbon.RibbonClient;
+import org.springframework.context.annotation.ComponentScan;
+import org.springframework.context.annotation.Configuration;
+import org.springframework.context.annotation.Import;
+import org.springframework.test.context.junit4.SpringRunner;
+
+@RunWith(SpringRunner.class)
+@SpringBootTest(
+    webEnvironment = SpringBootTest.WebEnvironment.DEFINED_PORT,
+    classes = {
+        AbstractPayrollTest.TestConfiguration.class
+    }
+)
+public class AbstractPayrollTest extends SuiteTestEnvironment {
+
+  @Configuration
+  @EnableEventRecording
+  @EnableFeignClients(basePackages = {
+      "io.mifos.payroll.api.v1.client"
+  })
+  @RibbonClient(name = SuiteTestEnvironment.APP_NAME)
+  @ComponentScan(
+      basePackages = {
+          "io.mifos.payroll.listener"
+      }
+  )
+  @Import({
+      PayrollServiceConfiguration.class
+  })
+  public static class TestConfiguration {
+    public TestConfiguration() {
+      super();
+    }
+  }
+
+  static final String TEST_USER = "mage";
+
+  @ClassRule
+  public final static TenantDataStoreContextTestRule tenantDataStoreContext =
+      TenantDataStoreContextTestRule.forRandomTenantName(SuiteTestEnvironment.cassandraInitializer,
+          SuiteTestEnvironment.mariaDBInitializer);
+
+  @Rule
+  public final TenantApplicationSecurityEnvironmentTestRule tenantApplicationSecurityEnvironment
+      = new TenantApplicationSecurityEnvironmentTestRule(SuiteTestEnvironment.testEnvironment, this::waitForInitialize);
+
+  @Autowired
+  EventRecorder eventRecorder;
+
+  private AutoUserContext userContext;
+
+  @Autowired
+  PayrollManager testSubject;
+
+  public AbstractPayrollTest() {
+    super();
+  }
+
+  @Before
+  public void prepareTest() {
+    this.userContext = this.tenantApplicationSecurityEnvironment.createAutoUserContext(AbstractPayrollTest.TEST_USER);
+  }
+
+  @After
+  public void cleanupTest() {
+    userContext.close();
+  }
+
+  public boolean waitForInitialize() {
+    try {
+      return this.eventRecorder.wait(EventConstants.INITIALIZE, SuiteTestEnvironment.APP_VERSION);
+    } catch (final InterruptedException e) {
+      throw new IllegalStateException(e);
+    }
+  }
+
+}
diff --git a/component-test/src/main/java/io/mifos/template/SuiteTestEnvironment.java b/component-test/src/main/java/io/mifos/payroll/SuiteTestEnvironment.java
similarity index 95%
rename from component-test/src/main/java/io/mifos/template/SuiteTestEnvironment.java
rename to component-test/src/main/java/io/mifos/payroll/SuiteTestEnvironment.java
index 923cf79..8341aec 100644
--- a/component-test/src/main/java/io/mifos/template/SuiteTestEnvironment.java
+++ b/component-test/src/main/java/io/mifos/payroll/SuiteTestEnvironment.java
@@ -13,7 +13,7 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-package io.mifos.template;
+package io.mifos.payroll;
 
 import io.mifos.core.test.env.TestEnvironment;
 import io.mifos.core.test.fixture.cassandra.CassandraInitializer;
@@ -31,7 +31,7 @@ import org.junit.rules.TestRule;
  */
 public class SuiteTestEnvironment {
   static final String APP_VERSION = "1";
-  static final String APP_NAME = "template-v" + APP_VERSION;
+  static final String APP_NAME = "payroll-v" + APP_VERSION;
 
   static final TestEnvironment testEnvironment = new TestEnvironment(APP_NAME);
   static final CassandraInitializer cassandraInitializer = new CassandraInitializer();
diff --git a/component-test/src/main/java/io/mifos/payroll/TestPayrollConfiguration.java b/component-test/src/main/java/io/mifos/payroll/TestPayrollConfiguration.java
new file mode 100644
index 0000000..f2db0c4
--- /dev/null
+++ b/component-test/src/main/java/io/mifos/payroll/TestPayrollConfiguration.java
@@ -0,0 +1,118 @@
+/*
+ * 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.payroll;
+
+import com.google.common.collect.Sets;
+import io.mifos.accounting.api.v1.domain.Account;
+import io.mifos.customer.api.v1.domain.Customer;
+import io.mifos.payroll.api.v1.EventConstants;
+import io.mifos.payroll.api.v1.domain.PayrollAllocation;
+import io.mifos.payroll.api.v1.domain.PayrollConfiguration;
+import io.mifos.payroll.domain.DomainObjectGenerator;
+import io.mifos.payroll.service.internal.service.adaptor.AccountingAdaptor;
+import io.mifos.payroll.service.internal.service.adaptor.CustomerAdaptor;
+import org.apache.commons.lang3.RandomStringUtils;
+import org.junit.Assert;
+import org.junit.Test;
+import org.mockito.Matchers;
+import org.mockito.Mockito;
+import org.springframework.boot.test.mock.mockito.MockBean;
+
+import java.math.BigDecimal;
+import java.util.Optional;
+
+public class TestPayrollConfiguration extends AbstractPayrollTest {
+
+  @MockBean
+  private CustomerAdaptor customerAdaptorSpy;
+  @MockBean
+  private AccountingAdaptor accountingAdaptorSpy;
+
+  public TestPayrollConfiguration() {
+    super();
+  }
+
+  @Test
+  public void shouldCreatePayrollDistribution() throws Exception {
+    final String customerIdentifier = RandomStringUtils.randomAlphanumeric(32);
+    final PayrollConfiguration payrollConfiguration = DomainObjectGenerator.getPayrollConfiguration();
+    this.prepareMocks(customerIdentifier, payrollConfiguration);
+
+    super.testSubject.setPayrollConfiguration(customerIdentifier, payrollConfiguration);
+    Assert.assertTrue(super.eventRecorder.wait(EventConstants.PUT_CONFIGURATION, customerIdentifier));
+  }
+
+  @Test
+  public void shouldUpdatePayrollDistribution() throws Exception {
+    final String customerIdentifier = RandomStringUtils.randomAlphanumeric(32);
+    final PayrollConfiguration payrollConfiguration = DomainObjectGenerator.getPayrollConfiguration();
+    this.prepareMocks(customerIdentifier, payrollConfiguration);
+
+    super.testSubject.setPayrollConfiguration(customerIdentifier, payrollConfiguration);
+    Assert.assertTrue(super.eventRecorder.wait(EventConstants.PUT_CONFIGURATION, customerIdentifier));
+
+    final PayrollAllocation newPayrollAllocation = new PayrollAllocation();
+    payrollConfiguration.setPayrollAllocations(Sets.newHashSet(newPayrollAllocation));
+    newPayrollAllocation.setAccountNumber(RandomStringUtils.randomAlphanumeric(34));
+    newPayrollAllocation.setAmount(BigDecimal.valueOf(15.00D));
+    newPayrollAllocation.setProportional(Boolean.FALSE);
+
+    Mockito
+        .doAnswer(invocation -> Optional.of(new Account()))
+        .when(this.accountingAdaptorSpy).findAccount(Matchers.eq(newPayrollAllocation.getAccountNumber()));
+
+    super.testSubject.setPayrollConfiguration(customerIdentifier, payrollConfiguration);
+    Assert.assertTrue(super.eventRecorder.wait(EventConstants.PUT_CONFIGURATION, customerIdentifier));
+
+    Thread.sleep(500L);
+
+    final PayrollConfiguration fetchedPayrollConfiguration =
+        super.testSubject.findPayrollConfiguration(customerIdentifier);
+
+    Assert.assertNotNull(fetchedPayrollConfiguration.getLastModifiedBy());
+    Assert.assertNotNull(fetchedPayrollConfiguration.getLastModifiedOn());
+    Assert.assertEquals(1, fetchedPayrollConfiguration.getPayrollAllocations().size());
+
+    final Optional<PayrollAllocation> optionalPayrollAllocation =
+        fetchedPayrollConfiguration.getPayrollAllocations().stream().findFirst();
+
+    Assert.assertTrue(optionalPayrollAllocation.isPresent());
+
+    this.comparePayrollAllocations(newPayrollAllocation, optionalPayrollAllocation.get());
+  }
+
+  private void prepareMocks(final String customerIdentifier, final PayrollConfiguration payrollConfiguration) {
+    Mockito
+        .doAnswer(invocation -> Optional.of(new Customer()))
+        .when(this.customerAdaptorSpy).findCustomer(Matchers.eq(customerIdentifier));
+
+    Mockito
+        .doAnswer(invocation -> Optional.of(new Account()))
+        .when(this.accountingAdaptorSpy).findAccount(Matchers.eq(payrollConfiguration.getMainAccountNumber()));
+
+    payrollConfiguration.getPayrollAllocations().forEach(payrollAllocation ->
+        Mockito
+            .doAnswer(invocation -> Optional.of(new Account()))
+            .when(this.accountingAdaptorSpy).findAccount(Matchers.eq(payrollAllocation.getAccountNumber()))
+    );
+  }
+
+  private void comparePayrollAllocations(final PayrollAllocation expected, final PayrollAllocation actual) {
+    Assert.assertEquals(expected.getAccountNumber(), actual.getAccountNumber());
+    Assert.assertTrue(expected.getAmount().compareTo(actual.getAmount()) == 0);
+    Assert.assertEquals(expected.getProportional(), actual.getProportional());
+  }
+}
diff --git a/component-test/src/main/java/io/mifos/payroll/TestPayrollDistribution.java b/component-test/src/main/java/io/mifos/payroll/TestPayrollDistribution.java
new file mode 100644
index 0000000..0bcae44
--- /dev/null
+++ b/component-test/src/main/java/io/mifos/payroll/TestPayrollDistribution.java
@@ -0,0 +1,101 @@
+/*
+ * 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.payroll;
+
+import com.google.common.collect.Lists;
+import io.mifos.accounting.api.v1.domain.Account;
+import io.mifos.customer.api.v1.domain.Customer;
+import io.mifos.payroll.api.v1.EventConstants;
+import io.mifos.payroll.api.v1.domain.PayrollCollectionHistory;
+import io.mifos.payroll.api.v1.domain.PayrollCollectionSheet;
+import io.mifos.payroll.api.v1.domain.PayrollConfiguration;
+import io.mifos.payroll.api.v1.domain.PayrollPayment;
+import io.mifos.payroll.api.v1.domain.PayrollPaymentPage;
+import io.mifos.payroll.domain.DomainObjectGenerator;
+import io.mifos.payroll.service.internal.service.adaptor.AccountingAdaptor;
+import io.mifos.payroll.service.internal.service.adaptor.CustomerAdaptor;
+import org.apache.commons.lang3.RandomStringUtils;
+import org.junit.Assert;
+import org.junit.Test;
+import org.mockito.Matchers;
+import org.mockito.Mockito;
+import org.springframework.boot.test.mock.mockito.MockBean;
+
+import java.math.BigDecimal;
+import java.util.List;
+import java.util.Optional;
+
+public class TestPayrollDistribution extends AbstractPayrollTest {
+
+  @MockBean
+  private CustomerAdaptor customerAdaptorSpy;
+  @MockBean
+  private AccountingAdaptor accountingAdaptorSpy;
+
+  public TestPayrollDistribution() {
+    super();
+  }
+
+  @Test
+  public void shouldDistributePayments() throws Exception {
+    final String customerIdentifier = RandomStringUtils.randomAlphanumeric(32);
+    final PayrollConfiguration payrollConfiguration = DomainObjectGenerator.getPayrollConfiguration();
+    this.prepareMocks(customerIdentifier, payrollConfiguration);
+
+    super.testSubject.setPayrollConfiguration(customerIdentifier, payrollConfiguration);
+    Assert.assertTrue(super.eventRecorder.wait(EventConstants.PUT_CONFIGURATION, customerIdentifier));
+
+    final PayrollCollectionSheet payrollCollectionSheet = new PayrollCollectionSheet();
+    payrollCollectionSheet.setSourceAccountNumber(RandomStringUtils.randomAlphanumeric(34));
+    final PayrollPayment payrollPayment = new PayrollPayment();
+    payrollPayment.setCustomerIdentifier(customerIdentifier);
+    payrollPayment.setEmployer("ACME, Inc.");
+    payrollPayment.setSalary(BigDecimal.valueOf(1234.56D));
+    payrollCollectionSheet.setPayrollPayments(Lists.newArrayList(payrollPayment));
+
+    Mockito
+        .doAnswer(invocation -> Optional.of(new Account()))
+        .when(this.accountingAdaptorSpy).findAccount(Matchers.eq(payrollCollectionSheet.getSourceAccountNumber()));
+
+    super.testSubject.distribute(payrollCollectionSheet);
+    Assert.assertTrue(super.eventRecorder.wait(EventConstants.POST_DISTRIBUTION, payrollCollectionSheet.getSourceAccountNumber()));
+
+    final List<PayrollCollectionHistory> payrollCollectionHistories = super.testSubject.fetchDistributionHistory();
+    Assert.assertEquals(1, payrollCollectionHistories.size());
+
+    final PayrollCollectionHistory payrollCollectionHistory = payrollCollectionHistories.get(0);
+    final PayrollPaymentPage payrollPaymentPage =
+        super.testSubject.fetchPayments(payrollCollectionHistory.getIdentifier(), 0, 10, null, null);
+    Assert.assertEquals(Long.valueOf(1L), payrollPaymentPage.getTotalElements());
+  }
+
+  private void prepareMocks(final String customerIdentifier, final PayrollConfiguration payrollConfiguration) {
+    Mockito
+        .doAnswer(invocation -> Optional.of(new Customer()))
+        .when(this.customerAdaptorSpy).findCustomer(Matchers.eq(customerIdentifier));
+
+    Mockito
+        .doAnswer(invocation -> Optional.of(new Account()))
+        .when(this.accountingAdaptorSpy).findAccount(Matchers.eq(payrollConfiguration.getMainAccountNumber()));
+
+    payrollConfiguration.getPayrollAllocations().forEach(payrollAllocation ->
+        Mockito
+            .doAnswer(invocation -> Optional.of(new Account()))
+            .when(this.accountingAdaptorSpy).findAccount(Matchers.eq(payrollAllocation.getAccountNumber()))
+    );
+  }
+
+}
diff --git a/component-test/src/main/java/io/mifos/template/TestSuite.java b/component-test/src/main/java/io/mifos/payroll/TestSuite.java
similarity index 84%
rename from component-test/src/main/java/io/mifos/template/TestSuite.java
rename to component-test/src/main/java/io/mifos/payroll/TestSuite.java
index 44ed340..09862e8 100644
--- a/component-test/src/main/java/io/mifos/template/TestSuite.java
+++ b/component-test/src/main/java/io/mifos/payroll/TestSuite.java
@@ -13,15 +13,15 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-package io.mifos.template;
+package io.mifos.payroll;
 
 import org.junit.runner.RunWith;
 import org.junit.runners.Suite;
 
 @RunWith(Suite.class)
 @Suite.SuiteClasses({
-    TestSample.class,
-    //TODO: when you create a new component test, add it here so you can run it with the suite.
+    TestPayrollConfiguration.class,
+    TestPayrollDistribution.class
 })
 public class TestSuite extends SuiteTestEnvironment {
 }
diff --git a/component-test/src/main/java/io/mifos/payroll/domain/DomainObjectGenerator.java b/component-test/src/main/java/io/mifos/payroll/domain/DomainObjectGenerator.java
new file mode 100644
index 0000000..389cde2
--- /dev/null
+++ b/component-test/src/main/java/io/mifos/payroll/domain/DomainObjectGenerator.java
@@ -0,0 +1,46 @@
+/*
+ * 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.payroll.domain;
+
+import io.mifos.payroll.api.v1.domain.PayrollAllocation;
+import io.mifos.payroll.api.v1.domain.PayrollConfiguration;
+import org.apache.commons.lang3.RandomStringUtils;
+
+import java.math.BigDecimal;
+import java.util.HashSet;
+
+public class DomainObjectGenerator {
+
+  private DomainObjectGenerator() {
+    super();
+  }
+
+  public static PayrollConfiguration getPayrollConfiguration() {
+    final PayrollConfiguration payrollConfiguration = new PayrollConfiguration();
+    payrollConfiguration.setMainAccountNumber(RandomStringUtils.randomAlphanumeric(34));
+
+    final HashSet<PayrollAllocation> payrollAllocations = new HashSet<>();
+    payrollConfiguration.setPayrollAllocations(payrollAllocations);
+
+    final PayrollAllocation savingsAllocation = new PayrollAllocation();
+    payrollAllocations.add(savingsAllocation);
+    savingsAllocation.setAccountNumber(RandomStringUtils.randomAlphanumeric(34));
+    savingsAllocation.setAmount(BigDecimal.valueOf(5.00D));
+    savingsAllocation.setProportional(Boolean.TRUE);
+
+    return payrollConfiguration;
+  }
+}
diff --git a/component-test/src/main/java/io/mifos/template/listener/MigrationEventListener.java b/component-test/src/main/java/io/mifos/payroll/listener/MigrationEventListener.java
similarity index 94%
copy from component-test/src/main/java/io/mifos/template/listener/MigrationEventListener.java
copy to component-test/src/main/java/io/mifos/payroll/listener/MigrationEventListener.java
index 52be53b..b521aad 100644
--- a/component-test/src/main/java/io/mifos/template/listener/MigrationEventListener.java
+++ b/component-test/src/main/java/io/mifos/payroll/listener/MigrationEventListener.java
@@ -13,11 +13,11 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-package io.mifos.template.listener;
+package io.mifos.payroll.listener;
 
 import io.mifos.core.lang.config.TenantHeaderFilter;
 import io.mifos.core.test.listener.EventRecorder;
-import io.mifos.template.api.v1.events.EventConstants;
+import io.mifos.payroll.api.v1.EventConstants;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.jms.annotation.JmsListener;
 import org.springframework.messaging.handler.annotation.Header;
diff --git a/component-test/src/main/java/io/mifos/template/listener/SampleEventListener.java b/component-test/src/main/java/io/mifos/payroll/listener/PayrollConfigurationListener.java
similarity index 57%
rename from component-test/src/main/java/io/mifos/template/listener/SampleEventListener.java
rename to component-test/src/main/java/io/mifos/payroll/listener/PayrollConfigurationListener.java
index b54a819..66e5719 100644
--- a/component-test/src/main/java/io/mifos/template/listener/SampleEventListener.java
+++ b/component-test/src/main/java/io/mifos/payroll/listener/PayrollConfigurationListener.java
@@ -13,35 +13,41 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-package io.mifos.template.listener;
+package io.mifos.payroll.listener;
 
 import io.mifos.core.lang.config.TenantHeaderFilter;
 import io.mifos.core.test.listener.EventRecorder;
-import io.mifos.template.api.v1.events.EventConstants;
+import io.mifos.payroll.api.v1.EventConstants;
+import io.mifos.payroll.service.ServiceConstants;
+import org.slf4j.Logger;
 import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.beans.factory.annotation.Qualifier;
 import org.springframework.jms.annotation.JmsListener;
 import org.springframework.messaging.handler.annotation.Header;
 import org.springframework.stereotype.Component;
 
-@SuppressWarnings("unused")
 @Component
-public class SampleEventListener {
+public class PayrollConfigurationListener {
 
+  private final Logger logger;
   private final EventRecorder eventRecorder;
 
   @Autowired
-  public SampleEventListener(@SuppressWarnings("SpringJavaAutowiringInspection") final EventRecorder eventRecorder) {
+  public PayrollConfigurationListener(@Qualifier(ServiceConstants.LOGGER_NAME) final Logger logger,
+                                      final EventRecorder eventRecorder) {
     super();
+    this.logger = logger;
     this.eventRecorder = eventRecorder;
   }
 
   @JmsListener(
       subscription = EventConstants.DESTINATION,
       destination = EventConstants.DESTINATION,
-      selector = EventConstants.SELECTOR_POST_SAMPLE
+      selector = EventConstants.SELECTOR_PUT_CONFIGURATION
   )
-  public void onCreateSample(@Header(TenantHeaderFilter.TENANT_HEADER) final String tenant,
-                             final String payload) {
-    this.eventRecorder.event(tenant, EventConstants.POST_SAMPLE, payload, String.class);
+  public void onPutConfiguration(@Header(TenantHeaderFilter.TENANT_HEADER) final String tenant,
+                                 final String payload) {
+    this.logger.info("Payment configuration for customer {} processed.", payload);
+    this.eventRecorder.event(tenant, EventConstants.PUT_CONFIGURATION, payload, String.class);
   }
 }
diff --git a/component-test/src/main/java/io/mifos/template/listener/MigrationEventListener.java b/component-test/src/main/java/io/mifos/payroll/listener/PayrollDistributionListener.java
similarity index 61%
rename from component-test/src/main/java/io/mifos/template/listener/MigrationEventListener.java
rename to component-test/src/main/java/io/mifos/payroll/listener/PayrollDistributionListener.java
index 52be53b..72edede 100644
--- a/component-test/src/main/java/io/mifos/template/listener/MigrationEventListener.java
+++ b/component-test/src/main/java/io/mifos/payroll/listener/PayrollDistributionListener.java
@@ -13,35 +13,41 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-package io.mifos.template.listener;
+package io.mifos.payroll.listener;
 
 import io.mifos.core.lang.config.TenantHeaderFilter;
 import io.mifos.core.test.listener.EventRecorder;
-import io.mifos.template.api.v1.events.EventConstants;
+import io.mifos.payroll.api.v1.EventConstants;
+import io.mifos.payroll.service.ServiceConstants;
+import org.slf4j.Logger;
 import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.beans.factory.annotation.Qualifier;
 import org.springframework.jms.annotation.JmsListener;
 import org.springframework.messaging.handler.annotation.Header;
 import org.springframework.stereotype.Component;
 
-@SuppressWarnings("unused")
 @Component
-public class MigrationEventListener {
+public class PayrollDistributionListener {
 
+  private final Logger logger;
   private final EventRecorder eventRecorder;
 
   @Autowired
-  public MigrationEventListener(@SuppressWarnings("SpringJavaAutowiringInspection") final EventRecorder eventRecorder) {
+  public PayrollDistributionListener(@Qualifier(ServiceConstants.LOGGER_NAME) final Logger logger,
+                                     final EventRecorder eventRecorder) {
     super();
+    this.logger = logger;
     this.eventRecorder = eventRecorder;
   }
 
   @JmsListener(
       subscription = EventConstants.DESTINATION,
       destination = EventConstants.DESTINATION,
-      selector = EventConstants.SELECTOR_INITIALIZE
+      selector = EventConstants.SELECTOR_POST_DISTRIBUTION
   )
-  public void onInitialization(@Header(TenantHeaderFilter.TENANT_HEADER) final String tenant,
+  public void onPostCollection(@Header(TenantHeaderFilter.TENANT_HEADER) final String tenant,
                                final String payload) {
-    this.eventRecorder.event(tenant, EventConstants.INITIALIZE, payload, String.class);
+    this.logger.info("Payment distribution with source account {0} processed.", payload);
+    this.eventRecorder.event(tenant, EventConstants.POST_DISTRIBUTION, payload, String.class);
   }
 }
diff --git a/component-test/src/main/java/io/mifos/template/TestSample.java b/component-test/src/main/java/io/mifos/template/TestSample.java
deleted file mode 100644
index 92ae690..0000000
--- a/component-test/src/main/java/io/mifos/template/TestSample.java
+++ /dev/null
@@ -1,130 +0,0 @@
-/*
- * 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.template;
-
-import io.mifos.anubis.test.v1.TenantApplicationSecurityEnvironmentTestRule;
-import io.mifos.core.api.context.AutoUserContext;
-import io.mifos.core.test.fixture.TenantDataStoreContextTestRule;
-import io.mifos.core.test.listener.EnableEventRecording;
-import io.mifos.core.test.listener.EventRecorder;
-import io.mifos.template.api.v1.events.EventConstants;
-import io.mifos.template.api.v1.client.TemplateManager;
-import io.mifos.template.api.v1.domain.Sample;
-import io.mifos.template.service.TemplateConfiguration;
-import org.apache.commons.lang3.RandomStringUtils;
-import org.junit.*;
-import org.junit.runner.RunWith;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-import org.springframework.beans.factory.annotation.Autowired;
-import org.springframework.beans.factory.annotation.Qualifier;
-import org.springframework.boot.test.context.SpringBootTest;
-import org.springframework.cloud.netflix.feign.EnableFeignClients;
-import org.springframework.cloud.netflix.ribbon.RibbonClient;
-import org.springframework.context.annotation.Bean;
-import org.springframework.context.annotation.ComponentScan;
-import org.springframework.context.annotation.Configuration;
-import org.springframework.context.annotation.Import;
-import org.springframework.test.context.junit4.SpringRunner;
-
-import java.util.List;
-
-@RunWith(SpringRunner.class)
-@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.DEFINED_PORT)
-public class TestSample extends SuiteTestEnvironment {
-  private static final String LOGGER_NAME = "test-logger";
-  private static final String TEST_USER = "homer";
-
-
-  @Configuration
-  @EnableEventRecording
-  @EnableFeignClients(basePackages = {"io.mifos.template.api.v1.client"})
-  @RibbonClient(name = APP_NAME)
-  @Import({TemplateConfiguration.class})
-  @ComponentScan("io.mifos.template.listener")
-  public static class TestConfiguration {
-    public TestConfiguration() {
-      super();
-    }
-
-    @Bean(name = LOGGER_NAME)
-    public Logger logger() {
-      return LoggerFactory.getLogger(LOGGER_NAME);
-    }
-  }
-
-  @ClassRule
-  public final static TenantDataStoreContextTestRule tenantDataStoreContext = TenantDataStoreContextTestRule.forRandomTenantName(cassandraInitializer, mariaDBInitializer);
-
-  @Rule
-  public final TenantApplicationSecurityEnvironmentTestRule tenantApplicationSecurityEnvironment
-          = new TenantApplicationSecurityEnvironmentTestRule(testEnvironment, this::waitForInitialize);
-
-  private AutoUserContext userContext;
-
-  @Autowired
-  private TemplateManager testSubject;
-
-  @Autowired
-  private EventRecorder eventRecorder;
-
-  @SuppressWarnings("WeakerAccess")
-  @Autowired
-  @Qualifier(LOGGER_NAME)
-  Logger logger;
-
-  public TestSample() {
-    super();
-  }
-
-  @Before
-  public void prepTest() {
-    userContext = tenantApplicationSecurityEnvironment.createAutoUserContext(TestSample.TEST_USER);
-  }
-
-  @After
-  public void cleanTest() {
-    userContext.close();
-    eventRecorder.clear();
-  }
-
-  public boolean waitForInitialize() {
-    try {
-      return this.eventRecorder.wait(EventConstants.INITIALIZE, APP_VERSION);
-    } catch (final InterruptedException e) {
-      throw new IllegalStateException(e);
-    }
-  }
-
-  @Test
-  public void shouldCreateSample() throws InterruptedException {
-    logger.info("Running test shouldCreateSample.");
-    final Sample sample = Sample.create(RandomStringUtils.randomAlphanumeric(8), RandomStringUtils.randomAlphanumeric(512));
-    this.testSubject.createEntity(sample);
-
-    Assert.assertTrue(this.eventRecorder.wait(EventConstants.POST_SAMPLE, sample.getIdentifier()));
-
-    final Sample createdSample = this.testSubject.getEntity(sample.getIdentifier());
-    Assert.assertEquals(sample, createdSample);
-  }
-
-  @Test
-  public void shouldListSamples() {
-    logger.info("Running test shouldListSamples.");
-    final List<Sample> allEntities = this.testSubject.findAllEntities();
-    Assert.assertNotNull(allEntities);
-  }
-}
diff --git a/component-test/src/main/resources/logback-test.xml b/component-test/src/main/resources/logback-test.xml
new file mode 100644
index 0000000..222fc38
--- /dev/null
+++ b/component-test/src/main/resources/logback-test.xml
@@ -0,0 +1,34 @@
+<!--
+
+    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.
+
+-->
+<configuration>
+    <appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender">
+        <encoder>
+            <pattern>%d{HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n</pattern>
+        </encoder>
+    </appender>
+
+    <logger name="org" level="OFF"/>
+    <logger name="org.hibernate" level="DEBUG"/>
+    <logger name="io" level="OFF"/>
+    <logger name="com" level="OFF"/>
+    <logger name="ch" level="OFF"/>
+
+    <root level="DEBUG">
+        <appender-ref ref="STDOUT"/>
+    </root>
+</configuration>
\ No newline at end of file
diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties
index 2888922..61d11e0 100644
--- a/gradle/wrapper/gradle-wrapper.properties
+++ b/gradle/wrapper/gradle-wrapper.properties
@@ -1,6 +1,6 @@
-#Fri Mar 17 17:54:20 CET 2017
+#Thu Sep 14 14:33:32 CEST 2017
 distributionBase=GRADLE_USER_HOME
 distributionPath=wrapper/dists
 zipStoreBase=GRADLE_USER_HOME
 zipStorePath=wrapper/dists
-distributionUrl=https\://services.gradle.org/distributions/gradle-3.4.1-bin.zip
+distributionUrl=https\://services.gradle.org/distributions/gradle-3.4.1-all.zip
diff --git a/service/build.gradle b/service/build.gradle
index a9b4de9..65e1431 100644
--- a/service/build.gradle
+++ b/service/build.gradle
@@ -30,7 +30,9 @@ dependencies {
             [group: 'org.springframework.cloud', name: 'spring-cloud-starter-config'],
             [group: 'org.springframework.cloud', name: 'spring-cloud-starter-eureka'],
             [group: 'org.springframework.boot', name: 'spring-boot-starter-jetty'],
-            [group: 'io.mifos.template', name: 'api', version: project.version],
+            [group: 'io.mifos.payroll', name: 'api', version: project.version],
+            [group: 'io.mifos.accounting', name: 'api', version: versions.frameworkaccounting],
+            [group: 'io.mifos.customer', name: 'api', version: versions.frameworkcustomer],
             [group: 'io.mifos.anubis', name: 'library', version: versions.frameworkanubis],
             [group: 'com.google.code.gson', name: 'gson'],
             [group: 'io.mifos.core', name: 'lang', version: versions.frameworklang],
diff --git a/service/src/main/java/io/mifos/template/service/TemplateApplication.java b/service/src/main/java/io/mifos/payroll/service/PayrollApplication.java
similarity index 81%
rename from service/src/main/java/io/mifos/template/service/TemplateApplication.java
rename to service/src/main/java/io/mifos/payroll/service/PayrollApplication.java
index 7ca88f0..2fe3036 100644
--- a/service/src/main/java/io/mifos/template/service/TemplateApplication.java
+++ b/service/src/main/java/io/mifos/payroll/service/PayrollApplication.java
@@ -13,17 +13,17 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-package io.mifos.template.service;
+package io.mifos.payroll.service;
 
 import org.springframework.boot.SpringApplication;
 
-public class TemplateApplication {
+public class PayrollApplication {
 
-  public TemplateApplication() {
+  public PayrollApplication() {
     super();
   }
 
   public static void main(String[] args) {
-    SpringApplication.run(TemplateConfiguration.class, args);
+    SpringApplication.run(PayrollServiceConfiguration.class, args);
   }
 }
diff --git a/service/src/main/java/io/mifos/template/service/TemplateConfiguration.java b/service/src/main/java/io/mifos/payroll/service/PayrollServiceConfiguration.java
similarity index 76%
rename from service/src/main/java/io/mifos/template/service/TemplateConfiguration.java
rename to service/src/main/java/io/mifos/payroll/service/PayrollServiceConfiguration.java
index 33ee609..d9a00e4 100644
--- a/service/src/main/java/io/mifos/template/service/TemplateConfiguration.java
+++ b/service/src/main/java/io/mifos/payroll/service/PayrollServiceConfiguration.java
@@ -13,8 +13,9 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-package io.mifos.template.service;
+package io.mifos.payroll.service;
 
+import io.mifos.accounting.api.v1.client.LedgerManager;
 import io.mifos.anubis.config.EnableAnubis;
 import io.mifos.core.async.config.EnableAsync;
 import io.mifos.core.cassandra.config.EnableCassandra;
@@ -22,10 +23,12 @@ import io.mifos.core.command.config.EnableCommandProcessing;
 import io.mifos.core.lang.config.EnableServiceException;
 import io.mifos.core.lang.config.EnableTenantContext;
 import io.mifos.core.mariadb.config.EnableMariaDB;
+import io.mifos.customer.api.v1.client.CustomerManager;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
 import org.springframework.cloud.client.discovery.EnableDiscoveryClient;
+import org.springframework.cloud.netflix.feign.EnableFeignClients;
 import org.springframework.context.annotation.Bean;
 import org.springframework.context.annotation.ComponentScan;
 import org.springframework.context.annotation.Configuration;
@@ -44,18 +47,22 @@ import org.springframework.web.servlet.config.annotation.WebMvcConfigurerAdapter
 @EnableCommandProcessing
 @EnableAnubis
 @EnableServiceException
+@EnableFeignClients(clients = {
+    LedgerManager.class,
+    CustomerManager.class
+})
 @ComponentScan({
-    "io.mifos.template.service.rest",
-    "io.mifos.template.service.internal.service",
-    "io.mifos.template.service.internal.repository",
-    "io.mifos.template.service.internal.command.handler"
+    "io.mifos.payroll.service.rest",
+    "io.mifos.payroll.service.internal.service",
+    "io.mifos.payroll.service.internal.repository",
+    "io.mifos.payroll.service.internal.command.handler"
 })
 @EnableJpaRepositories({
-    "io.mifos.template.service.internal.repository"
+    "io.mifos.payroll.service.internal.repository"
 })
-public class TemplateConfiguration extends WebMvcConfigurerAdapter {
+public class PayrollServiceConfiguration extends WebMvcConfigurerAdapter {
 
-  public TemplateConfiguration() {
+  public PayrollServiceConfiguration() {
     super();
   }
 
diff --git a/service/src/main/java/io/mifos/template/service/ServiceConstants.java b/service/src/main/java/io/mifos/payroll/service/ServiceConstants.java
similarity index 89%
rename from service/src/main/java/io/mifos/template/service/ServiceConstants.java
rename to service/src/main/java/io/mifos/payroll/service/ServiceConstants.java
index e9e0623..a5cfc4f 100644
--- a/service/src/main/java/io/mifos/template/service/ServiceConstants.java
+++ b/service/src/main/java/io/mifos/payroll/service/ServiceConstants.java
@@ -13,8 +13,8 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-package io.mifos.template.service;
+package io.mifos.payroll.service;
 
 public interface ServiceConstants {
-  String LOGGER_NAME = "rest-logger";
+  String LOGGER_NAME = "payroll-logger";
 }
diff --git a/service/src/main/java/io/mifos/template/service/internal/command/SampleCommand.java b/service/src/main/java/io/mifos/payroll/service/internal/command/DistributePayrollCommand.java
similarity index 57%
rename from service/src/main/java/io/mifos/template/service/internal/command/SampleCommand.java
rename to service/src/main/java/io/mifos/payroll/service/internal/command/DistributePayrollCommand.java
index 5957f1b..e3b4202 100644
--- a/service/src/main/java/io/mifos/template/service/internal/command/SampleCommand.java
+++ b/service/src/main/java/io/mifos/payroll/service/internal/command/DistributePayrollCommand.java
@@ -13,27 +13,19 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-package io.mifos.template.service.internal.command;
+package io.mifos.payroll.service.internal.command;
 
-import io.mifos.template.api.v1.domain.Sample;
+import io.mifos.payroll.api.v1.domain.PayrollCollectionSheet;
 
-public class SampleCommand {
+public class DistributePayrollCommand {
+  private final PayrollCollectionSheet payrollCollectionSheet;
 
-  private final Sample sample;
-
-  public SampleCommand(final Sample sample) {
+  public DistributePayrollCommand(final PayrollCollectionSheet payrollCollectionSheet) {
     super();
-    this.sample = sample;
-  }
-
-  public Sample sample() {
-    return this.sample;
+    this.payrollCollectionSheet = payrollCollectionSheet;
   }
 
-  @Override
-  public String toString() {
-    return "SampleCommand{" +
-        "sample=" + sample.getIdentifier() +
-        '}';
+  public PayrollCollectionSheet payrollCollectionSheet() {
+    return this.payrollCollectionSheet;
   }
 }
diff --git a/service/src/main/java/io/mifos/template/service/internal/command/InitializeServiceCommand.java b/service/src/main/java/io/mifos/payroll/service/internal/command/MigrateServiceCommand.java
similarity index 74%
rename from service/src/main/java/io/mifos/template/service/internal/command/InitializeServiceCommand.java
rename to service/src/main/java/io/mifos/payroll/service/internal/command/MigrateServiceCommand.java
index e02d2d0..4cacdc2 100644
--- a/service/src/main/java/io/mifos/template/service/internal/command/InitializeServiceCommand.java
+++ b/service/src/main/java/io/mifos/payroll/service/internal/command/MigrateServiceCommand.java
@@ -13,16 +13,10 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-package io.mifos.template.service.internal.command;
+package io.mifos.payroll.service.internal.command;
 
-public class InitializeServiceCommand {
-
-  public InitializeServiceCommand() {
+public class MigrateServiceCommand {
+  public MigrateServiceCommand() {
     super();
   }
-
-  @Override
-  public String toString() {
-    return "InitializeServiceCommand{}";
-  }
 }
diff --git a/service/src/main/java/io/mifos/payroll/service/internal/command/PutPayrollConfigurationCommand.java b/service/src/main/java/io/mifos/payroll/service/internal/command/PutPayrollConfigurationCommand.java
new file mode 100644
index 0000000..3507489
--- /dev/null
+++ b/service/src/main/java/io/mifos/payroll/service/internal/command/PutPayrollConfigurationCommand.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.payroll.service.internal.command;
+
+import io.mifos.payroll.api.v1.domain.PayrollConfiguration;
+
+public class PutPayrollConfigurationCommand {
+  private final String customerIdentifier;
+  private final PayrollConfiguration payrollConfiguration;
+
+  public PutPayrollConfigurationCommand(final String customerIdentifier,
+                                        final PayrollConfiguration payrollConfiguration) {
+    super();
+    this.customerIdentifier = customerIdentifier;
+    this.payrollConfiguration = payrollConfiguration;
+  }
+
+  public String customerIdentifier() {
+    return this.customerIdentifier;
+  }
+
+  public PayrollConfiguration payrollConfiguration() {
+    return this.payrollConfiguration;
+  }
+}
diff --git a/service/src/main/java/io/mifos/template/service/internal/command/handler/MigrationAggregate.java b/service/src/main/java/io/mifos/payroll/service/internal/command/handler/MigrationAggregate.java
similarity index 64%
rename from service/src/main/java/io/mifos/template/service/internal/command/handler/MigrationAggregate.java
rename to service/src/main/java/io/mifos/payroll/service/internal/command/handler/MigrationAggregate.java
index 12ae643..4d9d2c8 100644
--- a/service/src/main/java/io/mifos/template/service/internal/command/handler/MigrationAggregate.java
+++ b/service/src/main/java/io/mifos/payroll/service/internal/command/handler/MigrationAggregate.java
@@ -13,52 +13,42 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-package io.mifos.template.service.internal.command.handler;
+package io.mifos.payroll.service.internal.command.handler;
 
+import io.mifos.accounting.api.v1.EventConstants;
 import io.mifos.core.command.annotation.Aggregate;
 import io.mifos.core.command.annotation.CommandHandler;
-import io.mifos.core.command.annotation.CommandLogLevel;
 import io.mifos.core.command.annotation.EventEmitter;
 import io.mifos.core.lang.ApplicationName;
 import io.mifos.core.mariadb.domain.FlywayFactoryBean;
-import io.mifos.template.api.v1.events.EventConstants;
-import io.mifos.template.service.ServiceConstants;
-import io.mifos.template.service.internal.command.InitializeServiceCommand;
-import org.slf4j.Logger;
+import io.mifos.payroll.service.internal.command.MigrateServiceCommand;
 import org.springframework.beans.factory.annotation.Autowired;
-import org.springframework.beans.factory.annotation.Qualifier;
 import org.springframework.transaction.annotation.Transactional;
 
 import javax.sql.DataSource;
 
-@SuppressWarnings({
-    "unused"
-})
 @Aggregate
 public class MigrationAggregate {
 
-  private final Logger logger;
   private final DataSource dataSource;
   private final FlywayFactoryBean flywayFactoryBean;
   private final ApplicationName applicationName;
 
   @Autowired
-  public MigrationAggregate(@Qualifier(ServiceConstants.LOGGER_NAME) final Logger logger,
-                            final DataSource dataSource,
-                            final FlywayFactoryBean flywayFactoryBean,
+  public MigrationAggregate(@SuppressWarnings("SpringJavaAutowiringInspection") final DataSource dataSource,
+                            @SuppressWarnings("SpringJavaAutowiringInspection") final FlywayFactoryBean flywayFactoryBean,
                             final ApplicationName applicationName) {
     super();
-    this.logger = logger;
     this.dataSource = dataSource;
     this.flywayFactoryBean = flywayFactoryBean;
     this.applicationName = applicationName;
   }
 
-  @CommandHandler(logStart = CommandLogLevel.INFO, logFinish = CommandLogLevel.INFO)
+  @SuppressWarnings("unused")
   @Transactional
+  @CommandHandler
   @EventEmitter(selectorName = EventConstants.SELECTOR_NAME, selectorValue = EventConstants.INITIALIZE)
-  public String initialize(final InitializeServiceCommand initializeServiceCommand) {
-    this.logger.debug("Start service migration.");
+  public String initialize(final MigrateServiceCommand migrateServiceCommand) {
     this.flywayFactoryBean.create(this.dataSource).migrate();
     return this.applicationName.getVersionString();
   }
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
new file mode 100644
index 0000000..d71fe45
--- /dev/null
+++ b/service/src/main/java/io/mifos/payroll/service/internal/command/handler/PayrollConfigurationAggregate.java
@@ -0,0 +1,99 @@
+/*
+ * 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.payroll.service.internal.command.handler;
+
+import io.mifos.core.api.util.UserContextHolder;
+import io.mifos.core.command.annotation.Aggregate;
+import io.mifos.core.command.annotation.CommandHandler;
+import io.mifos.core.command.annotation.EventEmitter;
+import io.mifos.payroll.api.v1.EventConstants;
+import io.mifos.payroll.api.v1.domain.PayrollConfiguration;
+import io.mifos.payroll.service.ServiceConstants;
+import io.mifos.payroll.service.internal.command.PutPayrollConfigurationCommand;
+import io.mifos.payroll.service.internal.mapper.PayrollAllocationMapper;
+import io.mifos.payroll.service.internal.repository.PayrollAllocationEntity;
+import io.mifos.payroll.service.internal.repository.PayrollAllocationRepository;
+import io.mifos.payroll.service.internal.repository.PayrollConfigurationEntity;
+import io.mifos.payroll.service.internal.repository.PayrollConfigurationRepository;
+import io.mifos.payroll.service.internal.service.PayrollConfigurationService;
+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 java.time.Clock;
+import java.time.LocalDateTime;
+import java.util.Optional;
+
+@Aggregate
+public class PayrollConfigurationAggregate {
+
+  private Logger logger;
+  private PayrollConfigurationService payrollConfigurationService;
+  private PayrollConfigurationRepository payrollConfigurationRepository;
+  private PayrollAllocationRepository payrollAllocationRepository;
+
+  @Autowired
+  public PayrollConfigurationAggregate(@Qualifier(ServiceConstants.LOGGER_NAME) final Logger logger,
+                                       final PayrollConfigurationService payrollConfigurationService,
+                                       final PayrollConfigurationRepository payrollConfigurationRepository,
+                                       final PayrollAllocationRepository payrollAllocationRepository) {
+    super();
+    this.logger = logger;
+    this.payrollConfigurationService = payrollConfigurationService;
+    this.payrollConfigurationRepository = payrollConfigurationRepository;
+    this.payrollAllocationRepository = payrollAllocationRepository;
+  }
+
+  @Transactional
+  @CommandHandler
+  @EventEmitter(selectorName = EventConstants.SELECTOR_NAME, selectorValue = EventConstants.PUT_CONFIGURATION)
+  public String process(final PutPayrollConfigurationCommand putPayrollConfigurationCommand) {
+    final String customerIdentifier = putPayrollConfigurationCommand.customerIdentifier();
+    final PayrollConfiguration payrollConfiguration = putPayrollConfigurationCommand.payrollConfiguration();
+
+    final PayrollConfigurationEntity payrollConfigurationEntity;
+
+    final Optional<PayrollConfigurationEntity> optionalPayrollConfiguration =
+        this.payrollConfigurationRepository.findByCustomerIdentifier(customerIdentifier);
+    if (optionalPayrollConfiguration.isPresent()) {
+      payrollConfigurationEntity = optionalPayrollConfiguration.get();
+      this.payrollAllocationRepository.deleteByPayrollConfiguration(payrollConfigurationEntity);
+
+      payrollConfigurationEntity.setLastModifiedBy(UserContextHolder.checkedGetUser());
+      payrollConfigurationEntity.setLastModifiedOn(LocalDateTime.now(Clock.systemUTC()));
+    } else {
+      payrollConfigurationEntity = new PayrollConfigurationEntity();
+      payrollConfigurationEntity.setCustomerIdentifier(customerIdentifier);
+      payrollConfigurationEntity.setCreatedBy(UserContextHolder.checkedGetUser());
+      payrollConfigurationEntity.setCreatedOn(LocalDateTime.now(Clock.systemUTC()));
+    }
+
+    payrollConfigurationEntity.setMainAccountNumber(payrollConfiguration.getMainAccountNumber());
+    final PayrollConfigurationEntity savedPayrollConfigurationEntity =
+        this.payrollConfigurationRepository.save(payrollConfigurationEntity);
+
+    if (payrollConfiguration.getPayrollAllocations() != null) {
+      payrollConfiguration.getPayrollAllocations()
+          .forEach(payrollAllocation -> {
+            final PayrollAllocationEntity payrollAllocationEntity = PayrollAllocationMapper.map(payrollAllocation);
+            payrollAllocationEntity.setPayrollConfiguration(savedPayrollConfigurationEntity);
+            this.payrollAllocationRepository.save(payrollAllocationEntity);
+          });
+    }
+    return customerIdentifier;
+  }
+}
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
new file mode 100644
index 0000000..86f4aae
--- /dev/null
+++ b/service/src/main/java/io/mifos/payroll/service/internal/command/handler/PayrollDistributionAggregate.java
@@ -0,0 +1,96 @@
+/*
+ * 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.payroll.service.internal.command.handler;
+
+import io.mifos.core.api.util.UserContextHolder;
+import io.mifos.core.command.annotation.Aggregate;
+import io.mifos.core.command.annotation.CommandHandler;
+import io.mifos.core.command.annotation.EventEmitter;
+import io.mifos.payroll.api.v1.EventConstants;
+import io.mifos.payroll.api.v1.domain.PayrollCollectionSheet;
+import io.mifos.payroll.service.ServiceConstants;
+import io.mifos.payroll.service.internal.command.DistributePayrollCommand;
+import io.mifos.payroll.service.internal.repository.PayrollCollectionEntity;
+import io.mifos.payroll.service.internal.repository.PayrollCollectionRepository;
+import io.mifos.payroll.service.internal.repository.PayrollPaymentEntity;
+import io.mifos.payroll.service.internal.repository.PayrollPaymentRepository;
+import io.mifos.payroll.service.internal.service.PayrollConfigurationService;
+import io.mifos.payroll.service.internal.service.adaptor.AccountingAdaptor;
+import org.apache.commons.lang.RandomStringUtils;
+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 java.time.Clock;
+import java.time.LocalDateTime;
+
+@Aggregate
+public class PayrollDistributionAggregate {
+
+  private final Logger logger;
+  private final PayrollConfigurationService payrollConfigurationService;
+  private final PayrollCollectionRepository payrollCollectionRepository;
+  private final PayrollPaymentRepository payrollPaymentRepository;
+  private final AccountingAdaptor accountingAdaptor;
+
+  @Autowired
+  public PayrollDistributionAggregate(@Qualifier(ServiceConstants.LOGGER_NAME) final Logger logger,
+                                      PayrollConfigurationService payrollConfigurationService,
+                                      final PayrollCollectionRepository payrollCollectionRepository,
+                                      final PayrollPaymentRepository payrollPaymentRepository,
+                                      final AccountingAdaptor accountingAdaptor) {
+    super();
+    this.logger = logger;
+    this.payrollConfigurationService = payrollConfigurationService;
+    this.payrollCollectionRepository = payrollCollectionRepository;
+    this.payrollPaymentRepository = payrollPaymentRepository;
+    this.accountingAdaptor = accountingAdaptor;
+  }
+
+  @Transactional
+  @CommandHandler
+  @EventEmitter(selectorName = EventConstants.SELECTOR_NAME, selectorValue = EventConstants.POST_DISTRIBUTION)
+  public String process(final DistributePayrollCommand distributePayrollCommand) {
+    final PayrollCollectionSheet payrollCollectionSheet = distributePayrollCommand.payrollCollectionSheet();
+
+    final PayrollCollectionEntity payrollCollectionEntity = new PayrollCollectionEntity();
+    payrollCollectionEntity.setIdentifier(RandomStringUtils.randomAlphanumeric(32));
+    payrollCollectionEntity.setSourceAccountNumber(payrollCollectionSheet.getSourceAccountNumber());
+    payrollCollectionEntity.setCreatedBy(UserContextHolder.checkedGetUser());
+    payrollCollectionEntity.setCreatedOn(LocalDateTime.now(Clock.systemUTC()));
+
+    final PayrollCollectionEntity savedPayrollCollectionEntity = this.payrollCollectionRepository.save(payrollCollectionEntity);
+
+    payrollCollectionSheet.getPayrollPayments().forEach(payrollPayment ->
+        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());
+
+          this.payrollPaymentRepository.save(payrollPaymentEntity);
+
+          this.accountingAdaptor.postPayrollPayment(savedPayrollCollectionEntity, payrollPayment, payrollConfiguration);
+        })
+    );
+
+    return payrollCollectionSheet.getSourceAccountNumber();
+  }
+}
diff --git a/service/src/main/java/io/mifos/payroll/service/internal/mapper/PayrollAllocationMapper.java b/service/src/main/java/io/mifos/payroll/service/internal/mapper/PayrollAllocationMapper.java
new file mode 100644
index 0000000..832fd12
--- /dev/null
+++ b/service/src/main/java/io/mifos/payroll/service/internal/mapper/PayrollAllocationMapper.java
@@ -0,0 +1,42 @@
+/*
+ * 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.payroll.service.internal.mapper;
+
+import io.mifos.payroll.api.v1.domain.PayrollAllocation;
+import io.mifos.payroll.service.internal.repository.PayrollAllocationEntity;
+
+public class PayrollAllocationMapper {
+
+  private PayrollAllocationMapper() {
+    super();
+  }
+
+  public static PayrollAllocation map(final PayrollAllocationEntity payrollAllocationEntity) {
+    final PayrollAllocation payrollAllocation = new PayrollAllocation();
+    payrollAllocation.setAccountNumber(payrollAllocationEntity.getAccountNumber());
+    payrollAllocation.setAmount(payrollAllocationEntity.getAmount());
+    payrollAllocation.setProportional(payrollAllocationEntity.getProportional());
+    return payrollAllocation;
+  }
+
+  public static PayrollAllocationEntity map(final PayrollAllocation payrollAllocation) {
+    final PayrollAllocationEntity payrollAllocationEntity = new PayrollAllocationEntity();
+    payrollAllocationEntity.setAccountNumber(payrollAllocation.getAccountNumber());
+    payrollAllocationEntity.setAmount(payrollAllocation.getAmount());
+    payrollAllocationEntity.setProportional(payrollAllocation.getProportional());
+    return payrollAllocationEntity;
+  }
+}
diff --git a/service/src/main/java/io/mifos/payroll/service/internal/mapper/PayrollConfigurationMapper.java b/service/src/main/java/io/mifos/payroll/service/internal/mapper/PayrollConfigurationMapper.java
new file mode 100644
index 0000000..140a2e0
--- /dev/null
+++ b/service/src/main/java/io/mifos/payroll/service/internal/mapper/PayrollConfigurationMapper.java
@@ -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.
+ */
+package io.mifos.payroll.service.internal.mapper;
+
+import io.mifos.core.lang.DateConverter;
+import io.mifos.payroll.api.v1.domain.PayrollConfiguration;
+import io.mifos.payroll.service.internal.repository.PayrollConfigurationEntity;
+
+public class PayrollConfigurationMapper {
+
+  private PayrollConfigurationMapper() {
+    super();
+  }
+
+  public static PayrollConfiguration map(final PayrollConfigurationEntity payrollConfigurationEntity) {
+    final PayrollConfiguration payrollConfiguration = new PayrollConfiguration();
+    payrollConfiguration.setMainAccountNumber(payrollConfigurationEntity.getMainAccountNumber());
+    payrollConfiguration.setCreatedBy(payrollConfiguration.getCreatedOn());
+    payrollConfiguration.setCreatedOn(DateConverter.toIsoString(payrollConfigurationEntity.getCreatedOn()));
+    if (payrollConfigurationEntity.getLastModifiedBy() != null) {
+      payrollConfiguration.setLastModifiedBy(payrollConfigurationEntity.getLastModifiedBy());
+      payrollConfiguration.setLastModifiedOn(DateConverter.toIsoString(payrollConfigurationEntity.getLastModifiedOn()));
+    }
+    return payrollConfiguration;
+  }
+}
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
new file mode 100644
index 0000000..fd7538a
--- /dev/null
+++ b/service/src/main/java/io/mifos/payroll/service/internal/mapper/PayrollPaymentMapper.java
@@ -0,0 +1,34 @@
+/*
+ * 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.payroll.service.internal.mapper;
+
+import io.mifos.payroll.api.v1.domain.PayrollPayment;
+import io.mifos.payroll.service.internal.repository.PayrollPaymentEntity;
+
+public class PayrollPaymentMapper {
+
+  private PayrollPaymentMapper() {
+    super();
+  }
+
+  public static PayrollPayment map(final PayrollPaymentEntity payrollPaymentEntity) {
+    final PayrollPayment payrollPayment = new PayrollPayment();
+    payrollPayment.setCustomerIdentifier(payrollPaymentEntity.getCustomerIdentifier());
+    payrollPayment.setEmployer(payrollPaymentEntity.getEmployer());
+    payrollPayment.setSalary(payrollPaymentEntity.getSalary());
+    return payrollPayment;
+  }
+}
diff --git a/service/src/main/java/io/mifos/payroll/service/internal/repository/PayrollAllocationEntity.java b/service/src/main/java/io/mifos/payroll/service/internal/repository/PayrollAllocationEntity.java
new file mode 100644
index 0000000..d059f2a
--- /dev/null
+++ b/service/src/main/java/io/mifos/payroll/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.payroll.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 = "meketre_payroll_allocations")
+public class PayrollAllocationEntity {
+
+  @Id
+  @GeneratedValue(strategy = GenerationType.IDENTITY)
+  @Column(name = "id", nullable = false)
+  private Long id;
+  @ManyToOne
+  @JoinColumn(name = "payroll_configuration_id", nullable = false)
+  private PayrollConfigurationEntity payrollConfiguration;
+  @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 PayrollConfigurationEntity getPayrollConfiguration() {
+    return this.payrollConfiguration;
+  }
+
+  public void setPayrollConfiguration(final PayrollConfigurationEntity payrollConfiguration) {
+    this.payrollConfiguration = payrollConfiguration;
+  }
+
+  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/service/src/main/java/io/mifos/template/service/internal/repository/SampleJpaEntityRepository.java b/service/src/main/java/io/mifos/payroll/service/internal/repository/PayrollAllocationRepository.java
similarity index 62%
copy from service/src/main/java/io/mifos/template/service/internal/repository/SampleJpaEntityRepository.java
copy to service/src/main/java/io/mifos/payroll/service/internal/repository/PayrollAllocationRepository.java
index 87ea8a7..bcc43f5 100644
--- a/service/src/main/java/io/mifos/template/service/internal/repository/SampleJpaEntityRepository.java
+++ b/service/src/main/java/io/mifos/payroll/service/internal/repository/PayrollAllocationRepository.java
@@ -13,14 +13,16 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-package io.mifos.template.service.internal.repository;
+package io.mifos.payroll.service.internal.repository;
+
 
 import org.springframework.data.jpa.repository.JpaRepository;
-import org.springframework.stereotype.Repository;
 
-import java.util.Optional;
+import java.util.List;
+
+public interface PayrollAllocationRepository extends JpaRepository<PayrollAllocationEntity, Long> {
+
+  void deleteByPayrollConfiguration(final PayrollConfigurationEntity payrollConfigurationEntity);
 
-@Repository
-public interface SampleJpaEntityRepository extends JpaRepository<SampleJpaEntity, Long> {
-  Optional<SampleJpaEntity> findByIdentifier(String identifier);
+  List<PayrollAllocationEntity> findByPayrollConfiguration(final PayrollConfigurationEntity payrollConfigurationEntity);
 }
diff --git a/service/src/main/java/io/mifos/payroll/service/internal/repository/PayrollCollectionEntity.java b/service/src/main/java/io/mifos/payroll/service/internal/repository/PayrollCollectionEntity.java
new file mode 100644
index 0000000..c896995
--- /dev/null
+++ b/service/src/main/java/io/mifos/payroll/service/internal/repository/PayrollCollectionEntity.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.payroll.service.internal.repository;
+
+import io.mifos.core.mariadb.util.LocalDateTimeConverter;
+
+import javax.persistence.Column;
+import javax.persistence.Convert;
+import javax.persistence.Entity;
+import javax.persistence.GeneratedValue;
+import javax.persistence.GenerationType;
+import javax.persistence.Id;
+import javax.persistence.Table;
+import java.time.LocalDateTime;
+
+@Entity
+@Table(name = "meketre_payroll_collections")
+public class PayrollCollectionEntity {
+  @Id
+  @GeneratedValue(strategy = GenerationType.IDENTITY)
+  @Column(name = "id", nullable = false)
+  private Long id;
+  @Column(name = "identifier", nullable = false, length = 32)
+  private String identifier;
+  @Column(name = "source_account_number", nullable = false, length = 34)
+  private String sourceAccountNumber;
+  @Column(name = "created_by", nullable = false, length = 32)
+  private String createdBy;
+  @Column(name = "created_on")
+  @Convert(converter = LocalDateTimeConverter.class)
+  private LocalDateTime createdOn;
+
+  public PayrollCollectionEntity() {
+    super();
+  }
+
+  public Long getId() {
+    return this.id;
+  }
+
+  public void setId(final Long id) {
+    this.id = id;
+  }
+
+  public String getIdentifier() {
+    return this.identifier;
+  }
+
+  public void setIdentifier(final String identifier) {
+    this.identifier = identifier;
+  }
+
+  public String getSourceAccountNumber() {
+    return this.sourceAccountNumber;
+  }
+
+  public void setSourceAccountNumber(final String sourceAccountNumber) {
+    this.sourceAccountNumber = sourceAccountNumber;
+  }
+
+  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;
+  }
+}
diff --git a/service/src/main/java/io/mifos/template/service/internal/repository/SampleJpaEntityRepository.java b/service/src/main/java/io/mifos/payroll/service/internal/repository/PayrollCollectionRepository.java
similarity index 70%
copy from service/src/main/java/io/mifos/template/service/internal/repository/SampleJpaEntityRepository.java
copy to service/src/main/java/io/mifos/payroll/service/internal/repository/PayrollCollectionRepository.java
index 87ea8a7..8986a79 100644
--- a/service/src/main/java/io/mifos/template/service/internal/repository/SampleJpaEntityRepository.java
+++ b/service/src/main/java/io/mifos/payroll/service/internal/repository/PayrollCollectionRepository.java
@@ -13,14 +13,17 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-package io.mifos.template.service.internal.repository;
+package io.mifos.payroll.service.internal.repository;
 
 import org.springframework.data.jpa.repository.JpaRepository;
 import org.springframework.stereotype.Repository;
 
+import java.util.List;
 import java.util.Optional;
 
 @Repository
-public interface SampleJpaEntityRepository extends JpaRepository<SampleJpaEntity, Long> {
-  Optional<SampleJpaEntity> findByIdentifier(String identifier);
+public interface PayrollCollectionRepository extends JpaRepository<PayrollCollectionEntity, Long> {
+  List<PayrollCollectionEntity> findAllByOrderByCreatedOnDesc();
+
+  Optional<PayrollCollectionEntity> findByIdentifier(String identifier);
 }
diff --git a/service/src/main/java/io/mifos/payroll/service/internal/repository/PayrollConfigurationEntity.java b/service/src/main/java/io/mifos/payroll/service/internal/repository/PayrollConfigurationEntity.java
new file mode 100644
index 0000000..0ccd490
--- /dev/null
+++ b/service/src/main/java/io/mifos/payroll/service/internal/repository/PayrollConfigurationEntity.java
@@ -0,0 +1,111 @@
+/*
+ * 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.payroll.service.internal.repository;
+
+import io.mifos.core.mariadb.util.LocalDateTimeConverter;
+
+import javax.persistence.Column;
+import javax.persistence.Convert;
+import javax.persistence.Entity;
+import javax.persistence.GeneratedValue;
+import javax.persistence.GenerationType;
+import javax.persistence.Id;
+import javax.persistence.Table;
+import java.time.LocalDateTime;
+
+@Entity
+@Table(name = "meketre_payroll_configurations")
+public class PayrollConfigurationEntity {
+
+  @Id
+  @GeneratedValue(strategy = GenerationType.IDENTITY)
+  @Column(name = "id", nullable = false)
+  private Long id;
+  @Column(name = "customer_identifier", nullable = false, length = 32)
+  private String customerIdentifier;
+  @Column(name = "main_account_number", nullable = false, length = 34)
+  private String mainAccountNumber;
+  @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 PayrollConfigurationEntity() {
+    super();
+  }
+
+  public Long getId() {
+    return this.id;
+  }
+
+  public void setId(final Long id) {
+    this.id = id;
+  }
+
+  public String getCustomerIdentifier() {
+    return this.customerIdentifier;
+  }
+
+  public void setCustomerIdentifier(final String customerIdentifier) {
+    this.customerIdentifier = customerIdentifier;
+  }
+
+  public String getMainAccountNumber() {
+    return this.mainAccountNumber;
+  }
+
+  public void setMainAccountNumber(final String mainAccountNumber) {
+    this.mainAccountNumber = mainAccountNumber;
+  }
+
+  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/service/src/main/java/io/mifos/template/service/internal/repository/SampleJpaEntityRepository.java b/service/src/main/java/io/mifos/payroll/service/internal/repository/PayrollConfigurationRepository.java
similarity index 74%
copy from service/src/main/java/io/mifos/template/service/internal/repository/SampleJpaEntityRepository.java
copy to service/src/main/java/io/mifos/payroll/service/internal/repository/PayrollConfigurationRepository.java
index 87ea8a7..fb2944a 100644
--- a/service/src/main/java/io/mifos/template/service/internal/repository/SampleJpaEntityRepository.java
+++ b/service/src/main/java/io/mifos/payroll/service/internal/repository/PayrollConfigurationRepository.java
@@ -13,7 +13,7 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-package io.mifos.template.service.internal.repository;
+package io.mifos.payroll.service.internal.repository;
 
 import org.springframework.data.jpa.repository.JpaRepository;
 import org.springframework.stereotype.Repository;
@@ -21,6 +21,6 @@ import org.springframework.stereotype.Repository;
 import java.util.Optional;
 
 @Repository
-public interface SampleJpaEntityRepository extends JpaRepository<SampleJpaEntity, Long> {
-  Optional<SampleJpaEntity> findByIdentifier(String identifier);
+public interface PayrollConfigurationRepository extends JpaRepository<PayrollConfigurationEntity, Long> {
+  Optional<PayrollConfigurationEntity> findByCustomerIdentifier(final String customerIdentifier);
 }
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
new file mode 100644
index 0000000..3b782ed
--- /dev/null
+++ b/service/src/main/java/io/mifos/payroll/service/internal/repository/PayrollPaymentEntity.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.payroll.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 = "meketre_payroll_payments")
+public class PayrollPaymentEntity {
+
+  @Id
+  @GeneratedValue(strategy = GenerationType.IDENTITY)
+  @Column(name = "id", nullable = false)
+  private Long id;
+  @ManyToOne
+  @JoinColumn(name = "payroll_collection_id", nullable = false)
+  private PayrollCollectionEntity payrollCollection;
+  @Column(name = "customer_identifier", nullable = false, length = 32)
+  private String customerIdentifier;
+  @Column(name = "employer", nullable = false, length = 256)
+  private String employer;
+  @Column(name = "salary", nullable = false, precision = 15, scale = 5)
+  private BigDecimal salary;
+
+  public PayrollPaymentEntity() {
+    super();
+  }
+
+  public Long getId() {
+    return this.id;
+  }
+
+  public void setId(final Long id) {
+    this.id = id;
+  }
+
+  public PayrollCollectionEntity getPayrollCollection() {
+    return this.payrollCollection;
+  }
+
+  public void setPayrollCollection(final PayrollCollectionEntity payrollCollection) {
+    this.payrollCollection = payrollCollection;
+  }
+
+  public String getCustomerIdentifier() {
+    return this.customerIdentifier;
+  }
+
+  public void setCustomerIdentifier(final String customerIdentifier) {
+    this.customerIdentifier = customerIdentifier;
+  }
+
+  public String getEmployer() {
+    return this.employer;
+  }
+
+  public void setEmployer(final String employer) {
+    this.employer = employer;
+  }
+
+  public BigDecimal getSalary() {
+    return this.salary;
+  }
+
+  public void setSalary(final BigDecimal salary) {
+    this.salary = salary;
+  }
+}
diff --git a/service/src/main/java/io/mifos/template/service/internal/repository/SampleJpaEntityRepository.java b/service/src/main/java/io/mifos/payroll/service/internal/repository/PayrollPaymentRepository.java
similarity index 63%
rename from service/src/main/java/io/mifos/template/service/internal/repository/SampleJpaEntityRepository.java
rename to service/src/main/java/io/mifos/payroll/service/internal/repository/PayrollPaymentRepository.java
index 87ea8a7..91685ce 100644
--- a/service/src/main/java/io/mifos/template/service/internal/repository/SampleJpaEntityRepository.java
+++ b/service/src/main/java/io/mifos/payroll/service/internal/repository/PayrollPaymentRepository.java
@@ -13,14 +13,15 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-package io.mifos.template.service.internal.repository;
+package io.mifos.payroll.service.internal.repository;
 
+import org.springframework.data.domain.Page;
+import org.springframework.data.domain.Pageable;
 import org.springframework.data.jpa.repository.JpaRepository;
 import org.springframework.stereotype.Repository;
 
-import java.util.Optional;
-
 @Repository
-public interface SampleJpaEntityRepository extends JpaRepository<SampleJpaEntity, Long> {
-  Optional<SampleJpaEntity> findByIdentifier(String identifier);
+public interface PayrollPaymentRepository extends JpaRepository<PayrollPaymentEntity, Long> {
+  Page<PayrollPaymentEntity> findByPayrollCollection(final PayrollCollectionEntity payrollCollectionEntity,
+                                                     Pageable pageable);
 }
diff --git a/service/src/main/java/io/mifos/payroll/service/internal/service/PayrollConfigurationService.java b/service/src/main/java/io/mifos/payroll/service/internal/service/PayrollConfigurationService.java
new file mode 100644
index 0000000..eefeca3
--- /dev/null
+++ b/service/src/main/java/io/mifos/payroll/service/internal/service/PayrollConfigurationService.java
@@ -0,0 +1,83 @@
+/*
+ * 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.payroll.service.internal.service;
+
+import io.mifos.accounting.api.v1.domain.Account;
+import io.mifos.customer.api.v1.domain.Customer;
+import io.mifos.payroll.api.v1.domain.PayrollConfiguration;
+import io.mifos.payroll.service.ServiceConstants;
+import io.mifos.payroll.service.internal.mapper.PayrollAllocationMapper;
+import io.mifos.payroll.service.internal.mapper.PayrollConfigurationMapper;
+import io.mifos.payroll.service.internal.repository.PayrollAllocationRepository;
+import io.mifos.payroll.service.internal.repository.PayrollConfigurationRepository;
+import io.mifos.payroll.service.internal.service.adaptor.AccountingAdaptor;
+import io.mifos.payroll.service.internal.service.adaptor.CustomerAdaptor;
+import org.slf4j.Logger;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.beans.factory.annotation.Qualifier;
+import org.springframework.stereotype.Service;
+
+import java.util.Optional;
+import java.util.stream.Collectors;
+
+@Service
+public class PayrollConfigurationService {
+
+  private final Logger logger;
+  private final PayrollConfigurationRepository payrollConfigurationRepository;
+  private final PayrollAllocationRepository payrollAllocationRepository;
+  private final CustomerAdaptor customerAdaptor;
+  private final AccountingAdaptor accountingAdaptor;
+
+  @Autowired
+  public PayrollConfigurationService(@Qualifier(ServiceConstants.LOGGER_NAME) final Logger logger,
+                                     final PayrollConfigurationRepository payrollConfigurationRepository,
+                                     final PayrollAllocationRepository payrollAllocationRepository,
+                                     final CustomerAdaptor customerAdaptor,
+                                     final AccountingAdaptor accountingAdaptor) {
+    super();
+    this.logger = logger;
+    this.payrollConfigurationRepository = payrollConfigurationRepository;
+    this.payrollAllocationRepository = payrollAllocationRepository;
+    this.customerAdaptor = customerAdaptor;
+    this.accountingAdaptor = accountingAdaptor;
+  }
+
+  public Optional<Customer> findCustomer(final String customerIdentifier) {
+    return this.customerAdaptor.findCustomer(customerIdentifier);
+  }
+
+  public Optional<Account> findAccount(final String accountIdentifier) {
+    return this.accountingAdaptor.findAccount(accountIdentifier);
+  }
+
+  public Optional<PayrollConfiguration> findPayrollConfiguration(final String customerIdentifier) {
+    return this.payrollConfigurationRepository
+        .findByCustomerIdentifier(customerIdentifier)
+        .map(payrollConfigurationEntity -> {
+          final PayrollConfiguration payrollConfiguration = PayrollConfigurationMapper.map(payrollConfigurationEntity);
+
+          payrollConfiguration.setPayrollAllocations(
+              this.payrollAllocationRepository.findByPayrollConfiguration(payrollConfigurationEntity)
+                  .stream()
+                  .map(PayrollAllocationMapper::map)
+              .collect(Collectors.toSet())
+          );
+
+          return payrollConfiguration;
+        });
+  }
+}
diff --git a/service/src/main/java/io/mifos/payroll/service/internal/service/PayrollDistributionService.java b/service/src/main/java/io/mifos/payroll/service/internal/service/PayrollDistributionService.java
new file mode 100644
index 0000000..dd4012e
--- /dev/null
+++ b/service/src/main/java/io/mifos/payroll/service/internal/service/PayrollDistributionService.java
@@ -0,0 +1,100 @@
+/*
+ * 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.payroll.service.internal.service;
+
+import io.mifos.core.lang.DateConverter;
+import io.mifos.core.lang.ServiceException;
+import io.mifos.payroll.api.v1.domain.PayrollCollectionHistory;
+import io.mifos.payroll.api.v1.domain.PayrollPaymentPage;
+import io.mifos.payroll.service.ServiceConstants;
+import io.mifos.payroll.service.internal.mapper.PayrollPaymentMapper;
+import io.mifos.payroll.service.internal.repository.PayrollCollectionEntity;
+import io.mifos.payroll.service.internal.repository.PayrollCollectionRepository;
+import io.mifos.payroll.service.internal.repository.PayrollPaymentEntity;
+import io.mifos.payroll.service.internal.repository.PayrollPaymentRepository;
+import io.mifos.payroll.service.internal.service.adaptor.AccountingAdaptor;
+import org.slf4j.Logger;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.beans.factory.annotation.Qualifier;
+import org.springframework.data.domain.Page;
+import org.springframework.data.domain.Pageable;
+import org.springframework.stereotype.Service;
+
+import java.util.List;
+import java.util.Optional;
+import java.util.stream.Collectors;
+
+@Service
+public class PayrollDistributionService {
+
+  private final Logger logger;
+  private final PayrollCollectionRepository payrollCollectionRepository;
+  private final PayrollPaymentRepository payrollPaymentRepository;
+  private final AccountingAdaptor accountingAdaptor;
+
+  @Autowired
+  public PayrollDistributionService(@Qualifier(ServiceConstants.LOGGER_NAME) final Logger logger,
+                                    final PayrollCollectionRepository payrollCollectionRepository,
+                                    final PayrollPaymentRepository payrollPaymentRepository,
+                                    final AccountingAdaptor accountingAdaptor) {
+    super();
+    this.logger = logger;
+    this.payrollCollectionRepository = payrollCollectionRepository;
+    this.payrollPaymentRepository = payrollPaymentRepository;
+    this.accountingAdaptor = accountingAdaptor;
+  }
+
+
+  public List<PayrollCollectionHistory> fetchHistory() {
+    return this.payrollCollectionRepository.findAllByOrderByCreatedOnDesc()
+        .stream()
+        .map(this::mapPayrollCollection)
+        .collect(Collectors.toList());
+  }
+
+  public Optional<PayrollCollectionHistory> findDistribution(final String identifier) {
+    return this.payrollCollectionRepository.findByIdentifier(identifier)
+        .map(this::mapPayrollCollection);
+  }
+
+  public PayrollPaymentPage fetchPayments(final String identifier, final Pageable pageable) {
+    final PayrollPaymentPage payrollPaymentPage = new PayrollPaymentPage();
+
+    final PayrollCollectionEntity payrollCollectionEntity =
+        this.payrollCollectionRepository.findByIdentifier(identifier).orElseThrow(
+            () -> ServiceException.notFound("Payroll distribution {0} not found.", identifier)
+        );
+
+    final Page<PayrollPaymentEntity> pagedEntities =
+        this.payrollPaymentRepository.findByPayrollCollection(payrollCollectionEntity, pageable);
+    payrollPaymentPage.setTotalElements(pagedEntities.getTotalElements());
+    payrollPaymentPage.setTotalPages(pagedEntities.getTotalPages());
+    pagedEntities.forEach(
+        payrollPaymentEntity -> payrollPaymentPage.add(PayrollPaymentMapper.map(payrollPaymentEntity))
+    );
+
+    return payrollPaymentPage;
+  }
+
+  private PayrollCollectionHistory mapPayrollCollection(final PayrollCollectionEntity payrollCollectionEntity) {
+    final PayrollCollectionHistory payrollCollectionHistory = new PayrollCollectionHistory();
+    payrollCollectionHistory.setIdentifier(payrollCollectionEntity.getIdentifier());
+    payrollCollectionHistory.setSourceAccountNumber(payrollCollectionEntity.getSourceAccountNumber());
+    payrollCollectionHistory.setCreatedBy(payrollCollectionEntity.getCreatedBy());
+    payrollCollectionHistory.setCreatedOn(DateConverter.toIsoString(payrollCollectionEntity.getCreatedOn()));
+    return payrollCollectionHistory;
+  }
+}
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
new file mode 100644
index 0000000..41f19df
--- /dev/null
+++ b/service/src/main/java/io/mifos/payroll/service/internal/service/adaptor/AccountingAdaptor.java
@@ -0,0 +1,112 @@
+/*
+ * 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.payroll.service.internal.service.adaptor;
+
+import com.google.common.collect.Sets;
+import io.mifos.accounting.api.v1.client.AccountNotFoundException;
+import io.mifos.accounting.api.v1.client.LedgerManager;
+import io.mifos.accounting.api.v1.domain.Account;
+import io.mifos.accounting.api.v1.domain.Creditor;
+import io.mifos.accounting.api.v1.domain.Debtor;
+import io.mifos.accounting.api.v1.domain.JournalEntry;
+import io.mifos.core.lang.DateConverter;
+import io.mifos.payroll.api.v1.domain.PayrollConfiguration;
+import io.mifos.payroll.api.v1.domain.PayrollPayment;
+import io.mifos.payroll.service.ServiceConstants;
+import io.mifos.payroll.service.internal.repository.PayrollCollectionEntity;
+import org.slf4j.Logger;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.beans.factory.annotation.Qualifier;
+import org.springframework.stereotype.Service;
+
+import java.math.BigDecimal;
+import java.math.MathContext;
+import java.math.RoundingMode;
+import java.time.Clock;
+import java.time.LocalDateTime;
+import java.util.HashSet;
+import java.util.Optional;
+import java.util.UUID;
+
+@Service
+public class AccountingAdaptor {
+
+  private final Logger logger;
+  private final LedgerManager ledgerManager;
+
+  @Autowired
+  public AccountingAdaptor(@Qualifier(ServiceConstants.LOGGER_NAME) final Logger logger,
+                           final LedgerManager ledgerManager) {
+    super();
+    this.logger = logger;
+    this.ledgerManager = ledgerManager;
+  }
+
+  public Optional<Account> findAccount(final String accountIdentifier) {
+    try {
+      return Optional.of(this.ledgerManager.findAccount(accountIdentifier));
+    } catch (final AccountNotFoundException anfex) {
+      this.logger.warn("Account {} not found.", accountIdentifier);
+      return Optional.empty();
+    }
+  }
+
+  public void postPayrollPayment(final PayrollCollectionEntity payrollCollectionEntity,
+                                 final PayrollPayment payrollPayment,
+                                 final PayrollConfiguration payrollConfiguration) {
+
+    final MathContext mathContext = new MathContext(2, RoundingMode.HALF_EVEN);
+
+    final JournalEntry journalEntry = new JournalEntry();
+    journalEntry.setTransactionIdentifier(UUID.randomUUID().toString());
+    journalEntry.setTransactionDate(DateConverter.toIsoString(LocalDateTime.now(Clock.systemUTC())));
+    journalEntry.setTransactionType("SALA");
+    journalEntry.setClerk(payrollCollectionEntity.getCreatedBy());
+    journalEntry.setNote("Payroll Distribution");
+
+    final Debtor debtor = new Debtor();
+    debtor.setAccountNumber(payrollCollectionEntity.getSourceAccountNumber());
+    debtor.setAmount(payrollPayment.getSalary().toString());
+    journalEntry.setDebtors(Sets.newHashSet(debtor));
+
+    final HashSet<Creditor> creditors = new HashSet<>();
+    journalEntry.setCreditors(creditors);
+
+    payrollConfiguration.getPayrollAllocations().forEach(payrollAllocation -> {
+      final Creditor allocationCreditor = new Creditor();
+      allocationCreditor.setAccountNumber(payrollAllocation.getAccountNumber());
+      if (!payrollAllocation.getProportional()) {
+        allocationCreditor.setAmount(payrollAllocation.getAmount().toString());
+      } else {
+        final BigDecimal value = payrollPayment.getSalary().multiply(
+            payrollAllocation.getAmount().divide(BigDecimal.valueOf(100.00D), mathContext)
+        ).round(mathContext);
+        allocationCreditor.setAmount(value.toString());
+      }
+      creditors.add(allocationCreditor);
+    });
+
+    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);
+
+    this.ledgerManager.createJournalEntry(journalEntry);
+  }
+}
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
new file mode 100644
index 0000000..9fd9d0c
--- /dev/null
+++ b/service/src/main/java/io/mifos/payroll/service/internal/service/adaptor/CustomerAdaptor.java
@@ -0,0 +1,51 @@
+/*
+ * 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.payroll.service.internal.service.adaptor;
+
+import io.mifos.customer.api.v1.client.CustomerManager;
+import io.mifos.customer.api.v1.client.CustomerNotFoundException;
+import io.mifos.customer.api.v1.domain.Customer;
+import io.mifos.payroll.service.ServiceConstants;
+import org.slf4j.Logger;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.beans.factory.annotation.Qualifier;
+import org.springframework.stereotype.Service;
+
+import java.util.Optional;
+
+@Service
+public class CustomerAdaptor {
+
+  private final Logger logger;
+  private final CustomerManager customerManager;
+
+  @Autowired
+  public CustomerAdaptor(@Qualifier(ServiceConstants.LOGGER_NAME) final Logger logger,
+                         final CustomerManager customerManager) {
+    super();
+    this.logger = logger;
+    this.customerManager = customerManager;
+  }
+
+  public Optional<Customer> findCustomer(final String customerIdentifier) {
+    try {
+      return Optional.of(this.customerManager.findCustomer(customerIdentifier));
+    } catch (final CustomerNotFoundException cnfex) {
+      this.logger.warn("Customer {} not found.", customerIdentifier);
+      return Optional.empty();
+    }
+  }
+}
diff --git a/service/src/main/java/io/mifos/payroll/service/rest/MigrationRestController.java b/service/src/main/java/io/mifos/payroll/service/rest/MigrationRestController.java
new file mode 100644
index 0000000..84f58ef
--- /dev/null
+++ b/service/src/main/java/io/mifos/payroll/service/rest/MigrationRestController.java
@@ -0,0 +1,56 @@
+/*
+ * 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.payroll.service.rest;
+
+import io.mifos.anubis.annotation.AcceptedTokenType;
+import io.mifos.anubis.annotation.Permittable;
+import io.mifos.core.command.gateway.CommandGateway;
+import io.mifos.payroll.service.internal.command.MigrateServiceCommand;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.http.MediaType;
+import org.springframework.http.ResponseEntity;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RequestMethod;
+import org.springframework.web.bind.annotation.ResponseBody;
+import org.springframework.web.bind.annotation.RestController;
+
+@SuppressWarnings("unused")
+@RestController
+@RequestMapping("/")
+public class MigrationRestController {
+
+  private final CommandGateway commandGateway;
+
+  @Autowired
+  public MigrationRestController(final CommandGateway commandGateway) {
+    super();
+    this.commandGateway = commandGateway;
+  }
+
+  @Permittable(AcceptedTokenType.SYSTEM)
+  @RequestMapping(
+      value = "/initialize",
+      method = RequestMethod.POST,
+      consumes = MediaType.ALL_VALUE,
+      produces = MediaType.APPLICATION_JSON_VALUE
+  )
+  public
+  @ResponseBody
+  ResponseEntity<Void> initialize() throws InterruptedException {
+    this.commandGateway.process(new MigrateServiceCommand());
+    return ResponseEntity.accepted().build();
+  }
+}
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
new file mode 100644
index 0000000..100319d
--- /dev/null
+++ b/service/src/main/java/io/mifos/payroll/service/rest/PayrollConfigurationRestController.java
@@ -0,0 +1,113 @@
+/*
+ * 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.payroll.service.rest;
+
+import io.mifos.anubis.annotation.AcceptedTokenType;
+import io.mifos.anubis.annotation.Permittable;
+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.PayrollConfiguration;
+import io.mifos.payroll.service.ServiceConstants;
+import io.mifos.payroll.service.internal.command.PutPayrollConfigurationCommand;
+import io.mifos.payroll.service.internal.service.PayrollConfigurationService;
+import org.slf4j.Logger;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.beans.factory.annotation.Qualifier;
+import org.springframework.http.MediaType;
+import org.springframework.http.ResponseEntity;
+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.ResponseBody;
+import org.springframework.web.bind.annotation.RestController;
+
+import javax.validation.Valid;
+
+@RestController
+@RequestMapping("/customers/{identifier}/payroll")
+public class PayrollConfigurationRestController {
+
+  private final Logger logger;
+  private final CommandGateway commandGateway;
+  private final PayrollConfigurationService payrollConfigurationService;
+
+  @Autowired
+  public PayrollConfigurationRestController(@Qualifier(ServiceConstants.LOGGER_NAME) final Logger logger,
+                                            final CommandGateway commandGateway,
+                                            final PayrollConfigurationService payrollConfigurationService) {
+    super();
+    this.logger = logger;
+    this.commandGateway = commandGateway;
+    this.payrollConfigurationService = payrollConfigurationService;
+  }
+
+  @Permittables({
+      @Permittable(value = AcceptedTokenType.TENANT, groupId = PermittableGroupIds.CONFIGURATION)
+  })
+  @RequestMapping(
+      method = RequestMethod.PUT,
+      consumes = {
+          MediaType.APPLICATION_JSON_VALUE
+      },
+      produces = {
+          MediaType.APPLICATION_JSON_VALUE
+      }
+  )
+  @ResponseBody
+  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)
+    );
+
+    this.payrollConfigurationService.findAccount(payrollConfiguration.getMainAccountNumber())
+        .orElseThrow(() -> ServiceException.notFound("Main account {0} not found.", 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.");
+    }
+
+    this.commandGateway.process(new PutPayrollConfigurationCommand(customerIdentifier, payrollConfiguration));
+
+    return ResponseEntity.accepted().build();
+  }
+
+  @Permittables({
+      @Permittable(value = AcceptedTokenType.TENANT, groupId = PermittableGroupIds.CONFIGURATION)
+  })
+  @RequestMapping(
+      method = RequestMethod.GET,
+      consumes = {
+          MediaType.ALL_VALUE
+      },
+      produces = {
+          MediaType.APPLICATION_JSON_VALUE
+      }
+  )
+  @ResponseBody
+  PayrollConfiguration findPayrollConfiguration(@PathVariable(value = "identifier") final String customerIdentifier) {
+    return this.payrollConfigurationService.findPayrollConfiguration(customerIdentifier)
+        .orElseThrow(() -> ServiceException.notFound("Payroll configuration for customer {0} not found.", customerIdentifier));
+  }
+}
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
new file mode 100644
index 0000000..86d3203
--- /dev/null
+++ b/service/src/main/java/io/mifos/payroll/service/rest/PayrollDistributionRestController.java
@@ -0,0 +1,146 @@
+/*
+ * 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.payroll.service.rest;
+
+import io.mifos.anubis.annotation.AcceptedTokenType;
+import io.mifos.anubis.annotation.Permittable;
+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.PayrollCollectionHistory;
+import io.mifos.payroll.api.v1.domain.PayrollCollectionSheet;
+import io.mifos.payroll.api.v1.domain.PayrollPaymentPage;
+import io.mifos.payroll.service.ServiceConstants;
+import io.mifos.payroll.service.internal.command.DistributePayrollCommand;
+import io.mifos.payroll.service.internal.service.PayrollConfigurationService;
+import io.mifos.payroll.service.internal.service.PayrollDistributionService;
+import io.mifos.payroll.service.rest.util.PageableBuilder;
+import org.slf4j.Logger;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.beans.factory.annotation.Qualifier;
+import org.springframework.http.MediaType;
+import org.springframework.http.ResponseEntity;
+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 javax.validation.Valid;
+import java.util.List;
+
+@RestController
+@RequestMapping("/distribution")
+public class PayrollDistributionRestController {
+
+  private final Logger logger;
+  private final CommandGateway commandGateway;
+  private final PayrollDistributionService payrollDistributionService;
+  private final PayrollConfigurationService payrollConfigurationService;
+
+  @Autowired
+  public PayrollDistributionRestController(@Qualifier(ServiceConstants.LOGGER_NAME) final Logger logger,
+                                           final CommandGateway commandGateway,
+                                           final PayrollDistributionService payrollDistributionService,
+                                           final PayrollConfigurationService payrollConfigurationService) {
+    super();
+    this.logger = logger;
+    this.commandGateway = commandGateway;
+    this.payrollDistributionService = payrollDistributionService;
+    this.payrollConfigurationService = payrollConfigurationService;
+  }
+
+  @Permittables({
+      @Permittable(value = AcceptedTokenType.TENANT, groupId = PermittableGroupIds.DISTRIBUTION)
+  })
+  @RequestMapping(
+      method = RequestMethod.POST,
+      consumes = {
+          MediaType.APPLICATION_JSON_VALUE
+      },
+      produces = {
+          MediaType.APPLICATION_JSON_VALUE
+      }
+  )
+  @ResponseBody
+  public ResponseEntity<Void> distribute(@RequestBody @Valid final PayrollCollectionSheet payrollCollectionSheet) {
+
+    this.payrollConfigurationService.findAccount(payrollCollectionSheet.getSourceAccountNumber())
+        .orElseThrow(() -> ServiceException.notFound("Account {0} not found.", 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.");
+    }
+
+    this.commandGateway.process(new DistributePayrollCommand(payrollCollectionSheet));
+
+    return ResponseEntity.accepted().build();
+  }
+
+  @Permittables({
+      @Permittable(value = AcceptedTokenType.TENANT, groupId = PermittableGroupIds.DISTRIBUTION)
+  })
+  @RequestMapping(
+      method = RequestMethod.GET,
+      consumes = {
+          MediaType.ALL_VALUE
+      },
+      produces = {
+          MediaType.APPLICATION_JSON_VALUE
+      }
+  )
+  @ResponseBody
+  public ResponseEntity<List<PayrollCollectionHistory>> fetchDistributionHistory() {
+    return ResponseEntity.ok(this.payrollDistributionService.fetchHistory());
+  }
+
+  @Permittables({
+      @Permittable(value = AcceptedTokenType.TENANT, groupId = PermittableGroupIds.DISTRIBUTION)
+  })
+  @RequestMapping(
+      value = "/{identifier}/payments",
+      method = RequestMethod.GET,
+      consumes = {
+          MediaType.ALL_VALUE
+      },
+      produces = {
+          MediaType.APPLICATION_JSON_VALUE
+      }
+  )
+  @ResponseBody
+  ResponseEntity<PayrollPaymentPage> fetchPayments(
+      @PathVariable("identifier") final String identifier,
+      @RequestParam(value = "pageIndex", required = false) final Integer pageIndex,
+      @RequestParam(value = "size", required = false) final Integer size,
+      @RequestParam(value = "sortColumn", required = false) final String sortColumn,
+      @RequestParam(value = "sortDirection", required = false) final String sortDirection) {
+    this.payrollDistributionService.findDistribution(identifier)
+        .orElseThrow(() -> ServiceException.notFound("Payroll distribution {0} not found."));
+
+    return ResponseEntity.ok(this.payrollDistributionService
+        .fetchPayments(identifier, PageableBuilder.create(pageIndex, size, sortColumn, sortDirection)));
+  }
+}
diff --git a/service/src/main/java/io/mifos/payroll/service/rest/util/PageableBuilder.java b/service/src/main/java/io/mifos/payroll/service/rest/util/PageableBuilder.java
new file mode 100644
index 0000000..ff34371
--- /dev/null
+++ b/service/src/main/java/io/mifos/payroll/service/rest/util/PageableBuilder.java
@@ -0,0 +1,41 @@
+/*
+ * 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.payroll.service.rest.util;
+
+import org.springframework.data.domain.PageRequest;
+import org.springframework.data.domain.Pageable;
+import org.springframework.data.domain.Sort;
+
+import javax.annotation.Nullable;
+
+public class PageableBuilder {
+
+  private PageableBuilder() {
+    super();
+  }
+
+  public static Pageable create(
+      @Nullable final Integer pageIndex,
+      @Nullable final Integer size,
+      @Nullable final String sortColumn,
+      @Nullable final String sortDirection) {
+    final Integer pageIndexToUse = pageIndex != null ? pageIndex : 0;
+    final Integer sizeToUse = size != null ? size : 20;
+    final String sortColumnToUse = sortColumn != null ? sortColumn : "customerIdentifier";
+    final Sort.Direction direction = sortDirection != null ? Sort.Direction.valueOf(sortDirection.toUpperCase()) : Sort.Direction.ASC;
+    return new PageRequest(pageIndexToUse, sizeToUse, direction, sortColumnToUse);
+  }
+}
diff --git a/service/src/main/java/io/mifos/template/service/internal/command/handler/SampleAggregate.java b/service/src/main/java/io/mifos/template/service/internal/command/handler/SampleAggregate.java
deleted file mode 100644
index 9a7c572..0000000
--- a/service/src/main/java/io/mifos/template/service/internal/command/handler/SampleAggregate.java
+++ /dev/null
@@ -1,65 +0,0 @@
-/*
- * 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.template.service.internal.command.handler;
-
-import io.mifos.core.command.annotation.Aggregate;
-import io.mifos.core.command.annotation.CommandHandler;
-import io.mifos.core.command.annotation.CommandLogLevel;
-import io.mifos.core.command.annotation.EventEmitter;
-import io.mifos.template.api.v1.events.EventConstants;
-import io.mifos.template.service.internal.command.SampleCommand;
-import io.mifos.template.service.internal.repository.SampleJpaEntity;
-import io.mifos.template.service.internal.repository.SampleJpaEntityRepository;
-import org.springframework.beans.factory.annotation.Autowired;
-import org.springframework.transaction.annotation.Transactional;
-
-@SuppressWarnings("unused")
-@Aggregate
-public class SampleAggregate {
-
-  private final SampleJpaEntityRepository sampleJpaEntityRepository;
-
-  @Autowired
-  public SampleAggregate(final SampleJpaEntityRepository sampleJpaEntityRepository) {
-    super();
-    this.sampleJpaEntityRepository = sampleJpaEntityRepository;
-  }
-
-  //TODO: Think about your command handler logging, then delete this comment.
-  // The log levels provided in the command handler cause log messages to be emitted each time this
-  // command handler is called before and after the call. Before the call, the command is logged
-  // using its toString() method, and after the call, the emitted event is logged via its toString()
-  // method.
-  //
-  // If you wish to adjust the information in the log messages, do so via the toString() methods.
-  // Financial transactions, passwords, and customer address data are examples of information which
-  // should not be placed in the logs.
-  //
-  // If a command handler should not emit a log message, change logStart and logFinish to:
-  // CommandLogLevel.NONE.
-  @CommandHandler(logStart = CommandLogLevel.INFO, logFinish = CommandLogLevel.INFO)
-  @Transactional
-  @EventEmitter(selectorName = EventConstants.SELECTOR_NAME, selectorValue = EventConstants.POST_SAMPLE)
-  public String sample(final SampleCommand sampleCommand) {
-
-    final SampleJpaEntity entity = new SampleJpaEntity();
-    entity.setIdentifier(sampleCommand.sample().getIdentifier());
-    entity.setPayload(sampleCommand.sample().getPayload());
-    this.sampleJpaEntityRepository.save(entity);
-
-    return sampleCommand.sample().getIdentifier();
-  }
-}
diff --git a/service/src/main/java/io/mifos/template/service/internal/mapper/SampleMapper.java b/service/src/main/java/io/mifos/template/service/internal/mapper/SampleMapper.java
deleted file mode 100644
index 983b5d5..0000000
--- a/service/src/main/java/io/mifos/template/service/internal/mapper/SampleMapper.java
+++ /dev/null
@@ -1,43 +0,0 @@
-/*
- * 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.template.service.internal.mapper;
-
-import io.mifos.template.api.v1.domain.Sample;
-import io.mifos.template.service.internal.repository.SampleJpaEntity;
-
-import java.util.ArrayList;
-import java.util.List;
-import java.util.stream.Collectors;
-
-public class SampleMapper {
-
-  private SampleMapper() {
-    super();
-  }
-
-  public static Sample map(final SampleJpaEntity sampleJpaEntity) {
-    final Sample sample = new Sample();
-    sample.setIdentifier(sampleJpaEntity.getIdentifier());
-    sample.setPayload(sampleJpaEntity.getPayload());
-    return sample;
-  }
-
-  public static List<Sample> map(final List<SampleJpaEntity> sampleJpaEntities) {
-    final ArrayList<Sample> samples = new ArrayList<>(sampleJpaEntities.size());
-    samples.addAll(sampleJpaEntities.stream().map(SampleMapper::map).collect(Collectors.toList()));
-    return samples;
-  }
-}
diff --git a/service/src/main/java/io/mifos/template/service/internal/repository/SampleJpaEntity.java b/service/src/main/java/io/mifos/template/service/internal/repository/SampleJpaEntity.java
deleted file mode 100644
index 9cbcd73..0000000
--- a/service/src/main/java/io/mifos/template/service/internal/repository/SampleJpaEntity.java
+++ /dev/null
@@ -1,61 +0,0 @@
-/*
- * 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.template.service.internal.repository;
-
-import javax.persistence.*;
-
-@SuppressWarnings("unused")
-@Entity
-@Table(name = "template_samples")
-public class SampleJpaEntity {
-
-  @Id
-  @GeneratedValue(strategy = GenerationType.IDENTITY)
-  @Column(name = "id")
-  private Long id;
-  @Column(name = "identifier")
-  private String identifier;
-  @Column(name = "payload")
-  private String payload;
-
-  public SampleJpaEntity() {
-    super();
-  }
-
-  public Long getId() {
-    return id;
-  }
-
-  public void setId(Long id) {
-    this.id = id;
-  }
-
-  public String getIdentifier() {
-    return this.identifier;
-  }
-
-  public void setIdentifier(final String identifier) {
-    this.identifier = identifier;
-  }
-
-  public String getPayload() {
-    return payload;
-  }
-
-  public void setPayload(String payload) {
-    this.payload = payload;
-  }
-}
diff --git a/service/src/main/java/io/mifos/template/service/internal/service/SampleService.java b/service/src/main/java/io/mifos/template/service/internal/service/SampleService.java
deleted file mode 100644
index caba840..0000000
--- a/service/src/main/java/io/mifos/template/service/internal/service/SampleService.java
+++ /dev/null
@@ -1,45 +0,0 @@
-/*
- * 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.template.service.internal.service;
-
-import io.mifos.template.api.v1.domain.Sample;
-import io.mifos.template.service.internal.mapper.SampleMapper;
-import io.mifos.template.service.internal.repository.SampleJpaEntityRepository;
-import org.springframework.beans.factory.annotation.Autowired;
-import org.springframework.stereotype.Service;
-
-import java.util.List;
-import java.util.Optional;
-
-@Service
-public class SampleService {
-
-  private final SampleJpaEntityRepository sampleJpaEntityRepository;
-
-  @Autowired
-  public SampleService(final SampleJpaEntityRepository sampleJpaEntityRepository) {
-    super();
-    this.sampleJpaEntityRepository = sampleJpaEntityRepository;
-  }
-
-  public List<Sample> findAllEntities() {
-    return SampleMapper.map(this.sampleJpaEntityRepository.findAll());
-  }
-
-  public Optional<Sample> findByIdentifier(final String identifier) {
-    return this.sampleJpaEntityRepository.findByIdentifier(identifier).map(SampleMapper::map);
-  }
-}
diff --git a/service/src/main/java/io/mifos/template/service/rest/SampleRestController.java b/service/src/main/java/io/mifos/template/service/rest/SampleRestController.java
deleted file mode 100644
index 9919252..0000000
--- a/service/src/main/java/io/mifos/template/service/rest/SampleRestController.java
+++ /dev/null
@@ -1,112 +0,0 @@
-/*
- * 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.template.service.rest;
-
-import io.mifos.anubis.annotation.AcceptedTokenType;
-import io.mifos.anubis.annotation.Permittable;
-import io.mifos.core.command.gateway.CommandGateway;
-import io.mifos.core.lang.ServiceException;
-import io.mifos.template.api.v1.PermittableGroupIds;
-import io.mifos.template.api.v1.domain.Sample;
-import io.mifos.template.service.ServiceConstants;
-import io.mifos.template.service.internal.command.InitializeServiceCommand;
-import io.mifos.template.service.internal.command.SampleCommand;
-import io.mifos.template.service.internal.service.SampleService;
-import org.slf4j.Logger;
-import org.springframework.beans.factory.annotation.Autowired;
-import org.springframework.beans.factory.annotation.Qualifier;
-import org.springframework.http.MediaType;
-import org.springframework.http.ResponseEntity;
-import org.springframework.web.bind.annotation.*;
-
-import javax.validation.Valid;
-import java.util.List;
-
-@SuppressWarnings("unused")
-@RestController
-@RequestMapping("/")
-public class SampleRestController {
-
-  private final Logger logger;
-  private final CommandGateway commandGateway;
-  private final SampleService sampleService;
-
-  @Autowired
-  public SampleRestController(@Qualifier(ServiceConstants.LOGGER_NAME) final Logger logger,
-                              final CommandGateway commandGateway,
-                              final SampleService sampleService) {
-    super();
-    this.logger = logger;
-    this.commandGateway = commandGateway;
-    this.sampleService = sampleService;
-  }
-
-  @Permittable(value = AcceptedTokenType.SYSTEM)
-  @RequestMapping(
-      value = "/initialize",
-      method = RequestMethod.POST,
-      consumes = MediaType.ALL_VALUE,
-      produces = MediaType.APPLICATION_JSON_VALUE
-  )
-  public
-  @ResponseBody
-  ResponseEntity<Void> initialize() throws InterruptedException {
-      this.commandGateway.process(new InitializeServiceCommand());
-      return ResponseEntity.accepted().build();
-  }
-
-  @Permittable(value = AcceptedTokenType.TENANT, groupId = PermittableGroupIds.SAMPLE_MANAGEMENT)
-  @RequestMapping(
-          value = "/sample",
-          method = RequestMethod.GET,
-          consumes = MediaType.ALL_VALUE,
-          produces = MediaType.APPLICATION_JSON_VALUE
-  )
-  public
-  @ResponseBody
-  List<Sample> findAllEntities() {
-    return this.sampleService.findAllEntities();
-  }
-
-  @Permittable(value = AcceptedTokenType.TENANT, groupId = PermittableGroupIds.SAMPLE_MANAGEMENT)
-  @RequestMapping(
-          value = "/sample/{identifier}",
-          method = RequestMethod.GET,
-          consumes = MediaType.ALL_VALUE,
-          produces = MediaType.APPLICATION_JSON_VALUE
-  )
-  public
-  @ResponseBody
-  ResponseEntity<Sample> getEntity(@PathVariable("identifier") final String identifier) {
-    return this.sampleService.findByIdentifier(identifier)
-            .map(ResponseEntity::ok)
-            .orElseThrow(() -> ServiceException.notFound("Instance with identifier " + identifier + " doesn't exist."));
-  }
-
-  @Permittable(value = AcceptedTokenType.TENANT, groupId = PermittableGroupIds.SAMPLE_MANAGEMENT)
-  @RequestMapping(
-      value = "/sample",
-      method = RequestMethod.POST,
-      consumes = MediaType.APPLICATION_JSON_VALUE,
-      produces = MediaType.APPLICATION_JSON_VALUE
-  )
-  public
-  @ResponseBody
-  ResponseEntity<Void> createEntity(@RequestBody @Valid final Sample instance) throws InterruptedException {
-    this.commandGateway.process(new SampleCommand(instance));
-    return ResponseEntity.accepted().build();
-  }
-}
diff --git a/service/src/main/resources/application.yml b/service/src/main/resources/application.yml
index 8b395ca..124f606 100644
--- a/service/src/main/resources/application.yml
+++ b/service/src/main/resources/application.yml
@@ -28,7 +28,7 @@ eureka:
 
 server:
   port: 8081
-  contextPath: /template/v1/*
+  contextPath: /payroll/v1/*
 
 cassandra:
   clusterName: staging_cluster
diff --git a/service/src/main/resources/bootstrap.yml b/service/src/main/resources/bootstrap.yml
index 6b9e3e8..dac5589 100644
--- a/service/src/main/resources/bootstrap.yml
+++ b/service/src/main/resources/bootstrap.yml
@@ -16,4 +16,4 @@
 
 spring:
     application:
-        name: template-v1
+        name: payroll-v1
diff --git a/service/src/main/resources/db/migrations/mariadb/V1__initial_setup.sql b/service/src/main/resources/db/migrations/mariadb/V1__initial_setup.sql
index fb1b54e..578e373 100644
--- a/service/src/main/resources/db/migrations/mariadb/V1__initial_setup.sql
+++ b/service/src/main/resources/db/migrations/mariadb/V1__initial_setup.sql
@@ -14,9 +14,45 @@
 -- limitations under the License.
 --
 
-CREATE TABLE template_samples (
-  id BIGINT NOT NULL AUTO_INCREMENT,
-  identifier VARCHAR(8) NOT NULL,
-  payload VARCHAR(512) NULL,
-  CONSTRAINT template_samples_pk PRIMARY KEY (id)
+CREATE TABLE meketre_payroll_configurations (
+  id                  BIGINT       NOT NULL AUTO_INCREMENT,
+  customer_identifier VARCHAR(32)  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 meketre_payroll_config_pk PRIMARY KEY (id),
+  CONSTRAINT meketre_payroll_config_acct_uq UNIQUE (customer_identifier, main_account_number)
+);
+
+CREATE TABLE meketre_payroll_allocations (
+  id                       BIGINT        NOT NULL AUTO_INCREMENT,
+  payroll_configuration_id BIGINT        NOT NULL,
+  account_number           VARCHAR(34)   NOT NULL,
+  amount                   NUMERIC(15,5) NOT NULL,
+  proportional             BOOLEAN       NOT NULL,
+  CONSTRAINT meketre_payroll_allocations_pk PRIMARY KEY (id),
+  CONSTRAINT meketre_payroll_alloc_acct_uq UNIQUE (payroll_configuration_id, account_number),
+  CONSTRAINT meketre_payroll_alloc_config_fk FOREIGN KEY (payroll_configuration_id) REFERENCES meketre_payroll_configurations (id)
+);
+
+CREATE TABLE meketre_payroll_collections (
+  id                    BIGINT       NOT NULL AUTO_INCREMENT,
+  identifier            VARCHAR(32)  NOT NULL,
+  source_account_number VARCHAR(34)  NOT NULL,
+  created_by            VARCHAR(32)  NOT NULL,
+  created_on            TIMESTAMP(3) NOT NULL,
+  CONSTRAINT meketre_payroll_collections_pk PRIMARY KEY (id),
+  CONSTRAINT meketre_pay_col_identifier_uq UNIQUE (identifier)
+);
+
+CREATE TABLE meketre_payroll_payments (
+  id                    BIGINT        NOT NULL AUTO_INCREMENT,
+  payroll_collection_id BIGINT        NOT NULL,
+  customer_identifier   VARCHAR(32)   NOT NULL,
+  employer              VARCHAR(256)  NOT NULL,
+  salary                NUMERIC(15,5) NOT NULL,
+  CONSTRAINT meketre_payroll_payments_pk PRIMARY KEY (id),
+  CONSTRAINT meketre_payroll_pay_coll_fk FOREIGN KEY (payroll_collection_id) REFERENCES meketre_payroll_collections (id)
 );
diff --git a/service/src/main/resources/logback.xml b/service/src/main/resources/logback.xml
new file mode 100644
index 0000000..e594df5
--- /dev/null
+++ b/service/src/main/resources/logback.xml
@@ -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.
+
+-->
+<configuration>
+    <appender name="FILE" class="ch.qos.logback.core.rolling.RollingFileAppender">
+        <file>logs/payroll.log</file>
+        <rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
+            <fileNamePattern>logs/archive/payroll.%d{yyyy-MM-dd}.log</fileNamePattern>
+            <maxHistory>7</maxHistory>
+            <totalSizeCap>2GB</totalSizeCap>
+        </rollingPolicy>
+        <encoder>
+            <pattern>%d{HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n</pattern>
+        </encoder>
+    </appender>
+    <appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender">
+        <encoder>
+            <pattern>%d{HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n</pattern>
+        </encoder>
+    </appender>
+
+    <logger name="com" level="INFO">
+        <appender-ref ref="STDOUT" />
+    </logger>
+
+    <logger name="org" level="INFO">
+        <appender-ref ref="STDOUT" />
+    </logger>
+
+    <logger name="io" level="INFO">
+        <appender-ref ref="STDOUT" />
+    </logger>
+
+    <logger name="net" level="INFO">
+        <appender-ref ref="STDOUT" />
+    </logger>
+
+    <root level="DEBUG">
+        <appender-ref ref="FILE"/>
+    </root>
+</configuration>
\ No newline at end of file
diff --git a/settings.gradle b/settings.gradle
index 1630ef8..f97fef4 100644
--- a/settings.gradle
+++ b/settings.gradle
@@ -1,4 +1,4 @@
-rootProject.name = 'template'
+rootProject.name = 'payroll'
 
 includeBuild 'api'
 includeBuild 'service'
diff --git a/shared.gradle b/shared.gradle
index 1bfef46..831fede 100644
--- a/shared.gradle
+++ b/shared.gradle
@@ -1,4 +1,4 @@
-group 'io.mifos.template'
+group 'io.mifos.payroll'
 version '0.1.0.BUILD-SNAPSHOT'
 
 ext.versions = [
@@ -10,6 +10,8 @@ ext.versions = [
         frameworkcommand : '0.1.0-BUILD-SNAPSHOT',
         frameworktest: '0.1.0-BUILD-SNAPSHOT',
         frameworkanubis: '0.1.0-BUILD-SNAPSHOT',
+        frameworkcustomer: '0.1.0-BUILD-SNAPSHOT',
+        frameworkaccounting: '0.1.0-BUILD-SNAPSHOT',
         validator : '5.3.0.Final'
 ]