Merge pull request #21 from fynmanoj/statement-api

Statement-API
diff --git a/api/src/main/java/org/apache/fineract/cn/deposit/api/v1/EventConstants.java b/api/src/main/java/org/apache/fineract/cn/deposit/api/v1/EventConstants.java
index 8f8a101..1f70ac1 100644
--- a/api/src/main/java/org/apache/fineract/cn/deposit/api/v1/EventConstants.java
+++ b/api/src/main/java/org/apache/fineract/cn/deposit/api/v1/EventConstants.java
@@ -50,6 +50,9 @@
   String PUT_PRODUCT_INSTANCE = "put-product-instance";
   String SELECTOR_PUT_PRODUCT_INSTANCE = SELECTOR_NAME + " = '" + PUT_PRODUCT_INSTANCE + "'";
 
+  String POST_SUB_TXN_TYPE = "post-sub-txn-type";
+  String PUT_SUB_TXN_TYPE = "put-sub-txn-type";
+
   String ACTIVATE_PRODUCT_INSTANCE_COMMAND = "ACTIVATE";
   String CLOSE_PRODUCT_INSTANCE_COMMAND = "CLOSE";
   String PRODUCT_INSTANCE_TRANSACTION = "TRANSACTION";
diff --git a/api/src/main/java/org/apache/fineract/cn/deposit/api/v1/instance/domain/SubTransactionType.java b/api/src/main/java/org/apache/fineract/cn/deposit/api/v1/instance/domain/SubTransactionType.java
new file mode 100644
index 0000000..4bb6d4b
--- /dev/null
+++ b/api/src/main/java/org/apache/fineract/cn/deposit/api/v1/instance/domain/SubTransactionType.java
@@ -0,0 +1,105 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you 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 org.apache.fineract.cn.deposit.api.v1.instance.domain;
+
+import org.hibernate.validator.constraints.NotBlank;
+
+import javax.validation.constraints.NotNull;
+
+public class SubTransactionType {
+    @NotBlank
+    private String identifier;
+    @NotBlank
+    private String name;
+    private String description;
+    @NotNull
+    private Boolean cashPayment;
+    @NotNull
+    private Boolean active;
+    private Integer orderPosition;
+    private Integer tranType;
+    private String ledgerAccount;
+
+    public SubTransactionType() {
+    }
+
+    public String getIdentifier() {
+        return identifier;
+    }
+
+    public void setIdentifier(String identifier) {
+        this.identifier = identifier;
+    }
+
+    public String getName() {
+        return name;
+    }
+
+    public void setName(String name) {
+        this.name = name;
+    }
+
+    public String getDescription() {
+        return description;
+    }
+
+    public void setDescription(String description) {
+        this.description = description;
+    }
+
+    public Boolean getCashPayment() {
+        return cashPayment;
+    }
+
+    public void setCashPayment(Boolean cashPayment) {
+        this.cashPayment = cashPayment;
+    }
+
+    public Boolean getActive() {
+        return active;
+    }
+
+    public void setActive(Boolean active) {
+        this.active = active;
+    }
+
+    public Integer getOrderPosition() {
+        return orderPosition;
+    }
+
+    public void setOrderPosition(Integer orderPosition) {
+        this.orderPosition = orderPosition;
+    }
+
+    public Integer getTranType() {
+        return tranType;
+    }
+
+    public void setTranType(Integer tranType) {
+        this.tranType = tranType;
+    }
+
+    public String getLedgerAccount() {
+        return ledgerAccount;
+    }
+
+    public void setLedgerAccount(String ledgerAccount) {
+        this.ledgerAccount = ledgerAccount;
+    }
+}
diff --git a/api/src/main/java/org/apache/fineract/cn/deposit/api/v1/transaction/domain/data/ActionState.java b/api/src/main/java/org/apache/fineract/cn/deposit/api/v1/transaction/domain/data/ActionState.java
new file mode 100644
index 0000000..3a8ab82
--- /dev/null
+++ b/api/src/main/java/org/apache/fineract/cn/deposit/api/v1/transaction/domain/data/ActionState.java
@@ -0,0 +1,24 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you 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 org.apache.fineract.cn.deposit.api.v1.transaction.domain.data;
+
+public enum ActionState {
+        ACCEPTED,
+        REJECTED
+}
diff --git a/api/src/main/java/org/apache/fineract/cn/deposit/api/v1/transaction/domain/data/ExtensionData.java b/api/src/main/java/org/apache/fineract/cn/deposit/api/v1/transaction/domain/data/ExtensionData.java
new file mode 100644
index 0000000..746e5e4
--- /dev/null
+++ b/api/src/main/java/org/apache/fineract/cn/deposit/api/v1/transaction/domain/data/ExtensionData.java
@@ -0,0 +1,58 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you 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 org.apache.fineract.cn.deposit.api.v1.transaction.domain.data;
+
+import org.hibernate.validator.constraints.Length;
+
+import javax.validation.constraints.NotNull;
+
+public class ExtensionData {
+
+    @NotNull
+    @Length(min = 1, max = 128)
+    private String key;
+
+    @NotNull
+    @Length(min = 1, max = 128)
+    private String value;
+
+    public ExtensionData() {
+    }
+
+    public ExtensionData(@NotNull String key, @NotNull String value) {
+        this.key = key;
+        this.value = value;
+    }
+
+    public String getKey() {
+        return key;
+    }
+
+    public String getValue() {
+        return value;
+    }
+
+    protected void setKey(String key) {
+        this.key = key;
+    }
+
+    protected void setValue(String value) {
+        this.value = value;
+    }
+}
diff --git a/api/src/main/java/org/apache/fineract/cn/deposit/api/v1/transaction/domain/data/GeoCodeData.java b/api/src/main/java/org/apache/fineract/cn/deposit/api/v1/transaction/domain/data/GeoCodeData.java
new file mode 100644
index 0000000..e165489
--- /dev/null
+++ b/api/src/main/java/org/apache/fineract/cn/deposit/api/v1/transaction/domain/data/GeoCodeData.java
@@ -0,0 +1,57 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you 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 org.apache.fineract.cn.deposit.api.v1.transaction.domain.data;
+
+import javax.validation.constraints.NotNull;
+import javax.validation.constraints.Pattern;
+
+public class GeoCodeData {
+
+    @NotNull
+    @Pattern(regexp = "^(\\+|-)?(?:90(?:(?:\\.0{1,6})?)|(?:[0-9]|[1-8][0-9])(?:(?:\\.[0-9]{1,6})?))$")
+    private String latitude;
+
+    @NotNull
+    @Pattern(regexp = "^(\\+|-)?(?:180(?:(?:\\.0{1,6})?)|(?:[0-9]|[1-9][0-9]|1[0-7][0-9])(?:(?:\\.[0-9]{1,6})?))$")
+    private String longitude;
+
+    public GeoCodeData() {
+    }
+
+    public GeoCodeData(String latitude, String longitude) {
+        this.latitude = latitude;
+        this.longitude = longitude;
+    }
+
+    public String getLatitude() {
+        return latitude;
+    }
+
+    public String getLongitude() {
+        return longitude;
+    }
+
+    public void setLatitude(String latitude) {
+        this.latitude = latitude;
+    }
+
+    public void setLongitude(String longitude) {
+        this.longitude = longitude;
+    }
+}
diff --git a/api/src/main/java/org/apache/fineract/cn/deposit/api/v1/transaction/domain/data/MoneyData.java b/api/src/main/java/org/apache/fineract/cn/deposit/api/v1/transaction/domain/data/MoneyData.java
new file mode 100644
index 0000000..96a1625
--- /dev/null
+++ b/api/src/main/java/org/apache/fineract/cn/deposit/api/v1/transaction/domain/data/MoneyData.java
@@ -0,0 +1,78 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you 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 org.apache.fineract.cn.deposit.api.v1.transaction.domain.data;
+
+import org.apache.fineract.cn.deposit.api.v1.definition.domain.Currency;
+import org.apache.fineract.cn.deposit.api.v1.transaction.utils.MathUtil;
+import org.hibernate.validator.constraints.Length;
+
+import javax.validation.constraints.Digits;
+import javax.validation.constraints.Min;
+import javax.validation.constraints.NotNull;
+import java.math.BigDecimal;
+
+public class MoneyData {
+
+    @NotNull
+    @Min(0)
+    @Digits(integer = 15, fraction = 4) // interoperation schema allows integer = 18, AccountEntity amount allows fraction = 5
+    private BigDecimal amount;
+
+    @NotNull
+    @Length(min = 3, max = 3)
+    private String currency;
+
+    public MoneyData() {
+    }
+
+    public MoneyData(BigDecimal amount, String currency) {
+        this.amount = amount;
+        this.currency = currency;
+    }
+
+    public static MoneyData build(BigDecimal amount, String currency) {
+        return amount == null ? null : new MoneyData(amount, currency);
+    }
+
+    public static MoneyData build(BigDecimal amount, Currency currency) {
+        return amount == null ? null : build(amount, currency.getCode());
+    }
+
+    public BigDecimal getAmount() {
+        return amount;
+    }
+
+    public String getCurrency() {
+        return currency;
+    }
+
+    public void normalizeAmount(@NotNull Currency currency) {
+        if (!currency.getCode().equals(this.currency))
+            throw new UnsupportedOperationException("Internal error: Invalid currency " + currency.getCode());
+        MathUtil.normalize(amount, currency);
+    }
+
+    public void setAmount(BigDecimal amount) {
+        this.amount = amount;
+    }
+
+    public void setCurrency(String currency) {
+        this.currency = currency;
+    }
+}
diff --git a/api/src/main/java/org/apache/fineract/cn/deposit/api/v1/transaction/domain/data/StatementResponse.java b/api/src/main/java/org/apache/fineract/cn/deposit/api/v1/transaction/domain/data/StatementResponse.java
new file mode 100644
index 0000000..c6fc79e
--- /dev/null
+++ b/api/src/main/java/org/apache/fineract/cn/deposit/api/v1/transaction/domain/data/StatementResponse.java
@@ -0,0 +1,90 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you 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 org.apache.fineract.cn.deposit.api.v1.transaction.domain.data;
+
+import java.math.BigDecimal;
+import java.time.LocalDateTime;
+
+public class StatementResponse {
+    private String transactionCode;
+    private String tranType;
+    private BigDecimal amount;
+    private LocalDateTime transactionDate;
+    private String subTxnType;
+    private String type;
+    private String description;
+
+    public StatementResponse() {
+    }
+
+    public String getTransactionCode() {
+        return transactionCode;
+    }
+
+    public void setTransactionCode(String transactionCode) {
+        this.transactionCode = transactionCode;
+    }
+
+    public String getTranType() {
+        return tranType;
+    }
+
+    public void setTranType(String tranType) {
+        this.tranType = tranType;
+    }
+
+    public BigDecimal getAmount() {
+        return amount;
+    }
+
+    public void setAmount(BigDecimal amount) {
+        this.amount = amount;
+    }
+
+    public LocalDateTime getTransactionDate() {
+        return transactionDate;
+    }
+
+    public void setTransactionDate(LocalDateTime transactionDate) {
+        this.transactionDate = transactionDate;
+    }
+
+    public String getSubTxnType() {
+        return subTxnType;
+    }
+
+    public void setSubTxnType(String subTxnType) {
+        this.subTxnType = subTxnType;
+    }
+
+    public String getType() {
+        return type;
+    }
+
+    public void setType(String type) {
+        this.type = type;
+    }
+
+    public String getDescription() {
+        return description;
+    }
+
+    public void setDescription(String description) {
+        this.description = description;
+    }
+}
diff --git a/api/src/main/java/org/apache/fineract/cn/deposit/api/v1/transaction/domain/data/TransactionActionType.java b/api/src/main/java/org/apache/fineract/cn/deposit/api/v1/transaction/domain/data/TransactionActionType.java
new file mode 100644
index 0000000..efa253d
--- /dev/null
+++ b/api/src/main/java/org/apache/fineract/cn/deposit/api/v1/transaction/domain/data/TransactionActionType.java
@@ -0,0 +1,26 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you 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 org.apache.fineract.cn.deposit.api.v1.transaction.domain.data;
+
+public enum TransactionActionType {
+
+    WITHDRAWAL,
+    DEPOSIT,
+    ;
+}
diff --git a/api/src/main/java/org/apache/fineract/cn/deposit/api/v1/transaction/domain/data/TransactionRequestData.java b/api/src/main/java/org/apache/fineract/cn/deposit/api/v1/transaction/domain/data/TransactionRequestData.java
new file mode 100644
index 0000000..deb16ae
--- /dev/null
+++ b/api/src/main/java/org/apache/fineract/cn/deposit/api/v1/transaction/domain/data/TransactionRequestData.java
@@ -0,0 +1,154 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you 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 org.apache.fineract.cn.deposit.api.v1.transaction.domain.data;
+
+import org.apache.fineract.cn.deposit.api.v1.definition.domain.Currency;
+import org.hibernate.validator.constraints.Length;
+import org.hibernate.validator.constraints.NotEmpty;
+
+import javax.validation.constraints.NotNull;
+import javax.validation.constraints.Pattern;
+import java.beans.Transient;
+import java.time.LocalDate;
+import java.time.LocalDateTime;
+
+public class TransactionRequestData {
+
+    public static final String IDENTIFIER_SEPARATOR = "_";
+
+    @NotNull
+    //@Pattern(regexp = "^[0-9a-f]{8}-[0-9a-f]{4}-[1-5][0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$")
+    private String transactionCode;
+
+    //@Pattern(regexp = "^[0-9a-f]{8}-[0-9a-f]{4}-[1-5][0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$")
+    private String requestCode;
+
+    private String routingCode;
+    private String externalId;
+
+    @NotEmpty
+    @Length(max = 32)
+    private String accountId;
+
+    @Length(max = 128)
+    private String note;
+
+    private LocalDateTime expiration;
+
+    private MoneyData amount;
+    //private GeoCodeData geoCode;
+
+    private  String subTxnId;
+
+    public TransactionRequestData() {
+    }
+
+    public TransactionRequestData(String transactionCode, String requestCode, String routingCode, String externalId, String accountId,
+                                  String note, LocalDateTime expiration,
+                                  MoneyData amount, String subTxnId) {
+        this.transactionCode = transactionCode;
+        this.requestCode = requestCode;
+        this.routingCode = routingCode;
+        this.externalId = externalId;
+        this.accountId = accountId;
+        this.note = note;
+        this.expiration = expiration;
+        this.amount = amount;
+        //this.geoCode = geoCode;
+        this.subTxnId = subTxnId;
+    }
+
+    @NotNull
+    public String getTransactionCode() {
+        return transactionCode;
+    }
+
+    public String getRequestCode() {
+        return requestCode;
+    }
+
+    @NotNull
+    public String getAccountId() {
+        return accountId;
+    }
+
+    @NotNull
+    public MoneyData getAmount() {
+        return amount;
+    }
+
+    public String getNote() {
+        return note;
+    }
+
+    public void setNote(String note) {
+        this.note = note;
+    }
+
+    public LocalDateTime getExpiration() {
+        return expiration;
+    }
+
+    public LocalDate getExpirationLocalDate() {
+        return expiration == null ? null : expiration.toLocalDate();
+    }
+
+    public void setExpiration(LocalDateTime expiration) {
+        this.expiration = expiration;
+    }
+
+    public void normalizeAmounts(@NotNull Currency currency) {
+        amount.normalizeAmount(currency);
+    }
+
+    protected void setTransactionCode(String transactionCode) {
+        this.transactionCode = transactionCode;
+    }
+
+    protected void setRequestCode(String requestCode) {
+        this.requestCode = requestCode;
+    }
+
+    protected void setAccountId(String accountId) {
+        this.accountId = accountId;
+    }
+
+    protected void setAmount(MoneyData amount) {
+        this.amount = amount;
+    }
+
+    public String getRoutingCode() {
+        return routingCode;
+    }
+
+    public String getExternalId() {
+        return externalId;
+    }
+
+    public String getSubTxnId() {
+        return subTxnId;
+    }
+
+    @Transient
+    @NotNull
+    public String getIdentifier() {
+        return transactionCode;
+    }
+
+}
diff --git a/api/src/main/java/org/apache/fineract/cn/deposit/api/v1/transaction/domain/data/TransactionResponseData.java b/api/src/main/java/org/apache/fineract/cn/deposit/api/v1/transaction/domain/data/TransactionResponseData.java
new file mode 100644
index 0000000..237e627
--- /dev/null
+++ b/api/src/main/java/org/apache/fineract/cn/deposit/api/v1/transaction/domain/data/TransactionResponseData.java
@@ -0,0 +1,90 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you 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 org.apache.fineract.cn.deposit.api.v1.transaction.domain.data;
+
+import javax.validation.constraints.NotNull;
+import javax.validation.constraints.Pattern;
+import java.time.LocalDateTime;
+import java.time.format.DateTimeFormatter;
+
+public class TransactionResponseData {
+
+
+    @NotNull
+    private final String transactionCode;
+
+    private final String routingCode;
+    private final String externalId;
+
+    @NotNull
+    private final ActionState state;
+
+    private final String expiration;
+
+
+
+    private String completedTimestamp;
+
+
+    @NotNull
+    @Pattern(regexp = "^[0-9a-f]{8}-[0-9a-f]{4}-[1-5][0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$")
+    private final String requestCode;
+
+    public TransactionResponseData(String transactionCode, String routingCode, String externalId,
+                                   ActionState state, String expiration,
+                                   String requestCode,
+                                   String completedTimestamp) {
+        this.transactionCode = transactionCode;
+        this.routingCode = routingCode;
+        this.externalId = externalId;
+        this.state = state;
+        this.expiration = expiration;
+        this.requestCode = requestCode;
+        this.completedTimestamp =completedTimestamp;
+    }
+
+    public String getTransactionCode() {
+        return transactionCode;
+    }
+
+    public ActionState getState() {
+        return state;
+    }
+
+    public String getExpiration() {
+        return expiration;
+    }
+
+    public String getRequestCode() {
+        return requestCode;
+    }
+
+    public static TransactionResponseData build(String routingCode, String externalId, @NotNull String requestCode,
+                                                    @NotNull ActionState state,
+                                                    LocalDateTime expiration,
+                                                    @NotNull String txnIdentifier, LocalDateTime completedTimestamp) {
+        return new TransactionResponseData(txnIdentifier, routingCode, externalId, state, format(expiration), requestCode,
+                format(completedTimestamp));
+    }
+
+
+    protected static String format(LocalDateTime date) {
+        return date == null ? null : date.format(DateTimeFormatter.ISO_DATE_TIME);
+    }
+}
diff --git a/api/src/main/java/org/apache/fineract/cn/deposit/api/v1/transaction/domain/data/TransactionTypeEnum.java b/api/src/main/java/org/apache/fineract/cn/deposit/api/v1/transaction/domain/data/TransactionTypeEnum.java
new file mode 100644
index 0000000..19ef964
--- /dev/null
+++ b/api/src/main/java/org/apache/fineract/cn/deposit/api/v1/transaction/domain/data/TransactionTypeEnum.java
@@ -0,0 +1,106 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you 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 org.apache.fineract.cn.deposit.api.v1.transaction.domain.data;
+
+/**
+ * @code org.apache.fineract.cn.accounting.service.internal.repository.AccountEntryEntity.type
+ */
+public enum TransactionTypeEnum {
+
+    ACCOUNT_OPENING("ACCO"),
+    ACCOUNT_CLOSING("ACCC"),
+    ACCOUNT_TRANSFER("ACCT"),
+
+    ACH_CREDIT("ACDT"),
+    ACH_DEBIT("ADBT"),
+    ACH_ADJUSTMENTS("ADJT"),
+    ACH_PREAUTHORISED("APAC"),
+    ACH_RETURN("ARET"),
+    ACH_REVERSAL("AREV"),
+    ACH_SETTLEMENT("ASET"),
+    ACH_TRANSACTION("ATXN"),
+
+    ARP_DEBIT("ARPD"),
+    CURRENCY_DEPOSIT("FCDP"),
+    CURRENCY_WITHDRAWAL("FCWD"),
+
+    BRANCH_TRANSFER("BACT"),
+    BRANCH_DEPOSIT("BCDP"),
+    BRANCH_WITHDRAWAL("BCWD"),
+
+    DEPOSIT("CDPT"),
+    WITHDRAWAL("CWDL"),
+    CASH_LETTER("CASH"),
+
+    CHEQUE("CCHQ"),
+    BRANCH_CHEQUE("BCHQ"),
+    CERTIFIED_CHEQUE("CCCH"),
+    CROSSED_CHEQUE("CRCQ"),
+    CHEQUE_REVERSAL("CQRV"),
+    CHEQUE_OPEN("OPCQ"),
+    CHEQUE_ORDER("ORCQ"),
+
+    CHARGES_PAYMENT("CHRG"),
+    FEES_PAYMENT("FEES"),
+    TAXES_PAYMENT("TAXE"),
+    PRINCIPAL_PAYMENT("PPAY"),
+    INTEREST_PAYMENT("INTR"),
+
+    DIRECTDEBIT_PAYMENT("PMDD"),
+    DIRECTDEBIT_PREAUTHORISED("PADD"),
+    BRANCH_DIRECTDEBIT("BBDD"),
+
+    SMARTCARD_PAYMENT("SMRT"),
+    POINTOFSALE_CREDITCARD("POSC"),
+    POINTOFSALE_DEBITCARD("POSD"),
+    POINTOFSALE_PAYMENT("POSP"),
+
+    DOMESTIC_CREDIT("DMCT"),
+    INTRACOMPANY_TRANSFER("ICCT"),
+
+    MIXED_DEPOSIT("MIXD"),
+    MISCELLANEOUS_DEPOSIT("MSCD"),
+    OTHER("OTHR"),
+
+    CONTROLLED_DISBURSEMENT("CDIS"),
+    CONTROLLED_DISBURSEMENT2("DSBR"),
+    CREDIT_ADJUSTMENT("CAJT"),
+    DEBIT_ADJUSTMENT("DAJT"),
+    EXCHANGERATE_ADJUSTMENT("ERTA"),
+    YID_ADJUSTMENT("YTDA"),
+    REIMBURSEMENT("RIMB"),
+    DRAWDOWN("DDWN"),
+
+    ERROR_NOTAVAILABLE("NTAV"),
+    ERROR_POSTING("PSTE"),
+    ERROR_CANCELLATION("RCDD"),
+    ERROR_CANCELLATION2("RPCR"),
+    ERROR_ZEROBALANCE("ZABA"),
+    ;
+
+    private final String code;
+
+    TransactionTypeEnum(String code) {
+        this.code = code;
+    }
+
+    public String getCode() {
+        return code;
+    }
+}
diff --git a/api/src/main/java/org/apache/fineract/cn/deposit/api/v1/transaction/utils/MathUtil.java b/api/src/main/java/org/apache/fineract/cn/deposit/api/v1/transaction/utils/MathUtil.java
new file mode 100644
index 0000000..ae43db6
--- /dev/null
+++ b/api/src/main/java/org/apache/fineract/cn/deposit/api/v1/transaction/utils/MathUtil.java
@@ -0,0 +1,325 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you 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 org.apache.fineract.cn.deposit.api.v1.transaction.utils;
+
+import org.apache.fineract.cn.deposit.api.v1.definition.domain.Currency;
+
+import javax.validation.constraints.NotNull;
+import java.math.BigDecimal;
+import java.math.MathContext;
+import java.math.RoundingMode;
+
+public class MathUtil {
+
+    public static final MathContext DEFAULT_MATH_CONTEXT = new MathContext(2, RoundingMode.HALF_EVEN);
+    public static final MathContext CALCULATION_MATH_CONTEXT = new MathContext(5, RoundingMode.HALF_EVEN);
+
+    public static Double nullToZero(Double value) {
+        return nullToDefault(value, 0D);
+    }
+
+    public static Double nullToDefault(Double value, Double def) {
+        return value == null ? def : value;
+    }
+
+    public static Double zeroToNull(Double value) {
+        return isEmpty(value) ? null : value;
+    }
+
+    /** @return parameter value or ZERO if it is negative */
+    public static Double negativeToZero(Double value) {
+        return isGreaterThanZero(value) ? value : 0D;
+    }
+
+    public static boolean isEmpty(Double value) {
+        return value == null || value.equals(0D);
+    }
+
+    public static boolean isGreaterThanZero(Double value) {
+        return value != null && value > 0D;
+    }
+
+    public static boolean isLessThanZero(Double value) {
+        return value != null && value < 0D;
+    }
+
+    public static boolean isZero(Double value) {
+        return value != null && value.equals(0D);
+    }
+
+    public static boolean isEqualTo(Double first, Double second) {
+        return nullToZero(first).equals(nullToZero(second));
+    }
+
+    public static boolean isGreaterThan(Double first, Double second) {
+        return nullToZero(first) > nullToZero(second);
+    }
+
+    public static boolean isLessThan(Double first, Double second) {
+        return nullToZero(first) < nullToZero(second);
+    }
+
+    public static boolean isGreaterThanOrEqualTo(Double first, Double second) {
+        return nullToZero(first) >= nullToZero(second);
+    }
+
+    public static boolean isLessThanOrEqualZero(Double value) {
+        return nullToZero(value) <= 0D;
+    }
+
+    /** @return parameter value or negated value to positive */
+    public static Double abs(Double value) {
+        return value == null ? 0D : Math.abs(value);
+    }
+
+    /** @return calculates minimum of the two values considering null values
+     * @param notNull if true then null parameter is omitted, otherwise returns null */
+    public static Double min(Double first, Double second, boolean notNull) {
+        return first == null
+                ? (notNull ? second : null)
+                : second == null ? (notNull ? first : null) : Math.min(first, second);
+    }
+
+    /** @return calculates minimum of the values considering null values
+     * @param notNull if true then null parameter is omitted, otherwise returns null */
+    public static Double min(Double first, Double second, Double third, boolean notNull) {
+        return min(min(first, second, notNull), third, notNull);
+    }
+
+    /** @return sum the two values considering null values */
+    public static Double add(Double first, Double second) {
+        return first == null
+                ? second
+                : second == null ? first : first + second;
+    }
+
+    /** @return sum the values considering null values */
+    public static Double add(Double first, Double second, Double third) {
+        return add(add(first, second), third);
+    }
+
+    /** @return sum the values considering null values */
+    public static Double add(Double first, Double second, Double third, Double fourth) {
+        return add(add(add(first, second), third), fourth);
+    }
+
+    /** @return sum the values considering null values */
+    public static Double add(Double first, Double second, Double third, Double fourth, Double fifth) {
+        return add(add(add(add(first, second), third), fourth), fifth);
+    }
+
+    /** @return first minus second considering null values, maybe negative */
+    public static Double subtract(Double first, Double second) {
+        return first == null
+                ? null
+                : second == null ? first : first - second;
+    }
+
+    /** @return first minus the others considering null values, maybe negative */
+    public static Double subtractToZero(Double first, Double second, Double third) {
+        return subtractToZero(subtract(first, second), third);
+    }
+
+    /** @return first minus the others considering null values, maybe negative */
+    public static Double subtractToZero(Double first, Double second, Double third, Double fourth) {
+        return subtractToZero(subtract(subtract(first, second), third), fourth);
+    }
+
+    /** @return NONE negative first minus second considering null values */
+    public static Double subtractToZero(Double first, Double second) {
+        return negativeToZero(subtract(first, second));
+    }
+
+    /** @return BigDecimal with scale set to the 'digitsAfterDecimal' of the parameter currency */
+    public static Double normalize(Double amount, @NotNull Currency currency) {
+        return amount == null ? null : normalize(BigDecimal.valueOf(amount), currency).doubleValue();
+    }
+
+    /** @return BigDecimal with scale set to the 'digitsAfterDecimal' of the parameter currency */
+    public static Double normalize(Double amount, @NotNull MathContext mc) {
+        return amount == null ? null : normalize(BigDecimal.valueOf(amount), mc).doubleValue();
+    }
+
+    /** @return BigDecimal null safe negate */
+    public static Double negate(Double amount) {
+        return isEmpty(amount) ? amount : amount * -1;
+    }
+
+
+    // ----------------- BigDecimal -----------------
+
+    public static BigDecimal nullToZero(BigDecimal value) {
+        return nullToDefault(value, BigDecimal.ZERO);
+    }
+
+    public static BigDecimal nullToDefault(BigDecimal value, BigDecimal def) {
+        return value == null ? def : value;
+    }
+
+    public static BigDecimal zeroToNull(BigDecimal value) {
+        return isEmpty(value) ? null : value;
+    }
+
+    /** @return parameter value or ZERO if it is negative */
+    public static BigDecimal negativeToZero(BigDecimal value) {
+        return isGreaterThanZero(value) ? value : BigDecimal.ZERO;
+    }
+
+    public static boolean isEmpty(BigDecimal value) {
+        return value == null || BigDecimal.ZERO.compareTo(value) == 0;
+    }
+
+    public static boolean isGreaterThanZero(BigDecimal value) {
+        return value != null && value.compareTo(BigDecimal.ZERO) > 0;
+    }
+
+    public static boolean isLessThanZero(BigDecimal value) {
+        return value != null && value.compareTo(BigDecimal.ZERO) < 0;
+    }
+
+    public static boolean isZero(BigDecimal value) {
+        return value != null && value.compareTo(BigDecimal.ZERO) == 0;
+    }
+
+    public static boolean isEqualTo(BigDecimal first, BigDecimal second) {
+        return nullToZero(first).compareTo(nullToZero(second)) == 0;
+    }
+
+    public static boolean isGreaterThan(BigDecimal first, BigDecimal second) {
+        return nullToZero(first).compareTo(nullToZero(second)) > 0;
+    }
+
+    public static boolean isLessThan(BigDecimal first, BigDecimal second) {
+        return nullToZero(first).compareTo(nullToZero(second)) < 0;
+    }
+
+    public static boolean isGreaterThanOrEqualTo(BigDecimal first, BigDecimal second) {
+        return nullToZero(first).compareTo(nullToZero(second)) >= 0;
+    }
+
+    public static boolean isLessThanOrEqualZero(BigDecimal value) {
+        return nullToZero(value).compareTo(BigDecimal.ZERO) <= 0;
+    }
+
+    /** @return parameter value or negated value to positive */
+    public static BigDecimal abs(BigDecimal value) {
+        return value == null ? BigDecimal.ZERO : value.abs();
+    }
+
+    /** @return calculates minimum of the two values considering null values
+     * @param notNull if true then null parameter is omitted, otherwise returns null */
+    public static BigDecimal min(BigDecimal first, BigDecimal second, boolean notNull) {
+        return notNull
+                ? first == null
+                ? second
+                : second == null ? first : min(first, second, false)
+                : isLessThan(first, second) ? first : second;
+    }
+
+    /** @return calculates minimum of the values considering null values
+     * @param notNull if true then null parameter is omitted, otherwise returns null */
+    public static BigDecimal min(BigDecimal first, BigDecimal second, BigDecimal third, boolean notNull) {
+        return min(min(first, second, notNull), third, notNull);
+    }
+
+    /** @return sum the two values considering null values */
+    public static BigDecimal add(BigDecimal first, BigDecimal second) {
+        return add(first, second, CALCULATION_MATH_CONTEXT);
+    }
+
+    /** @return sum the two values considering null values */
+    public static BigDecimal add(BigDecimal first, BigDecimal second, MathContext mc) {
+        return first == null
+                ? second
+                : second == null ? first : first.add(second, mc);
+    }
+
+    /** @return sum the values considering null values */
+    public static BigDecimal add(BigDecimal first, BigDecimal second, BigDecimal third) {
+        return add(first, second, third, CALCULATION_MATH_CONTEXT);
+    }
+
+    /** @return sum the values considering null values */
+    public static BigDecimal add(BigDecimal first, BigDecimal second, BigDecimal third, MathContext mc) {
+        return add(add(first, second, mc), third, mc);
+    }
+
+    /** @return sum the values considering null values */
+    public static BigDecimal add(BigDecimal first, BigDecimal second, BigDecimal third, BigDecimal fourth) {
+        return add(first, second, third, fourth, CALCULATION_MATH_CONTEXT);
+    }
+
+    /** @return sum the values considering null values */
+    public static BigDecimal add(BigDecimal first, BigDecimal second, BigDecimal third, BigDecimal fourth, MathContext mc) {
+        return add(add(add(first, second, mc), third, mc), fourth, mc);
+    }
+
+    /** @return sum the values considering null values */
+    public static BigDecimal add(BigDecimal first, BigDecimal second, BigDecimal third, BigDecimal fourth, BigDecimal fifth) {
+        return add(first, second, third, fourth, fifth, CALCULATION_MATH_CONTEXT);
+    }
+
+    /** @return sum the values considering null values */
+    public static BigDecimal add(BigDecimal first, BigDecimal second, BigDecimal third, BigDecimal fourth, BigDecimal fifth, MathContext mc) {
+        return add(add(add(add(first, second, mc), third, mc), fourth, mc), fifth, mc);
+    }
+
+    /** @return first minus second considering null values, maybe negative */
+    public static BigDecimal subtract(BigDecimal first, BigDecimal second) {
+        return first == null
+                ? null
+                : second == null ? first : first.subtract(second, CALCULATION_MATH_CONTEXT);
+    }
+
+    /** @return NONE negative first minus second considering null values */
+    public static BigDecimal subtractToZero(BigDecimal first, BigDecimal second) {
+        return negativeToZero(subtract(first, second));
+    }
+
+    /** @return first minus the others considering null values, maybe negative */
+    public static BigDecimal subtractToZero(BigDecimal first, BigDecimal second, BigDecimal third) {
+        MathContext mc = CALCULATION_MATH_CONTEXT;
+        return subtractToZero(subtract(first, second), third);
+    }
+
+    /** @return first minus the others considering null values, maybe negative */
+    public static BigDecimal subtractToZero(BigDecimal first, BigDecimal second, BigDecimal third, BigDecimal fourth) {
+        return subtractToZero(subtract(subtract(first, second), third), fourth);
+    }
+
+    /** @return BigDecimal with scale set to the 'digitsAfterDecimal' of the parameter currency */
+    public static BigDecimal normalize(BigDecimal amount, @NotNull Currency currency) {
+        return amount == null ? null : amount.setScale(currency.getScale(), CALCULATION_MATH_CONTEXT.getRoundingMode());
+    }
+
+    /** @return BigDecimal with scale set to the 'digitsAfterDecimal' of the parameter currency */
+    public static BigDecimal normalize(BigDecimal amount, @NotNull MathContext mc) {
+        return amount == null ? null : amount.setScale(mc.getPrecision(), mc.getRoundingMode());
+    }
+
+    /** @return BigDecimal null safe negate */
+    public static BigDecimal negate(BigDecimal amount) {
+        return negate(amount, CALCULATION_MATH_CONTEXT);
+    }
+
+    /** @return BigDecimal null safe negate */
+    public static BigDecimal negate(BigDecimal amount, MathContext mc) {
+        return isEmpty(amount) ? amount : amount.negate(mc);
+    }
+}
diff --git a/service/src/main/java/org/apache/fineract/cn/deposit/service/internal/command/CreateSubTxnTypeCommand.java b/service/src/main/java/org/apache/fineract/cn/deposit/service/internal/command/CreateSubTxnTypeCommand.java
new file mode 100644
index 0000000..394d0ee
--- /dev/null
+++ b/service/src/main/java/org/apache/fineract/cn/deposit/service/internal/command/CreateSubTxnTypeCommand.java
@@ -0,0 +1,34 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you 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 org.apache.fineract.cn.deposit.service.internal.command;
+
+import org.apache.fineract.cn.deposit.api.v1.instance.domain.SubTransactionType;
+
+public class CreateSubTxnTypeCommand {
+    private final SubTransactionType subTransactionType;
+
+    public CreateSubTxnTypeCommand(final SubTransactionType subTransactionType) {
+        super();
+        this.subTransactionType = subTransactionType;
+    }
+
+    public SubTransactionType subTransactionType() {
+        return subTransactionType;
+    }
+}
diff --git a/service/src/main/java/org/apache/fineract/cn/deposit/service/internal/command/TransactionCommand.java b/service/src/main/java/org/apache/fineract/cn/deposit/service/internal/command/TransactionCommand.java
new file mode 100644
index 0000000..631fb55
--- /dev/null
+++ b/service/src/main/java/org/apache/fineract/cn/deposit/service/internal/command/TransactionCommand.java
@@ -0,0 +1,40 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you 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 org.apache.fineract.cn.deposit.service.internal.command;
+
+import org.apache.fineract.cn.deposit.api.v1.transaction.domain.data.TransactionActionType;
+import org.apache.fineract.cn.deposit.api.v1.transaction.domain.data.TransactionRequestData;
+
+public class TransactionCommand {
+    private final TransactionRequestData transactionRequest;
+    private final TransactionActionType action;
+
+    public TransactionCommand(TransactionRequestData transactionRequest, TransactionActionType action) {
+        this.transactionRequest = transactionRequest;
+        this.action = action;
+    }
+
+    public TransactionRequestData getTransactionRequest() {
+        return transactionRequest;
+    }
+
+    public TransactionActionType getAction() {
+        return action;
+    }
+}
diff --git a/service/src/main/java/org/apache/fineract/cn/deposit/service/internal/command/UpdateSubTxnTypeCommand.java b/service/src/main/java/org/apache/fineract/cn/deposit/service/internal/command/UpdateSubTxnTypeCommand.java
new file mode 100644
index 0000000..8e1e18b
--- /dev/null
+++ b/service/src/main/java/org/apache/fineract/cn/deposit/service/internal/command/UpdateSubTxnTypeCommand.java
@@ -0,0 +1,34 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you 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 org.apache.fineract.cn.deposit.service.internal.command;
+
+import org.apache.fineract.cn.deposit.api.v1.instance.domain.SubTransactionType;
+
+public class UpdateSubTxnTypeCommand {
+    private final SubTransactionType subTransactionType;
+
+    public UpdateSubTxnTypeCommand(final SubTransactionType subTransactionType) {
+        super();
+        this.subTransactionType = subTransactionType;
+    }
+
+    public SubTransactionType subTransactionType() {
+        return this.subTransactionType;
+    }
+}
diff --git a/service/src/main/java/org/apache/fineract/cn/deposit/service/internal/command/handler/InterestCalculator.java b/service/src/main/java/org/apache/fineract/cn/deposit/service/internal/command/handler/InterestCalculator.java
index 79dcc60..7d2a71a 100644
--- a/service/src/main/java/org/apache/fineract/cn/deposit/service/internal/command/handler/InterestCalculator.java
+++ b/service/src/main/java/org/apache/fineract/cn/deposit/service/internal/command/handler/InterestCalculator.java
@@ -457,7 +457,7 @@
     final BigDecimal annualInterest = amount.multiply(baseFactor.pow(periods).subtract(BigDecimal.ONE));
 
     return annualInterest
