fineract-commits mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From my...@apache.org
Subject [fineract-cn-deposit-account-management] 02/23: first iteration server side implementation
Date Mon, 22 Jan 2018 15:28:35 GMT
This is an automated email from the ASF dual-hosted git repository.

myrle pushed a commit to branch develop
in repository https://gitbox.apache.org/repos/asf/fineract-cn-deposit-account-management.git

commit 5261f12ef733cb26f39acb8aa416b22165f5480a
Author: mgeiss <mgeiss@mifos.org>
AuthorDate: Sat May 27 18:15:24 2017 +0700

    first iteration server side implementation
---
 .../io/mifos/deposit/api/v1/EventConstants.java    |   3 +
 .../api/v1/client/DepositAccountManager.java       |  45 ++---
 .../deposit/api/v1/definition/domain/Action.java   |   7 +
 .../deposit/api/v1/definition/domain/Charge.java   |  17 ++
 .../v1/definition/domain/ProductDefinition.java    |  29 ++--
 .../api/v1/instance/domain/ProductInstance.java    |  15 +-
 .../internal/command/CreateActionCommand.java      |  31 ++++
 .../command/CreateProductDefinitionCommand.java    |  32 ++++
 .../command/CreateProductInstanceCommand.java      |  32 ++++
 .../internal/command/handler/ActionAggregate.java  |  51 ++++++
 .../handler/ProductDefinitionAggregate.java        |  63 +++++++
 .../command/handler/ProductInstanceAggregate.java  |  60 +++++++
 .../service/internal/mapper/ActionMapper.java      |  46 ++++++
 .../service/internal/mapper/ChargesMapper.java     |  63 +++++++
 .../service/internal/mapper/CurrencyMapper.java    |  46 ++++++
 .../internal/mapper/ProductDefinitionMapper.java   |  73 ++++++++
 .../internal/mapper/ProductInstanceMapper.java     |  58 +++++++
 .../service/internal/mapper/TermMapper.java        |  44 +++++
 .../service/internal/repository/ActionEntity.java  |  31 +++-
 .../internal/repository/ActionRepository.java      |  25 +++
 .../service/internal/repository/ChargeEntity.java  | 130 +++++++++++++++
 .../internal/repository/CurrencyEntity.java        |  98 +++++++++++
 .../repository/ProductDefinitionEntity.java        | 183 +++++++++++++++++++++
 .../repository/ProductDefinitionRepository.java    |  25 +++
 .../internal/repository/ProductInstanceEntity.java |  92 +++++++++++
 .../repository/ProductInstanceRepository.java      |  27 +++
 .../service/internal/repository/TermEntity.java    |  88 ++++++++++
 .../service/internal/service/ActionService.java    |  52 ++++++
 .../internal/service/ProductDefinitionService.java |  59 +++++++
 .../internal/service/ProductInstanceService.java   |  71 ++++++++
 ...stController.java => ActionRestController.java} |  64 +++----
 .../rest/ProductDefinitionRestController.java      |  43 ++++-
 .../rest/ProductInstanceRestController.java        |  35 +---
 33 files changed, 1629 insertions(+), 109 deletions(-)

