balance-api-collection-init
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 1f70ac1..5bd1063 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
@@ -63,4 +63,5 @@
   String SELECTOR_INTEREST_ACCRUED = SELECTOR_NAME + " = '" + INTEREST_ACCRUED + "'";
   String INTEREST_PAYED = "interest-payed";
   String SELECTOR_INTEREST_PAYED = SELECTOR_NAME + " = '" + INTEREST_PAYED + "'";
+  String CALCULATE_IBB = "calculate-ibb";
 }
diff --git a/api/src/main/java/org/apache/fineract/cn/deposit/api/v1/transaction/domain/data/BalanceResponse.java b/api/src/main/java/org/apache/fineract/cn/deposit/api/v1/transaction/domain/data/BalanceResponse.java
new file mode 100644
index 0000000..41a42fb
--- /dev/null
+++ b/api/src/main/java/org/apache/fineract/cn/deposit/api/v1/transaction/domain/data/BalanceResponse.java
@@ -0,0 +1,44 @@
+/*
+ * 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;
+
+public class BalanceResponse {
+    private BigDecimal balance;
+    private BigDecimal interest;
+
+    public BalanceResponse() {
+    }
+
+    public BigDecimal getBalance() {
+        return balance;
+    }
+
+    public void setBalance(BigDecimal balance) {
+        this.balance = balance;
+    }
+
+    public BigDecimal getInterest() {
+        return interest;
+    }
+
+    public void setInterest(BigDecimal interest) {
+        this.interest = interest;
+    }
+}
diff --git a/service/src/main/java/org/apache/fineract/cn/deposit/service/internal/command/CalculateIBBCommand.java b/service/src/main/java/org/apache/fineract/cn/deposit/service/internal/command/CalculateIBBCommand.java
new file mode 100644
index 0000000..c6751ed
--- /dev/null
+++ b/service/src/main/java/org/apache/fineract/cn/deposit/service/internal/command/CalculateIBBCommand.java
@@ -0,0 +1,33 @@
+/*
+ * 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 java.time.LocalDate;
+
+public class CalculateIBBCommand {
+    private final LocalDate dueDate;
+
+    public CalculateIBBCommand(final LocalDate dueDate) {
+        super();
+        this.dueDate = dueDate;
+    }
+
+    public LocalDate dueDate() {
+        return this.dueDate;
+    }
+}
diff --git a/service/src/main/java/org/apache/fineract/cn/deposit/service/internal/command/handler/InterestBearingBalanceCalculator.java b/service/src/main/java/org/apache/fineract/cn/deposit/service/internal/command/handler/InterestBearingBalanceCalculator.java
new file mode 100644
index 0000000..9d5647b
--- /dev/null
+++ b/service/src/main/java/org/apache/fineract/cn/deposit/service/internal/command/handler/InterestBearingBalanceCalculator.java
@@ -0,0 +1,131 @@
+/*
+ * 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.command.annotation.EventEmitter;
+import org.apache.fineract.cn.deposit.api.v1.EventConstants;
+import org.apache.fineract.cn.deposit.api.v1.domain.Type;
+import org.apache.fineract.cn.deposit.service.internal.command.CalculateIBBCommand;
+import org.apache.fineract.cn.deposit.service.internal.repository.*;
+import org.apache.fineract.cn.deposit.service.internal.service.TransactionService;
+import org.apache.fineract.cn.lang.DateConverter;
+
+import javax.transaction.Transactional;
+import java.math.BigDecimal;
+import java.time.LocalDate;
+import java.util.List;
+import java.util.Optional;
+
+@Aggregate
+public class InterestBearingBalanceCalculator {
+
+    private static final String ACTIVE = "ACTIVE";
+
+    private ProductDefinitionRepository productDefinitionRepository;
+    private ProductInstanceRepository productInstanceRepository;
+    private TransactionRepository transactionRepository;
+    private SubTransactionTypeRepository subTransactionTypeRepository;
+
+    //TODO: constructor
+
+    @Transactional
+    @CommandHandler(logStart = CommandLogLevel.DEBUG, logFinish =  CommandLogLevel.DEBUG)
+    @EventEmitter(selectorName = EventConstants.SELECTOR_NAME, selectorValue = EventConstants.CALCULATE_IBB)
+    public String process(final CalculateIBBCommand calculateIBBCommand) {
+        final LocalDate dueDate = calculateIBBCommand.dueDate();
+        //calculate and store ibb for the date-1day
+        final List<ProductDefinitionEntity> productDefinitions = this.productDefinitionRepository.findAll();
+
+        productDefinitions.forEach(productDefinitionEntity -> {
+            if (this.canFindIBBForProduct(productDefinitionEntity)) {
+                final List<ProductInstanceEntity> productInstances =
+                        this.productInstanceRepository.findByProductDefinition(productDefinitionEntity);
+
+                productInstances.forEach(productInstanceEntity -> {
+                    if (productInstanceEntity.getState().equals(ACTIVE)) {
+                        //get transactions
+                        List<TransactionEntity> transactions =  transactionRepository.findByAccountId(productInstanceEntity.getAccountIdentifier());
+                        if(!transactions.isEmpty())
+                            calculateAndSaveIBB(productInstanceEntity, transactions, dueDate);
+                    }
+                });
+            }
+        });
+
+        return DateConverter.toIsoString(dueDate);
+    }
+
+    private void calculateAndSaveIBB(ProductInstanceEntity productInstanceEntity, List<TransactionEntity> transactions,
+                                     LocalDate dueDate) {
+        BigDecimal ibBalance = BigDecimal.ZERO;
+        for(TransactionEntity transaction: transactions){
+            SubTransactionTypeEntity subTransactionTypeEntity = getSubTxnTypeEntityFromTxn(transaction);
+            if(subTransactionTypeEntity!= null && (subTransactionTypeEntity.getIbbConfPlusDays() != 0
+                || subTransactionTypeEntity.getIbbConfMinusDays() !=0)) {
+
+                if(TransactionService.CREDIT.equals(transaction.getType()) &&
+                        isTxnDateOnOrAfterTodayPlusX(dueDate, transaction.getTransactionDate().toLocalDate(),
+                                subTransactionTypeEntity.getIbbConfPlusDays())){
+                    //add credit after checking day passed condition: Deposit Value Date - T+x
+                    ibBalance = ibBalance.add(transaction.getAmount());
+
+                }else if(TransactionService.DEBIT.equals(transaction.getType())&&
+                        isTxnDateOnOrBeforeTodayMinusY(dueDate, transaction.getTransactionDate().toLocalDate(),
+                                subTransactionTypeEntity.getIbbConfMinusDays())){
+                    //subtract debit after checking day condition: Withdrawal Value Date - T-y
+                    ibBalance = ibBalance.subtract(transaction.getAmount());
+                }
+                //else ignore
+            }else if(TransactionService.CREDIT.equals(transaction.getType())){
+                //add credit
+                ibBalance = ibBalance.add(transaction.getAmount());
+
+            }else if(TransactionService.DEBIT.equals(transaction.getType())) {
+                //subtract debit
+                ibBalance = ibBalance.subtract(transaction.getAmount());
+            }
+        }
+    }
+
+    private SubTransactionTypeEntity getSubTxnTypeEntityFromTxn(TransactionEntity transaction){
+        if(transaction.getSubTxnType() == null) return null;
+        Optional<SubTransactionTypeEntity> optsubTxn = subTransactionTypeRepository.findByIdentifier(transaction.getSubTxnType());
+        return (optsubTxn.isPresent() ? optsubTxn.get(): null);
+    }
+
+    private boolean canFindIBBForProduct(final ProductDefinitionEntity productDefinitionEntity) {
+        return productDefinitionEntity.getActive()
+                && !productDefinitionEntity.getType().equals(Type.SHARE.name())
+                && productDefinitionEntity.getInterest() != null
+                && productDefinitionEntity.getInterest() > 0.00D;
+    }
+
+    private boolean isTxnDateOnOrAfterTodayPlusX(LocalDate today, LocalDate txnDate, int x){
+
+        return false;
+    }
+
+    private boolean isTxnDateOnOrBeforeTodayMinusY(LocalDate today, LocalDate txnDate, int y){
+        return false;
+    }
+
+}
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
index ba9e525..a245543 100644
--- 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
@@ -52,6 +52,12 @@
     @Column(name = "ledger_account_identifier", nullable = false)
     private String ledgerAccount;
 
+    @Column(name = "ibb_conf_plus_days")
+    private Integer ibbConfPlusDays;
+
+    @Column(name = "ibb_conf_minus_days")
+    private Integer ibbConfMinusDays;
+
     public SubTransactionTypeEntity() {
         super();
     }
@@ -127,4 +133,20 @@
     public void setLedgerAccount(String ledgerAccount) {
         this.ledgerAccount = ledgerAccount;
     }
+
+    public Integer getIbbConfPlusDays() {
+        return ibbConfPlusDays;
+    }
+
+    public void setIbbConfPlusDays(Integer ibbConfPlusDays) {
+        this.ibbConfPlusDays = ibbConfPlusDays;
+    }
+
+    public Integer getIbbConfMinusDays() {
+        return ibbConfMinusDays;
+    }
+
+    public void setIbbConfMinusDays(Integer ibbConfMinusDays) {
+        this.ibbConfMinusDays = ibbConfMinusDays;
+    }
 }
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
index df96b58..03f989f 100644
--- 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
@@ -432,6 +432,14 @@
                     return statementObj;
                 }).collect(Collectors.toList());
     }
+    
+    public BalanceResponse fetchBalance(String identifier) {
+        Account account = ledgerManager.findAccount(identifier);
+        BalanceResponse balance = new BalanceResponse();
+        balance.setBalance(new BigDecimal(account.getBalance()));
+        balance.setInterest(BigDecimal.ZERO);
+        return balance;
+    }
 
 
     public static class AccountWrapper {
diff --git a/service/src/main/java/org/apache/fineract/cn/deposit/service/rest/BeatListenerRestController.java b/service/src/main/java/org/apache/fineract/cn/deposit/service/rest/BeatListenerRestController.java
index 32d017f..f5461f1 100644
--- a/service/src/main/java/org/apache/fineract/cn/deposit/service/rest/BeatListenerRestController.java
+++ b/service/src/main/java/org/apache/fineract/cn/deposit/service/rest/BeatListenerRestController.java
@@ -65,5 +65,6 @@
   {
     this.commandGateway.process(new BeatListenerCommand(beatPublish));
     return ResponseEntity.accepted().build();
+
   }
 }
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 aece9a3..f0cc9fb 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
@@ -25,10 +25,22 @@
 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.BalanceResponse;
 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.*;
 import org.apache.fineract.cn.deposit.service.internal.service.ProductInstanceService;
+
+import java.time.LocalDateTime;
+import java.time.ZoneId;
+import java.util.Date;
+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;
@@ -222,6 +234,18 @@
     return ResponseEntity.ok(statement);
   }
 
+  @Permittable(value = AcceptedTokenType.TENANT, groupId = PermittableGroupIds.INSTANCE_MANAGEMENT)
+  @RequestMapping(
+          value = "/{identifier}/balance",
+          method = RequestMethod.GET,
+          consumes = MediaType.ALL_VALUE,
+          produces = MediaType.APPLICATION_JSON_VALUE
+  )
+  @ResponseBody
+  ResponseEntity<BalanceResponse> balance(@PathVariable("identifier") final String identifier) {
+    return ResponseEntity.ok(transactionService.fetchBalance(identifier));
+  }
+
   private  LocalDateTime convertToLocalDateTime(Date dateToConvert) {
     return dateToConvert.toInstant()
             .atZone(ZoneId.systemDefault())
diff --git a/service/src/main/resources/db/migrations/postgresql/V10__ibb_conf_to_sub_txn.sql b/service/src/main/resources/db/migrations/postgresql/V10__ibb_conf_to_sub_txn.sql
new file mode 100644
index 0000000..1abb9af
--- /dev/null
+++ b/service/src/main/resources/db/migrations/postgresql/V10__ibb_conf_to_sub_txn.sql
@@ -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.
+--
+
+ALTER TABLE shed_sub_tx_type
+ADD COLUMN ibb_conf_plus_days  INT  0;
+
+ALTER TABLE shed_sub_tx_type
+ADD COLUMN ibb_conf_minus_days  INT  0;
diff --git a/service/src/main/resources/db/migrations/postgresql/V11__collections.sql b/service/src/main/resources/db/migrations/postgresql/V11__collections.sql
new file mode 100644
index 0000000..43f951d
--- /dev/null
+++ b/service/src/main/resources/db/migrations/postgresql/V11__collections.sql
@@ -0,0 +1,67 @@
+--
+-- 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_collections (
+  id                          bigserial       NOT null,
+  transaction_date            TIMESTAMP   NULL,
+  amount          			  numeric(15,5) NOT NULL,
+  transport_fee_amount        numeric(15,5)  NULL,
+  currency                    VARCHAR(10)   NULL,
+  remarks                     VARCHAR(1024)  NULL,
+  account_identifier 		  BIGINT  NULL,
+  sub_txn_type_id			  BIGINT  NULL,
+  status                      VARCHAR(20)      NOT NULL,
+  c_reference                 VARCHAR(36)  NOT NULL,
+  created_by                  VARCHAR(32)    NOT NULL,
+  created_on                  TIMESTAMP   NOT NULL,
+  last_modified_by            VARCHAR(32)    NULL,
+  last_modified_on            TIMESTAMP   NULL,
+  CONSTRAINT pk_shed_collections PRIMARY KEY (id),
+  CONSTRAINT uk_shed_collections_ref UNIQUE (c_reference),
+  CONSTRAINT fk_collection_sub_txn_type_id FOREIGN KEY (sub_txn_type_id) REFERENCES shed_sub_tx_type (id),
+  CONSTRAINT fk_collection_account_identifier FOREIGN KEY (account_identifier) REFERENCES shed_product_instances (account_identifier)
+);
+
+
+CREATE TABLE shed_collections_inidividual (
+  id                          bigserial      NOT NULL,
+  collections_id              BIGINT         NOT NULL,
+  account_identifier          BIGINT         NULL,
+  account_external_id         VARCHAR(64)    NULL,
+  amount                      numeric(15,5) NOT NULL,
+  i_reference                 VARCHAR(36)   NOT NULL,
+  CONSTRAINT pk_shed_collections_inidividual PRIMARY KEY (id),
+  CONSTRAINT uk_shed_collections_inidividual_ref UNIQUE (i_reference),
+  CONSTRAINT fk_indidual_collections FOREIGN KEY (collections_id) REFERENCES shed_collections (id),
+  CONSTRAINT fk_ind_collections_account_identifier FOREIGN KEY (account_identifier) REFERENCES shed_product_instances (account_identifier)
+);
+
+
+
+CREATE TABLE shed_self_expiring_tokens (
+  id                            bigserial      NOT NULL,
+  token                         VARCHAR(10)   NOT NULL,
+  token_expires_by              TIMESTAMP  NOT NULL,
+  status                        VARCHAR(10)   NOT NULL,
+  entity_type                   VARCHAR(36)   NOT NULL,
+  entity_reference              VARCHAR(36)   NOT NULL,
+  CONSTRAINT pk_shed_self_expiring_tokens PRIMARY KEY (id),
+  CONSTRAINT uk_shed_self_expiring_tokens_token UNIQUE (token, status)
+);
diff --git a/service/src/main/resources/db/migrations/postgresql/V8__transaction.sql b/service/src/main/resources/db/migrations/postgresql/V8__transaction.sql
index 9acf61e..8fba6c2 100644
--- a/service/src/main/resources/db/migrations/postgresql/V8__transaction.sql
+++ b/service/src/main/resources/db/migrations/postgresql/V8__transaction.sql
@@ -43,4 +43,4 @@
   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
index 450715a..07bfe2e 100644
--- a/service/src/main/resources/db/migrations/postgresql/V9__transaction_update.sql
+++ b/service/src/main/resources/db/migrations/postgresql/V9__transaction_update.sql
@@ -1,3 +1,4 @@
+<<<<<<< HEAD
 --
 -- Licensed to the Apache Software Foundation (ASF) under one
 -- or more contributor license agreements.  See the NOTICE file
@@ -23,8 +24,7 @@
 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
+REFERENCES shed_transactions (id);