-            .divide(BigDecimal.valueOf(lengthOfYear),
+            .divide(  BigDecimal.valueOf(lengthOfYear),
                 amount.scale() + INTEREST_PRECISION, BigDecimal.ROUND_HALF_EVEN);
   }
 }
\ No newline at end of file
diff --git a/service/src/main/java/org/apache/fineract/cn/deposit/service/internal/command/handler/ProductInstanceAggregate.java b/service/src/main/java/org/apache/fineract/cn/deposit/service/internal/command/handler/ProductInstanceAggregate.java
index 0ea7f07..15b7aae 100644
--- a/service/src/main/java/org/apache/fineract/cn/deposit/service/internal/command/handler/ProductInstanceAggregate.java
+++ b/service/src/main/java/org/apache/fineract/cn/deposit/service/internal/command/handler/ProductInstanceAggregate.java
@@ -50,6 +50,7 @@
 import org.slf4j.Logger;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.beans.factory.annotation.Qualifier;
+import org.springframework.beans.factory.annotation.Value;
 import org.springframework.transaction.annotation.Transactional;
 
 @Aggregate
@@ -60,6 +61,9 @@
   private final ProductDefinitionRepository productDefinitionRepository;
   private final AccountingService accountingService;
 
+  @Value("${config.fixedAccountId}")
+  private Boolean fixedAccountId;
+
   @Autowired
   public ProductInstanceAggregate(@Qualifier(ServiceConstants.LOGGER_NAME) final Logger logger,
                                   final ProductInstanceRepository productInstanceRepository,
@@ -89,7 +93,7 @@
           this.productInstanceRepository.findByCustomerIdentifier(productInstance.getCustomerIdentifier());
 
       final int accountSuffix = currentProductInstances.size() + 1;
-      final String accountNumber =
+      final String accountNumber = fixedAccountId ? productInstance.getCustomerIdentifier() :
           productInstance.getCustomerIdentifier() +
               "." + productDefinitionEntity.getEquityLedgerIdentifier() +
               "." + String.format("%05d", accountSuffix);
diff --git a/service/src/main/java/org/apache/fineract/cn/deposit/service/internal/command/handler/SubTxnTypeAggrigate.java b/service/src/main/java/org/apache/fineract/cn/deposit/service/internal/command/handler/SubTxnTypeAggrigate.java
new file mode 100644
index 0000000..b56c690
--- /dev/null
+++ b/service/src/main/java/org/apache/fineract/cn/deposit/service/internal/command/handler/SubTxnTypeAggrigate.java
@@ -0,0 +1,78 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you 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 org.apache.fineract.cn.deposit.service.internal.command.handler;
+
+import org.apache.fineract.cn.accounting.api.v1.client.LedgerManager;
+import org.apache.fineract.cn.command.annotation.Aggregate;
+import org.apache.fineract.cn.command.annotation.CommandHandler;
+import org.apache.fineract.cn.command.annotation.EventEmitter;
+import org.apache.fineract.cn.deposit.api.v1.EventConstants;
+import org.apache.fineract.cn.deposit.api.v1.instance.domain.SubTransactionType;
+import org.apache.fineract.cn.deposit.service.ServiceConstants;
+import org.apache.fineract.cn.deposit.service.internal.command.CreateSubTxnTypeCommand;
+import org.apache.fineract.cn.deposit.service.internal.command.UpdateSubTxnTypeCommand;
+import org.apache.fineract.cn.deposit.service.internal.mapper.SubTransactionTypeMapper;
+import org.apache.fineract.cn.deposit.service.internal.repository.SubTransactionTypeEntity;
+import org.apache.fineract.cn.deposit.service.internal.repository.SubTransactionTypeRepository;
+import org.apache.fineract.cn.lang.ServiceException;
+import org.slf4j.Logger;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.beans.factory.annotation.Qualifier;
+import org.springframework.transaction.annotation.Transactional;
+
+@Aggregate
+public class SubTxnTypeAggrigate {
+    private final Logger logger;
+    private final LedgerManager ledgerManager;
+    private final SubTransactionTypeRepository subTransactionTypeRepository;
+
+    @Autowired
+    public SubTxnTypeAggrigate(@Qualifier(ServiceConstants.LOGGER_NAME) Logger logger,
+                               LedgerManager ledgerManager,
+                               SubTransactionTypeRepository subTransactionTypeRepository) {
+        this.logger = logger;
+        this.ledgerManager = ledgerManager;
+        this.subTransactionTypeRepository = subTransactionTypeRepository;
+    }
+
+    @CommandHandler
+    @EventEmitter(selectorName = EventConstants.SELECTOR_NAME, selectorValue = EventConstants.POST_SUB_TXN_TYPE)
+    @Transactional
+    public String createProductInstance(final CreateSubTxnTypeCommand createSubTxnTypeCommand) {
+        final SubTransactionType subTransactionType = createSubTxnTypeCommand.subTransactionType();
+
+        final SubTransactionTypeEntity subTransactionTypeEntity = SubTransactionTypeMapper.map(subTransactionType);
+        this.subTransactionTypeRepository.save(subTransactionTypeEntity);
+        return subTransactionTypeEntity.getIdentifier();
+    }
+
+    @CommandHandler
+    @EventEmitter(selectorName = EventConstants.SELECTOR_NAME, selectorValue = EventConstants.PUT_SUB_TXN_TYPE)
+    @Transactional
+    public String updateProductInstance(final UpdateSubTxnTypeCommand createSubTxnTypeCommand) {
+        final SubTransactionType subTransactionType = createSubTxnTypeCommand.subTransactionType();
+
+        final SubTransactionTypeEntity subTransactionTypeEntity = subTransactionTypeRepository.findByIdentifier(subTransactionType.getIdentifier())
+                .orElseThrow(() ->
+                        ServiceException.notFound("Sub transaction type {0} not found.", subTransactionType.getIdentifier()));
+        SubTransactionTypeMapper.update(subTransactionTypeEntity, subTransactionType);
+        this.subTransactionTypeRepository.save(subTransactionTypeEntity);
+        return subTransactionTypeEntity.getIdentifier();
+    }
+}
diff --git a/service/src/main/java/org/apache/fineract/cn/deposit/service/internal/command/handler/TransactionCommandHandler.java b/service/src/main/java/org/apache/fineract/cn/deposit/service/internal/command/handler/TransactionCommandHandler.java
new file mode 100644
index 0000000..f3740ad
--- /dev/null
+++ b/service/src/main/java/org/apache/fineract/cn/deposit/service/internal/command/handler/TransactionCommandHandler.java
@@ -0,0 +1,71 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you 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 org.apache.fineract.cn.deposit.service.internal.command.handler;
+
+import org.apache.fineract.cn.command.annotation.Aggregate;
+import org.apache.fineract.cn.command.annotation.CommandHandler;
+import org.apache.fineract.cn.command.annotation.CommandLogLevel;
+import org.apache.fineract.cn.deposit.api.v1.transaction.domain.data.TransactionResponseData;
+import org.apache.fineract.cn.deposit.service.ServiceConstants;
+import org.apache.fineract.cn.deposit.service.internal.command.TransactionCommand;
+import org.apache.fineract.cn.deposit.service.internal.command.TransactionProcessedCommand;
+import org.apache.fineract.cn.deposit.service.internal.repository.ProductInstanceEntity;
+import org.apache.fineract.cn.deposit.service.internal.service.TransactionService;
+import org.apache.fineract.cn.lang.ServiceException;
+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 javax.validation.constraints.NotNull;
+import java.time.Clock;
+import java.time.LocalDateTime;
+import java.util.Optional;
+
+@Aggregate
+public class TransactionCommandHandler {
+    private final Logger logger;
+    private final TransactionService transactionService;
+
+    @Autowired
+    public TransactionCommandHandler(@Qualifier(ServiceConstants.LOGGER_NAME)Logger logger,
+                                     TransactionService transactionService) {
+        this.logger = logger;
+        this.transactionService = transactionService;
+    }
+
+    @NotNull
+    @Transactional
+    @CommandHandler(logStart = CommandLogLevel.INFO, logFinish = CommandLogLevel.INFO)
+    public TransactionResponseData performTransfer(@NotNull TransactionCommand command) {
+        switch (command.getAction()) {
+            case WITHDRAWAL: {
+                //command = dataValidator.validatePrepareTransfer(command);
+                return transactionService.withdraw(command);
+            }
+            case DEPOSIT: {
+                //command = dataValidator.validateCommitTransfer(command);
+                return transactionService.deposit(command);
+            }
+            default:
+                return null;
+        }
+    }
+
+}
diff --git a/service/src/main/java/org/apache/fineract/cn/deposit/service/internal/mapper/SubTransactionTypeMapper.java b/service/src/main/java/org/apache/fineract/cn/deposit/service/internal/mapper/SubTransactionTypeMapper.java
new file mode 100644
index 0000000..af3c639
--- /dev/null
+++ b/service/src/main/java/org/apache/fineract/cn/deposit/service/internal/mapper/SubTransactionTypeMapper.java
@@ -0,0 +1,70 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you 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 org.apache.fineract.cn.deposit.service.internal.mapper;
+
+import org.apache.fineract.cn.deposit.api.v1.instance.domain.SubTransactionType;
+import org.apache.fineract.cn.deposit.service.internal.repository.SubTransactionTypeEntity;
+
+public class SubTransactionTypeMapper {
+
+    public SubTransactionTypeMapper() {
+    }
+
+    public static SubTransactionTypeEntity map(SubTransactionType subTransactionType){
+        SubTransactionTypeEntity subTransactionTypeEntity = new SubTransactionTypeEntity();
+        subTransactionTypeEntity.setIdentifier(subTransactionType.getIdentifier());
+        subTransactionTypeEntity.setName(subTransactionType.getName());
+        subTransactionTypeEntity.setDescription(subTransactionType.getDescription());
+        subTransactionTypeEntity.setCashPayment(subTransactionType.getCashPayment());
+        subTransactionTypeEntity.setActive(subTransactionType.getActive());
+        subTransactionTypeEntity.setOrderPosition(subTransactionType.getOrderPosition());
+        subTransactionTypeEntity.setTranType(subTransactionType.getTranType());
+        subTransactionTypeEntity.setLedgerAccount(subTransactionType.getLedgerAccount());
+        return subTransactionTypeEntity;
+    }
+
+    public static SubTransactionType map(SubTransactionTypeEntity subTransactionTypeEntity) {
+        SubTransactionType subTransactionType = new SubTransactionType();
+        subTransactionType.setIdentifier(subTransactionTypeEntity.getIdentifier());
+        subTransactionType.setName(subTransactionTypeEntity.getName());
+        subTransactionType.setDescription(subTransactionTypeEntity.getDescription());
+        subTransactionType.setCashPayment(subTransactionTypeEntity.getCashPayment());
+        subTransactionType.setActive(subTransactionTypeEntity.getActive());
+        subTransactionType.setOrderPosition(subTransactionTypeEntity.getOrderPosition());
+        subTransactionType.setTranType(subTransactionTypeEntity.getTranType());
+        subTransactionType.setLedgerAccount(subTransactionTypeEntity.getLedgerAccount());
+        return subTransactionType;
+    }
+    public static void update(SubTransactionTypeEntity subTransactionTypeEntity, SubTransactionType subTransactionType){
+        if(subTransactionType.getName() != null)
+            subTransactionTypeEntity.setName(subTransactionType.getName());
+        if(subTransactionType.getDescription() != null)
+            subTransactionTypeEntity.setDescription(subTransactionType.getDescription());
+        if(subTransactionType.getCashPayment() != null)
+            subTransactionTypeEntity.setCashPayment(subTransactionType.getCashPayment());
+        if(subTransactionType.getActive() != null)
+            subTransactionTypeEntity.setActive(subTransactionType.getActive());
+        if(subTransactionType.getOrderPosition() != null)
+            subTransactionTypeEntity.setOrderPosition(subTransactionType.getOrderPosition());
+        if(subTransactionType.getTranType() != null)
+            subTransactionTypeEntity.setTranType(subTransactionType.getTranType());
+        if(subTransactionType.getLedgerAccount() != null)
+            subTransactionTypeEntity.setLedgerAccount(subTransactionType.getLedgerAccount());
+    }
+}
diff --git a/service/src/main/java/org/apache/fineract/cn/deposit/service/internal/repository/SubTransactionTypeEntity.java b/service/src/main/java/org/apache/fineract/cn/deposit/service/internal/repository/SubTransactionTypeEntity.java
new file mode 100644
index 0000000..ba9e525
--- /dev/null
+++ b/service/src/main/java/org/apache/fineract/cn/deposit/service/internal/repository/SubTransactionTypeEntity.java
@@ -0,0 +1,130 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you 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 org.apache.fineract.cn.deposit.service.internal.repository;
+
+import javax.persistence.*;
+
+@Entity
+@Table(name = "shed_sub_tx_type")
+public class SubTransactionTypeEntity {
+    @Id
+    @GeneratedValue(strategy = GenerationType.IDENTITY)
+    @Column(name = "id", nullable = false)
+    private Long id;
+
+    @Column(name = "identifier", nullable = false)
+    private String identifier;
+
+    @Column(name = "a_name", nullable = false)
+    private String name;
+
+    @Column(name = "description", nullable = false)
+    private String description;
+
+    @Column(name = "is_cash_payment", nullable = false)
+    private Boolean isCashPayment;
+
+    @Column(name = "is_active", nullable = false)
+    private Boolean isActive;
+
+    @Column(name = "order_position", nullable = false)
+    private Integer orderPosition;
+
+    @Column(name = "tran_type_enum", nullable = false)
+    private Integer tranType;
+
+    @Column(name = "ledger_account_identifier", nullable = false)
+    private String ledgerAccount;
+
+    public SubTransactionTypeEntity() {
+        super();
+    }
+
+    public Long getId() {
+        return id;
+    }
+
+    public void setId(Long id) {
+        this.id = id;
+    }
+
+    public String getIdentifier() {
+        return identifier;
+    }
+
+    public void setIdentifier(String identifier) {
+        this.identifier = identifier;
+    }
+
+    public String getName() {
+        return name;
+    }
+
+    public void setName(String name) {
+        this.name = name;
+    }
+
+    public String getDescription() {
+        return description;
+    }
+
+    public void setDescription(String description) {
+        this.description = description;
+    }
+
+    public Boolean getCashPayment() {
+        return isCashPayment;
+    }
+
+    public void setCashPayment(Boolean cashPayment) {
+        isCashPayment = cashPayment;
+    }
+
+    public Boolean getActive() {
+        return isActive;
+    }
+
+    public void setActive(Boolean active) {
+        isActive = active;
+    }
+
+    public Integer getOrderPosition() {
+        return orderPosition;
+    }
+
+    public void setOrderPosition(Integer orderPosition) {
+        this.orderPosition = orderPosition;
+    }
+
+    public Integer getTranType() {
+        return tranType;
+    }
+
+    public void setTranType(Integer tranType) {
+        this.tranType = tranType;
+    }
+
+    public String getLedgerAccount() {
+        return ledgerAccount;
+    }
+
+    public void setLedgerAccount(String ledgerAccount) {
+        this.ledgerAccount = ledgerAccount;
+    }
+}
diff --git a/service/src/main/java/org/apache/fineract/cn/deposit/service/internal/repository/SubTransactionTypeRepository.java b/service/src/main/java/org/apache/fineract/cn/deposit/service/internal/repository/SubTransactionTypeRepository.java
new file mode 100644
index 0000000..53f32cb
--- /dev/null
+++ b/service/src/main/java/org/apache/fineract/cn/deposit/service/internal/repository/SubTransactionTypeRepository.java
@@ -0,0 +1,28 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you 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 org.apache.fineract.cn.deposit.service.internal.repository;
+
+import org.springframework.data.jpa.repository.JpaRepository;
+
+import java.util.List;
+import java.util.Optional;
+
+public interface SubTransactionTypeRepository extends JpaRepository<SubTransactionTypeEntity, Long> {
+    Optional<SubTransactionTypeEntity> findByIdentifier(final String identifier);
+}
diff --git a/service/src/main/java/org/apache/fineract/cn/deposit/service/internal/repository/TransactionEntity.java b/service/src/main/java/org/apache/fineract/cn/deposit/service/internal/repository/TransactionEntity.java
new file mode 100644
index 0000000..59b028b
--- /dev/null
+++ b/service/src/main/java/org/apache/fineract/cn/deposit/service/internal/repository/TransactionEntity.java
@@ -0,0 +1,294 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you 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 org.apache.fineract.cn.deposit.service.internal.repository;
+
+import org.apache.fineract.cn.deposit.api.v1.transaction.domain.data.ActionState;
+import org.apache.fineract.cn.deposit.api.v1.transaction.domain.data.TransactionTypeEnum;
+import org.apache.fineract.cn.postgresql.util.LocalDateTimeConverter;
+
+import javax.persistence.*;
+import java.math.BigDecimal;
+import java.time.LocalDateTime;
+
+@Entity
+@Table(name = "shed_transactions")
+public class TransactionEntity {
+
+    @Id
+    @GeneratedValue(strategy = GenerationType.IDENTITY)
+    @Column(name = "id")
+    private Long id;
+
+    @Column(name = "identifier", nullable = false, length = 36)
+    private String identifier;
+
+    @Column(name = "account_identifier", length = 36)
+    private String accountId;
+
+    @Column(name = "routing_code", length = 256)
+    private String routingCode;
+
+    @Column(name = "external_id", length = 256)
+    private String externalId;
+
+    @Column(name = "a_name", length = 256)
+    private String name;
+
+    @Column(name = "description", length = 1024)
+    private String description;
+
+    @Column(name = "transaction_type", nullable = false, length = 32)
+    @Enumerated(EnumType.STRING)
+    private TransactionTypeEnum transactionType;
+
+    @Column(name = "sub_txn_type", length = 36)
+    private String subTxnType;
+
+    @Column(name = "amount", nullable = false)
+    private BigDecimal amount;
+
+
+    @Column(name = "fee_amount")
+    private BigDecimal feeAmount;
+
+    @Column(name = "state", nullable = false, length = 32)
+    @Enumerated(EnumType.STRING)
+    private ActionState state;
+
+    @Column(name = "customer_account_identifier", nullable = false, length = 32)
+    private String customerAccountIdentifier;
+
+    @Column(name = "payable_account_identifier", length = 32)
+    private String prepareAccountIdentifier;
+
+    @Column(name = "nostro_account_identifier", length = 32)
+    private String nostroAccountIdentifier;
+
+    @Column(name = "transaction_date")
+    @Convert(converter = LocalDateTimeConverter.class)
+    private LocalDateTime transactionDate;
+
+    @Column(name = "expiration_date")
+    @Convert(converter = LocalDateTimeConverter.class)
+    private LocalDateTime expirationDate;
+
+    @Column(name = "created_by", nullable = false, length = 32)
+    private String createdBy;
+
+    @Column(name = "created_on", nullable = false)
+    @Convert(converter = LocalDateTimeConverter.class)
+    private LocalDateTime createdOn;
+
+    @Column(name = "last_modified_by", length = 32)
+    private String lastModifiedBy;
+
+    @Column(name = "last_modified_on")
+    @Convert(converter = LocalDateTimeConverter.class)
+    private LocalDateTime lastModifiedOn;
+
+    @Column(name = "a_type", length = 32)
+    private String type;
+
+    @ManyToOne(fetch = FetchType.EAGER, optional = true, cascade = CascadeType.ALL)
+    @JoinColumn(name = "parent_txn_id", nullable = false)
+    private TransactionEntity parentTransaction;
+
+    public TransactionEntity() {
+    }
+
+    public Long getId() {
+        return id;
+    }
+
+    public String getIdentifier() {
+        return identifier;
+    }
+
+    public void setIdentifier(String identifier) {
+        this.identifier = identifier;
+    }
+
+    public String getName() {
+        return name;
+    }
+
+    public void setName(String name) {
+        this.name = name;
+    }
+
+    public String getDescription() {
+        return description;
+    }
+
+    public void setDescription(String description) {
+        this.description = description;
+    }
+
+    public TransactionTypeEnum getTransactionType() {
+        return transactionType;
+    }
+
+    public void setTransactionType(TransactionTypeEnum transactionType) {
+        this.transactionType = transactionType;
+    }
+
+    public BigDecimal getAmount() {
+        return amount;
+    }
+
+    public void setAmount(BigDecimal amount) {
+        this.amount = amount;
+    }
+
+    public ActionState getState() {
+        return state;
+    }
+
+    public void setState(ActionState state) {
+        this.state = state;
+    }
+
+    public String getCustomerAccountIdentifier() {
+        return customerAccountIdentifier;
+    }
+
+    public void setCustomerAccountIdentifier(String customerAccountIdentifier) {
+        this.customerAccountIdentifier = customerAccountIdentifier;
+    }
+
+    public String getPrepareAccountIdentifier() {
+        return prepareAccountIdentifier;
+    }
+
+    public void setPrepareAccountIdentifier(String prepareAccountIdentifier) {
+        this.prepareAccountIdentifier = prepareAccountIdentifier;
+    }
+
+    public String getNostroAccountIdentifier() {
+        return nostroAccountIdentifier;
+    }
+
+    public void setNostroAccountIdentifier(String nostroAccountIdentifier) {
+        this.nostroAccountIdentifier = nostroAccountIdentifier;
+    }
+
+    public LocalDateTime getTransactionDate() {
+        return transactionDate;
+    }
+
+    public void setTransactionDate(LocalDateTime transactionDate) {
+        this.transactionDate = transactionDate;
+    }
+
+    public LocalDateTime getExpirationDate() {
+        return expirationDate;
+    }
+
+    public void setExpirationDate(LocalDateTime expirationDate) {
+        this.expirationDate = expirationDate;
+    }
+
+    public String getCreatedBy() {
+        return createdBy;
+    }
+
+    public void setCreatedBy(String createdBy) {
+        this.createdBy = createdBy;
+    }
+
+    public LocalDateTime getCreatedOn() {
+        return createdOn;
+    }
+
+    public void setCreatedOn(LocalDateTime createdOn) {
+        this.createdOn = createdOn;
+    }
+
+    public String getLastModifiedBy() {
+        return lastModifiedBy;
+    }
+
+    public void setLastModifiedBy(String lastModifiedBy) {
+        this.lastModifiedBy = lastModifiedBy;
+    }
+
+    public LocalDateTime getLastModifiedOn() {
+        return lastModifiedOn;
+    }
+
+    public void setLastModifiedOn(LocalDateTime lastModifiedOn) {
+        this.lastModifiedOn = lastModifiedOn;
+    }
+
+    public BigDecimal getFeeAmount() {
+        return feeAmount;
+    }
+
+    public void setFeeAmount(BigDecimal feeAmount) {
+        this.feeAmount = feeAmount;
+    }
+
+    public String getRoutingCode() {
+        return routingCode;
+    }
+
+    public void setRoutingCode(String routingCode) {
+        this.routingCode = routingCode;
+    }
+
+    public String getExternalId() {
+        return externalId;
+    }
+
+    public void setExternalId(String externalId) {
+        this.externalId = externalId;
+    }
+
+    public String getSubTxnType() {
+        return subTxnType;
+    }
+
+    public void setSubTxnType(String subTxnType) {
+        this.subTxnType = subTxnType;
+    }
+
+    public String getAccountId() {
+        return accountId;
+    }
+
+    public void setAccountId(String accountId) {
+        this.accountId = accountId;
+    }
+
+    public String getType() {
+        return type;
+    }
+
+    public void setType(String type) {
+        this.type = type;
+    }
+
+    public TransactionEntity getParentTransaction() {
+        return parentTransaction;
+    }
+
+    public void setParentTransaction(TransactionEntity parentTransaction) {
+        this.parentTransaction = parentTransaction;
+    }
+}
diff --git a/service/src/main/java/org/apache/fineract/cn/deposit/service/internal/repository/TransactionRepository.java b/service/src/main/java/org/apache/fineract/cn/deposit/service/internal/repository/TransactionRepository.java
new file mode 100644
index 0000000..b59bc94
--- /dev/null
+++ b/service/src/main/java/org/apache/fineract/cn/deposit/service/internal/repository/TransactionRepository.java
@@ -0,0 +1,35 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you 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 org.apache.fineract.cn.deposit.service.internal.repository;
+
+import org.springframework.data.jpa.repository.JpaRepository;
+
+import java.time.LocalDateTime;
+import java.util.List;
+import java.util.Optional;
+
+public interface TransactionRepository extends JpaRepository<TransactionEntity, Long> {
+    Optional<TransactionEntity> findByIdentifier(final String identifier);
+
+    List<TransactionEntity> findByAccountId(final String accountId);
+
+    List<TransactionEntity> findByAccountIdAndTransactionDateBetween(final String accountId, LocalDateTime fromDate,
+                                                                     LocalDateTime toDate);
+}
+
diff --git a/service/src/main/java/org/apache/fineract/cn/deposit/service/internal/service/SubTxnTypesService.java b/service/src/main/java/org/apache/fineract/cn/deposit/service/internal/service/SubTxnTypesService.java
new file mode 100644
index 0000000..a9e84bc
--- /dev/null
+++ b/service/src/main/java/org/apache/fineract/cn/deposit/service/internal/service/SubTxnTypesService.java
@@ -0,0 +1,77 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you 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 org.apache.fineract.cn.deposit.service.internal.service;
+
+import org.apache.commons.lang.StringUtils;
+import org.apache.fineract.cn.accounting.api.v1.client.LedgerManager;
+import org.apache.fineract.cn.accounting.api.v1.domain.Account;
+import org.apache.fineract.cn.deposit.api.v1.instance.domain.ProductInstance;
+import org.apache.fineract.cn.deposit.api.v1.instance.domain.SubTransactionType;
+import org.apache.fineract.cn.deposit.service.ServiceConstants;
+import org.apache.fineract.cn.deposit.service.internal.mapper.ProductInstanceMapper;
+import org.apache.fineract.cn.deposit.service.internal.mapper.SubTransactionTypeMapper;
+import org.apache.fineract.cn.deposit.service.internal.repository.SubTransactionTypeRepository;
+import org.apache.fineract.cn.deposit.service.internal.service.helper.AccountingService;
+import org.apache.fineract.cn.lang.ServiceException;
+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 SubTxnTypesService {
+    private final Logger logger;
+    private final SubTransactionTypeRepository subTransactionTypeRepository;
+    private final LedgerManager ledgerManager;
+
+    @Autowired
+    public SubTxnTypesService(@Qualifier(ServiceConstants.LOGGER_NAME) Logger logger,
+                              SubTransactionTypeRepository subTransactionTypeRepository,
+                              LedgerManager ledgerManager) {
+        this.logger = logger;
+        this.subTransactionTypeRepository = subTransactionTypeRepository;
+        this.ledgerManager = ledgerManager;
+    }
+
+    public Optional<SubTransactionType> findByIdentifier(final String identifier) {
+        return this.subTransactionTypeRepository.findByIdentifier(identifier).map(SubTransactionTypeMapper::map);
+    }
+    public List<SubTransactionType> findAll() {
+        return this.subTransactionTypeRepository.findAll()
+                .stream().map(SubTransactionTypeMapper::map).collect(Collectors.toList());
+    }
+
+    public Boolean subTxnTypeExists(final String identifier) {
+        return this.findByIdentifier(identifier).isPresent();
+    }
+
+    public Boolean ledgerExists(SubTransactionType subTransactionType){
+        if(StringUtils.isNotBlank(subTransactionType.getLedgerAccount())){
+            if(this.ledgerManager.findAccount(subTransactionType.getLedgerAccount()) == null){
+                throw ServiceException.conflict("Ledger Account not found.", subTransactionType.getLedgerAccount());
+            }
+        }
+        return false;
+    }
+
+}
diff --git a/service/src/main/java/org/apache/fineract/cn/deposit/service/internal/service/TransactionService.java b/service/src/main/java/org/apache/fineract/cn/deposit/service/internal/service/TransactionService.java
new file mode 100644
index 0000000..82b0f8e
--- /dev/null
+++ b/service/src/main/java/org/apache/fineract/cn/deposit/service/internal/service/TransactionService.java
@@ -0,0 +1,440 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you 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 org.apache.fineract.cn.deposit.service.internal.service;
+
+import org.apache.commons.lang.StringUtils;
+import org.apache.fineract.cn.accounting.api.v1.client.LedgerManager;
+import org.apache.fineract.cn.accounting.api.v1.domain.Account;
+import org.apache.fineract.cn.accounting.api.v1.domain.Creditor;
+import org.apache.fineract.cn.accounting.api.v1.domain.Debtor;
+import org.apache.fineract.cn.accounting.api.v1.domain.JournalEntry;
+import org.apache.fineract.cn.api.util.UserContextHolder;
+import org.apache.fineract.cn.deposit.api.v1.definition.domain.Action;
+import org.apache.fineract.cn.deposit.api.v1.definition.domain.Charge;
+import org.apache.fineract.cn.deposit.api.v1.definition.domain.Currency;
+import org.apache.fineract.cn.deposit.api.v1.definition.domain.ProductDefinition;
+import org.apache.fineract.cn.deposit.api.v1.instance.domain.ProductInstance;
+import org.apache.fineract.cn.deposit.api.v1.instance.domain.SubTransactionType;
+import org.apache.fineract.cn.deposit.api.v1.transaction.domain.data.*;
+import org.apache.fineract.cn.deposit.api.v1.transaction.utils.MathUtil;
+import org.apache.fineract.cn.deposit.service.ServiceConstants;
+import org.apache.fineract.cn.deposit.service.internal.command.TransactionCommand;
+import org.apache.fineract.cn.deposit.service.internal.repository.ProductInstanceEntity;
+import org.apache.fineract.cn.deposit.service.internal.repository.ProductInstanceRepository;
+import org.apache.fineract.cn.deposit.service.internal.repository.TransactionEntity;
+import org.apache.fineract.cn.deposit.service.internal.repository.TransactionRepository;
+import org.apache.fineract.cn.lang.DateConverter;
+import org.apache.fineract.cn.lang.ServiceException;
+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 org.springframework.transaction.annotation.Transactional;
+
+import javax.validation.constraints.NotNull;
+import java.math.BigDecimal;
+import java.math.MathContext;
+import java.time.Clock;
+import java.time.LocalDateTime;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Optional;
+import java.util.UUID;
+import java.util.stream.Collectors;
+
+@Service
+public class TransactionService {
+    private final Logger logger;
+    private final LedgerManager ledgerManager;
+    private final ProductInstanceService productInstanceService;
+    private final ProductDefinitionService productDefinitionService;
+    private final ActionService actionService;
+    private final SubTxnTypesService subTxnTypesService;
+    private final TransactionRepository transactionRepository;
+    private final ProductInstanceRepository productInstanceRepository;
+
+    public static final String DEBIT = "DEBIT";
+    public static final String CREDIT = "CREDIT";
+
+    @Autowired
+    public TransactionService(@Qualifier(ServiceConstants.LOGGER_NAME) Logger logger, LedgerManager ledgerManager,
+                              ProductInstanceService productInstanceService,
+                              ProductDefinitionService productDefinitionService, ActionService actionService,
+                              SubTxnTypesService subTxnTypesService, TransactionRepository transactionRepository, ProductInstanceRepository productInstanceRepository) {
+        this.logger = logger;
+        this.ledgerManager = ledgerManager;
+        this.productInstanceService = productInstanceService;
+        this.productDefinitionService = productDefinitionService;
+        this.actionService = actionService;
+        this.subTxnTypesService = subTxnTypesService;
+        this.transactionRepository = transactionRepository;
+        this.productInstanceRepository = productInstanceRepository;
+    }
+
+    @Transactional
+    public TransactionResponseData withdraw(TransactionCommand command) {
+        TransactionRequestData request = command.getTransactionRequest();
+        AccountWrapper accountWrapper = validateAndGetAccount(request, TransactionTypeEnum.WITHDRAWAL);
+        LocalDateTime transactionDate = getNow();
+        //get txntype charges
+        List<Charge> charges = getCharges(accountWrapper.account.getIdentifier(), TransactionTypeEnum.WITHDRAWAL);
+        //todo: get subTxnType charges
+
+        TransactionEntity txn = doWithdraw(request, accountWrapper, charges, getNow());
+
+
+        return TransactionResponseData.build(request.getRoutingCode(), request.getExternalId(),
+                request.getRequestCode(), ActionState.ACCEPTED,
+                null, txn.getIdentifier(), transactionDate);
+    }
+
+    @Transactional
+    public TransactionResponseData deposit(TransactionCommand command) {
+        TransactionRequestData request = command.getTransactionRequest();
+        AccountWrapper accountWrapper = validateAndGetAccount(request, TransactionTypeEnum.DEPOSIT);
+        LocalDateTime transactionDate = getNow();
+        //get txntype charges
+        List<Charge> charges = getCharges(accountWrapper.account.getIdentifier(), TransactionTypeEnum.DEPOSIT);
+        //todo: get subTxnType charges
+        TransactionEntity txn = doDeposit(request, accountWrapper, charges, getNow());
+
+        return TransactionResponseData.build(request.getRoutingCode(), request.getExternalId(),
+                request.getRequestCode(), ActionState.ACCEPTED,
+                null, txn.getIdentifier(), transactionDate);
+    }
+
+    private TransactionEntity doDeposit(TransactionRequestData request, AccountWrapper accountWrapper, List<Charge> charges, LocalDateTime transactionDate) {
+        BigDecimal amount = request.getAmount().getAmount();
+
+        TransactionEntity txn = createTransaction(request,TransactionTypeEnum.DEPOSIT, transactionDate, CREDIT, null);
+        String debitAccountIdentifier = accountWrapper.productDefinition.getCashAccountIdentifier();
+        /* if subtxn is provided and it has an account configured the do debit that account*/
+        if(StringUtils.isNotBlank(request.getSubTxnId())){
+            Optional<SubTransactionType> subTxnTypeOpt = this.subTxnTypesService.findByIdentifier(request.getSubTxnId());
+            if(subTxnTypeOpt.isPresent()) {
+                txn.setSubTxnType(subTxnTypeOpt.get().getIdentifier());
+                if (subTxnTypeOpt.get().getLedgerAccount() != null) {
+                    debitAccountIdentifier = subTxnTypeOpt.get().getLedgerAccount();
+                }
+            }
+        }
+        final JournalEntry journalEntry = createJournalEntry(txn.getIdentifier(), TransactionTypeEnum.DEPOSIT.getCode(),
+                DateConverter.toIsoString(transactionDate), request.getNote(), getLoginUser());
+
+        HashSet<Debtor> debtors = new HashSet<>(1);
+        HashSet<Creditor> creditors = new HashSet<>(1);
+
+        addCreditor(accountWrapper.account.getIdentifier(), amount.doubleValue(), creditors);
+        addDebtor(debitAccountIdentifier, amount.doubleValue(), debtors);
+
+
+        prepareCharges(request, accountWrapper, charges, debtors, creditors, txn);
+
+        if (debtors.isEmpty()) // must be same size as creditors
+            throw ServiceException.badRequest("Debit and Credit doesn't match");
+
+        journalEntry.setDebtors(debtors);
+        journalEntry.setCreditors(creditors);
+
+        transactionRepository.save(txn);
+
+        ledgerManager.createJournalEntry(journalEntry);
+        return txn;
+    }
+
+
+    private TransactionEntity doWithdraw(@NotNull TransactionRequestData request, @NotNull AccountWrapper accountWrapper,
+                                 List<Charge> charges, LocalDateTime transactionDate) {
+        BigDecimal amount = request.getAmount().getAmount();
+
+        TransactionEntity txn = createTransaction(request, TransactionTypeEnum.WITHDRAWAL, transactionDate, DEBIT, null);
+
+        String creditAccountIdentifier = accountWrapper.productDefinition.getCashAccountIdentifier();
+        /* if subtxn is provided and it has an account configured the do credit that account*/
+        if(StringUtils.isNotBlank(request.getSubTxnId())){
+            Optional<SubTransactionType> subTxnTypeOpt = this.subTxnTypesService.findByIdentifier(request.getSubTxnId());
+            if(subTxnTypeOpt.isPresent()) {
+                txn.setSubTxnType(subTxnTypeOpt.get().getIdentifier());
+                if (subTxnTypeOpt.get().getLedgerAccount() != null) {
+                    creditAccountIdentifier = subTxnTypeOpt.get().getLedgerAccount();
+                }
+            }
+        }
+        final JournalEntry journalEntry = createJournalEntry(txn.getIdentifier(), TransactionTypeEnum.WITHDRAWAL.getCode(),
+                DateConverter.toIsoString(transactionDate), request.getNote(), getLoginUser());
+
+        HashSet<Debtor> debtors = new HashSet<>(1);
+        HashSet<Creditor> creditors = new HashSet<>(1);
+
+        addCreditor(creditAccountIdentifier, amount.doubleValue(), creditors);
+        addDebtor(accountWrapper.account.getIdentifier(), amount.doubleValue(), debtors);
+
+        prepareCharges(request, accountWrapper, charges, debtors, creditors, txn);
+
+        if (debtors.isEmpty()) // must be same size as creditors
+            throw ServiceException.badRequest("Debit and Credit doesn't match");
+
+        journalEntry.setDebtors(debtors);
+        journalEntry.setCreditors(creditors);
+        transactionRepository.save(txn);
+        ledgerManager.createJournalEntry(journalEntry);
+        return txn;
+    }
+
+
+
+    private void prepareCharges(@NotNull TransactionRequestData request, @NotNull AccountWrapper accountWrapper,
+                                @NotNull List<Charge> charges, HashSet<Debtor> debtors, HashSet<Creditor> creditors,
+                                TransactionEntity txn) {
+
+
+        BigDecimal amount = request.getAmount().getAmount();
+        Currency currency = accountWrapper.productDefinition.getCurrency();
+
+        BigDecimal total = MathUtil.normalize(calcTotalCharges(charges, amount), currency);
+        if (MathUtil.isEmpty(total)) {
+            return;
+        }
+        txn.setFeeAmount(total);
+
+        if (creditors == null) {
+            creditors = new HashSet<>(1);
+        }
+        if (debtors == null) {
+            debtors = new HashSet<>(charges.size());
+        }
+        for(Charge charge : charges){
+            addCreditor(charge.getIncomeAccountIdentifier(), calcChargeAmount(amount, charge).doubleValue(), creditors);
+            addDebtor(accountWrapper.account.getIdentifier(), calcChargeAmount(amount, charge).doubleValue(), debtors);
+            createTransaction(request,TransactionTypeEnum.CHARGES_PAYMENT, getNow(), DEBIT, txn);
+        }
+
+    }
+
+
+
+    private AccountWrapper validateAndGetAccount(@NotNull TransactionRequestData request, TransactionTypeEnum txnType) {
+        //TODO: error handling
+        String accountId = request.getAccountId();
+        Account account = ledgerManager.findAccount(accountId);
+        validateAccount(request, account);
+
+        ProductInstance product = productInstanceService.findByAccountIdentifier(accountId).get();
+        ProductDefinition productDefinition = productDefinitionService.findProductDefinition(product.getProductIdentifier()).get();
+
+        Currency currency = productDefinition.getCurrency();
+        if (!currency.getCode().equals(request.getAmount().getCurrency()))
+            throw new UnsupportedOperationException();
+
+        request.normalizeAmounts(currency);
+
+        Double withdrawableBalance = getWithdrawableBalance(account, productDefinition);
+        if (txnType == TransactionTypeEnum.WITHDRAWAL && withdrawableBalance < request.getAmount().getAmount().doubleValue())
+            throw new UnsupportedOperationException();
+
+        return new AccountWrapper(account, product, productDefinition, withdrawableBalance);
+    }
+
+    Double getWithdrawableBalance(Account account, ProductDefinition productDefinition) {
+        // on-hold amount, if any, is subtracted to payable account
+        return MathUtil.subtractToZero(account.getBalance(), productDefinition.getMinimumBalance());
+    }
+
+
+    private void validateAccount(@NotNull TransactionRequestData request, Account account) {
+        validateAccount(account);
+
+        String accountId = account.getIdentifier();
+
+        if (account.getHolders() != null) { // customer account
+            ProductInstance product = productInstanceService.findByAccountIdentifier(accountId).get();
+            ProductDefinition productDefinition = productDefinitionService.findProductDefinition(product.getProductIdentifier()).get();
+            if (!Boolean.TRUE.equals(productDefinition.getActive()))
+                throw new UnsupportedOperationException("Product Definition is inactive");
+
+            Currency currency = productDefinition.getCurrency();
+            if (!currency.getCode().equals(request.getAmount().getCurrency()))
+                throw new UnsupportedOperationException();
+        }
+    }
+
+    private void validateAccount(Account account) {
+        if (account == null)
+            throw new UnsupportedOperationException("Account not found");
+        if (!account.getState().equals(Account.State.OPEN.name()))
+            throw new UnsupportedOperationException("Account is in state " + account.getState());
+    }
+
+    public List<Charge> getCharges(String accountIdentifier, TransactionTypeEnum transactionType) {
+        List<Action> actions = actionService.fetchActions();
+
+        List<String> actionIds = actions
+                .stream()
+                .filter(action -> action.getTransactionType().equals(transactionType.getCode()))
+                .map(Action::getIdentifier)
+                .collect(Collectors.toList());
+
+        ProductInstance product = productInstanceService.findByAccountIdentifier(accountIdentifier).get();
+        ProductDefinition productDefinition = productDefinitionService.findProductDefinition(product.getProductIdentifier()).get();
+
+        return productDefinition.getCharges()
+                .stream()
+                .filter(charge -> actionIds.contains(charge.getActionIdentifier()))
+                .collect(Collectors.toList());
+    }
+    // Util
+
+
+    private LocalDateTime getNow() {
+        return LocalDateTime.now(Clock.systemUTC());
+    }
+    private String getLoginUser() {
+        return UserContextHolder.checkedGetUser();
+    }
+
+
+    private JournalEntry createJournalEntry(String actionIdentifier, String transactionType, String transactionDate, String message, String loginUser) {
+        final JournalEntry journalEntry = new JournalEntry();
+        journalEntry.setTransactionIdentifier(actionIdentifier);
+        journalEntry.setTransactionType(transactionType);
+        journalEntry.setTransactionDate(transactionDate);
+        journalEntry.setMessage(message);
+        journalEntry.setClerk(loginUser);
+        return journalEntry;
+    }
+
+    private void addCreditor(String accountNumber, double amount, HashSet<Creditor> creditors) {
+        Creditor creditor = new Creditor();
+        creditor.setAccountNumber(accountNumber);
+        creditor.setAmount(Double.toString(amount));
+        creditors.add(creditor);
+    }
+
+    private void addDebtor(String accountNumber, double amount, HashSet<Debtor> debtors) {
+        Debtor debtor = new Debtor();
+        debtor.setAccountNumber(accountNumber);
+        debtor.setAmount(Double.toString(amount));
+        debtors.add(debtor);
+    }
+
+    private BigDecimal calcChargeAmount(BigDecimal amount, Charge charge) {
+        return calcChargeAmount(amount, charge, null, false);
+    }
+
+    private BigDecimal calcChargeAmount(@NotNull BigDecimal amount, @NotNull Charge charge, Currency currency, boolean norm) {
+        Double value = charge.getAmount();
+        if (value == null)
+            return null;
+
+        BigDecimal portion = BigDecimal.valueOf(100.00d);
+        MathContext mc = MathUtil.CALCULATION_MATH_CONTEXT;
+        BigDecimal feeAmount = BigDecimal.valueOf(MathUtil.nullToZero(charge.getAmount()));
+        BigDecimal result = charge.getProportional()
+                ? amount.multiply(feeAmount.divide(portion, mc), mc)
+                : feeAmount;
+        return norm ? MathUtil.normalize(result, currency) : result;
+    }
+
+    @NotNull
+    private BigDecimal calcTotalCharges(@NotNull List<Charge> charges, BigDecimal amount) {
+        return charges.stream().map(charge -> calcChargeAmount(amount, charge)).reduce(MathUtil::add).orElse(BigDecimal.ZERO);
+    }
+
+
+    private TransactionEntity createTransaction(TransactionRequestData request, TransactionTypeEnum txnType,
+                                                LocalDateTime transactionDate, String tranType,
+                                                TransactionEntity parent) {
+        TransactionEntity txn = new TransactionEntity();
+        UUID uuid=UUID.randomUUID();
+
+        while(transactionRepository.findByIdentifier(uuid.toString()).isPresent()){
+            uuid=UUID.randomUUID();
+        }
+
+        txn.setIdentifier(uuid.toString());
+        txn.setRoutingCode(request.getRoutingCode());
+        txn.setExternalId(request.getExternalId());
+        txn.setTransactionType(txnType);
+        txn.setAmount(request.getAmount().getAmount());
+        //txn.setFeeAmount();
+        txn.setState(ActionState.ACCEPTED);
+        //txn.setCustomerAccountIdentifier();
+        txn.setTransactionDate(transactionDate);
+        txn.setExpirationDate(request.getExpiration());
+        txn.setCreatedBy(getLoginUser());
+        txn.setCreatedOn(getNow());
+        /*txn.setLastModifiedBy();
+        txn.setLastModifiedOn();*/
+        markLastTransaction(request.getAccountId(), transactionDate);
+        txn.setAccountId(request.getAccountId());
+        txn.setType(tranType);
+        txn.setParentTransaction(parent);
+        transactionRepository.save(txn);
+        return txn;
+    }
+
+    private void markLastTransaction(final String productInstanceIdentifier, LocalDateTime transactionDate) {
+        final Optional<ProductInstanceEntity> optionalProductInstance =
+                this.productInstanceRepository.findByAccountIdentifier(productInstanceIdentifier);
+
+        final ProductInstanceEntity productInstanceEntity = optionalProductInstance.orElseThrow(() ->
+                ServiceException.notFound("Product instance {0} not found.", productInstanceIdentifier));
+
+        productInstanceEntity.setLastTransactionDate(transactionDate);
+
+        this.productInstanceRepository.save(productInstanceEntity);
+
+    }
+    public List<StatementResponse> fetchStatement(String accountId,
+                                                  LocalDateTime fromDateTime,
+                                                  LocalDateTime toDateTime) {
+        return transactionRepository.findByAccountIdAndTransactionDateBetween(accountId, fromDateTime, toDateTime)
+                .stream().map(txn -> {
+                    StatementResponse statementObj = new StatementResponse();
+                    statementObj.setTransactionCode(txn.getIdentifier());
+                    statementObj.setTranType(txn.getTransactionType().name());
+                    statementObj.setAmount(txn.getAmount());
+                    statementObj.setTransactionDate(txn.getTransactionDate());
+                    statementObj.setSubTxnType(txn.getSubTxnType());
+                    statementObj.setType(txn.getType());
+                    statementObj.setDescription(txn.getDescription());
+                    return statementObj;
+                }).collect(Collectors.toList());
+    }
+
+    public static class AccountWrapper {
+        @NotNull
+        private final Account account;
+        @NotNull
+        private final ProductInstance product;
+        @NotNull
+        private final ProductDefinition productDefinition;
+        @NotNull
+        private final Double withdrawableBalance;
+
+        public AccountWrapper(Account account, ProductInstance product, ProductDefinition productDefinition, Double withdrawableBalance) {
+            this.account = account;
+            this.product = product;
+            this.productDefinition = productDefinition;
+            this.withdrawableBalance = withdrawableBalance;
+        }
+    }
+}
diff --git a/service/src/main/java/org/apache/fineract/cn/deposit/service/rest/ProductInstanceRestController.java b/service/src/main/java/org/apache/fineract/cn/deposit/service/rest/ProductInstanceRestController.java
index d9025c9..aece9a3 100644
--- a/service/src/main/java/org/apache/fineract/cn/deposit/service/rest/ProductInstanceRestController.java
+++ b/service/src/main/java/org/apache/fineract/cn/deposit/service/rest/ProductInstanceRestController.java
@@ -18,37 +18,34 @@
  */
 package org.apache.fineract.cn.deposit.service.rest;
 
+import org.apache.fineract.cn.anubis.annotation.AcceptedTokenType;
+import org.apache.fineract.cn.anubis.annotation.Permittable;
+import org.apache.fineract.cn.command.gateway.CommandGateway;
 import org.apache.fineract.cn.deposit.api.v1.EventConstants;
 import org.apache.fineract.cn.deposit.api.v1.PermittableGroupIds;
 import org.apache.fineract.cn.deposit.api.v1.instance.domain.AvailableTransactionType;
 import org.apache.fineract.cn.deposit.api.v1.instance.domain.ProductInstance;
+import org.apache.fineract.cn.deposit.api.v1.transaction.domain.data.StatementResponse;
 import org.apache.fineract.cn.deposit.service.ServiceConstants;
-import org.apache.fineract.cn.deposit.service.internal.command.ActivateProductInstanceCommand;
-import org.apache.fineract.cn.deposit.service.internal.command.CloseProductInstanceCommand;
-import org.apache.fineract.cn.deposit.service.internal.command.CreateProductInstanceCommand;
-import org.apache.fineract.cn.deposit.service.internal.command.TransactionProcessedCommand;
-import org.apache.fineract.cn.deposit.service.internal.command.UpdateProductInstanceCommand;
+import org.apache.fineract.cn.deposit.service.internal.command.*;
 import org.apache.fineract.cn.deposit.service.internal.service.ProductInstanceService;
-import java.util.HashSet;
-import java.util.List;
-import java.util.Set;
-import javax.validation.Valid;
-import org.apache.fineract.cn.anubis.annotation.AcceptedTokenType;
-import org.apache.fineract.cn.anubis.annotation.Permittable;
-import org.apache.fineract.cn.command.gateway.CommandGateway;
+import org.apache.fineract.cn.deposit.service.internal.service.TransactionService;
 import org.apache.fineract.cn.lang.ServiceException;
 import org.slf4j.Logger;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.beans.factory.annotation.Qualifier;
+import org.springframework.format.annotation.DateTimeFormat;
 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 org.springframework.web.bind.annotation.*;
+
+import javax.validation.Valid;
+import java.time.LocalDateTime;
+import java.time.ZoneId;
+import java.util.Date;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Set;
 
 @RestController
 @RequestMapping("/instances")
@@ -57,15 +54,18 @@
   private final Logger logger;
   private final CommandGateway commandGateway;
   private final ProductInstanceService productInstanceService;
+  private final TransactionService transactionService;
 
   @Autowired
   public ProductInstanceRestController(@Qualifier(ServiceConstants.LOGGER_NAME) final Logger logger,
                                        final CommandGateway commandGateway,
-                                       final ProductInstanceService productInstanceService) {
+                                       final ProductInstanceService productInstanceService,
+                                       TransactionService transactionService) {
     super();
     this.logger = logger;
     this.commandGateway = commandGateway;
     this.productInstanceService = productInstanceService;
+    this.transactionService = transactionService;
   }
 
   @Permittable(value = AcceptedTokenType.TENANT, groupId = PermittableGroupIds.INSTANCE_MANAGEMENT)
@@ -199,4 +199,32 @@
         .orElseThrow(() -> ServiceException.notFound("Product instance {0} not found.", identifier))
     );
   }