diff --git a/api/src/main/java/io/mifos/deposit/api/v1/EventConstants.java b/api/src/main/java/io/mifos/deposit/api/v1/EventConstants.java
index 52e41fb..f6c20a3 100644
--- a/api/src/main/java/io/mifos/deposit/api/v1/EventConstants.java
+++ b/api/src/main/java/io/mifos/deposit/api/v1/EventConstants.java
@@ -24,6 +24,9 @@ public interface EventConstants {
   String INITIALIZE = "initialize";
   String SELECTOR_INITIALIZE = SELECTOR_NAME + " = '" + INITIALIZE + "'";
 
+  String POST_PRODUCT_ACTION = "post-product-action";
+  String SELECTOR_POST_PRODUCT_ACTION = SELECTOR_NAME + " = " + POST_PRODUCT_ACTION;
+
   String POST_PRODUCT_DEFINITION = "post-product-definition";
   String SELECTOR_POST_PRODUCT_DEFINITION = SELECTOR_NAME + " = '" + POST_PRODUCT_DEFINITION + "'";
   String POST_PRODUCT_DEFINITION_COMMAND = "post-product-definition-command";
diff --git a/api/src/main/java/io/mifos/deposit/api/v1/client/DepositAccountManager.java b/api/src/main/java/io/mifos/deposit/api/v1/client/DepositAccountManager.java
index 52ab843..80b69bc 100644
--- a/api/src/main/java/io/mifos/deposit/api/v1/client/DepositAccountManager.java
+++ b/api/src/main/java/io/mifos/deposit/api/v1/client/DepositAccountManager.java
@@ -16,6 +16,7 @@
 package io.mifos.deposit.api.v1.client;
 
 import io.mifos.core.api.util.CustomFeignClientsConfiguration;
+import io.mifos.deposit.api.v1.definition.domain.Action;
 import io.mifos.deposit.api.v1.definition.domain.ProductDefinition;
 import io.mifos.deposit.api.v1.definition.domain.ProductDefinitionCommand;
 import io.mifos.deposit.api.v1.instance.domain.ProductInstance;
@@ -36,6 +37,22 @@ import java.util.List;
 public interface DepositAccountManager {
 
   @RequestMapping(
+      value = "/actions",
+      method = RequestMethod.POST,
+      consumes = MediaType.APPLICATION_JSON_VALUE,
+      produces = MediaType.APPLICATION_JSON_VALUE
+  )
+  void create(@RequestBody @Valid final Action action);
+
+  @RequestMapping(
+      value = "/actions",
+      method = RequestMethod.GET,
+      consumes = MediaType.APPLICATION_JSON_VALUE,
+      produces = MediaType.ALL_VALUE
+  )
+  List<Action> fetchActions();
+
+  @RequestMapping(
       value = "/definitions",
       method = RequestMethod.POST,
       consumes = MediaType.APPLICATION_JSON_VALUE,
@@ -60,6 +77,14 @@ public interface DepositAccountManager {
   ProductDefinition findProductDefinition(@PathVariable("identifier") final String Identifier);
 
   @RequestMapping(
+      value = "/definitions/{identifier}/instances",
+      method = RequestMethod.GET,
+      consumes = MediaType.APPLICATION_JSON_VALUE,
+      produces = MediaType.ALL_VALUE
+  )
+  List<ProductInstance> findProductInstances(@PathVariable("identifier") final String Identifier);
+
+  @RequestMapping(
       value = "/definitions/{identifier}/commands",
       method = RequestMethod.POST,
       consumes = MediaType.APPLICATION_JSON_VALUE,
@@ -82,23 +107,5 @@ public interface DepositAccountManager {
       consumes = MediaType.APPLICATION_JSON_VALUE,
       produces = MediaType.ALL_VALUE
   )
-  List<ProductInstance> fetchProductInstances(@RequestParam(value = "customer", required = true) final String customer,
-                                              @RequestParam(value = "product", required = false) final String product);
-
-  @RequestMapping(
-      value = "/instances/{identifier}",
-      method = RequestMethod.GET,
-      consumes = MediaType.APPLICATION_JSON_VALUE,
-      produces = MediaType.ALL_VALUE
-  )
-  ProductInstance findProductInstance(@PathVariable("identifier") final String identifier);
-
-  @RequestMapping(
-      value = "/instances/{identifier}/states",
-      method = RequestMethod.POST,
-      consumes = MediaType.APPLICATION_JSON_VALUE,
-      produces = MediaType.APPLICATION_JSON_VALUE
-  )
-  void change(@PathVariable("identifier") final String identifier,
-              @RequestBody @Valid final StateChange stateChange);
+  List<ProductInstance> fetchProductInstances(@RequestParam(value = "customer", required = true) final String customer);
 }
diff --git a/api/src/main/java/io/mifos/deposit/api/v1/definition/domain/Action.java b/api/src/main/java/io/mifos/deposit/api/v1/definition/domain/Action.java
index b0315ed..b5ca3d2 100644
--- a/api/src/main/java/io/mifos/deposit/api/v1/definition/domain/Action.java
+++ b/api/src/main/java/io/mifos/deposit/api/v1/definition/domain/Action.java
@@ -15,11 +15,18 @@
  */
 package io.mifos.deposit.api.v1.definition.domain;
 
+import io.mifos.core.lang.validation.constraints.ValidIdentifier;
+
+import javax.validation.constraints.NotNull;
+
 public class Action {
 
+  @ValidIdentifier
   private String identifier;
+  @NotNull
   private String name;
   private String description;
+  @ValidIdentifier
   private String transactionType;
 
   public Action() {
diff --git a/api/src/main/java/io/mifos/deposit/api/v1/definition/domain/Charge.java b/api/src/main/java/io/mifos/deposit/api/v1/definition/domain/Charge.java
index 5109244..20dcf56 100644
--- a/api/src/main/java/io/mifos/deposit/api/v1/definition/domain/Charge.java
+++ b/api/src/main/java/io/mifos/deposit/api/v1/definition/domain/Charge.java
@@ -15,10 +15,19 @@
  */
 package io.mifos.deposit.api.v1.definition.domain;
 
+import io.mifos.core.lang.validation.constraints.ValidIdentifier;
+
+import javax.validation.constraints.NotNull;
+
 public class Charge {
 
+  @ValidIdentifier
   private String identifier;
+  @ValidIdentifier
   private String actionIdentifier;
+  @ValidIdentifier
+  private String incomeAccountIdentifier;
+  @NotNull
   private String name;
   private String description;
   private Boolean proportional;
@@ -44,6 +53,14 @@ public class Charge {
     this.actionIdentifier = actionIdentifier;
   }
 
+  public String getIncomeAccountIdentifier() {
+    return this.incomeAccountIdentifier;
+  }
+
+  public void setIncomeAccountIdentifier(final String incomeAccountIdentifier) {
+    this.incomeAccountIdentifier = incomeAccountIdentifier;
+  }
+
   public String getName() {
     return this.name;
   }
diff --git a/api/src/main/java/io/mifos/deposit/api/v1/definition/domain/ProductDefinition.java b/api/src/main/java/io/mifos/deposit/api/v1/definition/domain/ProductDefinition.java
index f4c6ea0..0dffd20 100644
--- a/api/src/main/java/io/mifos/deposit/api/v1/definition/domain/ProductDefinition.java
+++ b/api/src/main/java/io/mifos/deposit/api/v1/definition/domain/ProductDefinition.java
@@ -36,14 +36,15 @@ public class ProductDefinition {
   private Currency currency;
   @NotNull
   private Double minimumBalance;
+  private String equityLedgerIdentifier;
+  @ValidIdentifier
+  private String expenseAccountIdentifier;
   private Double interest;
   @Valid
   @NotNull
   private Term term;
   @Valid
   private List<Charge> charges;
-  @Valid
-  private List<Action> actions;
   private Boolean flexible;
   private Boolean active;
 
@@ -99,6 +100,22 @@ public class ProductDefinition {
     this.minimumBalance = minimumBalance;
   }
 
+  public String getEquityLedgerIdentifier() {
+    return this.equityLedgerIdentifier;
+  }
+
+  public void setEquityLedgerIdentifier(final String equityLedgerIdentifier) {
+    this.equityLedgerIdentifier = equityLedgerIdentifier;
+  }
+
+  public String getExpenseAccountIdentifier() {
+    return this.expenseAccountIdentifier;
+  }
+
+  public void setExpenseAccountIdentifier(final String expenseAccountIdentifier) {
+    this.expenseAccountIdentifier = expenseAccountIdentifier;
+  }
+
   public Double getInterest() {
     return this.interest;
   }
@@ -123,14 +140,6 @@ public class ProductDefinition {
     this.charges = charges;
   }
 
-  public List<Action> getActions() {
-    return this.actions;
-  }
-
-  public void setActions(final List<Action> actions) {
-    this.actions = actions;
-  }
-
   public Boolean getFlexible() {
     return this.flexible;
   }
diff --git a/api/src/main/java/io/mifos/deposit/api/v1/instance/domain/ProductInstance.java b/api/src/main/java/io/mifos/deposit/api/v1/instance/domain/ProductInstance.java
index 0342e61..4beb9eb 100644
--- a/api/src/main/java/io/mifos/deposit/api/v1/instance/domain/ProductInstance.java
+++ b/api/src/main/java/io/mifos/deposit/api/v1/instance/domain/ProductInstance.java
@@ -23,7 +23,8 @@ public class ProductInstance {
   private String customerIdentifier;
   @ValidIdentifier
   private String productIdentifier;
-  private State state;
+  private String accountIdentifier;
+  private String state;
 
   public ProductInstance() {
     super();
@@ -45,11 +46,19 @@ public class ProductInstance {
     this.productIdentifier = productIdentifier;
   }
 
-  public State getState() {
+  public String getAccountIdentifier() {
+    return this.accountIdentifier;
+  }
+
+  public void setAccountIdentifier(final String accountIdentifier) {
+    this.accountIdentifier = accountIdentifier;
+  }
+
+  public String getState() {
     return this.state;
   }
 
-  public void setState(final State state) {
+  public void setState(final String state) {
     this.state = state;
   }
 }
diff --git a/service/src/main/java/io/mifos/deposit/service/internal/command/CreateActionCommand.java b/service/src/main/java/io/mifos/deposit/service/internal/command/CreateActionCommand.java
new file mode 100644
index 0000000..747d4bb
--- /dev/null
+++ b/service/src/main/java/io/mifos/deposit/service/internal/command/CreateActionCommand.java
@@ -0,0 +1,31 @@
+/*
+ * 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.deposit.service.internal.command;
+
+import io.mifos.deposit.api.v1.definition.domain.Action;
+
+public class CreateActionCommand {
+  private final Action action;
+
+  public CreateActionCommand(final Action action) {
+    super();
+    this.action = action;
+  }
+
+  public Action action() {
+    return this.action;
+  }
+}
diff --git a/service/src/main/java/io/mifos/deposit/service/internal/command/CreateProductDefinitionCommand.java b/service/src/main/java/io/mifos/deposit/service/internal/command/CreateProductDefinitionCommand.java
new file mode 100644
index 0000000..a463cb1
--- /dev/null
+++ b/service/src/main/java/io/mifos/deposit/service/internal/command/CreateProductDefinitionCommand.java
@@ -0,0 +1,32 @@
+/*
+ * 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.deposit.service.internal.command;
+
+import io.mifos.deposit.api.v1.definition.domain.ProductDefinition;
+
+public class CreateProductDefinitionCommand {
+
+  private final ProductDefinition productDefinition;
+
+  public CreateProductDefinitionCommand(final ProductDefinition productDefinition) {
+    super();
+    this.productDefinition = productDefinition;
+  }
+
+  public ProductDefinition productDefinition() {
+    return this.productDefinition;
+  }
+}
diff --git a/service/src/main/java/io/mifos/deposit/service/internal/command/CreateProductInstanceCommand.java b/service/src/main/java/io/mifos/deposit/service/internal/command/CreateProductInstanceCommand.java
new file mode 100644
index 0000000..fc0547c
--- /dev/null
+++ b/service/src/main/java/io/mifos/deposit/service/internal/command/CreateProductInstanceCommand.java
@@ -0,0 +1,32 @@
+/*
+ * 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.deposit.service.internal.command;
+
+import io.mifos.deposit.api.v1.instance.domain.ProductInstance;
+
+public class CreateProductInstanceCommand {
+
+  private final ProductInstance productInstance;
+
+  public CreateProductInstanceCommand(final ProductInstance productInstance) {
+    super();
+    this.productInstance = productInstance;
+  }
+
+  public ProductInstance productInstance() {
+    return this.productInstance;
+  }
+}
diff --git a/service/src/main/java/io/mifos/deposit/service/internal/command/handler/ActionAggregate.java b/service/src/main/java/io/mifos/deposit/service/internal/command/handler/ActionAggregate.java
new file mode 100644
index 0000000..81aa4af
--- /dev/null
+++ b/service/src/main/java/io/mifos/deposit/service/internal/command/handler/ActionAggregate.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.deposit.service.internal.command.handler;
+
+import io.mifos.core.command.annotation.Aggregate;
+import io.mifos.core.command.annotation.CommandHandler;
+import io.mifos.core.command.annotation.EventEmitter;
+import io.mifos.deposit.api.v1.EventConstants;
+import io.mifos.deposit.api.v1.definition.domain.Action;
+import io.mifos.deposit.service.ServiceConstants;
+import io.mifos.deposit.service.internal.command.CreateActionCommand;
+import io.mifos.deposit.service.internal.mapper.ActionMapper;
+import io.mifos.deposit.service.internal.repository.ActionRepository;
+import org.slf4j.Logger;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.beans.factory.annotation.Qualifier;
+
+@Aggregate
+public class ActionAggregate {
+
+  private final Logger logger;
+  private final ActionRepository actionRepository;
+
+  @Autowired
+  public ActionAggregate(@Qualifier(ServiceConstants.LOGGER_NAME) final Logger logger,
+                         final ActionRepository actionRepository) {
+    this.logger = logger;
+    this.actionRepository = actionRepository;
+  }
+
+  @CommandHandler
+  @EventEmitter(selectorName = EventConstants.SELECTOR_NAME, selectorValue = EventConstants.POST_PRODUCT_ACTION)
+  public String createAction(final CreateActionCommand createActionCommand) {
+    final Action action = createActionCommand.action();
+    this.actionRepository.save(ActionMapper.map(action));
+    return action.getIdentifier();
+  }
+}
diff --git a/service/src/main/java/io/mifos/deposit/service/internal/command/handler/ProductDefinitionAggregate.java b/service/src/main/java/io/mifos/deposit/service/internal/command/handler/ProductDefinitionAggregate.java
new file mode 100644
index 0000000..fcd4968
--- /dev/null
+++ b/service/src/main/java/io/mifos/deposit/service/internal/command/handler/ProductDefinitionAggregate.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.deposit.service.internal.command.handler;
+
+import io.mifos.core.command.annotation.Aggregate;
+import io.mifos.core.command.annotation.CommandHandler;
+import io.mifos.core.command.annotation.EventEmitter;
+import io.mifos.deposit.api.v1.EventConstants;
+import io.mifos.deposit.api.v1.definition.domain.ProductDefinition;
+import io.mifos.deposit.service.ServiceConstants;
+import io.mifos.deposit.service.internal.command.CreateProductDefinitionCommand;
+import io.mifos.deposit.service.internal.mapper.ProductDefinitionMapper;
+import io.mifos.deposit.service.internal.repository.ActionRepository;
+import io.mifos.deposit.service.internal.repository.ProductDefinitionEntity;
+import io.mifos.deposit.service.internal.repository.ProductDefinitionRepository;
+import org.slf4j.Logger;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.beans.factory.annotation.Qualifier;
+
+@Aggregate
+public class ProductDefinitionAggregate {
+
+  private final Logger logger;
+  private final ProductDefinitionRepository productDefinitionRepository;
+  private final ActionRepository actionRepository;
+
+  @Autowired
+  public ProductDefinitionAggregate(@Qualifier(ServiceConstants.LOGGER_NAME) final Logger logger,
+                                    final ProductDefinitionRepository productDefinitionRepository,
+                                    final ActionRepository actionRepository) {
+    super();
+    this.logger = logger;
+    this.productDefinitionRepository = productDefinitionRepository;
+    this.actionRepository = actionRepository;
+  }
+
+  @CommandHandler
+  @EventEmitter(selectorName = EventConstants.SELECTOR_NAME, selectorValue = EventConstants.POST_PRODUCT_DEFINITION)
+  public String createProductDefinition(final CreateProductDefinitionCommand createProductDefinitionCommand) {
+
+    final ProductDefinition productDefinition = createProductDefinitionCommand.productDefinition();
+
+    final ProductDefinitionEntity productDefinitionEntity =
+        ProductDefinitionMapper.map(productDefinition, this.actionRepository);
+
+    this.productDefinitionRepository.save(productDefinitionEntity);
+
+    return createProductDefinitionCommand.productDefinition().getIdentifier();
+  }
+}
diff --git a/service/src/main/java/io/mifos/deposit/service/internal/command/handler/ProductInstanceAggregate.java b/service/src/main/java/io/mifos/deposit/service/internal/command/handler/ProductInstanceAggregate.java
new file mode 100644
index 0000000..84badec
--- /dev/null
+++ b/service/src/main/java/io/mifos/deposit/service/internal/command/handler/ProductInstanceAggregate.java
@@ -0,0 +1,60 @@
+/*
+ * 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.deposit.service.internal.command.handler;
+
+import io.mifos.core.command.annotation.Aggregate;
+import io.mifos.core.command.annotation.CommandHandler;
+import io.mifos.core.command.annotation.EventEmitter;
+import io.mifos.deposit.api.v1.EventConstants;
+import io.mifos.deposit.api.v1.instance.domain.ProductInstance;
+import io.mifos.deposit.service.ServiceConstants;
+import io.mifos.deposit.service.internal.command.CreateProductInstanceCommand;
+import io.mifos.deposit.service.internal.mapper.ProductInstanceMapper;
+import io.mifos.deposit.service.internal.repository.ProductDefinitionRepository;
+import io.mifos.deposit.service.internal.repository.ProductInstanceEntity;
+import io.mifos.deposit.service.internal.repository.ProductInstanceRepository;
+import org.slf4j.Logger;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.beans.factory.annotation.Qualifier;
+
+@Aggregate
+public class ProductInstanceAggregate {
+
+  private final Logger logger;
+  private final ProductInstanceRepository productInstanceRepository;
+  private final ProductDefinitionRepository productDefinitionRepository;
+
+  @Autowired
+  public ProductInstanceAggregate(@Qualifier(ServiceConstants.LOGGER_NAME) final Logger logger,
+                                  final ProductInstanceRepository productInstanceRepository,
+                                  final ProductDefinitionRepository productDefinitionRepository) {
+    this.logger = logger;
+    this.productInstanceRepository = productInstanceRepository;
+    this.productDefinitionRepository = productDefinitionRepository;
+  }
+
+  @CommandHandler
+  @EventEmitter(selectorName = EventConstants.SELECTOR_NAME, selectorValue = EventConstants.POST_PRODUCT_INSTANCE)
+  public String createProductInstance(final CreateProductInstanceCommand createProductInstanceCommand) {
+    final ProductInstance productInstance = createProductInstanceCommand.productInstance();
+
+    final ProductInstanceEntity productInstanceEntity =
+        ProductInstanceMapper.map(productInstance, this.productDefinitionRepository);
+
+    this.productInstanceRepository.save(productInstanceEntity);
+    return productInstance.getCustomerIdentifier();
+  }
+}
diff --git a/service/src/main/java/io/mifos/deposit/service/internal/mapper/ActionMapper.java b/service/src/main/java/io/mifos/deposit/service/internal/mapper/ActionMapper.java
new file mode 100644
index 0000000..0111c28
--- /dev/null
+++ b/service/src/main/java/io/mifos/deposit/service/internal/mapper/ActionMapper.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.deposit.service.internal.mapper;
+
+import io.mifos.deposit.api.v1.definition.domain.Action;
+import io.mifos.deposit.service.internal.repository.ActionEntity;
+
+public class ActionMapper {
+
+  private ActionMapper() {
+    super();
+  }
+
+  public static Action map(final ActionEntity actionEntity) {
+    final Action action = new Action();
+    action.setIdentifier(actionEntity.getIdentifier());
+    action.setName(actionEntity.getName());
+    action.setDescription(actionEntity.getDescription());
+    action.setTransactionType(actionEntity.getTransactionType());
+
+    return action;
+  }
+
+  public static ActionEntity map(final Action action) {
+    final ActionEntity actionEntity = new ActionEntity();
+    actionEntity.setIdentifier(action.getIdentifier());
+    actionEntity.setName(action.getName());
+    actionEntity.setDescription(action.getDescription());
+    actionEntity.setTransactionType(action.getTransactionType());
+
+    return actionEntity;
+  }
+}
diff --git a/service/src/main/java/io/mifos/deposit/service/internal/mapper/ChargesMapper.java b/service/src/main/java/io/mifos/deposit/service/internal/mapper/ChargesMapper.java
new file mode 100644
index 0000000..3bde640
--- /dev/null
+++ b/service/src/main/java/io/mifos/deposit/service/internal/mapper/ChargesMapper.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.deposit.service.internal.mapper;
+
+import io.mifos.core.lang.ServiceException;
+import io.mifos.deposit.api.v1.definition.domain.Charge;
+import io.mifos.deposit.service.internal.repository.ActionEntity;
+import io.mifos.deposit.service.internal.repository.ActionRepository;
+import io.mifos.deposit.service.internal.repository.ChargeEntity;
+
+import java.util.Optional;
+
+public class ChargesMapper {
+
+  private ChargesMapper() {
+    super();
+  }
+
+  public static ChargeEntity map(final Charge charge, final ActionRepository actionRepository) {
+    final Optional<ActionEntity> optionalActionEntity = actionRepository.findByIdentifier(charge.getActionIdentifier());
+    if (optionalActionEntity.isPresent()) {
+      final ChargeEntity chargeEntity = new ChargeEntity();
+      chargeEntity.setIdentifier(charge.getIdentifier());
+      chargeEntity.setAction(optionalActionEntity.get());
+      chargeEntity.setIncomeAccountIdentifier(charge.getIncomeAccountIdentifier());
+      chargeEntity.setName(charge.getName());
+      chargeEntity.setDescription(charge.getDescription());
+      chargeEntity.setProportional(charge.getProportional());
+      chargeEntity.setAmount(charge.getAmount());
+
+      return chargeEntity;
+    } else {
+      throw ServiceException.notFound("Can not create charge {0}, action {1} not found.",
+          charge.getIdentifier(), charge.getActionIdentifier());
+    }
+  }
+
+  public static Charge map(final ChargeEntity chargeEntity) {
+    final Charge charge = new Charge();
+    charge.setIdentifier(chargeEntity.getIdentifier());
+    charge.setActionIdentifier(chargeEntity.getAction().getIdentifier());
+    charge.setIncomeAccountIdentifier(chargeEntity.getIncomeAccountIdentifier());
+    charge.setName(chargeEntity.getName());
+    charge.setDescription(chargeEntity.getDescription());
+    charge.setProportional(chargeEntity.getProportional());
+    charge.setAmount(chargeEntity.getAmount());
+
+    return charge;
+  }
+}
diff --git a/service/src/main/java/io/mifos/deposit/service/internal/mapper/CurrencyMapper.java b/service/src/main/java/io/mifos/deposit/service/internal/mapper/CurrencyMapper.java
new file mode 100644
index 0000000..c2cd25a
--- /dev/null
+++ b/service/src/main/java/io/mifos/deposit/service/internal/mapper/CurrencyMapper.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.deposit.service.internal.mapper;
+
+import io.mifos.deposit.api.v1.definition.domain.Currency;
+import io.mifos.deposit.service.internal.repository.CurrencyEntity;
+
+public class CurrencyMapper {
+
+  private CurrencyMapper() {
+    super();
+  }
+
+  public static CurrencyEntity map(final Currency currency) {
+    final CurrencyEntity currencyEntity = new CurrencyEntity();
+    currencyEntity.setCode(currency.getCode());
+    currencyEntity.setName(currency.getName());
+    currencyEntity.setSign(currency.getSign());
+    currencyEntity.setScale(currency.getScale());
+
+    return currencyEntity;
+  }
+
+  public static Currency map(final CurrencyEntity currencyEntity) {
+    final Currency currency = new Currency();
+    currency.setCode(currencyEntity.getCode());
+    currency.setName(currencyEntity.getName());
+    currency.setSign(currencyEntity.getSign());
+    currency.setScale(currencyEntity.getScale());
+
+    return currency;
+  }
+}
diff --git a/service/src/main/java/io/mifos/deposit/service/internal/mapper/ProductDefinitionMapper.java b/service/src/main/java/io/mifos/deposit/service/internal/mapper/ProductDefinitionMapper.java
new file mode 100644
index 0000000..a559dd2
--- /dev/null
+++ b/service/src/main/java/io/mifos/deposit/service/internal/mapper/ProductDefinitionMapper.java
@@ -0,0 +1,73 @@
+/*
+ * 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.deposit.service.internal.mapper;
+
+import io.mifos.deposit.api.v1.definition.domain.ProductDefinition;
+import io.mifos.deposit.service.internal.repository.ActionRepository;
+import io.mifos.deposit.service.internal.repository.ProductDefinitionEntity;
+
+import java.util.stream.Collectors;
+
+public class ProductDefinitionMapper {
+
+  private ProductDefinitionMapper() {
+    super();
+  }
+
+  public static ProductDefinitionEntity map(final ProductDefinition productDefinition, final ActionRepository actionRepository) {
+    final ProductDefinitionEntity productDefinitionEntity = new ProductDefinitionEntity();
+    productDefinitionEntity.setType(productDefinition.getType());
+    productDefinitionEntity.setIdentifier(productDefinition.getIdentifier());
+    productDefinitionEntity.setName(productDefinition.getName());
+    productDefinitionEntity.setDescription(productDefinition.getName());
+    productDefinitionEntity.setCurrency(CurrencyMapper.map(productDefinition.getCurrency()));
+    productDefinitionEntity.setMinimumBalance(productDefinition.getMinimumBalance());
+    productDefinitionEntity.setEquityLedgerIdentifier(productDefinition.getEquityLedgerIdentifier());
+    productDefinitionEntity.setExpenseAccountIdentifier(productDefinition.getExpenseAccountIdentifier());
+    productDefinitionEntity.setInterest(productDefinition.getInterest());
+    productDefinitionEntity.setTerm(TermMapper.map(productDefinition.getTerm()));
+    productDefinitionEntity.setCharges(productDefinition.getCharges()
+        .stream()
+        .map(charge -> ChargesMapper.map(charge, actionRepository))
+        .collect(Collectors.toList())
+    );
+    productDefinitionEntity.setFlexible(productDefinition.getFlexible());
+
+    return productDefinitionEntity;
+  }
+
+  public static ProductDefinition map (final ProductDefinitionEntity productDefinitionEntity) {
+    final ProductDefinition productDefinition = new ProductDefinition();
+    productDefinition.setType(productDefinitionEntity.getType());
+    productDefinition.setIdentifier(productDefinitionEntity.getIdentifier());
+    productDefinition.setName(productDefinitionEntity.getName());
+    productDefinition.setDescription(productDefinitionEntity.getName());
+    productDefinition.setCurrency(CurrencyMapper.map(productDefinitionEntity.getCurrency()));
+    productDefinition.setMinimumBalance(productDefinitionEntity.getMinimumBalance());
+    productDefinition.setEquityLedgerIdentifier(productDefinitionEntity.getEquityLedgerIdentifier());
+    productDefinition.setExpenseAccountIdentifier(productDefinitionEntity.getExpenseAccountIdentifier());
+    productDefinition.setInterest(productDefinitionEntity.getInterest());
+    productDefinition.setTerm(TermMapper.map(productDefinitionEntity.getTerm()));
+    productDefinition.setCharges(productDefinitionEntity.getCharges()
+        .stream()
+        .map(ChargesMapper::map)
+        .collect(Collectors.toList())
+    );
+    productDefinition.setFlexible(productDefinitionEntity.getFlexible());
+
+    return productDefinition;
+  }
+}
diff --git a/service/src/main/java/io/mifos/deposit/service/internal/mapper/ProductInstanceMapper.java b/service/src/main/java/io/mifos/deposit/service/internal/mapper/ProductInstanceMapper.java
new file mode 100644
index 0000000..9bea583
--- /dev/null
+++ b/service/src/main/java/io/mifos/deposit/service/internal/mapper/ProductInstanceMapper.java
@@ -0,0 +1,58 @@
+/*
+ * Copyright 2017 The Mifos Initiative.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package io.mifos.deposit.service.internal.mapper;
+
+import io.mifos.core.lang.ServiceException;
+import io.mifos.deposit.api.v1.instance.domain.ProductInstance;
+import io.mifos.deposit.service.internal.repository.ProductDefinitionEntity;
+import io.mifos.deposit.service.internal.repository.ProductDefinitionRepository;
+import io.mifos.deposit.service.internal.repository.ProductInstanceEntity;
+
+import java.util.Optional;
+
+public class ProductInstanceMapper {
+
+  private ProductInstanceMapper() {
+    super();
+  }
+
+  public static ProductInstanceEntity map(final ProductInstance productInstance,
+                                          final ProductDefinitionRepository productDefinitionRepository) {
+    final Optional<ProductDefinitionEntity> optionalProductDefinitionEntity = productDefinitionRepository.findByIdentifier(productInstance.getProductIdentifier());
+    if (optionalProductDefinitionEntity.isPresent()) {
+      final ProductInstanceEntity productInstanceEntity = new ProductInstanceEntity();
+      productInstanceEntity.setCustomerIdentifier(productInstance.getCustomerIdentifier());
+      productInstanceEntity.setAccountIdentifier(productInstance.getAccountIdentifier());
+      productInstanceEntity.setState(productInstance.getState());
+      productInstanceEntity.setProductDefinition(optionalProductDefinitionEntity.get());
+
+      return productInstanceEntity;
+    } else {
+      throw ServiceException.notFound("Unable to assign product {0} to customer {1}, product not found.",
+          productInstance.getProductIdentifier(), productInstance.getCustomerIdentifier());
+    }
+  }
+
+  public static ProductInstance map(final ProductInstanceEntity productInstanceEntity) {
+    final ProductInstance productInstance = new ProductInstance();
+    productInstance.setCustomerIdentifier(productInstanceEntity.getCustomerIdentifier());
+    productInstance.setAccountIdentifier(productInstanceEntity.getAccountIdentifier());
+    productInstance.setProductIdentifier(productInstanceEntity.getProductDefinition().getIdentifier());
+    productInstance.setState(productInstanceEntity.getState());
+
+    return productInstance;
+  }
+}
diff --git a/service/src/main/java/io/mifos/deposit/service/internal/mapper/TermMapper.java b/service/src/main/java/io/mifos/deposit/service/internal/mapper/TermMapper.java
new file mode 100644
index 0000000..b6f3dbf
--- /dev/null
+++ b/service/src/main/java/io/mifos/deposit/service/internal/mapper/TermMapper.java
@@ -0,0 +1,44 @@
+/*
+ * 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.deposit.service.internal.mapper;
+
+import io.mifos.deposit.api.v1.definition.domain.Term;
+import io.mifos.deposit.service.internal.repository.TermEntity;
+
+public class TermMapper {
+
+  private TermMapper() {
+    super();
+  }
+
+  public static TermEntity map(final Term term) {
+    final TermEntity termEntity = new TermEntity();
+    termEntity.setPeriod(term.getPeriod());
+    termEntity.setTimeUnit(term.getTimeUnit());
+    termEntity.setInterestPayable(term.getInterestPayable());
+
+    return termEntity;
+  }
+
+  public static Term map(final TermEntity termEntity) {
+    final Term term = new Term();
+    term.setPeriod(termEntity.getPeriod());
+    term.setTimeUnit(termEntity.getTimeUnit());
+    term.setInterestPayable(termEntity.getInterestPayable());
+
+    return term;
+  }
+}
diff --git a/api/src/main/java/io/mifos/deposit/api/v1/definition/domain/Action.java b/service/src/main/java/io/mifos/deposit/service/internal/repository/ActionEntity.java
similarity index 63%
copy from api/src/main/java/io/mifos/deposit/api/v1/definition/domain/Action.java
copy to service/src/main/java/io/mifos/deposit/service/internal/repository/ActionEntity.java
index b0315ed..3df6279 100644
--- a/api/src/main/java/io/mifos/deposit/api/v1/definition/domain/Action.java
+++ b/service/src/main/java/io/mifos/deposit/service/internal/repository/ActionEntity.java
@@ -13,19 +13,44 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-package io.mifos.deposit.api.v1.definition.domain;
+package io.mifos.deposit.service.internal.repository;
 
-public class Action {
+import javax.persistence.Column;
+import javax.persistence.Entity;
+import javax.persistence.GeneratedValue;
+import javax.persistence.GenerationType;
+import javax.persistence.Id;
+import javax.persistence.Table;
 
+@Entity
+@Table(name = "shed_actions")
+public class ActionEntity {
+
+  @Id
+  @GeneratedValue(strategy = GenerationType.IDENTITY)
+  @Column(name = "id", nullable = false)
+  private Long id;
+  @Column(name = "identifier", nullable = false, unique = true, length = 32)
   private String identifier;
+  @Column(name = "name", nullable = false)
   private String name;
+  @Column(name = "description", nullable = true)
   private String description;
+  @Column(name = "transaction_type", nullable = false)
   private String transactionType;
 
-  public Action() {
+  public ActionEntity() {
     super();
   }
 
+  public Long getId() {
+    return this.id;
+  }
+
+  public void setId(final Long id) {
+    this.id = id;
+  }
+
   public String getIdentifier() {
     return this.identifier;
   }
diff --git a/service/src/main/java/io/mifos/deposit/service/internal/repository/ActionRepository.java b/service/src/main/java/io/mifos/deposit/service/internal/repository/ActionRepository.java
new file mode 100644
index 0000000..3967770
--- /dev/null
+++ b/service/src/main/java/io/mifos/deposit/service/internal/repository/ActionRepository.java
@@ -0,0 +1,25 @@
+/*
+ * 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.deposit.service.internal.repository;
+
+import org.springframework.data.jpa.repository.JpaRepository;
+
+import java.util.Optional;
+
+public interface ActionRepository extends JpaRepository<ActionEntity, Long> {
+
+  Optional<ActionEntity> findByIdentifier(final String identifier);
+}
diff --git a/service/src/main/java/io/mifos/deposit/service/internal/repository/ChargeEntity.java b/service/src/main/java/io/mifos/deposit/service/internal/repository/ChargeEntity.java
new file mode 100644
index 0000000..c8071e2
--- /dev/null
+++ b/service/src/main/java/io/mifos/deposit/service/internal/repository/ChargeEntity.java
@@ -0,0 +1,130 @@
+/*
+ * 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.deposit.service.internal.repository;
+
+import javax.persistence.Column;
+import javax.persistence.Entity;
+import javax.persistence.FetchType;
+import javax.persistence.GeneratedValue;
+import javax.persistence.GenerationType;
+import javax.persistence.Id;
+import javax.persistence.JoinColumn;
+import javax.persistence.ManyToOne;
+import javax.persistence.Table;
+
+@Entity
+@Table(name = "shed_charges")
+public class ChargeEntity {
+
+  @Id
+  @GeneratedValue(strategy = GenerationType.IDENTITY)
+  @Column(name = "id", nullable = false, unique = true)
+  private Long id;
+  @Column(name = "identifier", nullable = false, unique = true, length = 32)
+  private String identifier;
+  @ManyToOne(fetch = FetchType.EAGER)
+  @JoinColumn(name = "action_id", nullable = false)
+  private ActionEntity action;
+  @Column(name = "income_account_identifier", nullable = false, length = 32)
+  private String incomeAccountIdentifier;
+  @ManyToOne
+  @JoinColumn(name = "product_definition_id", nullable = false)
+  private ProductDefinitionEntity productDefinition;
+  @Column(name = "name", nullable = false)
+  private String name;
+  @Column(name = "description", nullable = true)
+  private String description;
+  @Column(name = "proportional", nullable = false)
+  private Boolean proportional;
+  @Column(name = "amount", nullable = false)
+  private Double amount;
+
+  public ChargeEntity() {
+    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 ActionEntity getAction() {
+    return this.action;
+  }
+
+  public void setAction(final ActionEntity action) {
+    this.action = action;
+  }
+
+  public String getIncomeAccountIdentifier() {
+    return this.incomeAccountIdentifier;
+  }
+
+  public void setIncomeAccountIdentifier(final String incomeAccountIdentifier) {
+    this.incomeAccountIdentifier = incomeAccountIdentifier;
+  }
+
+  public ProductDefinitionEntity getProductDefinition() {
+    return this.productDefinition;
+  }
+
+  public void setProductDefinition(final ProductDefinitionEntity productDefinition) {
+    this.productDefinition = productDefinition;
+  }
+
+  public String getName() {
+    return this.name;
+  }
+
+  public void setName(final String name) {
+    this.name = name;
+  }
+
+  public String getDescription() {
+    return this.description;
+  }
+
+  public void setDescription(final String description) {
+    this.description = description;
+  }
+
+  public Boolean getProportional() {
+    return this.proportional;
+  }
+
+  public void setProportional(final Boolean proportional) {
+    this.proportional = proportional;
+  }
+
+  public Double getAmount() {
+    return this.amount;
+  }
+
+  public void setAmount(final Double amount) {
+    this.amount = amount;
+  }
+}
diff --git a/service/src/main/java/io/mifos/deposit/service/internal/repository/CurrencyEntity.java b/service/src/main/java/io/mifos/deposit/service/internal/repository/CurrencyEntity.java
new file mode 100644
index 0000000..8b55cba
--- /dev/null
+++ b/service/src/main/java/io/mifos/deposit/service/internal/repository/CurrencyEntity.java
@@ -0,0 +1,98 @@
+/*
+ * 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.deposit.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.OneToOne;
+import javax.persistence.Table;
+
+@Entity
+@Table(name = "shed_currencies")
+public class CurrencyEntity {
+
+  @Id
+  @GeneratedValue(strategy = GenerationType.IDENTITY)
+  @Column(name = "id", nullable = false)
+  private Long id;
+  @OneToOne
+  @JoinColumn(name = "product_definition_id", nullable = false, unique = true)
+  private ProductDefinitionEntity productDefinition;
+  @Column(name = "a_code", nullable = false)
+  private String code;
+  @Column(name = "a_name", nullable = false)
+  private String name;
+  @Column(name = "sign", nullable = false)
+  private String sign;
+  @Column(name = "scale", nullable = false)
+  private Integer scale;
+
+  public CurrencyEntity() {
+    super();
+  }
+
+  public Long getId() {
+    return this.id;
+  }
+
+  public void setId(final Long id) {
+    this.id = id;
+  }
+
+  public ProductDefinitionEntity getProductDefinition() {
+    return this.productDefinition;
+  }
+
+  public void setProductDefinition(final ProductDefinitionEntity productDefinition) {
+    this.productDefinition = productDefinition;
+  }
+
+  public String getCode() {
+    return this.code;
+  }
+
+  public void setCode(final String code) {
+    this.code = code;
+  }
+
+  public String getName() {
+    return this.name;
+  }
+
+  public void setName(final String name) {
+    this.name = name;
+  }
+
+  public String getSign() {
+    return this.sign;
+  }
+
+  public void setSign(final String sign) {
+    this.sign = sign;
+  }
+
+  public Integer getScale() {
+    return this.scale;
+  }
+
+  public void setScale(final Integer scale) {
+    this.scale = scale;
+  }
+}
diff --git a/service/src/main/java/io/mifos/deposit/service/internal/repository/ProductDefinitionEntity.java b/service/src/main/java/io/mifos/deposit/service/internal/repository/ProductDefinitionEntity.java
new file mode 100644
index 0000000..a916661
--- /dev/null
+++ b/service/src/main/java/io/mifos/deposit/service/internal/repository/ProductDefinitionEntity.java
@@ -0,0 +1,183 @@
+/*
+ * 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.deposit.service.internal.repository;
+
+import javax.persistence.CascadeType;
+import javax.persistence.Column;
+import javax.persistence.Entity;
+import javax.persistence.FetchType;
+import javax.persistence.GeneratedValue;
+import javax.persistence.GenerationType;
+import javax.persistence.Id;
+import javax.persistence.OneToMany;
+import javax.persistence.OneToOne;
+import javax.persistence.Table;
+import java.util.List;
+
+@Entity
+@Table(name = "shed_product_definitions")
+public class ProductDefinitionEntity {
+
+  @Id
+  @GeneratedValue(strategy = GenerationType.IDENTITY)
+  @Column(name = "id", nullable = false)
+  private Long id;
+  @Column(name = "a_type", nullable = false)
+  private String type;
+  @Column(name = "identifier", nullable = false, unique = true, length = 32)
+  private String identifier;
+  @Column(name = "a_name", nullable = false, length = 256)
+  private String name;
+  @Column(name = "description", nullable = true, length = 4096)
+  private String description;
+  @OneToOne(mappedBy = "productDefinition", cascade = CascadeType.ALL, optional = false, fetch = FetchType.EAGER)
+  private CurrencyEntity currency;
+  @Column(name = "minimum_balance", nullable = true)
+  private Double minimumBalance;
+  @Column(name = "equity_ledger_identifier", nullable = false)
+  private String equityLedgerIdentifier;
+  @Column(name = "expense_account_identifier", nullable = false)
+  private String expenseAccountIdentifier;
+  @Column(name = "interest", nullable = true)
+  private Double interest;
+  @OneToOne(mappedBy = "productDefinition", cascade = CascadeType.ALL, optional = false, fetch = FetchType.EAGER)
+  private TermEntity term;
+  @OneToMany(mappedBy = "productDefinition", cascade = CascadeType.ALL, fetch = FetchType.EAGER)
+  private List<ChargeEntity> charges;
+  @Column(name = "is_flexible", nullable = false)
+  private Boolean flexible;
+  @Column(name = "is_active", nullable = false)
+  private Boolean active;
+
+  public ProductDefinitionEntity() {
+    super();
+  }
+
+  public Long getId() {
+    return this.id;
+  }
+
+  public void setId(final Long id) {
+    this.id = id;
+  }
+
+  public String getType() {
+    return this.type;
+  }
+
+  public void setType(final String type) {
+    this.type = type;
+  }
+
+  public String getIdentifier() {
+    return this.identifier;
+  }
+
+  public void setIdentifier(final String identifier) {
+    this.identifier = identifier;
+  }
+
+  public String getName() {
+    return this.name;
+  }
+
+  public void setName(final String name) {
+    this.name = name;
+  }
+
+  public String getDescription() {
+    return this.description;
+  }
+
+  public void setDescription(final String description) {
+    this.description = description;
+  }
+
+  public CurrencyEntity getCurrency() {
+    return this.currency;
+  }
+
+  public void setCurrency(final CurrencyEntity currency) {
+    this.currency = currency;
+    this.currency.setProductDefinition(this);
+  }
+
+  public Double getMinimumBalance() {
+    return this.minimumBalance;
+  }
+
+  public void setMinimumBalance(final Double minimumBalance) {
+    this.minimumBalance = minimumBalance;
+  }
+
+  public String getEquityLedgerIdentifier() {
+    return this.equityLedgerIdentifier;
+  }
+
+  public void setEquityLedgerIdentifier(final String equityLedgerIdentifier) {
+    this.equityLedgerIdentifier = equityLedgerIdentifier;
+  }
+
+  public String getExpenseAccountIdentifier() {
+    return this.expenseAccountIdentifier;
+  }
+
+  public void setExpenseAccountIdentifier(final String expenseAccountIdentifier) {
+    this.expenseAccountIdentifier = expenseAccountIdentifier;
+  }
+
+  public Double getInterest() {
+    return this.interest;
+  }
+
+  public void setInterest(final Double interest) {
+    this.interest = interest;
+  }
+
+  public TermEntity getTerm() {
+    return this.term;
+  }
+
+  public void setTerm(final TermEntity term) {
+    this.term = term;
+    this.term.setProductDefinition(this);
+  }
+
+  public List<ChargeEntity> getCharges() {
+    return this.charges;
+  }
+
+  public void setCharges(final List<ChargeEntity> charges) {
+    this.charges = charges;
+    charges.forEach(chargeEntity -> chargeEntity.setProductDefinition(this));
+  }
+
+  public Boolean getFlexible() {
+    return this.flexible;
+  }
+
+  public void setFlexible(final Boolean flexible) {
+    this.flexible = flexible;
+  }
+
+  public Boolean getActive() {
+    return this.active;
+  }
+
+  public void setActive(final Boolean active) {
+    this.active = active;
+  }
+}
diff --git a/service/src/main/java/io/mifos/deposit/service/internal/repository/ProductDefinitionRepository.java b/service/src/main/java/io/mifos/deposit/service/internal/repository/ProductDefinitionRepository.java
new file mode 100644
index 0000000..a9d5a02
--- /dev/null
+++ b/service/src/main/java/io/mifos/deposit/service/internal/repository/ProductDefinitionRepository.java
@@ -0,0 +1,25 @@
+/*
+ * 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.deposit.service.internal.repository;
+
+import org.springframework.data.jpa.repository.JpaRepository;
+
+import java.util.Optional;
+
+public interface ProductDefinitionRepository extends JpaRepository<ProductDefinitionEntity, Long> {
+
+  Optional<ProductDefinitionEntity> findByIdentifier(final String identifier);
+}
diff --git a/service/src/main/java/io/mifos/deposit/service/internal/repository/ProductInstanceEntity.java b/service/src/main/java/io/mifos/deposit/service/internal/repository/ProductInstanceEntity.java
new file mode 100644
index 0000000..c75edeb
--- /dev/null
+++ b/service/src/main/java/io/mifos/deposit/service/internal/repository/ProductInstanceEntity.java
@@ -0,0 +1,92 @@
+/*
+ * 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.deposit.service.internal.repository;
+
+import io.mifos.deposit.api.v1.definition.domain.ProductDefinition;
+
+import javax.persistence.CascadeType;
+import javax.persistence.Column;
+import javax.persistence.Entity;
+import javax.persistence.FetchType;
+import javax.persistence.GeneratedValue;
+import javax.persistence.GenerationType;
+import javax.persistence.Id;
+import javax.persistence.JoinColumn;
+import javax.persistence.ManyToOne;
+import javax.persistence.Table;
+
+@Entity
+@Table(name = "shed_product_instance")
+public class ProductInstanceEntity {
+
+  @Id
+  @GeneratedValue(strategy = GenerationType.IDENTITY)
+  @Column(name = "id", nullable = false)
+  private Long id;
+  @Column(name = "customer_identifier", nullable = false)
+  private String customerIdentifier;
+  @ManyToOne(fetch = FetchType.EAGER, optional = false, cascade = CascadeType.ALL)
+  @JoinColumn(name = "product_definition_id", nullable = false)
+  private ProductDefinitionEntity productDefinition;
+  @Column(name = "account_identifier", nullable = false)
+  private String accountIdentifier;
+  @Column(name = "a_state", nullable = false)
+  private String state;
+
+  public ProductInstanceEntity() {
+    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 ProductDefinitionEntity getProductDefinition() {
+    return this.productDefinition;
+  }
+
+  public void setProductDefinition(final ProductDefinitionEntity productDefinition) {
+    this.productDefinition = productDefinition;
+  }
+
+  public String getAccountIdentifier() {
+    return this.accountIdentifier;
+  }
+
+  public void setAccountIdentifier(final String accountIdentifier) {
+    this.accountIdentifier = accountIdentifier;
+  }
+
+  public String getState() {
+    return this.state;
+  }
+
+  public void setState(final String state) {
+    this.state = state;
+  }
+}
diff --git a/service/src/main/java/io/mifos/deposit/service/internal/repository/ProductInstanceRepository.java b/service/src/main/java/io/mifos/deposit/service/internal/repository/ProductInstanceRepository.java
new file mode 100644
index 0000000..ff29575
--- /dev/null
+++ b/service/src/main/java/io/mifos/deposit/service/internal/repository/ProductInstanceRepository.java
@@ -0,0 +1,27 @@
+/*
+ * 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.deposit.service.internal.repository;
+
+import org.springframework.data.jpa.repository.JpaRepository;
+
+import java.util.List;
+
+public interface ProductInstanceRepository extends JpaRepository<ProductInstanceEntity, Long> {
+
+  List<ProductInstanceEntity> findByCustomerIdentifier(final String customerIdentifier);
+
+  List<ProductInstanceEntity> findByProductDefinition(final ProductDefinitionEntity productDefinitionEntity);
+}
diff --git a/service/src/main/java/io/mifos/deposit/service/internal/repository/TermEntity.java b/service/src/main/java/io/mifos/deposit/service/internal/repository/TermEntity.java
new file mode 100644
index 0000000..4a9f8d8
--- /dev/null
+++ b/service/src/main/java/io/mifos/deposit/service/internal/repository/TermEntity.java
@@ -0,0 +1,88 @@
+/*
+ * 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.deposit.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.OneToOne;
+import javax.persistence.Table;
+
+@Entity
+@Table(name = "shed_terms")
+public class TermEntity {
+
+  @Id
+  @GeneratedValue(strategy = GenerationType.IDENTITY)
+  @Column(name = "id", nullable = false)
+  private Long id;
+  @OneToOne
+  @JoinColumn(name = "product_definition_id", nullable = false, unique = true)
+  private ProductDefinitionEntity productDefinition;
+  @Column(name = "period", nullable = false)
+  private Integer period;
+  @Column(name = "time_unit", nullable = false)
+  private String timeUnit;
+  @Column(name = "interest_payable", nullable = false)
+  private String interestPayable;
+
+  public TermEntity() {
+    super();
+  }
+
+  public Long getId() {
+    return this.id;
+  }
+
+  public ProductDefinitionEntity getProductDefinition() {
+    return this.productDefinition;
+  }
+
+  public void setProductDefinition(final ProductDefinitionEntity productDefinition) {
+    this.productDefinition = productDefinition;
+  }
+
+  public void setId(final Long id) {
+    this.id = id;
+  }
+
+  public Integer getPeriod() {
+    return this.period;
+  }
+
+  public void setPeriod(final Integer period) {
+    this.period = period;
+  }
+
+  public String getTimeUnit() {
+    return this.timeUnit;
+  }
+
+  public void setTimeUnit(final String timeUnit) {
+    this.timeUnit = timeUnit;
+  }
+
+  public String getInterestPayable() {
+    return this.interestPayable;
+  }
+
+  public void setInterestPayable(final String interestPayable) {
+    this.interestPayable = interestPayable;
+  }
+}
diff --git a/service/src/main/java/io/mifos/deposit/service/internal/service/ActionService.java b/service/src/main/java/io/mifos/deposit/service/internal/service/ActionService.java
new file mode 100644
index 0000000..ae5d6bb
--- /dev/null
+++ b/service/src/main/java/io/mifos/deposit/service/internal/service/ActionService.java
@@ -0,0 +1,52 @@
+/*
+ * 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.deposit.service.internal.service;
+
+import io.mifos.deposit.api.v1.definition.domain.Action;
+import io.mifos.deposit.service.ServiceConstants;
+import io.mifos.deposit.service.internal.mapper.ActionMapper;
+import io.mifos.deposit.service.internal.repository.ActionRepository;
+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.List;
+import java.util.Optional;
+import java.util.stream.Collectors;
+
+@Service
+public class ActionService {
+
+  private final Logger logger;
+  private final ActionRepository actionRepository;
+
+  @Autowired
+  public ActionService(@Qualifier(ServiceConstants.LOGGER_NAME) final Logger logger,
+                       final ActionRepository actionRepository) {
+    super();
+    this.logger = logger;
+    this.actionRepository = actionRepository;
+  }
+
+  public Optional<Action> findByIdentifier(final String identifier) {
+    return this.actionRepository.findByIdentifier(identifier).map(ActionMapper::map);
+  }
+
+  public List<Action> fetchActions() {
+    return this.actionRepository.findAll().stream().map(ActionMapper::map).collect(Collectors.toList());
+  }
+}
diff --git a/service/src/main/java/io/mifos/deposit/service/internal/service/ProductDefinitionService.java b/service/src/main/java/io/mifos/deposit/service/internal/service/ProductDefinitionService.java
new file mode 100644
index 0000000..770387f
--- /dev/null
+++ b/service/src/main/java/io/mifos/deposit/service/internal/service/ProductDefinitionService.java
@@ -0,0 +1,59 @@
+/*
+ * 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.deposit.service.internal.service;
+
+import io.mifos.deposit.api.v1.definition.domain.ProductDefinition;
+import io.mifos.deposit.service.ServiceConstants;
+import io.mifos.deposit.service.internal.mapper.ProductDefinitionMapper;
+import io.mifos.deposit.service.internal.repository.ActionRepository;
+import io.mifos.deposit.service.internal.repository.ProductDefinitionRepository;
+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.List;
+import java.util.Optional;
+import java.util.stream.Collectors;
+
+@Service
+public class ProductDefinitionService {
+
+  private final Logger logger;
+  private final ProductDefinitionRepository productDefinitionRepository;
+  private final ActionRepository actionRepository;
+
+  @Autowired
+  public ProductDefinitionService(@Qualifier(ServiceConstants.LOGGER_NAME) final Logger logger,
+                                  final ProductDefinitionRepository productDefinitionRepository,
+                                  final ActionRepository actionRepository) {
+    super();
+    this.logger = logger;
+    this.productDefinitionRepository = productDefinitionRepository;
+    this.actionRepository = actionRepository;
+  }
+
+  public List<ProductDefinition> fetchProductDefinitions() {
+    return this.productDefinitionRepository.findAll()
+        .stream()
+        .map(ProductDefinitionMapper::map)
+        .collect(Collectors.toList());
+  }
+
+  public Optional<ProductDefinition> findProductDefinition(final String identfier) {
+    return this.productDefinitionRepository.findByIdentifier(identfier).map(ProductDefinitionMapper::map);
+  }
+}
diff --git a/service/src/main/java/io/mifos/deposit/service/internal/service/ProductInstanceService.java b/service/src/main/java/io/mifos/deposit/service/internal/service/ProductInstanceService.java
new file mode 100644
index 0000000..842b7e1
--- /dev/null
+++ b/service/src/main/java/io/mifos/deposit/service/internal/service/ProductInstanceService.java
@@ -0,0 +1,71 @@
+/*
+ * 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.deposit.service.internal.service;
+
+import io.mifos.deposit.api.v1.definition.domain.ProductDefinition;
+import io.mifos.deposit.api.v1.instance.domain.ProductInstance;
+import io.mifos.deposit.service.ServiceConstants;
+import io.mifos.deposit.service.internal.mapper.ProductDefinitionMapper;
+import io.mifos.deposit.service.internal.mapper.ProductInstanceMapper;
+import io.mifos.deposit.service.internal.repository.ActionRepository;
+import io.mifos.deposit.service.internal.repository.ProductDefinitionEntity;
+import io.mifos.deposit.service.internal.repository.ProductDefinitionRepository;
+import io.mifos.deposit.service.internal.repository.ProductInstanceRepository;
+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.Collections;
+import java.util.List;
+import java.util.Optional;
+import java.util.stream.Collectors;
+
+@Service
+public class ProductInstanceService {
+
+  private final Logger logger;
+  private final ProductInstanceRepository productInstanceRepository;
+  private final ProductDefinitionRepository productDefinitionRepository;
+
+  @Autowired
+  public ProductInstanceService(@Qualifier(ServiceConstants.LOGGER_NAME) final Logger logger,
+                                final ProductInstanceRepository productInstanceRepository,
+                                final ProductDefinitionRepository productDefinitionRepository) {
+    super();
+    this.logger = logger;
+    this.productInstanceRepository = productInstanceRepository;
+    this.productDefinitionRepository = productDefinitionRepository;
+  }
+
+  public List<ProductInstance> findByCustomer(final String customerIdentifier) {
+    return this.productInstanceRepository.findByCustomerIdentifier(customerIdentifier)
+        .stream()
+        .map(ProductInstanceMapper::map).
+        collect(Collectors.toList());
+  }
+
+  public List<ProductInstance> findByProductDefinition(final String identifier) {
+    final Optional<ProductDefinitionEntity> optionalProductDefinition = this.productDefinitionRepository.findByIdentifier(identifier);
+
+    return optionalProductDefinition
+        .map(productDefinitionEntity -> this.productInstanceRepository.findByProductDefinition(productDefinitionEntity)
+          .stream()
+          .map(ProductInstanceMapper::map)
+          .collect(Collectors.toList())).orElseGet(Collections::emptyList);
+
+  }
+}
diff --git a/service/src/main/java/io/mifos/deposit/service/rest/ProductDefinitionRestController.java b/service/src/main/java/io/mifos/deposit/service/rest/ActionRestController.java
similarity index 54%
copy from service/src/main/java/io/mifos/deposit/service/rest/ProductDefinitionRestController.java
copy to service/src/main/java/io/mifos/deposit/service/rest/ActionRestController.java
index dec7089..c1af8cf 100644
--- a/service/src/main/java/io/mifos/deposit/service/rest/ProductDefinitionRestController.java
+++ b/service/src/main/java/io/mifos/deposit/service/rest/ActionRestController.java
@@ -18,87 +18,69 @@ package io.mifos.deposit.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.deposit.api.v1.PermittableGroupIds;
-import io.mifos.deposit.api.v1.definition.domain.ProductDefinition;
-import io.mifos.deposit.api.v1.definition.domain.ProductDefinitionCommand;
+import io.mifos.deposit.api.v1.definition.domain.Action;
 import io.mifos.deposit.service.ServiceConstants;
+import io.mifos.deposit.service.internal.command.CreateActionCommand;
+import io.mifos.deposit.service.internal.service.ActionService;
 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;
-import java.util.Collections;
 import java.util.List;
 
 @RestController
-@RequestMapping("/definitions")
-public class ProductDefinitionRestController {
+@RequestMapping("/actions")
+public class ActionRestController {
 
   private final Logger logger;
   private final CommandGateway commandGateway;
+  private final ActionService actionService;
 
   @Autowired
-  public ProductDefinitionRestController(@Qualifier(ServiceConstants.LOGGER_NAME) final Logger logger,
-                                         final CommandGateway commandGateway) {
+  public ActionRestController(@Qualifier(ServiceConstants.LOGGER_NAME) final Logger logger,
+                              final CommandGateway commandGateway,
+                              final ActionService actionService) {
     super();
     this.logger = logger;
     this.commandGateway = commandGateway;
+    this.actionService = actionService;
   }
 
-  @Permittable(value = AcceptedTokenType.TENANT, groupId = PermittableGroupIds.DEFINITION_MANAGEMENT)
   @RequestMapping(
-      value = "/",
+      value = "/actions",
       method = RequestMethod.POST,
       consumes = MediaType.APPLICATION_JSON_VALUE,
       produces = MediaType.APPLICATION_JSON_VALUE
   )
-  @ResponseBody
-  public ResponseEntity<Void> create(@RequestBody @Valid final ProductDefinition productDefinition) {
+  @Permittable(value = AcceptedTokenType.TENANT, groupId = PermittableGroupIds.DEFINITION_MANAGEMENT)
+  public ResponseEntity<Void> create(@RequestBody @Valid final Action action) {
+    this.actionService.findByIdentifier(action.getIdentifier()).ifPresent(actionEntity -> {
+      throw ServiceException.conflict("Action {0} already exists.", action.getIdentifier());
+    });
+
+    this.commandGateway.process(new CreateActionCommand(action));
     return ResponseEntity.accepted().build();
   }
 
-  @Permittable(value = AcceptedTokenType.TENANT, groupId = PermittableGroupIds.DEFINITION_MANAGEMENT)
   @RequestMapping(
-      value = "/",
+      value = "/actions",
       method = RequestMethod.GET,
       consumes = MediaType.ALL_VALUE,
       produces = MediaType.APPLICATION_JSON_VALUE
   )
-  @ResponseBody
-  ResponseEntity<List<ProductDefinition>> fetchProductDefinitions() {
-    return ResponseEntity.ok(Collections.emptyList());
-  }
-
   @Permittable(value = AcceptedTokenType.TENANT, groupId = PermittableGroupIds.DEFINITION_MANAGEMENT)
-  @RequestMapping(
-      value = "/{identifier}",
-      method = RequestMethod.GET,
-      consumes = MediaType.ALL_VALUE,
-      produces = MediaType.APPLICATION_JSON_VALUE
-  )
-  @ResponseBody
-  ResponseEntity<ProductDefinition> findProductDefinition(@PathVariable("identifier") final String Identifier) {
-    return ResponseEntity.ok(null);
+  public ResponseEntity<List<Action>> fetchActions() {
+    return ResponseEntity.ok(this.actionService.fetchActions());
   }
 
-  @Permittable(value = AcceptedTokenType.TENANT, groupId = PermittableGroupIds.DEFINITION_MANAGEMENT)
-  @RequestMapping(
-      value = "/{identifier}/commands",
-      method = RequestMethod.POST,
-      consumes = MediaType.APPLICATION_JSON_VALUE,
-      produces = MediaType.APPLICATION_JSON_VALUE
-  )
-  @ResponseBody
-  public ResponseEntity<Void> process(@PathVariable("identifier") final String identifier,
-                                      @RequestBody @Valid final ProductDefinitionCommand command) {
-    return ResponseEntity.accepted().build();
-  }
+
 }
diff --git a/service/src/main/java/io/mifos/deposit/service/rest/ProductDefinitionRestController.java b/service/src/main/java/io/mifos/deposit/service/rest/ProductDefinitionRestController.java
index dec7089..62ec1f9 100644
--- a/service/src/main/java/io/mifos/deposit/service/rest/ProductDefinitionRestController.java
+++ b/service/src/main/java/io/mifos/deposit/service/rest/ProductDefinitionRestController.java
@@ -18,10 +18,16 @@ package io.mifos.deposit.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.deposit.api.v1.PermittableGroupIds;
 import io.mifos.deposit.api.v1.definition.domain.ProductDefinition;
 import io.mifos.deposit.api.v1.definition.domain.ProductDefinitionCommand;
+import io.mifos.deposit.api.v1.instance.domain.ProductInstance;
 import io.mifos.deposit.service.ServiceConstants;
+import io.mifos.deposit.service.internal.command.CreateProductDefinitionCommand;
+import io.mifos.deposit.service.internal.repository.ProductInstanceRepository;
+import io.mifos.deposit.service.internal.service.ProductDefinitionService;
+import io.mifos.deposit.service.internal.service.ProductInstanceService;
 import org.slf4j.Logger;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.beans.factory.annotation.Qualifier;
@@ -35,8 +41,8 @@ import org.springframework.web.bind.annotation.ResponseBody;
 import org.springframework.web.bind.annotation.RestController;
 
 import javax.validation.Valid;
-import java.util.Collections;
 import java.util.List;
+import java.util.Optional;
 
 @RestController
 @RequestMapping("/definitions")
@@ -44,13 +50,19 @@ public class ProductDefinitionRestController {
 
   private final Logger logger;
   private final CommandGateway commandGateway;
+  private final ProductDefinitionService productDefinitionService;
+  private final ProductInstanceService productInstanceService;
 
   @Autowired
   public ProductDefinitionRestController(@Qualifier(ServiceConstants.LOGGER_NAME) final Logger logger,
-                                         final CommandGateway commandGateway) {
+                                         final CommandGateway commandGateway,
+                                         final ProductDefinitionService productDefinitionService,
+                                         final ProductInstanceService productInstanceService) {
     super();
     this.logger = logger;
     this.commandGateway = commandGateway;
+    this.productDefinitionService = productDefinitionService;
+    this.productInstanceService = productInstanceService;
   }
 
   @Permittable(value = AcceptedTokenType.TENANT, groupId = PermittableGroupIds.DEFINITION_MANAGEMENT)
@@ -62,6 +74,7 @@ public class ProductDefinitionRestController {
   )
   @ResponseBody
   public ResponseEntity<Void> create(@RequestBody @Valid final ProductDefinition productDefinition) {
+    this.commandGateway.process(new CreateProductDefinitionCommand(productDefinition));
     return ResponseEntity.accepted().build();
   }
 
@@ -74,7 +87,7 @@ public class ProductDefinitionRestController {
   )
   @ResponseBody
   ResponseEntity<List<ProductDefinition>> fetchProductDefinitions() {
-    return ResponseEntity.ok(Collections.emptyList());
+    return ResponseEntity.ok(this.productDefinitionService.fetchProductDefinitions());
   }
 
   @Permittable(value = AcceptedTokenType.TENANT, groupId = PermittableGroupIds.DEFINITION_MANAGEMENT)
@@ -85,8 +98,28 @@ public class ProductDefinitionRestController {
       produces = MediaType.APPLICATION_JSON_VALUE
   )
   @ResponseBody
-  ResponseEntity<ProductDefinition> findProductDefinition(@PathVariable("identifier") final String Identifier) {
-    return ResponseEntity.ok(null);
+  ResponseEntity<ProductDefinition> findProductDefinition(@PathVariable("identifier") final String identifier) {
+    return ResponseEntity.ok(
+        this.productDefinitionService.findProductDefinition(identifier)
+            .orElseThrow(() -> ServiceException.notFound("Product definition {0} not found.", identifier))
+    );
+  }
+
+  @RequestMapping(
+      value = "/definitions/{identifier}/instances",
+      method = RequestMethod.GET,
+      consumes = MediaType.ALL_VALUE,
+      produces = MediaType.APPLICATION_JSON_VALUE
+  )
+  @Permittable(value = AcceptedTokenType.TENANT, groupId = PermittableGroupIds.INSTANCE_MANAGEMENT)
+  public ResponseEntity<List<ProductInstance>> findProductInstances(@PathVariable("identifier") final String identifier) {
+
+    final Optional<ProductDefinition> optionalProductDefinition = this.productDefinitionService.findProductDefinition(identifier);
+    if (!this.productDefinitionService.findProductDefinition(identifier).isPresent()) {
+      throw ServiceException.notFound("Product definition {0} not found.", identifier);
+    } else {
+      return ResponseEntity.ok(this.productInstanceService.findByProductDefinition(identifier));
+    }
   }
 
   @Permittable(value = AcceptedTokenType.TENANT, groupId = PermittableGroupIds.DEFINITION_MANAGEMENT)
diff --git a/service/src/main/java/io/mifos/deposit/service/rest/ProductInstanceRestController.java b/service/src/main/java/io/mifos/deposit/service/rest/ProductInstanceRestController.java
index 2c3146e..e833070 100644
--- a/service/src/main/java/io/mifos/deposit/service/rest/ProductInstanceRestController.java
+++ b/service/src/main/java/io/mifos/deposit/service/rest/ProductInstanceRestController.java
@@ -22,6 +22,7 @@ import io.mifos.deposit.api.v1.PermittableGroupIds;
 import io.mifos.deposit.api.v1.instance.domain.ProductInstance;
 import io.mifos.deposit.api.v1.instance.domain.StateChange;
 import io.mifos.deposit.service.ServiceConstants;
+import io.mifos.deposit.service.internal.service.ProductInstanceService;
 import org.slf4j.Logger;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.beans.factory.annotation.Qualifier;
@@ -45,13 +46,16 @@ public class ProductInstanceRestController {
 
   private final Logger logger;
   private final CommandGateway commandGateway;
+  private final ProductInstanceService productInstanceService;
 
   @Autowired
   public ProductInstanceRestController(@Qualifier(ServiceConstants.LOGGER_NAME) final Logger logger,
-                                       final CommandGateway commandGateway) {
+                                       final CommandGateway commandGateway,
+                                       final ProductInstanceService productInstanceService) {
     super();
     this.logger = logger;
     this.commandGateway = commandGateway;
+    this.productInstanceService = productInstanceService;
   }
 
   @Permittable(value = AcceptedTokenType.TENANT, groupId = PermittableGroupIds.INSTANCE_MANAGEMENT)
@@ -74,32 +78,7 @@ public class ProductInstanceRestController {
       produces = MediaType.APPLICATION_JSON_VALUE
   )
   @ResponseBody
-  public ResponseEntity<List<ProductInstance>> fetchProductInstances(@RequestParam(value = "customer", required = true) final String customer,
-                                                                     @RequestParam(value = "product", required = false) final String product) {
-    return ResponseEntity.ok(Collections.emptyList());
-  }
-
-  @Permittable(value = AcceptedTokenType.TENANT, groupId = PermittableGroupIds.INSTANCE_MANAGEMENT)
-  @RequestMapping(
-      value = "/{identifier}",
-      method = RequestMethod.GET,
-      consumes = MediaType.ALL_VALUE,
-      produces = MediaType.APPLICATION_JSON_VALUE
-  )
-  @ResponseBody
-  public ResponseEntity<ProductInstance> findProductInstance(@PathVariable("identifier") final String identifier) {
-    return ResponseEntity.ok(null);
-  }
-
-  @Permittable(value = AcceptedTokenType.TENANT, groupId = PermittableGroupIds.INSTANCE_MANAGEMENT)
-  @RequestMapping(
-      value = "/{identifier}/states",
-      method = RequestMethod.POST,
-      consumes = MediaType.APPLICATION_JSON_VALUE,
-      produces = MediaType.APPLICATION_JSON_VALUE
-  )
-  public ResponseEntity<Void> change(@PathVariable("identifier") final String identifier,
-                                     @RequestBody @Valid final StateChange stateChange) {
-    return ResponseEntity.accepted().build();
+  public ResponseEntity<List<ProductInstance>> fetchProductInstances(@RequestParam(value = "customer", required = true) final String customerIdentifier) {
+    return ResponseEntity.ok(this.productInstanceService.findByCustomer(customerIdentifier));
   }
 }

-- 
To stop receiving notification emails like this one, please contact
myrle@apache.org.

Mime
View raw message