+
+  @Permittable(value = AcceptedTokenType.TENANT, groupId = PermittableGroupIds.INSTANCE_MANAGEMENT)
+  @RequestMapping(
+          value = "/{identifier}/statement",
+          method = RequestMethod.GET,
+          consumes = MediaType.ALL_VALUE,
+          produces = MediaType.APPLICATION_JSON_VALUE
+  )
+  @ResponseBody
+  ResponseEntity<List<StatementResponse>> statement(@PathVariable("identifier") final String identifier,
+                                                    @RequestParam("fromDate")
+                                            @DateTimeFormat(pattern = "dd.MM.yyyy") Date fromDate,
+                                                    @RequestParam("toDate")
+                                            @DateTimeFormat(pattern = "dd.MM.yyyy") Date toDate
+                                            ) {
+    LocalDateTime fromDateTime = convertToLocalDateTime(fromDate);
+    LocalDateTime toDateTime = convertToLocalDateTime(toDate);
+
+    List<StatementResponse> statement= transactionService.fetchStatement(identifier, fromDateTime, toDateTime);
+
+    return ResponseEntity.ok(statement);
+  }
+
+  private  LocalDateTime convertToLocalDateTime(Date dateToConvert) {
+    return dateToConvert.toInstant()
+            .atZone(ZoneId.systemDefault())
+            .toLocalDateTime();
+  }
 }
diff --git a/service/src/main/java/org/apache/fineract/cn/deposit/service/rest/SubTxnTypeRestController.java b/service/src/main/java/org/apache/fineract/cn/deposit/service/rest/SubTxnTypeRestController.java
new file mode 100644
index 0000000..8a875f4
--- /dev/null
+++ b/service/src/main/java/org/apache/fineract/cn/deposit/service/rest/SubTxnTypeRestController.java
@@ -0,0 +1,132 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you 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 org.apache.fineract.cn.deposit.service.rest;
+
+import org.apache.commons.lang.StringUtils;
+import org.apache.fineract.cn.anubis.annotation.AcceptedTokenType;
+import org.apache.fineract.cn.anubis.annotation.Permittable;
+import org.apache.fineract.cn.command.gateway.CommandGateway;
+import org.apache.fineract.cn.deposit.api.v1.PermittableGroupIds;
+import org.apache.fineract.cn.deposit.api.v1.instance.domain.ProductInstance;
+import org.apache.fineract.cn.deposit.api.v1.instance.domain.SubTransactionType;
+import org.apache.fineract.cn.deposit.service.ServiceConstants;
+import org.apache.fineract.cn.deposit.service.internal.command.CreateSubTxnTypeCommand;
+import org.apache.fineract.cn.deposit.service.internal.command.UpdateSubTxnTypeCommand;
+import org.apache.fineract.cn.deposit.service.internal.service.SubTxnTypesService;
+import org.apache.fineract.cn.lang.ServiceException;
+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;
+import java.util.Optional;
+
+@RestController
+@RequestMapping("/subtxntype")
+public class SubTxnTypeRestController {
+    private final Logger logger;
+    private final CommandGateway commandGateway;
+    private final SubTxnTypesService service;
+
+    @Autowired
+    public SubTxnTypeRestController(@Qualifier(ServiceConstants.LOGGER_NAME) final Logger logger,
+                                    CommandGateway commandGateway,
+                                    SubTxnTypesService service) {
+        this.logger = logger;
+        this.commandGateway = commandGateway;
+        this.service = service;
+    }
+
+    @Permittable(value = AcceptedTokenType.TENANT, groupId = PermittableGroupIds.DEFINITION_MANAGEMENT)
+    @RequestMapping(
+            value = "",
+            method = RequestMethod.POST,
+            consumes = MediaType.APPLICATION_JSON_VALUE,
+            produces = MediaType.APPLICATION_JSON_VALUE
+    )
+    public
+    @ResponseBody
+    ResponseEntity<Void> create(@RequestBody @Valid final SubTransactionType subTransactionType) {
+
+        if (this.service.subTxnTypeExists(subTransactionType.getIdentifier())) {
+            throw ServiceException.conflict("Sub Txn Type {0} already exists.", subTransactionType.getIdentifier());
+        }
+
+        this.service.ledgerExists(subTransactionType);
+
+        this.commandGateway.process(new CreateSubTxnTypeCommand(subTransactionType));
+        return ResponseEntity.accepted().build();
+    }
+
+    @Permittable(value = AcceptedTokenType.TENANT, groupId = PermittableGroupIds.DEFINITION_MANAGEMENT)
+    @RequestMapping(
+            value = "",
+            method = RequestMethod.GET,
+            consumes = MediaType.ALL_VALUE,
+            produces = MediaType.APPLICATION_JSON_VALUE
+    )
+    public
+    @ResponseBody
+    ResponseEntity<List<SubTransactionType>> fetchSubTxnTypes() {
+        return ResponseEntity.ok(this.service.findAll());
+    }
+
+
+    @Permittable(value = AcceptedTokenType.TENANT, groupId = PermittableGroupIds.DEFINITION_MANAGEMENT)
+    @RequestMapping(
+            value = "/{identifier}",
+            method = RequestMethod.GET,
+            consumes = MediaType.APPLICATION_JSON_VALUE,
+            produces = MediaType.APPLICATION_JSON_VALUE
+    )
+    public
+    @ResponseBody
+    ResponseEntity<SubTransactionType> fetchOne(@PathVariable("identifier") final String identifier) {
+        Optional<SubTransactionType> optSubTxnType = service.findByIdentifier(identifier);
+        if (!optSubTxnType.isPresent()) {
+            throw ServiceException.notFound("Sub transaction type {0} not found.", identifier);
+        }
+        return ResponseEntity.ok(optSubTxnType.get());
+    }
+
+
+    @Permittable(value = AcceptedTokenType.TENANT, groupId = PermittableGroupIds.DEFINITION_MANAGEMENT)
+    @RequestMapping(
+            value = "/{identifier}",
+            method = RequestMethod.PUT,
+            produces = MediaType.APPLICATION_JSON_VALUE,
+            consumes = MediaType.APPLICATION_JSON_VALUE
+    )
+    public
+    @ResponseBody
+    ResponseEntity<Void> updateCustomer(@PathVariable("identifier") final String identifier,
+                                        @RequestBody final SubTransactionType subTransactionType) {
+        if (this.service.subTxnTypeExists(identifier)) {
+            this.commandGateway.process(new UpdateSubTxnTypeCommand(subTransactionType));
+        } else {
+            throw ServiceException.notFound("Sub transaction type {0} not found.", identifier);
+        }
+        return ResponseEntity.accepted().build();
+    }
+
+}
diff --git a/service/src/main/java/org/apache/fineract/cn/deposit/service/rest/TransactionRestController.java b/service/src/main/java/org/apache/fineract/cn/deposit/service/rest/TransactionRestController.java
new file mode 100644
index 0000000..3b6e278
--- /dev/null
+++ b/service/src/main/java/org/apache/fineract/cn/deposit/service/rest/TransactionRestController.java
@@ -0,0 +1,79 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you 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 org.apache.fineract.cn.deposit.service.rest;
+
+import org.apache.fineract.cn.anubis.annotation.AcceptedTokenType;
+import org.apache.fineract.cn.anubis.annotation.Permittable;
+import org.apache.fineract.cn.command.domain.CommandCallback;
+import org.apache.fineract.cn.command.gateway.CommandGateway;
+import org.apache.fineract.cn.deposit.api.v1.PermittableGroupIds;
+import org.apache.fineract.cn.deposit.api.v1.instance.domain.SubTransactionType;
+import org.apache.fineract.cn.deposit.api.v1.transaction.domain.data.TransactionActionType;
+import org.apache.fineract.cn.deposit.api.v1.transaction.domain.data.TransactionRequestData;
+import org.apache.fineract.cn.deposit.api.v1.transaction.domain.data.TransactionResponseData;
+import org.apache.fineract.cn.deposit.api.v1.transaction.domain.data.TransactionTypeEnum;
+import org.apache.fineract.cn.deposit.service.ServiceConstants;
+import org.apache.fineract.cn.deposit.service.internal.command.CreateSubTxnTypeCommand;
+import org.apache.fineract.cn.deposit.service.internal.command.TransactionCommand;
+import org.apache.fineract.cn.deposit.service.internal.service.SubTxnTypesService;
+import org.apache.fineract.cn.lang.ServiceException;
+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 java.util.List;
+
+
+@RestController
+@RequestMapping("/transaction")
+public class TransactionRestController {
+    private final Logger logger;
+    private final CommandGateway commandGateway;
+    private final SubTxnTypesService service;
+
+    @Autowired
+    public TransactionRestController(@Qualifier(ServiceConstants.LOGGER_NAME) final Logger logger,
+                                     CommandGateway commandGateway,
+                                     SubTxnTypesService service) {
+        this.logger = logger;
+        this.commandGateway = commandGateway;
+        this.service = service;
+    }
+
+    @Permittable(value = AcceptedTokenType.TENANT, groupId = PermittableGroupIds.INSTANCE_MANAGEMENT)
+    @RequestMapping(
+            value = "",
+            method = RequestMethod.POST,
+            consumes = MediaType.APPLICATION_JSON_VALUE,
+            produces = MediaType.APPLICATION_JSON_VALUE
+    )
+    public
+    @ResponseBody
+    ResponseEntity<TransactionResponseData> performTxn(@RequestParam("action") String action, @RequestBody TransactionRequestData requestData)
+            throws Throwable {
+        CommandCallback<TransactionResponseData> result = commandGateway.process(new TransactionCommand(requestData, TransactionActionType.valueOf(action)),
+                TransactionResponseData.class);
+
+        return ResponseEntity.ok(result.get());
+    }
+
+}
diff --git a/service/src/main/resources/application.yml b/service/src/main/resources/application.yml
index 26e8854..16e3bee 100644
--- a/service/src/main/resources/application.yml
+++ b/service/src/main/resources/application.yml
@@ -1,4 +1,4 @@
-#
+  #
 # Licensed to the Apache Software Foundation (ASF) under one
 # or more contributor license agreements.  See the NOTICE file
 # distributed with this work for additional information
@@ -69,3 +69,6 @@
 
 flyway:
   enabled: false
+
+config:
+  fixedAccountId: true
diff --git a/service/src/main/resources/db/migrations/postgresql/V7__sub_txn_type.sql b/service/src/main/resources/db/migrations/postgresql/V7__sub_txn_type.sql
new file mode 100644
index 0000000..0078941
--- /dev/null
+++ b/service/src/main/resources/db/migrations/postgresql/V7__sub_txn_type.sql
@@ -0,0 +1,32 @@
+--
+-- Licensed to the Apache Software Foundation (ASF) under one
+-- or more contributor license agreements.  See the NOTICE file
+-- distributed with this work for additional information
+-- regarding copyright ownership.  The ASF licenses this file
+-- to you under the Apache License, Version 2.0 (the
+-- "License"); you may not use this file except in compliance
+-- with the License.  You may obtain a copy of the License at
+--
+--   http://www.apache.org/licenses/LICENSE-2.0
+--
+-- Unless required by applicable law or agreed to in writing,
+-- software distributed under the License is distributed on an
+-- "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+-- KIND, either express or implied.  See the License for the
+-- specific language governing permissions and limitations
+-- under the License.
+--
+
+CREATE TABLE shed_sub_tx_type (
+	id bigserial NOT NULL,
+	identifier varchar(32) NOT NULL,
+	a_name varchar(256) NOT NULL,
+	description varchar(2048) NULL,
+	is_cash_payment bool NOT NULL,
+	is_active  bool NOT null,
+	order_position int8 NOT null,
+	tran_type_enum int8  NULL,
+	ledger_account_identifier varchar(32) NULL,
+	CONSTRAINT shed_sub_tx_type_pk PRIMARY KEY (id),
+	CONSTRAINT shed_sub_tx_type_identifier_uq UNIQUE (identifier)
+);
\ No newline at end of file
diff --git a/service/src/main/resources/db/migrations/postgresql/V8__transaction.sql b/service/src/main/resources/db/migrations/postgresql/V8__transaction.sql
new file mode 100644
index 0000000..9acf61e
--- /dev/null
+++ b/service/src/main/resources/db/migrations/postgresql/V8__transaction.sql
@@ -0,0 +1,46 @@
+--
+-- Licensed to the Apache Software Foundation (ASF) under one
+-- or more contributor license agreements.  See the NOTICE file
+-- distributed with this work for additional information
+-- regarding copyright ownership.  The ASF licenses this file
+-- to you under the Apache License, Version 2.0 (the
+-- "License"); you may not use this file except in compliance
+-- with the License.  You may obtain a copy of the License at
+--
+--   http://www.apache.org/licenses/LICENSE-2.0
+--
+-- Unless required by applicable law or agreed to in writing,
+-- software distributed under the License is distributed on an
+-- "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+-- KIND, either express or implied.  See the License for the
+-- specific language governing permissions and limitations
+-- under the License.
+--
+
+CREATE TABLE shed_transactions (
+  id                          bigserial       NOT NULL,
+  identifier                  VARCHAR(40)    NOT NULL,
+  account_identifier                  VARCHAR(32)  NOT NULL,
+  routing_code                  VARCHAR(40)    NULL,
+  external_id                  VARCHAR(40)     NULL,
+  a_name                      VARCHAR(256)   NULL,
+  description                 VARCHAR(1024)  NULL,
+  transaction_type            VARCHAR(32)    NOT NULL,
+  sub_txn_type                VARCHAR(32)  NULL,
+  amount                      numeric(15,5) NOT NULL,
+  fee_amount                  numeric(15,5)  NULL,
+  state                       VARCHAR(32)    NOT NULL,
+  customer_account_identifier VARCHAR(32)     NULL,
+  payable_account_identifier  VARCHAR(32)    NULL,
+  nostro_account_identifier   VARCHAR(32)    NULL,
+  transaction_date            TIMESTAMP   NULL,
+  expiration_date             TIMESTAMP   NULL,
+  created_by                  VARCHAR(32)     NULL,
+  created_on                  TIMESTAMP    NULL,
+  last_modified_by            VARCHAR(32)    NULL,
+  last_modified_on            TIMESTAMP   NULL,
+  CONSTRAINT pk_shed_transactions PRIMARY KEY (id),
+  CONSTRAINT uk_shed_transactions_id UNIQUE (identifier),
+  CONSTRAINT shed_txn_sub_txn_type_fk FOREIGN KEY (sub_txn_type) REFERENCES shed_sub_tx_type (identifier),
+  CONSTRAINT shed_txn_prod_instance_fk FOREIGN KEY (account_identifier) REFERENCES shed_product_instances (account_identifier)
+);
\ No newline at end of file
diff --git a/service/src/main/resources/db/migrations/postgresql/V9__transaction_update.sql b/service/src/main/resources/db/migrations/postgresql/V9__transaction_update.sql
new file mode 100644
index 0000000..450715a
--- /dev/null
+++ b/service/src/main/resources/db/migrations/postgresql/V9__transaction_update.sql
@@ -0,0 +1,30 @@
+--
+-- Licensed to the Apache Software Foundation (ASF) under one
+-- or more contributor license agreements.  See the NOTICE file
+-- distributed with this work for additional information
+-- regarding copyright ownership.  The ASF licenses this file
+-- to you under the Apache License, Version 2.0 (the
+-- "License"); you may not use this file except in compliance
+-- with the License.  You may obtain a copy of the License at
+--
+--   http://www.apache.org/licenses/LICENSE-2.0
+--
+-- Unless required by applicable law or agreed to in writing,
+-- software distributed under the License is distributed on an
+-- "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+-- KIND, either express or implied.  See the License for the
+-- specific language governing permissions and limitations
+-- under the License.
+--
+
+ALTER TABLE shed_transactions
+ADD COLUMN a_type varchar(32)  NULL;
+
+ALTER TABLE shed_transactions
+ADD COLUMN parent_txn_id bigint NULL;
+
+
+ALTER TABLE shed_transactions
+ADD CONSTRAINT shed_txn_to_txn_fk
+FOREIGN KEY (parent_txn_id)
+REFERENCES shed_transactions (id);
\ No newline at end of file
diff --git a/shared.gradle b/shared.gradle
index 5d8ffee..a95dc9d 100644
--- a/shared.gradle
+++ b/shared.gradle
@@ -29,6 +29,7 @@
         frameworkanubis    : '0.1.0-BUILD-SNAPSHOT',
         frameworkledger    : '0.1.0-BUILD-SNAPSHOT',
         frameworkrhythm    : '0.1.0-BUILD-SNAPSHOT',
+        frameworkdeposit   : '0.1.0-BUILD-SNAPSHOT',
         javamoneylib       : '0.9-SNAPSHOT',
         validator          : '5.3.0.Final'
 ]