You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@fineract.apache.org by my...@apache.org on 2018/01/22 15:49:22 UTC

[fineract-cn-deposit-account-management] branch develop updated (b76aa90 -> 9f00a39)

This is an automated email from the ASF dual-hosted git repository.

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


    from b76aa90  removing duplicate resources from artifact.
     new 22b1f49  Merge pull request #1 from myrle-krantz/develop
     new 0522ab8  Merge pull request #2 from myrle-krantz/develop
     new 333cc52  added interest calculation
     new adc669e  added ability to fetch available TX types for a customer
     new caf9585  Merge pull request #1 from markusgeiss/develop
     new f776290  added cheque transaction to available transactions for customer
     new 9e4fcde  close product with commands
     new 0888194  using numbers instead of a date for dividends due date
     new e564578  set beat to trigger daily accrual
     new 9b93726  Merge pull request #2 from markusgeiss/develop
     new ebda8e9  fixed bug while closing an unused product
     new 0362703  Merge pull request #3 from markusgeiss/develop
     new 3c848f0  accrued interest will be payed even if product is not active
     new 9388eb0  Merge pull request #4 from markusgeiss/develop
     new 7b202a3  added ability to use legacy account numbers
     new afe6c8f  Merge pull request #5 from markusgeiss/develop
     new 72e80f6  fix date range only use dates
     new 30bc082  Merge pull request #6 from markusgeiss/develop
     new 11a939c  added opened on and last transaction date to product instance
     new 5be1dbf  Merge pull request #7 from markusgeiss/develop
     new 9680ecb  added time zone 'Z' handling to ease UI usage
     new 102f0d7  Merge pull request #8 from markusgeiss/develop
     new a646446  Add null check to prevent NPE when saving product definition without charges Add null check for flexible to prevent SQL exception
     new addc4cb  Merge pull request #9 from markvanveen/develop
     new 055b2fd  added proper alternative account and initial balance handling
     new 9f00a39  Merge pull request #10 from markusgeiss/develop

The 26 revisions listed above as "new" are entirely new to this
repository and will be described in separate emails.  The revisions
listed as "add" were already present in the repository and have only
been added to this reference.


Summary of changes:
 .gitignore                                         |   1 +
 .../io/mifos/deposit/api/v1/EventConstants.java    |   8 +
 .../api/v1/client/DepositAccountManager.java       |  39 ++
 .../v1/definition/domain/DividendDistribution.java |  67 +++
 .../v1/definition/domain/ProductDefinition.java    |  25 +-
 .../domain/AvailableTransactionType.java}          |  52 +--
 .../api/v1/instance/domain/ProductInstance.java    |  27 ++
 .../AbstractDepositAccountManagementTest.java      |   6 +-
 .../src/main/java/io/mifos/deposit/Fixture.java    |   8 +-
 .../main/java/io/mifos/deposit/TestAccrual.java    | 117 ++++++
 .../main/java/io/mifos/deposit/TestActions.java    |   2 +-
 .../io/mifos/deposit/TestDividendDistribution.java |  96 +++++
 .../io/mifos/deposit/TestProductDefinition.java    |  29 ++
 .../java/io/mifos/deposit/TestProductInstance.java | 131 +++++-
 .../src/main/java/io/mifos/deposit/TestSuite.java  |   4 +-
 ....java => InterestCalculationEventListener.java} |  26 +-
 gradle/wrapper/gradle-wrapper.properties           |   4 +-
 service/build.gradle                               |   8 +-
 .../DepositAccountManagementConfiguration.java     |   4 +-
 ...uctInstanceCommand.java => AccrualCommand.java} |  15 +-
 ...ActionCommand.java => BeatListenerCommand.java} |  15 +-
 ...mmand.java => DividendDistributionCommand.java} |  22 +-
 ...grationCommand.java => PayInterestCommand.java} |  13 +-
 ...mmand.java => TransactionProcessedCommand.java} |  13 +-
 .../handler/BeatListenerCommandHandler.java        |  58 +++
 .../command/handler/InterestCalculator.java        | 466 +++++++++++++++++++++
 .../command/handler/MigrationAggregate.java        |   8 +-
 .../handler/ProductDefinitionAggregate.java        |  25 +-
 .../command/handler/ProductInstanceAggregate.java  |  58 ++-
 .../mapper/DividendDistributionMapper.java         |  56 +++
 .../internal/mapper/ProductDefinitionMapper.java   |   4 +
 .../internal/mapper/ProductInstanceMapper.java     |  34 +-
 ...ctionEntity.java => AccruedInterestEntity.java} |  54 +--
 ...ository.java => AccruedInterestRepository.java} |   6 +-
 ...Entity.java => DividendDistributionEntity.java} |  33 +-
 ...ry.java => DividendDistributionRepository.java} |   4 +-
 .../repository/ProductDefinitionCommandEntity.java |   3 +-
 .../repository/ProductDefinitionEntity.java        |  20 +
 .../internal/repository/ProductInstanceEntity.java |  24 ++
 .../repository/ProductInstanceRepository.java      |   3 -
 .../internal/service/ProductDefinitionService.java |  21 +-
 .../internal/service/helper/AccountingService.java |  61 +--
 .../internal/service/helper/RhythmService.java     |  60 +++
 ...roller.java => BeatListenerRestController.java} |  30 +-
 .../rest/ProductDefinitionRestController.java      |  51 +++
 .../rest/ProductInstanceRestController.java        |  48 ++-
 .../mariadb/V5__interest_calculation.sql           |  40 ++
 ...add_opened_on_last_transaction_to_instance.sql} |   6 +-
 service/src/main/resources/logback.xml             |   8 +-
 shared.gradle                                      |   2 +
 50 files changed, 1696 insertions(+), 219 deletions(-)
 create mode 100644 api/src/main/java/io/mifos/deposit/api/v1/definition/domain/DividendDistribution.java
 copy api/src/main/java/io/mifos/deposit/api/v1/{definition/domain/Action.java => instance/domain/AvailableTransactionType.java} (52%)
 create mode 100644 component-test/src/main/java/io/mifos/deposit/TestAccrual.java
 create mode 100644 component-test/src/main/java/io/mifos/deposit/TestDividendDistribution.java
 copy component-test/src/main/java/io/mifos/deposit/listener/{MigrationEventListener.java => InterestCalculationEventListener.java} (56%)
 copy service/src/main/java/io/mifos/deposit/service/internal/command/{CloseProductInstanceCommand.java => AccrualCommand.java} (74%)
 copy service/src/main/java/io/mifos/deposit/service/internal/command/{CreateActionCommand.java => BeatListenerCommand.java} (70%)
 copy service/src/main/java/io/mifos/deposit/service/internal/command/{CreateProductDefinitionCommand.java => DividendDistributionCommand.java} (60%)
 copy service/src/main/java/io/mifos/deposit/service/internal/command/{MigrationCommand.java => PayInterestCommand.java} (75%)
 copy service/src/main/java/io/mifos/deposit/service/internal/command/{CreateActionCommand.java => TransactionProcessedCommand.java} (71%)
 create mode 100644 service/src/main/java/io/mifos/deposit/service/internal/command/handler/BeatListenerCommandHandler.java
 create mode 100644 service/src/main/java/io/mifos/deposit/service/internal/command/handler/InterestCalculator.java
 create mode 100644 service/src/main/java/io/mifos/deposit/service/internal/mapper/DividendDistributionMapper.java
 copy service/src/main/java/io/mifos/deposit/service/internal/repository/{ActionEntity.java => AccruedInterestEntity.java} (50%)
 copy service/src/main/java/io/mifos/deposit/service/internal/repository/{ProductDefinitionRepository.java => AccruedInterestRepository.java} (73%)
 copy service/src/main/java/io/mifos/deposit/service/internal/repository/{ProductDefinitionCommandEntity.java => DividendDistributionEntity.java} (80%)
 copy service/src/main/java/io/mifos/deposit/service/internal/repository/{ProductDefinitionCommandRepository.java => DividendDistributionRepository.java} (75%)
 create mode 100644 service/src/main/java/io/mifos/deposit/service/internal/service/helper/RhythmService.java
 copy service/src/main/java/io/mifos/deposit/service/rest/{DepositAccountManagementRestController.java => BeatListenerRestController.java} (64%)
 create mode 100644 service/src/main/resources/db/migrations/mariadb/V5__interest_calculation.sql
 copy service/src/main/resources/db/migrations/mariadb/{V2__modify_product_instances.sql => V6__add_opened_on_last_transaction_to_instance.sql} (71%)

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

[fineract-cn-deposit-account-management] 10/26: Merge pull request #2 from markusgeiss/develop

Posted by my...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

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

commit 9b93726e57a83fc43e3ee1be68e2cf00251fd9fa
Merge: caf9585 e564578
Author: Markus Geiss <ma...@kuelap.io>
AuthorDate: Wed Sep 6 14:49:56 2017 +0200

    Merge pull request #2 from markusgeiss/develop
    
    Cleanup and adding daily accrual beat

 .../v1/definition/domain/DividendDistribution.java | 15 +++++---
 .../io/mifos/deposit/TestDividendDistribution.java |  7 +++-
 .../java/io/mifos/deposit/TestProductInstance.java |  4 +-
 .../DepositAccountManagementConfiguration.java     |  4 +-
 .../command/handler/MigrationAggregate.java        |  8 +++-
 .../handler/ProductDefinitionAggregate.java        |  5 ++-
 .../mapper/DividendDistributionMapper.java         |  5 ++-
 .../internal/service/helper/RhythmService.java     | 45 ++++++++++++++++++++++
 .../rest/ProductDefinitionRestController.java      |  2 +-
 .../rest/ProductInstanceRestController.java        |  3 ++
 10 files changed, 82 insertions(+), 16 deletions(-)

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

[fineract-cn-deposit-account-management] 24/26: Merge pull request #9 from markvanveen/develop

Posted by my...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

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

commit addc4cb4909201e84643f3505a3af0564b9ee9e8
Merge: 102f0d7 a646446
Author: Mark van Veen <30...@users.noreply.github.com>
AuthorDate: Wed Nov 1 18:47:44 2017 +0100

    Merge pull request #9 from markvanveen/develop
    
    Add null check to prevent NPE when saving product definition without …

 .../api/v1/definition/domain/ProductDefinition.java  |  1 +
 .../command/handler/ProductDefinitionAggregate.java  | 20 +++++++++++---------
 2 files changed, 12 insertions(+), 9 deletions(-)

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

[fineract-cn-deposit-account-management] 13/26: accrued interest will be payed even if product is not active

Posted by my...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

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

commit 3c848f005f510e026d1d9cfadb3505f93f42a8d0
Author: mgeiss <mg...@mifos.org>
AuthorDate: Wed Sep 27 07:41:42 2017 +0200

    accrued interest will be payed even if product is not active
---
 .../command/handler/InterestCalculator.java        | 74 +++++++++++-----------
 1 file changed, 36 insertions(+), 38 deletions(-)

diff --git a/service/src/main/java/io/mifos/deposit/service/internal/command/handler/InterestCalculator.java b/service/src/main/java/io/mifos/deposit/service/internal/command/handler/InterestCalculator.java
index 4ac279d..8f8ffd4 100644
--- a/service/src/main/java/io/mifos/deposit/service/internal/command/handler/InterestCalculator.java
+++ b/service/src/main/java/io/mifos/deposit/service/internal/command/handler/InterestCalculator.java
@@ -210,44 +210,42 @@ public class InterestCalculator {
               this.productInstanceRepository.findByProductDefinition(productDefinitionEntity);
 
           productInstanceEntities.forEach(productInstanceEntity -> {
-            if (productInstanceEntity.getState().equals(ACTIVE)) {
-              final Optional<AccruedInterestEntity> optionalAccruedInterestEntity =
-                  this.accruedInterestRepository.findByCustomerAccountIdentifier(productInstanceEntity.getAccountIdentifier());
-
-              if (optionalAccruedInterestEntity.isPresent()) {
-                final AccruedInterestEntity accruedInterestEntity = optionalAccruedInterestEntity.get();
-
-                final String roundedAmount =
-                    BigDecimal.valueOf(accruedInterestEntity.getAmount())
-                        .setScale(2, BigDecimal.ROUND_HALF_EVEN).toString();
-
-                final JournalEntry accrueToExpenseJournalEntry = new JournalEntry();
-                accrueToExpenseJournalEntry.setTransactionIdentifier(RandomStringUtils.randomAlphanumeric(32));
-                accrueToExpenseJournalEntry.setTransactionDate(DateConverter.toIsoString(LocalDateTime.now(Clock.systemUTC())));
-                accrueToExpenseJournalEntry.setTransactionType("INTR");
-                accrueToExpenseJournalEntry.setClerk(UserContextHolder.checkedGetUser());
-                accrueToExpenseJournalEntry.setNote("Interest paid.");
-
-                final Debtor accrueDebtor = new Debtor();
-                accrueDebtor.setAccountNumber(accruedInterestEntity.getAccrueAccountIdentifier());
-                accrueDebtor.setAmount(roundedAmount);
-                accrueToExpenseJournalEntry.setDebtors(Sets.newHashSet(accrueDebtor));
-
-                final Creditor expenseCreditor = new Creditor();
-                expenseCreditor.setAccountNumber(productDefinitionEntity.getExpenseAccountIdentifier());
-                expenseCreditor.setAmount(roundedAmount);
-                accrueToExpenseJournalEntry.setCreditors(Sets.newHashSet(expenseCreditor));
-
-                this.accruedInterestRepository.delete(accruedInterestEntity);
-
-                this.accountingService.post(accrueToExpenseJournalEntry);
-
-                this.payoutInterest(
-                    productDefinitionEntity.getExpenseAccountIdentifier(),
-                    accruedInterestEntity.getCustomerAccountIdentifier(),
-                    roundedAmount
-                );
-              }
+            final Optional<AccruedInterestEntity> optionalAccruedInterestEntity =
+                this.accruedInterestRepository.findByCustomerAccountIdentifier(productInstanceEntity.getAccountIdentifier());
+
+            if (optionalAccruedInterestEntity.isPresent()) {
+              final AccruedInterestEntity accruedInterestEntity = optionalAccruedInterestEntity.get();
+
+              final String roundedAmount =
+                  BigDecimal.valueOf(accruedInterestEntity.getAmount())
+                      .setScale(2, BigDecimal.ROUND_HALF_EVEN).toString();
+
+              final JournalEntry accrueToExpenseJournalEntry = new JournalEntry();
+              accrueToExpenseJournalEntry.setTransactionIdentifier(RandomStringUtils.randomAlphanumeric(32));
+              accrueToExpenseJournalEntry.setTransactionDate(DateConverter.toIsoString(LocalDateTime.now(Clock.systemUTC())));
+              accrueToExpenseJournalEntry.setTransactionType("INTR");
+              accrueToExpenseJournalEntry.setClerk(UserContextHolder.checkedGetUser());
+              accrueToExpenseJournalEntry.setNote("Interest paid.");
+
+              final Debtor accrueDebtor = new Debtor();
+              accrueDebtor.setAccountNumber(accruedInterestEntity.getAccrueAccountIdentifier());
+              accrueDebtor.setAmount(roundedAmount);
+              accrueToExpenseJournalEntry.setDebtors(Sets.newHashSet(accrueDebtor));
+
+              final Creditor expenseCreditor = new Creditor();
+              expenseCreditor.setAccountNumber(productDefinitionEntity.getExpenseAccountIdentifier());
+              expenseCreditor.setAmount(roundedAmount);
+              accrueToExpenseJournalEntry.setCreditors(Sets.newHashSet(expenseCreditor));
+
+              this.accruedInterestRepository.delete(accruedInterestEntity);
+
+              this.accountingService.post(accrueToExpenseJournalEntry);
+
+              this.payoutInterest(
+                  productDefinitionEntity.getExpenseAccountIdentifier(),
+                  accruedInterestEntity.getCustomerAccountIdentifier(),
+                  roundedAmount
+              );
             }
           });
         }

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

[fineract-cn-deposit-account-management] 08/26: using numbers instead of a date for dividends due date

Posted by my...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

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

commit 0888194184598fdc9968f0a9e0fae29eb648b79b
Author: mgeiss <mg...@mifos.org>
AuthorDate: Wed Sep 6 14:23:42 2017 +0200

    using numbers instead of a date for dividends due date
---
 .../api/v1/definition/domain/DividendDistribution.java    | 15 +++++++++------
 .../java/io/mifos/deposit/TestDividendDistribution.java   |  7 ++++++-
 .../internal/mapper/DividendDistributionMapper.java       |  5 +++--
 .../service/rest/ProductDefinitionRestController.java     |  2 +-
 4 files changed, 19 insertions(+), 10 deletions(-)

diff --git a/api/src/main/java/io/mifos/deposit/api/v1/definition/domain/DividendDistribution.java b/api/src/main/java/io/mifos/deposit/api/v1/definition/domain/DividendDistribution.java
index 3186deb..01c9a12 100644
--- a/api/src/main/java/io/mifos/deposit/api/v1/definition/domain/DividendDistribution.java
+++ b/api/src/main/java/io/mifos/deposit/api/v1/definition/domain/DividendDistribution.java
@@ -15,12 +15,15 @@
  */
 package io.mifos.deposit.api.v1.definition.domain;
 
+import io.mifos.core.lang.DateOfBirth;
 import org.hibernate.validator.constraints.NotBlank;
 
+import javax.validation.constraints.NotNull;
+
 public class DividendDistribution {
 
-  @NotBlank
-  private String dueDate;
+  @NotNull
+  private DateOfBirth dueDate;
   @NotBlank
   private String dividendRate;
 
@@ -28,11 +31,11 @@ public class DividendDistribution {
     super();
   }
 
-  public String getDueDate() {
+  public DateOfBirth getDueDate() {
     return this.dueDate;
   }
 
-  public void setDueDate(final String dueDate) {
+  public void setDueDate(final DateOfBirth dueDate) {
     this.dueDate = dueDate;
   }
 
@@ -51,13 +54,13 @@ public class DividendDistribution {
 
     final DividendDistribution that = (DividendDistribution) o;
 
-    if (!dueDate.equals(that.dueDate)) return false;
+    if (!dueDate.toLocalDate().isEqual(that.dueDate.toLocalDate())) return false;
     return dividendRate.equals(that.dividendRate);
   }
 
   @Override
   public int hashCode() {
-    int result = dueDate.hashCode();
+    int result = dueDate.toLocalDate().hashCode();
     result = 31 * result + dividendRate.hashCode();
     return result;
   }
diff --git a/component-test/src/main/java/io/mifos/deposit/TestDividendDistribution.java b/component-test/src/main/java/io/mifos/deposit/TestDividendDistribution.java
index e6360ed..27f2410 100644
--- a/component-test/src/main/java/io/mifos/deposit/TestDividendDistribution.java
+++ b/component-test/src/main/java/io/mifos/deposit/TestDividendDistribution.java
@@ -18,6 +18,7 @@ package io.mifos.deposit;
 import io.mifos.accounting.api.v1.domain.Account;
 import io.mifos.accounting.api.v1.domain.AccountType;
 import io.mifos.accounting.api.v1.domain.JournalEntry;
+import io.mifos.core.lang.DateOfBirth;
 import io.mifos.deposit.api.v1.EventConstants;
 import io.mifos.deposit.api.v1.definition.domain.DividendDistribution;
 import io.mifos.deposit.api.v1.definition.domain.ProductDefinition;
@@ -74,7 +75,11 @@ public class TestDividendDistribution extends AbstractDepositAccountManagementTe
         .when(super.accountingServiceSpy).findAccount(shareAccount.getIdentifier());
 
     final DividendDistribution dividendDistribution = new DividendDistribution();
-    dividendDistribution.setDueDate("2017-07-31Z");
+    final DateOfBirth dueDate = new DateOfBirth();
+    dueDate.setYear(2017);
+    dueDate.setMonth(7);
+    dueDate.setDay(31);
+    dividendDistribution.setDueDate(dueDate);
     dividendDistribution.setDividendRate("2.5");
     this.depositAccountManager.dividendDistribution(productDefinition.getIdentifier(), dividendDistribution);
 
diff --git a/service/src/main/java/io/mifos/deposit/service/internal/mapper/DividendDistributionMapper.java b/service/src/main/java/io/mifos/deposit/service/internal/mapper/DividendDistributionMapper.java
index 7c01a8f..6503836 100644
--- a/service/src/main/java/io/mifos/deposit/service/internal/mapper/DividendDistributionMapper.java
+++ b/service/src/main/java/io/mifos/deposit/service/internal/mapper/DividendDistributionMapper.java
@@ -17,6 +17,7 @@ package io.mifos.deposit.service.internal.mapper;
 
 import io.mifos.core.api.util.UserContextHolder;
 import io.mifos.core.lang.DateConverter;
+import io.mifos.core.lang.DateOfBirth;
 import io.mifos.deposit.api.v1.definition.domain.DividendDistribution;
 import io.mifos.deposit.service.internal.repository.DividendDistributionEntity;
 import io.mifos.deposit.service.internal.repository.ProductDefinitionEntity;
@@ -36,7 +37,7 @@ public class DividendDistributionMapper {
     final DividendDistributionEntity dividendDistributionEntity = new DividendDistributionEntity();
 
     dividendDistributionEntity.setProductDefinition(productDefinitionEntity);
-    final Date dueDate = Date.valueOf(DateConverter.dateFromIsoString(dividendDistribution.getDueDate()));
+    final Date dueDate = Date.valueOf(dividendDistribution.getDueDate().toLocalDate());
     dividendDistributionEntity.setDueDate(dueDate);
     dividendDistributionEntity.setRate(Double.valueOf(dividendDistribution.getDividendRate()));
     dividendDistributionEntity.setCreatedOn(LocalDateTime.now(Clock.systemUTC()));
@@ -49,7 +50,7 @@ public class DividendDistributionMapper {
     final DividendDistribution dividendDistribution = new DividendDistribution();
 
     dividendDistribution.setDividendRate(dividendDistributionEntity.getRate().toString());
-    dividendDistribution.setDueDate(DateConverter.toIsoString(dividendDistributionEntity.getDueDate().toLocalDate()));
+    dividendDistribution.setDueDate(DateOfBirth.fromLocalDate(dividendDistributionEntity.getDueDate().toLocalDate()));
 
     return dividendDistribution;
   }
diff --git a/service/src/main/java/io/mifos/deposit/service/rest/ProductDefinitionRestController.java b/service/src/main/java/io/mifos/deposit/service/rest/ProductDefinitionRestController.java
index 7c8f875..dfd1c1f 100644
--- a/service/src/main/java/io/mifos/deposit/service/rest/ProductDefinitionRestController.java
+++ b/service/src/main/java/io/mifos/deposit/service/rest/ProductDefinitionRestController.java
@@ -258,7 +258,7 @@ public class ProductDefinitionRestController {
       }
     }
 
-    final LocalDate dueDate = DateConverter.dateFromIsoString(dividendDistribution.getDueDate());
+    final LocalDate dueDate = dividendDistribution.getDueDate().toLocalDate();
     final Double amount = Double.valueOf(dividendDistribution.getDividendRate());
 
     this.commandGateway.process(new DividendDistributionCommand(identifier, dueDate, amount));

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

[fineract-cn-deposit-account-management] 09/26: set beat to trigger daily accrual

Posted by my...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

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

commit e564578828b41bb85d4d51858fcd276394248b00
Author: mgeiss <mg...@mifos.org>
AuthorDate: Wed Sep 6 14:38:55 2017 +0200

    set beat to trigger daily accrual
---
 .../DepositAccountManagementConfiguration.java     |  4 +-
 .../command/handler/MigrationAggregate.java        |  8 +++-
 .../internal/service/helper/RhythmService.java     | 45 ++++++++++++++++++++++
 3 files changed, 55 insertions(+), 2 deletions(-)

diff --git a/service/src/main/java/io/mifos/deposit/service/DepositAccountManagementConfiguration.java b/service/src/main/java/io/mifos/deposit/service/DepositAccountManagementConfiguration.java
index 0500302..f3f97cf 100644
--- a/service/src/main/java/io/mifos/deposit/service/DepositAccountManagementConfiguration.java
+++ b/service/src/main/java/io/mifos/deposit/service/DepositAccountManagementConfiguration.java
@@ -23,6 +23,7 @@ import io.mifos.core.command.config.EnableCommandProcessing;
 import io.mifos.core.lang.config.EnableServiceException;
 import io.mifos.core.lang.config.EnableTenantContext;
 import io.mifos.core.mariadb.config.EnableMariaDB;
+import io.mifos.rhythm.api.v1.client.RhythmManager;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
@@ -47,7 +48,8 @@ import org.springframework.web.servlet.config.annotation.WebMvcConfigurerAdapter
 @EnableAnubis
 @EnableServiceException
 @EnableFeignClients(clients = {
-    LedgerManager.class
+    LedgerManager.class,
+    RhythmManager.class
 })
 @ComponentScan({
     "io.mifos.deposit.service.rest",
diff --git a/service/src/main/java/io/mifos/deposit/service/internal/command/handler/MigrationAggregate.java b/service/src/main/java/io/mifos/deposit/service/internal/command/handler/MigrationAggregate.java
index 436cf42..524b6a8 100644
--- a/service/src/main/java/io/mifos/deposit/service/internal/command/handler/MigrationAggregate.java
+++ b/service/src/main/java/io/mifos/deposit/service/internal/command/handler/MigrationAggregate.java
@@ -23,6 +23,7 @@ import io.mifos.core.mariadb.domain.FlywayFactoryBean;
 import io.mifos.deposit.api.v1.EventConstants;
 import io.mifos.deposit.service.ServiceConstants;
 import io.mifos.deposit.service.internal.command.MigrationCommand;
+import io.mifos.deposit.service.internal.service.helper.RhythmService;
 import org.slf4j.Logger;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.beans.factory.annotation.Qualifier;
@@ -37,17 +38,20 @@ public class MigrationAggregate {
   private final DataSource dataSource;
   private final FlywayFactoryBean flywayFactoryBean;
   private final ApplicationName applicationName;
+  private final RhythmService rhythmService;
 
   @Autowired
   public MigrationAggregate(@Qualifier(ServiceConstants.LOGGER_NAME) final Logger logger,
                             final DataSource dataSource,
                             final FlywayFactoryBean flywayFactoryBean,
-                            final ApplicationName applicationName) {
+                            final ApplicationName applicationName,
+                            final RhythmService rhythmService) {
     super();
     this.logger = logger;
     this.dataSource = dataSource;
     this.flywayFactoryBean = flywayFactoryBean;
     this.applicationName = applicationName;
+    this.rhythmService = rhythmService;
   }
 
   @CommandHandler
@@ -57,6 +61,8 @@ public class MigrationAggregate {
     this.logger.info("Starting migration for deposit account management version: {}.", applicationName.getVersionString());
     this.flywayFactoryBean.create(this.dataSource).migrate();
 
+    this.rhythmService.setBeat();
+
     this.logger.info("Migration finished.");
     return this.applicationName.getVersionString();
   }
diff --git a/service/src/main/java/io/mifos/deposit/service/internal/service/helper/RhythmService.java b/service/src/main/java/io/mifos/deposit/service/internal/service/helper/RhythmService.java
new file mode 100644
index 0000000..dfa7d18
--- /dev/null
+++ b/service/src/main/java/io/mifos/deposit/service/internal/service/helper/RhythmService.java
@@ -0,0 +1,45 @@
+package io.mifos.deposit.service.internal.service.helper;
+
+import io.mifos.core.api.util.NotFoundException;
+import io.mifos.core.lang.ApplicationName;
+import io.mifos.deposit.service.ServiceConstants;
+import io.mifos.rhythm.api.v1.client.RhythmManager;
+import io.mifos.rhythm.api.v1.domain.Beat;
+import org.slf4j.Logger;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.beans.factory.annotation.Qualifier;
+import org.springframework.stereotype.Service;
+
+@Service
+public class RhythmService {
+
+  private final Logger logger;
+  private final RhythmManager rhythmManager;
+  private final ApplicationName applicationName;
+
+  @Autowired
+  public RhythmService(@Qualifier(ServiceConstants.LOGGER_NAME) final Logger logger,
+                       final RhythmManager rhythmManager,
+                       final ApplicationName applicationName) {
+    super();
+    this.logger = logger;
+    this.rhythmManager = rhythmManager;
+    this.applicationName = applicationName;
+  }
+
+  public void setBeat() {
+    try {
+      rhythmManager.getBeat(this.applicationName.toString(), "deposit-interest-accrual");
+    } catch (final NotFoundException nfex) {
+      final Beat beat = new Beat();
+      beat.setIdentifier("deposit-interest-accrual");
+      beat.setAlignmentHour(22);
+
+      try {
+        this.rhythmManager.createBeat(applicationName.toString(), beat);
+      } catch (final Throwable th) {
+        this.logger.error("Error while creating beat: ", th);
+      }
+    }
+  }
+}

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

[fineract-cn-deposit-account-management] 16/26: Merge pull request #5 from markusgeiss/develop

Posted by my...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

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

commit afe6c8fd62d98c47efda09a14a6fb48c16e46c87
Merge: 9388eb0 7b202a3
Author: Markus Geiss <ma...@kuelap.io>
AuthorDate: Tue Oct 3 11:31:38 2017 +0200

    Merge pull request #5 from markusgeiss/develop
    
    added ability to use legacy account numbers

 .../main/java/io/mifos/deposit/TestActions.java    |  2 +-
 .../command/handler/ProductInstanceAggregate.java  | 37 +++++++++--------
 .../mapper/DividendDistributionMapper.java         |  1 -
 .../repository/ProductDefinitionCommandEntity.java |  1 -
 .../internal/service/helper/AccountingService.java | 47 +++++++++++-----------
 .../internal/service/helper/RhythmService.java     | 15 +++++++
 .../rest/ProductDefinitionRestController.java      |  1 -
 7 files changed, 58 insertions(+), 46 deletions(-)

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

[fineract-cn-deposit-account-management] 06/26: added cheque transaction to available transactions for customer

Posted by my...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

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

commit f7762906ebad39d9ff132a704b1b91e3d048365f
Author: mgeiss <mg...@mifos.org>
AuthorDate: Wed Sep 6 11:40:34 2017 +0200

    added cheque transaction to available transactions for customer
---
 .../src/main/java/io/mifos/deposit/TestProductInstance.java           | 4 ++--
 .../io/mifos/deposit/service/rest/ProductInstanceRestController.java  | 3 +++
 2 files changed, 5 insertions(+), 2 deletions(-)

diff --git a/component-test/src/main/java/io/mifos/deposit/TestProductInstance.java b/component-test/src/main/java/io/mifos/deposit/TestProductInstance.java
index d023ee9..cb875e5 100644
--- a/component-test/src/main/java/io/mifos/deposit/TestProductInstance.java
+++ b/component-test/src/main/java/io/mifos/deposit/TestProductInstance.java
@@ -322,8 +322,8 @@ public class TestProductInstance extends AbstractDepositAccountManagementTest {
         super.depositAccountManager.fetchPossibleTransactionTypes(productInstance.getCustomerIdentifier());
 
     Assert.assertFalse(availableTransactionTypesAfterActivation.isEmpty());
-    Assert.assertTrue(availableTransactionTypesAfterActivation.size() == 4);
-    final HashSet<String> expectedTransactionTypes = Sets.newHashSet("ACCC", "ACCT", "CDPT", "CWDL");
+    Assert.assertTrue(availableTransactionTypesAfterActivation.size() == 5);
+    final HashSet<String> expectedTransactionTypes = Sets.newHashSet("ACCC", "ACCT", "CDPT", "CWDL", "CCHQ");
     availableTransactionTypesAfterActivation.forEach(availableTransactionType ->
         expectedTransactionTypes.remove(availableTransactionType.getTransactionType())
     );
diff --git a/service/src/main/java/io/mifos/deposit/service/rest/ProductInstanceRestController.java b/service/src/main/java/io/mifos/deposit/service/rest/ProductInstanceRestController.java
index 205fd91..0d0deb4 100644
--- a/service/src/main/java/io/mifos/deposit/service/rest/ProductInstanceRestController.java
+++ b/service/src/main/java/io/mifos/deposit/service/rest/ProductInstanceRestController.java
@@ -121,6 +121,9 @@ public class ProductInstanceRestController {
         final AvailableTransactionType actionClose = new AvailableTransactionType();
         actionClose.setTransactionType("ACCC");
         availableTransactionTypes.add(actionClose);
+        final AvailableTransactionType actionCheque = new AvailableTransactionType();
+        actionCheque.setTransactionType("CCHQ");
+        availableTransactionTypes.add(actionCheque);
       }
     });
     return ResponseEntity.ok(availableTransactionTypes);

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

[fineract-cn-deposit-account-management] 02/26: Merge pull request #2 from myrle-krantz/develop

Posted by my...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

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

commit 0522ab87b10698e188f6ba0d1e957f8238a8e580
Merge: 22b1f49 b76aa90
Author: Myrle Krantz <my...@apache.org>
AuthorDate: Wed Jul 12 23:45:22 2017 +0200

    Merge pull request #2 from myrle-krantz/develop
    
    removing duplicate resources from artifact.

 shared.gradle | 1 +
 1 file changed, 1 insertion(+)

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

[fineract-cn-deposit-account-management] 14/26: Merge pull request #4 from markusgeiss/develop

Posted by my...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

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

commit 9388eb0280a4beafcd5387139e8e0358de139118
Merge: 0362703 3c848f0
Author: Markus Geiss <ma...@kuelap.io>
AuthorDate: Wed Sep 27 07:42:31 2017 +0200

    Merge pull request #4 from markusgeiss/develop
    
    accrued interest will be payed even if product is not active

 .../command/handler/InterestCalculator.java        | 74 +++++++++++-----------
 1 file changed, 36 insertions(+), 38 deletions(-)

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

[fineract-cn-deposit-account-management] 07/26: close product with commands

Posted by my...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

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

commit 9e4fcdea48f0d009985357c970014ddfba552be4
Author: mgeiss <mg...@mifos.org>
AuthorDate: Wed Sep 6 14:07:05 2017 +0200

    close product with commands
---
 .../service/internal/command/handler/ProductDefinitionAggregate.java | 5 +++--
 1 file changed, 3 insertions(+), 2 deletions(-)

diff --git a/service/src/main/java/io/mifos/deposit/service/internal/command/handler/ProductDefinitionAggregate.java b/service/src/main/java/io/mifos/deposit/service/internal/command/handler/ProductDefinitionAggregate.java
index 3e51c69..788c4c4 100644
--- a/service/src/main/java/io/mifos/deposit/service/internal/command/handler/ProductDefinitionAggregate.java
+++ b/service/src/main/java/io/mifos/deposit/service/internal/command/handler/ProductDefinitionAggregate.java
@@ -109,7 +109,7 @@ public class ProductDefinitionAggregate {
   @CommandHandler
   @EventEmitter(selectorName = EventConstants.SELECTOR_NAME, selectorValue = EventConstants.POST_PRODUCT_DEFINITION_COMMAND)
   @Transactional
-  public String activateProductdefintion(final ActivateProductDefinitionCommand activateProductDefinitionCommand) {
+  public String activateProductDefinition(final ActivateProductDefinitionCommand activateProductDefinitionCommand) {
     final Optional<ProductDefinitionEntity> optionalProductDefinition = productDefinitionRepository.findByIdentifier(activateProductDefinitionCommand.identifier());
 
     if (optionalProductDefinition.isPresent()) {
@@ -137,7 +137,7 @@ public class ProductDefinitionAggregate {
   @CommandHandler
   @EventEmitter(selectorName = EventConstants.SELECTOR_NAME, selectorValue = EventConstants.POST_PRODUCT_DEFINITION_COMMAND)
   @Transactional
-  public String deactivateProductdefintion(final DeactivateProductDefinitionCommand activateProductDefinitionCommand) {
+  public String deactivateProductDefinition(final DeactivateProductDefinitionCommand activateProductDefinitionCommand) {
     final Optional<ProductDefinitionEntity> optionalProductDefinition = productDefinitionRepository.findByIdentifier(activateProductDefinitionCommand.identifier());
 
     if (optionalProductDefinition.isPresent()) {
@@ -207,6 +207,7 @@ public class ProductDefinitionAggregate {
       this.productDefinitionCommandRepository.delete(
           this.productDefinitionCommandRepository.findByProductDefinition(productDefinitionEntity)
       );
+      this.productDefinitionCommandRepository.flush();
 
       this.deleteDependingEntities(productDefinitionEntity);
 

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

[fineract-cn-deposit-account-management] 11/26: fixed bug while closing an unused product

Posted by my...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

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

commit ebda8e9613833710e1845054094032ac2cddf366
Author: mgeiss <mg...@mifos.org>
AuthorDate: Thu Sep 7 11:07:49 2017 +0200

    fixed bug while closing an unused product
---
 .../AbstractDepositAccountManagementTest.java      |  4 +++
 .../io/mifos/deposit/TestProductDefinition.java    | 29 ++++++++++++++++++++++
 .../repository/ProductDefinitionCommandEntity.java |  2 +-
 3 files changed, 34 insertions(+), 1 deletion(-)

diff --git a/component-test/src/main/java/io/mifos/deposit/AbstractDepositAccountManagementTest.java b/component-test/src/main/java/io/mifos/deposit/AbstractDepositAccountManagementTest.java
index 6617bc6..d757ad2 100644
--- a/component-test/src/main/java/io/mifos/deposit/AbstractDepositAccountManagementTest.java
+++ b/component-test/src/main/java/io/mifos/deposit/AbstractDepositAccountManagementTest.java
@@ -25,6 +25,7 @@ import io.mifos.deposit.api.v1.EventConstants;
 import io.mifos.deposit.api.v1.client.DepositAccountManager;
 import io.mifos.deposit.service.DepositAccountManagementConfiguration;
 import io.mifos.deposit.service.internal.service.helper.AccountingService;
+import io.mifos.deposit.service.internal.service.helper.RhythmService;
 import org.junit.After;
 import org.junit.Before;
 import org.junit.ClassRule;
@@ -76,6 +77,9 @@ public abstract class AbstractDepositAccountManagementTest extends SuiteTestEnvi
   @MockBean
   AccountingService accountingServiceSpy;
 
+  @MockBean
+  RhythmService rhythmService;
+
   private AutoUserContext autoUserContext;
 
   AbstractDepositAccountManagementTest() {
diff --git a/component-test/src/main/java/io/mifos/deposit/TestProductDefinition.java b/component-test/src/main/java/io/mifos/deposit/TestProductDefinition.java
index 7125390..9d2e417 100644
--- a/component-test/src/main/java/io/mifos/deposit/TestProductDefinition.java
+++ b/component-test/src/main/java/io/mifos/deposit/TestProductDefinition.java
@@ -145,6 +145,35 @@ public class TestProductDefinition extends AbstractDepositAccountManagementTest
     Assert.assertTrue(super.eventRecorder.wait(EventConstants.DELETE_PRODUCT_DEFINITION, productDefinition.getIdentifier()));
   }
 
+  @Test
+  public void shouldDeleteProductDefinitionEvenWhenActed() throws Exception {
+    final ProductDefinition productDefinition = Fixture.productDefinition();
+
+    super.depositAccountManager.create(productDefinition);
+
+    super.eventRecorder.wait(EventConstants.POST_PRODUCT_DEFINITION, productDefinition.getIdentifier());
+
+    final ProductDefinitionCommand activateProduct = new ProductDefinitionCommand();
+    activateProduct.setAction(ProductDefinitionCommand.Action.ACTIVATE.name());
+    activateProduct.setNote(RandomStringUtils.randomAlphanumeric(2048));
+
+    super.depositAccountManager.process(productDefinition.getIdentifier(), activateProduct);
+
+    super.eventRecorder.wait(EventConstants.POST_PRODUCT_DEFINITION_COMMAND, productDefinition.getIdentifier());
+
+    final ProductDefinitionCommand deactivateProduct = new ProductDefinitionCommand();
+    deactivateProduct.setAction(ProductDefinitionCommand.Action.DEACTIVATE.name());
+    deactivateProduct.setNote(RandomStringUtils.randomAlphanumeric(2048));
+
+    super.depositAccountManager.process(productDefinition.getIdentifier(), deactivateProduct);
+
+    super.eventRecorder.wait(EventConstants.POST_PRODUCT_DEFINITION_COMMAND, productDefinition.getIdentifier());
+
+    super.depositAccountManager.deleteProductDefinition(productDefinition.getIdentifier());
+
+    Assert.assertTrue(super.eventRecorder.wait(EventConstants.DELETE_PRODUCT_DEFINITION, productDefinition.getIdentifier()));
+  }
+
   @Test(expected = ProductDefinitionValidationException.class)
   public void shouldNotDeleteProductDefinitionInstanceExists() throws Exception {
     final ProductDefinition productDefinition = Fixture.productDefinition();
diff --git a/service/src/main/java/io/mifos/deposit/service/internal/repository/ProductDefinitionCommandEntity.java b/service/src/main/java/io/mifos/deposit/service/internal/repository/ProductDefinitionCommandEntity.java
index 6eae234..42208d7 100644
--- a/service/src/main/java/io/mifos/deposit/service/internal/repository/ProductDefinitionCommandEntity.java
+++ b/service/src/main/java/io/mifos/deposit/service/internal/repository/ProductDefinitionCommandEntity.java
@@ -38,7 +38,7 @@ public class ProductDefinitionCommandEntity {
   @GeneratedValue(strategy = GenerationType.IDENTITY)
   @Column(name = "id", nullable = false)
   private Long id;
-  @ManyToOne(fetch = FetchType.LAZY, cascade = CascadeType.ALL)
+  @ManyToOne(fetch = FetchType.LAZY)
   @JoinColumn(name = "product_definition_id", nullable = false)
   private ProductDefinitionEntity productDefinition;
   @Column(name = "a_action", nullable = false)

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

[fineract-cn-deposit-account-management] 03/26: added interest calculation

Posted by my...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

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

commit 333cc52b2083523c7dbcdfd6b0466e3cbe54bb1d
Author: mgeiss <mg...@mifos.org>
AuthorDate: Thu Aug 3 17:49:17 2017 +0200

    added interest calculation
---
 .gitignore                                         |   1 +
 .../io/mifos/deposit/api/v1/EventConstants.java    |   7 +
 .../api/v1/client/DepositAccountManager.java       |  25 ++
 .../v1/definition/domain/DividendDistribution.java |  64 +++
 .../v1/definition/domain/ProductDefinition.java    |  24 +-
 .../AbstractDepositAccountManagementTest.java      |   2 +-
 .../src/main/java/io/mifos/deposit/Fixture.java    |   8 +-
 .../main/java/io/mifos/deposit/TestAccrual.java    | 117 ++++++
 .../io/mifos/deposit/TestDividendDistribution.java |  91 ++++
 .../java/io/mifos/deposit/TestProductInstance.java |   1 -
 .../src/main/java/io/mifos/deposit/TestSuite.java  |   4 +-
 .../listener/InterestCalculationEventListener.java |  64 +++
 gradle/wrapper/gradle-wrapper.properties           |   4 +-
 service/build.gradle                               |   8 +-
 .../service/internal/command/AccrualCommand.java   |  27 +-
 .../internal/command/BeatListenerCommand.java      |  27 +-
 .../command/DividendDistributionCommand.java       |  44 ++
 .../internal/command/PayInterestCommand.java       |  27 +-
 .../handler/BeatListenerCommandHandler.java        |  58 +++
 .../command/handler/InterestCalculator.java        | 468 +++++++++++++++++++++
 .../mapper/DividendDistributionMapper.java         |  56 +++
 .../internal/mapper/ProductDefinitionMapper.java   |   4 +
 .../internal/repository/AccruedInterestEntity.java |  75 ++++
 .../repository/AccruedInterestRepository.java      |  22 +-
 .../repository/DividendDistributionEntity.java     | 106 +++++
 .../repository/DividendDistributionRepository.java |  20 +-
 .../repository/ProductDefinitionEntity.java        |  20 +
 .../repository/ProductInstanceRepository.java      |   3 -
 .../internal/service/ProductDefinitionService.java |  21 +-
 .../internal/service/helper/AccountingService.java |  13 +
 .../service/rest/BeatListenerRestController.java   |  67 +++
 .../rest/ProductDefinitionRestController.java      |  52 +++
 .../mariadb/V5__interest_calculation.sql           |  40 ++
 service/src/main/resources/logback.xml             |   8 +-
 shared.gradle                                      |   2 +
 35 files changed, 1496 insertions(+), 84 deletions(-)

diff --git a/.gitignore b/.gitignore
index f9d7cba..1d62734 100644
--- a/.gitignore
+++ b/.gitignore
@@ -2,6 +2,7 @@
 .idea
 build/
 target/
+out/
 
 # Ignore Gradle GUI config
 gradle-app.setting
diff --git a/api/src/main/java/io/mifos/deposit/api/v1/EventConstants.java b/api/src/main/java/io/mifos/deposit/api/v1/EventConstants.java
index 2ebb53b..7e63d55 100644
--- a/api/src/main/java/io/mifos/deposit/api/v1/EventConstants.java
+++ b/api/src/main/java/io/mifos/deposit/api/v1/EventConstants.java
@@ -49,4 +49,11 @@ public interface EventConstants {
 
   String ACTIVATE_PRODUCT_INSTANCE_COMMAND = "ACTIVATE";
   String CLOSE_PRODUCT_INSTANCE_COMMAND = "CLOSE";
+
+  String DIVIDEND_DISTRIBUTION = "dividend-distribution";
+  String SELECTOR_DIVIDEND_DISTRIBUTION = SELECTOR_NAME + " = '" + DIVIDEND_DISTRIBUTION + "'";
+  String INTEREST_ACCRUED = "interest-accrued";
+  String SELECTOR_INTEREST_ACCRUED = SELECTOR_NAME + " = '" + INTEREST_ACCRUED + "'";
+  String INTEREST_PAYED = "interest-payed";
+  String SELECTOR_INTEREST_PAYED = SELECTOR_NAME + " = '" + INTEREST_PAYED + "'";
 }
diff --git a/api/src/main/java/io/mifos/deposit/api/v1/client/DepositAccountManager.java b/api/src/main/java/io/mifos/deposit/api/v1/client/DepositAccountManager.java
index f6ce405..aae77a7 100644
--- a/api/src/main/java/io/mifos/deposit/api/v1/client/DepositAccountManager.java
+++ b/api/src/main/java/io/mifos/deposit/api/v1/client/DepositAccountManager.java
@@ -23,6 +23,7 @@ import io.mifos.deposit.api.v1.definition.ProductDefinitionAlreadyExistsExceptio
 import io.mifos.deposit.api.v1.definition.ProductDefinitionNotFoundException;
 import io.mifos.deposit.api.v1.definition.ProductDefinitionValidationException;
 import io.mifos.deposit.api.v1.definition.domain.Action;
+import io.mifos.deposit.api.v1.definition.domain.DividendDistribution;
 import io.mifos.deposit.api.v1.definition.domain.ProductDefinition;
 import io.mifos.deposit.api.v1.definition.domain.ProductDefinitionCommand;
 import io.mifos.deposit.api.v1.instance.ProductInstanceNotFoundException;
@@ -188,4 +189,28 @@ public interface DepositAccountManager {
       @ThrowsException(status = HttpStatus.NOT_FOUND, exception = ProductInstanceNotFoundException.class)
   })
   ProductInstance findProductInstance(@PathVariable("identifier") final String identifier);
+
+  @RequestMapping(
+      value = "/definitions/{identifier}/dividends",
+      method = RequestMethod.POST,
+      consumes = MediaType.APPLICATION_JSON_VALUE,
+      produces = MediaType.APPLICATION_JSON_VALUE
+  )
+  @ThrowsExceptions({
+      @ThrowsException(status = HttpStatus.NOT_FOUND, exception = ProductDefinitionNotFoundException.class),
+      @ThrowsException(status = HttpStatus.BAD_REQUEST, exception = ProductDefinitionValidationException.class)
+  })
+  void dividendDistribution(@PathVariable("identifier") final String identifier,
+                            @RequestBody @Valid final DividendDistribution dividendDistribution);
+
+  @RequestMapping(
+      value = "/definitions/{identifier}/dividends",
+      method = RequestMethod.GET,
+      consumes = MediaType.APPLICATION_JSON_VALUE,
+      produces = MediaType.ALL_VALUE
+  )
+  @ThrowsExceptions({
+      @ThrowsException(status = HttpStatus.NOT_FOUND, exception = ProductDefinitionNotFoundException.class),
+  })
+  List<DividendDistribution> fetchDividendDistributions(@PathVariable("identifier") final String identifier);
 }
diff --git a/api/src/main/java/io/mifos/deposit/api/v1/definition/domain/DividendDistribution.java b/api/src/main/java/io/mifos/deposit/api/v1/definition/domain/DividendDistribution.java
new file mode 100644
index 0000000..3186deb
--- /dev/null
+++ b/api/src/main/java/io/mifos/deposit/api/v1/definition/domain/DividendDistribution.java
@@ -0,0 +1,64 @@
+/*
+ * Copyright 2017 The Mifos Initiative.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package io.mifos.deposit.api.v1.definition.domain;
+
+import org.hibernate.validator.constraints.NotBlank;
+
+public class DividendDistribution {
+
+  @NotBlank
+  private String dueDate;
+  @NotBlank
+  private String dividendRate;
+
+  public DividendDistribution() {
+    super();
+  }
+
+  public String getDueDate() {
+    return this.dueDate;
+  }
+
+  public void setDueDate(final String dueDate) {
+    this.dueDate = dueDate;
+  }
+
+  public String getDividendRate() {
+    return this.dividendRate;
+  }
+
+  public void setDividendRate(final String dividendRate) {
+    this.dividendRate = dividendRate;
+  }
+
+  @Override
+  public boolean equals(final Object o) {
+    if (this == o) return true;
+    if (o == null || getClass() != o.getClass()) return false;
+
+    final DividendDistribution that = (DividendDistribution) o;
+
+    if (!dueDate.equals(that.dueDate)) return false;
+    return dividendRate.equals(that.dividendRate);
+  }
+
+  @Override
+  public int hashCode() {
+    int result = dueDate.hashCode();
+    result = 31 * result + dividendRate.hashCode();
+    return result;
+  }
+}
diff --git a/api/src/main/java/io/mifos/deposit/api/v1/definition/domain/ProductDefinition.java b/api/src/main/java/io/mifos/deposit/api/v1/definition/domain/ProductDefinition.java
index 05846b8..59d89c3 100644
--- a/api/src/main/java/io/mifos/deposit/api/v1/definition/domain/ProductDefinition.java
+++ b/api/src/main/java/io/mifos/deposit/api/v1/definition/domain/ProductDefinition.java
@@ -36,10 +36,14 @@ public class ProductDefinition {
   private Currency currency;
   @NotNull
   private Double minimumBalance;
-  @ValidIdentifier
+  @ValidIdentifier(maxLength = 34)
   private String equityLedgerIdentifier;
-  @ValidIdentifier
+  @ValidIdentifier(maxLength = 34)
+  private String cashAccountIdentifier;
+  @ValidIdentifier(maxLength = 34)
   private String expenseAccountIdentifier;
+  @ValidIdentifier(maxLength = 34, optional = true)
+  private String accrueAccountIdentifier;
   private Double interest;
   @Valid
   @NotNull
@@ -109,6 +113,14 @@ public class ProductDefinition {
     this.equityLedgerIdentifier = equityLedgerIdentifier;
   }
 
+  public String getCashAccountIdentifier() {
+    return this.cashAccountIdentifier;
+  }
+
+  public void setCashAccountIdentifier(final String cashAccountIdentifier) {
+    this.cashAccountIdentifier = cashAccountIdentifier;
+  }
+
   public String getExpenseAccountIdentifier() {
     return this.expenseAccountIdentifier;
   }
@@ -117,6 +129,14 @@ public class ProductDefinition {
     this.expenseAccountIdentifier = expenseAccountIdentifier;
   }
 
+  public String getAccrueAccountIdentifier() {
+    return this.accrueAccountIdentifier;
+  }
+
+  public void setAccrueAccountIdentifier(final String accrueAccountIdentifier) {
+    this.accrueAccountIdentifier = accrueAccountIdentifier;
+  }
+
   public Double getInterest() {
     return this.interest;
   }
diff --git a/component-test/src/main/java/io/mifos/deposit/AbstractDepositAccountManagementTest.java b/component-test/src/main/java/io/mifos/deposit/AbstractDepositAccountManagementTest.java
index b93a584..6617bc6 100644
--- a/component-test/src/main/java/io/mifos/deposit/AbstractDepositAccountManagementTest.java
+++ b/component-test/src/main/java/io/mifos/deposit/AbstractDepositAccountManagementTest.java
@@ -62,7 +62,7 @@ public abstract class AbstractDepositAccountManagementTest extends SuiteTestEnvi
 
   @Autowired
   @Qualifier(TEST_LOGGER)
-  private Logger logger;
+  protected Logger logger;
 
   @Autowired
   DepositAccountManager depositAccountManager;
diff --git a/component-test/src/main/java/io/mifos/deposit/Fixture.java b/component-test/src/main/java/io/mifos/deposit/Fixture.java
index b4929a1..bf2451d 100644
--- a/component-test/src/main/java/io/mifos/deposit/Fixture.java
+++ b/component-test/src/main/java/io/mifos/deposit/Fixture.java
@@ -62,15 +62,17 @@ public class Fixture {
     currency.setScale(3);
 
     final ProductDefinition productDefinition = new ProductDefinition();
-    productDefinition.setType(Type.SHARE.name());
+    productDefinition.setType(Type.SAVINGS.name());
     productDefinition.setIdentifier(RandomStringUtils.randomAlphanumeric(8));
     productDefinition.setName(RandomStringUtils.randomAlphanumeric(256));
     productDefinition.setDescription(RandomStringUtils.randomAlphanumeric(2048));
     productDefinition.setCharges(new HashSet<>(Arrays.asList(openingCharge, closingCharge)));
     productDefinition.setCurrency(currency);
     productDefinition.setInterest(1.25D);
-    productDefinition.setEquityLedgerIdentifier("20300");
-    productDefinition.setExpenseAccountIdentifier("30300");
+    productDefinition.setEquityLedgerIdentifier("91xx");
+    productDefinition.setCashAccountIdentifier("76xx");
+    productDefinition.setExpenseAccountIdentifier("38xx");
+    productDefinition.setAccrueAccountIdentifier("82xx");
     productDefinition.setFlexible(Boolean.FALSE);
     productDefinition.setMinimumBalance(50.00);
     productDefinition.setTerm(term);
diff --git a/component-test/src/main/java/io/mifos/deposit/TestAccrual.java b/component-test/src/main/java/io/mifos/deposit/TestAccrual.java
new file mode 100644
index 0000000..88d50c5
--- /dev/null
+++ b/component-test/src/main/java/io/mifos/deposit/TestAccrual.java
@@ -0,0 +1,117 @@
+/*
+ * Copyright 2017 The Mifos Initiative.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package io.mifos.deposit;
+
+import io.mifos.accounting.api.v1.domain.Account;
+import io.mifos.accounting.api.v1.domain.AccountType;
+import io.mifos.core.api.util.ApiFactory;
+import io.mifos.core.lang.DateConverter;
+import io.mifos.deposit.api.v1.EventConstants;
+import io.mifos.deposit.api.v1.definition.domain.ProductDefinition;
+import io.mifos.deposit.api.v1.definition.domain.ProductDefinitionCommand;
+import io.mifos.deposit.api.v1.domain.Type;
+import io.mifos.deposit.api.v1.instance.domain.ProductInstance;
+import io.mifos.deposit.service.internal.repository.AccruedInterestEntity;
+import io.mifos.deposit.service.internal.repository.AccruedInterestRepository;
+import io.mifos.rhythm.spi.v1.client.BeatListener;
+import io.mifos.rhythm.spi.v1.domain.BeatPublish;
+import org.apache.commons.lang.RandomStringUtils;
+import org.junit.Assert;
+import org.junit.Before;
+import org.junit.Test;
+import org.mockito.Mockito;
+import org.springframework.beans.factory.annotation.Autowired;
+
+import java.math.BigDecimal;
+import java.time.LocalDateTime;
+import java.util.List;
+import java.util.Optional;
+
+public class TestAccrual extends AbstractDepositAccountManagementTest {
+
+  @Autowired
+  private AccruedInterestRepository accruedInterestRepository;
+
+  private BeatListener depositBeatListener;
+
+  public TestAccrual() {
+    super();
+  }
+
+  @Before
+  public void prepBeatListener() {
+    depositBeatListener = new ApiFactory(super.logger)
+        .create(BeatListener.class, AbstractDepositAccountManagementTest.testEnvironment.serverURI());
+  }
+
+  @Test
+  public void shouldAccrueInterest() throws Exception {
+    final ProductDefinition productDefinition = Fixture.productDefinition();
+    productDefinition.setType(Type.SAVINGS.name());
+    productDefinition.setInterest(2.50D);
+    super.depositAccountManager.create(productDefinition);
+    super.eventRecorder.wait(EventConstants.POST_PRODUCT_DEFINITION, productDefinition.getIdentifier());
+
+    final ProductDefinitionCommand productDefinitionCommand = new ProductDefinitionCommand();
+    productDefinitionCommand.setAction(ProductDefinitionCommand.Action.ACTIVATE.name());
+    super.depositAccountManager.process(productDefinition.getIdentifier(), productDefinitionCommand);
+    super.eventRecorder.wait(EventConstants.POST_PRODUCT_DEFINITION_COMMAND, productDefinition.getIdentifier());
+
+    final ProductInstance productInstance = Fixture.productInstance(productDefinition.getIdentifier());
+    super.depositAccountManager.create(productInstance);
+    super.eventRecorder.wait(EventConstants.POST_PRODUCT_INSTANCE, productInstance.getCustomerIdentifier());
+
+    final List<ProductInstance> productInstances = super.depositAccountManager.findProductInstances(productDefinition.getIdentifier());
+    Assert.assertNotNull(productInstances);
+    Assert.assertEquals(1, productInstances.size());
+    final ProductInstance foundProductInstance = productInstances.get(0);
+
+    super.depositAccountManager.postProductInstanceCommand(
+        foundProductInstance.getAccountIdentifier(), EventConstants.ACTIVATE_PRODUCT_INSTANCE_COMMAND);
+    super.eventRecorder.wait(EventConstants.ACTIVATE_PRODUCT_INSTANCE, foundProductInstance.getAccountIdentifier());
+
+    final Account shareAccount = new Account();
+    shareAccount.setType(AccountType.EQUITY.name());
+    shareAccount.setIdentifier(foundProductInstance.getAccountIdentifier());
+    shareAccount.setBalance(1000.00D);
+
+    Mockito
+        .doAnswer(invocation -> shareAccount)
+        .when(super.accountingServiceSpy).findAccount(shareAccount.getIdentifier());
+
+    final LocalDateTime dueDate = DateConverter.fromIsoString("2017-08-02T22:00:00.000Z");
+    final BeatPublish beatPublish = new BeatPublish();
+    beatPublish.setIdentifier(RandomStringUtils.randomAlphanumeric(32));
+    beatPublish.setForTime(DateConverter.toIsoString(dueDate));
+    this.depositBeatListener.publishBeat(beatPublish);
+
+    super.eventRecorder.wait(EventConstants.INTEREST_ACCRUED, DateConverter.toIsoString(dueDate.toLocalDate()));
+
+    final Optional<AccruedInterestEntity> optionalAccruedInterest =
+        this.accruedInterestRepository.findByCustomerAccountIdentifier(foundProductInstance.getAccountIdentifier());
+
+    Assert.assertTrue(optionalAccruedInterest.isPresent());
+    final AccruedInterestEntity accruedInterestEntity = optionalAccruedInterest.get();
+    final Double interest =
+        accruedInterestEntity.getAmount()
+            * DateConverter.fromIsoString(beatPublish.getForTime()).toLocalDate().lengthOfYear();
+
+    final Double roundedInterest =
+        BigDecimal.valueOf(interest).setScale(2, BigDecimal.ROUND_HALF_EVEN).doubleValue();
+
+    Assert.assertEquals(25.00D, roundedInterest, 0.00D);
+  }
+}
diff --git a/component-test/src/main/java/io/mifos/deposit/TestDividendDistribution.java b/component-test/src/main/java/io/mifos/deposit/TestDividendDistribution.java
new file mode 100644
index 0000000..e6360ed
--- /dev/null
+++ b/component-test/src/main/java/io/mifos/deposit/TestDividendDistribution.java
@@ -0,0 +1,91 @@
+/*
+ * Copyright 2017 The Mifos Initiative.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package io.mifos.deposit;
+
+import io.mifos.accounting.api.v1.domain.Account;
+import io.mifos.accounting.api.v1.domain.AccountType;
+import io.mifos.accounting.api.v1.domain.JournalEntry;
+import io.mifos.deposit.api.v1.EventConstants;
+import io.mifos.deposit.api.v1.definition.domain.DividendDistribution;
+import io.mifos.deposit.api.v1.definition.domain.ProductDefinition;
+import io.mifos.deposit.api.v1.definition.domain.ProductDefinitionCommand;
+import io.mifos.deposit.api.v1.domain.Type;
+import io.mifos.deposit.api.v1.instance.domain.ProductInstance;
+import org.junit.Assert;
+import org.junit.Test;
+import org.mockito.Matchers;
+import org.mockito.Mockito;
+
+import java.util.List;
+
+public class TestDividendDistribution extends AbstractDepositAccountManagementTest {
+
+  public TestDividendDistribution() {
+    super();
+  }
+
+  @Test
+  public void shouldDistributeDividend() throws Exception {
+    final ProductDefinition productDefinition = Fixture.productDefinition();
+    productDefinition.setType(Type.SHARE.name());
+    productDefinition.setInterest(null);
+    productDefinition.setAccrueAccountIdentifier(null);
+    super.depositAccountManager.create(productDefinition);
+    super.eventRecorder.wait(EventConstants.POST_PRODUCT_DEFINITION, productDefinition.getIdentifier());
+
+    final ProductDefinitionCommand productDefinitionCommand = new ProductDefinitionCommand();
+    productDefinitionCommand.setAction(ProductDefinitionCommand.Action.ACTIVATE.name());
+    super.depositAccountManager.process(productDefinition.getIdentifier(), productDefinitionCommand);
+    super.eventRecorder.wait(EventConstants.POST_PRODUCT_DEFINITION_COMMAND, productDefinition.getIdentifier());
+
+    final ProductInstance productInstance = Fixture.productInstance(productDefinition.getIdentifier());
+    super.depositAccountManager.create(productInstance);
+    super.eventRecorder.wait(EventConstants.POST_PRODUCT_INSTANCE, productInstance.getCustomerIdentifier());
+
+    final List<ProductInstance> productInstances = super.depositAccountManager.findProductInstances(productDefinition.getIdentifier());
+    Assert.assertNotNull(productInstances);
+    Assert.assertEquals(1, productInstances.size());
+    final ProductInstance foundProductInstance = productInstances.get(0);
+
+    super.depositAccountManager.postProductInstanceCommand(
+        foundProductInstance.getAccountIdentifier(), EventConstants.ACTIVATE_PRODUCT_INSTANCE_COMMAND);
+    super.eventRecorder.wait(EventConstants.ACTIVATE_PRODUCT_INSTANCE, foundProductInstance.getAccountIdentifier());
+
+    final Account shareAccount = new Account();
+    shareAccount.setType(AccountType.EQUITY.name());
+    shareAccount.setIdentifier(foundProductInstance.getAccountIdentifier());
+    shareAccount.setBalance(1000.00D);
+
+    Mockito
+        .doAnswer(invocation -> shareAccount)
+        .when(super.accountingServiceSpy).findAccount(shareAccount.getIdentifier());
+
+    final DividendDistribution dividendDistribution = new DividendDistribution();
+    dividendDistribution.setDueDate("2017-07-31Z");
+    dividendDistribution.setDividendRate("2.5");
+    this.depositAccountManager.dividendDistribution(productDefinition.getIdentifier(), dividendDistribution);
+
+    Assert.assertTrue(super.eventRecorder.wait(EventConstants.DIVIDEND_DISTRIBUTION, productDefinition.getIdentifier()));
+
+    final List<DividendDistribution> dividendDistributions =
+        super.depositAccountManager.fetchDividendDistributions(productDefinition.getIdentifier());
+
+    Assert.assertEquals(1, dividendDistributions.size());
+    Assert.assertTrue(dividendDistribution.equals(dividendDistributions.get(0)));
+
+    Mockito.verify(super.accountingServiceSpy, Mockito.times(2)).post(Matchers.any(JournalEntry.class));
+  }
+}
diff --git a/component-test/src/main/java/io/mifos/deposit/TestProductInstance.java b/component-test/src/main/java/io/mifos/deposit/TestProductInstance.java
index e867830..be05a00 100644
--- a/component-test/src/main/java/io/mifos/deposit/TestProductInstance.java
+++ b/component-test/src/main/java/io/mifos/deposit/TestProductInstance.java
@@ -30,7 +30,6 @@ import org.mockito.Mockito;
 import java.util.Arrays;
 import java.util.HashSet;
 import java.util.List;
-import java.util.Set;
 
 public class TestProductInstance extends AbstractDepositAccountManagementTest {
 
diff --git a/component-test/src/main/java/io/mifos/deposit/TestSuite.java b/component-test/src/main/java/io/mifos/deposit/TestSuite.java
index abb4cc2..5ffc740 100644
--- a/component-test/src/main/java/io/mifos/deposit/TestSuite.java
+++ b/component-test/src/main/java/io/mifos/deposit/TestSuite.java
@@ -23,9 +23,11 @@ import org.junit.runners.Suite;
  */
 @RunWith(Suite.class)
 @Suite.SuiteClasses({
-    TestActions.class,
     TestProductDefinition.class,
     TestProductInstance.class,
+    TestActions.class,
+    TestAccrual.class,
+    TestDividendDistribution.class
 })
 public class TestSuite extends SuiteTestEnvironment {
 }
diff --git a/component-test/src/main/java/io/mifos/deposit/listener/InterestCalculationEventListener.java b/component-test/src/main/java/io/mifos/deposit/listener/InterestCalculationEventListener.java
new file mode 100644
index 0000000..6593497
--- /dev/null
+++ b/component-test/src/main/java/io/mifos/deposit/listener/InterestCalculationEventListener.java
@@ -0,0 +1,64 @@
+/*
+ * Copyright 2017 The Mifos Initiative.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package io.mifos.deposit.listener;
+
+import io.mifos.core.lang.config.TenantHeaderFilter;
+import io.mifos.core.test.listener.EventRecorder;
+import io.mifos.deposit.AbstractDepositAccountManagementTest;
+import io.mifos.deposit.api.v1.EventConstants;
+import org.slf4j.Logger;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.beans.factory.annotation.Qualifier;
+import org.springframework.jms.annotation.JmsListener;
+import org.springframework.messaging.handler.annotation.Header;
+import org.springframework.stereotype.Component;
+
+@Component
+public class InterestCalculationEventListener {
+
+  private final Logger logger;
+  private final EventRecorder eventRecorder;
+
+  @Autowired
+  public InterestCalculationEventListener(@Qualifier(AbstractDepositAccountManagementTest.TEST_LOGGER) final Logger logger,
+                                          final EventRecorder eventRecorder) {
+    super();
+    this.logger = logger;
+    this.eventRecorder = eventRecorder;
+  }
+
+  @JmsListener(
+      destination = EventConstants.DESTINATION,
+      selector = EventConstants.SELECTOR_INTEREST_ACCRUED,
+      subscription = EventConstants.DESTINATION
+  )
+  public void onAccrual(@Header(TenantHeaderFilter.TENANT_HEADER) final String tenant,
+                        final String payload) {
+    this.logger.debug("Accrual processed, payload: {}.", payload);
+    this.eventRecorder.event(tenant, EventConstants.INTEREST_ACCRUED, payload, String.class);
+  }
+
+  @JmsListener(
+      destination = EventConstants.DESTINATION,
+      selector = EventConstants.SELECTOR_DIVIDEND_DISTRIBUTION,
+      subscription = EventConstants.DESTINATION
+  )
+  public void onDividendDistribution(@Header(TenantHeaderFilter.TENANT_HEADER) final String tenant,
+                                     final String payload) {
+    this.logger.debug("Dividend distributed for product {}.", payload);
+    this.eventRecorder.event(tenant, EventConstants.DIVIDEND_DISTRIBUTION, payload, String.class);
+  }
+}
diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties
index 2888922..71e5108 100644
--- a/gradle/wrapper/gradle-wrapper.properties
+++ b/gradle/wrapper/gradle-wrapper.properties
@@ -1,6 +1,6 @@
-#Fri Mar 17 17:54:20 CET 2017
+#Tue Jul 25 13:05:05 CEST 2017
 distributionBase=GRADLE_USER_HOME
 distributionPath=wrapper/dists
 zipStoreBase=GRADLE_USER_HOME
 zipStorePath=wrapper/dists
-distributionUrl=https\://services.gradle.org/distributions/gradle-3.4.1-bin.zip
+distributionUrl=https\://services.gradle.org/distributions/gradle-3.4.1-all.zip
diff --git a/service/build.gradle b/service/build.gradle
index bee970e..bf6ef13 100644
--- a/service/build.gradle
+++ b/service/build.gradle
@@ -39,7 +39,13 @@ dependencies {
             [group: 'io.mifos.core', name: 'mariadb', version: versions.frameworkmariadb],
             [group: 'io.mifos.core', name: 'command', version: versions.frameworkcommand],
             [group: 'io.mifos.accounting', name: 'api', version: versions.frameworkledger],
-            [group: 'org.hibernate', name: 'hibernate-validator', version: versions.validator]
+            [group: 'io.mifos.rhythm', name: 'spi', version: versions.frameworkrhythm],
+            [group: 'io.mifos.rhythm', name: 'api', version: versions.frameworkrhythm],
+            [group: 'org.hibernate', name: 'hibernate-validator', version: versions.validator],
+            [group: 'org.javamoney.lib', name: 'javamoney-calc', version: versions.javamoneylib],
+            [group: 'javax.money', name: 'money-api', version: '1.0.1'],
+            [group: 'org.javamoney', name: 'moneta', version: '1.0.1'],
+            [group: 'org.threeten', name: 'threeten-extra', version: '1.2']
     )
 }
 
diff --git a/component-test/src/main/java/io/mifos/deposit/TestSuite.java b/service/src/main/java/io/mifos/deposit/service/internal/command/AccrualCommand.java
similarity index 66%
copy from component-test/src/main/java/io/mifos/deposit/TestSuite.java
copy to service/src/main/java/io/mifos/deposit/service/internal/command/AccrualCommand.java
index abb4cc2..b306f6f 100644
--- a/component-test/src/main/java/io/mifos/deposit/TestSuite.java
+++ b/service/src/main/java/io/mifos/deposit/service/internal/command/AccrualCommand.java
@@ -13,19 +13,20 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-package io.mifos.deposit;
+package io.mifos.deposit.service.internal.command;
 
-import org.junit.runner.RunWith;
-import org.junit.runners.Suite;
+import java.time.LocalDate;
 
-/**
- * @author Myrle Krantz
- */
-@RunWith(Suite.class)
-@Suite.SuiteClasses({
-    TestActions.class,
-    TestProductDefinition.class,
-    TestProductInstance.class,
-})
-public class TestSuite extends SuiteTestEnvironment {
+public class AccrualCommand {
+
+  private final LocalDate dueDate;
+
+  public AccrualCommand(final LocalDate dueDate) {
+    super();
+    this.dueDate = dueDate;
+  }
+
+  public LocalDate dueDate() {
+    return this.dueDate;
+  }
 }
diff --git a/component-test/src/main/java/io/mifos/deposit/TestSuite.java b/service/src/main/java/io/mifos/deposit/service/internal/command/BeatListenerCommand.java
similarity index 62%
copy from component-test/src/main/java/io/mifos/deposit/TestSuite.java
copy to service/src/main/java/io/mifos/deposit/service/internal/command/BeatListenerCommand.java
index abb4cc2..0f99a93 100644
--- a/component-test/src/main/java/io/mifos/deposit/TestSuite.java
+++ b/service/src/main/java/io/mifos/deposit/service/internal/command/BeatListenerCommand.java
@@ -13,19 +13,20 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-package io.mifos.deposit;
+package io.mifos.deposit.service.internal.command;
 
-import org.junit.runner.RunWith;
-import org.junit.runners.Suite;
+import io.mifos.rhythm.spi.v1.domain.BeatPublish;
 
-/**
- * @author Myrle Krantz
- */
-@RunWith(Suite.class)
-@Suite.SuiteClasses({
-    TestActions.class,
-    TestProductDefinition.class,
-    TestProductInstance.class,
-})
-public class TestSuite extends SuiteTestEnvironment {
+public class BeatListenerCommand {
+
+  private final BeatPublish beatPublish;
+
+  public BeatListenerCommand(final BeatPublish beatPublish) {
+    super();
+    this.beatPublish = beatPublish;
+  }
+
+  public BeatPublish beatPublish() {
+    return this.beatPublish;
+  }
 }
diff --git a/service/src/main/java/io/mifos/deposit/service/internal/command/DividendDistributionCommand.java b/service/src/main/java/io/mifos/deposit/service/internal/command/DividendDistributionCommand.java
new file mode 100644
index 0000000..d993dc7
--- /dev/null
+++ b/service/src/main/java/io/mifos/deposit/service/internal/command/DividendDistributionCommand.java
@@ -0,0 +1,44 @@
+/*
+ * Copyright 2017 The Mifos Initiative.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package io.mifos.deposit.service.internal.command;
+
+import java.time.LocalDate;
+
+public class DividendDistributionCommand {
+
+  private final String productDefinition;
+  private final LocalDate dueDate;
+  private final Double rate;
+
+  public DividendDistributionCommand(final String productDefinition, final LocalDate dueDate, final Double rate) {
+    super();
+    this.productDefinition = productDefinition;
+    this.dueDate = dueDate;
+    this.rate = rate;
+  }
+
+  public String productDefinition() {
+    return this.productDefinition;
+  }
+
+  public LocalDate dueDate() {
+    return this.dueDate;
+  }
+
+  public Double rate() {
+    return this.rate;
+  }
+}
diff --git a/component-test/src/main/java/io/mifos/deposit/TestSuite.java b/service/src/main/java/io/mifos/deposit/service/internal/command/PayInterestCommand.java
similarity index 66%
copy from component-test/src/main/java/io/mifos/deposit/TestSuite.java
copy to service/src/main/java/io/mifos/deposit/service/internal/command/PayInterestCommand.java
index abb4cc2..b987190 100644
--- a/component-test/src/main/java/io/mifos/deposit/TestSuite.java
+++ b/service/src/main/java/io/mifos/deposit/service/internal/command/PayInterestCommand.java
@@ -13,19 +13,20 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-package io.mifos.deposit;
+package io.mifos.deposit.service.internal.command;
 
-import org.junit.runner.RunWith;
-import org.junit.runners.Suite;
+import java.time.LocalDate;
 
-/**
- * @author Myrle Krantz
- */
-@RunWith(Suite.class)
-@Suite.SuiteClasses({
-    TestActions.class,
-    TestProductDefinition.class,
-    TestProductInstance.class,
-})
-public class TestSuite extends SuiteTestEnvironment {
+public class PayInterestCommand {
+
+  private final LocalDate date;
+
+  public PayInterestCommand(final LocalDate date) {
+    super();
+    this.date = date;
+  }
+
+  public LocalDate date() {
+    return this.date;
+  }
 }
diff --git a/service/src/main/java/io/mifos/deposit/service/internal/command/handler/BeatListenerCommandHandler.java b/service/src/main/java/io/mifos/deposit/service/internal/command/handler/BeatListenerCommandHandler.java
new file mode 100644
index 0000000..d47c81e
--- /dev/null
+++ b/service/src/main/java/io/mifos/deposit/service/internal/command/handler/BeatListenerCommandHandler.java
@@ -0,0 +1,58 @@
+/*
+ * Copyright 2017 The Mifos Initiative.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package io.mifos.deposit.service.internal.command.handler;
+
+import io.mifos.core.command.annotation.Aggregate;
+import io.mifos.core.command.annotation.CommandHandler;
+import io.mifos.core.command.domain.CommandCallback;
+import io.mifos.core.command.gateway.CommandGateway;
+import io.mifos.core.lang.DateConverter;
+import io.mifos.core.lang.ServiceException;
+import io.mifos.deposit.service.internal.command.AccrualCommand;
+import io.mifos.deposit.service.internal.command.BeatListenerCommand;
+import io.mifos.deposit.service.internal.command.PayInterestCommand;
+import org.springframework.beans.factory.annotation.Autowired;
+
+import javax.transaction.Transactional;
+import java.time.LocalDateTime;
+
+@Aggregate
+public class BeatListenerCommandHandler {
+
+  private final CommandGateway commandGateway;
+
+  @Autowired
+  public BeatListenerCommandHandler(final CommandGateway commandGateway) {
+    super();
+    this.commandGateway = commandGateway;
+  }
+
+  @Transactional
+  @CommandHandler
+  public void process(final BeatListenerCommand beatListenerCommand) {
+    try {
+      final LocalDateTime dueDate = DateConverter.fromIsoString(beatListenerCommand.beatPublish().getForTime());
+      final CommandCallback<String> commandCallback =
+          this.commandGateway.process(new AccrualCommand(dueDate.toLocalDate()), String.class);
+
+      final String date = commandCallback.get();
+      this.commandGateway.process(new PayInterestCommand(DateConverter.dateFromIsoString(date)));
+
+    } catch (Exception ex) {
+      throw ServiceException.internalError("Could not handle beat: {0}", ex.getMessage());
+    }
+  }
+}
diff --git a/service/src/main/java/io/mifos/deposit/service/internal/command/handler/InterestCalculator.java b/service/src/main/java/io/mifos/deposit/service/internal/command/handler/InterestCalculator.java
new file mode 100644
index 0000000..4ac279d
--- /dev/null
+++ b/service/src/main/java/io/mifos/deposit/service/internal/command/handler/InterestCalculator.java
@@ -0,0 +1,468 @@
+/*
+ * Copyright 2017 The Mifos Initiative.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package io.mifos.deposit.service.internal.command.handler;
+
+import com.google.common.collect.Sets;
+import io.mifos.accounting.api.v1.domain.Account;
+import io.mifos.accounting.api.v1.domain.AccountEntry;
+import io.mifos.accounting.api.v1.domain.Creditor;
+import io.mifos.accounting.api.v1.domain.Debtor;
+import io.mifos.accounting.api.v1.domain.JournalEntry;
+import io.mifos.core.api.util.UserContextHolder;
+import io.mifos.core.command.annotation.Aggregate;
+import io.mifos.core.command.annotation.CommandHandler;
+import io.mifos.core.command.annotation.CommandLogLevel;
+import io.mifos.core.command.annotation.EventEmitter;
+import io.mifos.core.lang.DateConverter;
+import io.mifos.deposit.api.v1.EventConstants;
+import io.mifos.deposit.api.v1.domain.InterestPayable;
+import io.mifos.deposit.api.v1.domain.Type;
+import io.mifos.deposit.service.ServiceConstants;
+import io.mifos.deposit.service.internal.command.AccrualCommand;
+import io.mifos.deposit.service.internal.command.DividendDistributionCommand;
+import io.mifos.deposit.service.internal.command.PayInterestCommand;
+import io.mifos.deposit.service.internal.repository.AccruedInterestEntity;
+import io.mifos.deposit.service.internal.repository.AccruedInterestRepository;
+import io.mifos.deposit.service.internal.repository.CurrencyEntity;
+import io.mifos.deposit.service.internal.repository.CurrencyRepository;
+import io.mifos.deposit.service.internal.repository.DividendDistributionEntity;
+import io.mifos.deposit.service.internal.repository.DividendDistributionRepository;
+import io.mifos.deposit.service.internal.repository.ProductDefinitionEntity;
+import io.mifos.deposit.service.internal.repository.ProductDefinitionRepository;
+import io.mifos.deposit.service.internal.repository.ProductInstanceEntity;
+import io.mifos.deposit.service.internal.repository.ProductInstanceRepository;
+import io.mifos.deposit.service.internal.repository.TermEntity;
+import io.mifos.deposit.service.internal.repository.TermRepository;
+import io.mifos.deposit.service.internal.service.helper.AccountingService;
+import org.apache.commons.lang.RandomStringUtils;
+import org.javamoney.calc.banking.AnnualPercentageYield;
+import org.javamoney.calc.common.Rate;
+import org.javamoney.moneta.Money;
+import org.slf4j.Logger;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.beans.factory.annotation.Qualifier;
+import org.springframework.data.domain.Sort;
+import org.threeten.extra.YearQuarter;
+
+import javax.money.CurrencyUnit;
+import javax.money.Monetary;
+import javax.money.MonetaryAmount;
+import javax.transaction.Transactional;
+import java.math.BigDecimal;
+import java.sql.Date;
+import java.time.Clock;
+import java.time.LocalDate;
+import java.time.LocalDateTime;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Optional;
+import java.util.stream.Collectors;
+import java.util.stream.IntStream;
+
+@Aggregate
+public class InterestCalculator {
+
+  public static final String ACTIVE = "ACTIVE";
+  private final Logger logger;
+  private final ProductDefinitionRepository productDefinitionRepository;
+  private final ProductInstanceRepository productInstanceRepository;
+  private final TermRepository termRepository;
+  private final CurrencyRepository currencyRepository;
+  private final AccountingService accountingService;
+  private final AccruedInterestRepository accruedInterestRepository;
+  private final DividendDistributionRepository dividendDistributionRepository;
+
+  @Autowired
+  public InterestCalculator(@Qualifier(ServiceConstants.LOGGER_NAME) final Logger logger,
+                            final ProductDefinitionRepository productDefinitionRepository,
+                            final ProductInstanceRepository productInstanceRepository,
+                            final TermRepository termRepository,
+                            final CurrencyRepository currencyRepository,
+                            final AccountingService accountingService,
+                            final AccruedInterestRepository accruedInterestRepository,
+                            final DividendDistributionRepository dividendDistributionRepository) {
+    super();
+    this.logger = logger;
+    this.productDefinitionRepository = productDefinitionRepository;
+    this.productInstanceRepository = productInstanceRepository;
+    this.termRepository = termRepository;
+    this.currencyRepository = currencyRepository;
+    this.accruedInterestRepository = accruedInterestRepository;
+    this.accountingService = accountingService;
+    this.dividendDistributionRepository = dividendDistributionRepository;
+  }
+
+  @Transactional
+  @CommandHandler(logStart = CommandLogLevel.DEBUG, logFinish =  CommandLogLevel.DEBUG)
+  @EventEmitter(selectorName = EventConstants.SELECTOR_NAME, selectorValue = EventConstants.INTEREST_ACCRUED)
+  public String process(final AccrualCommand accrualCommand) {
+    final LocalDate accrualDate = accrualCommand.dueDate();
+
+    final List<ProductDefinitionEntity> productDefinitions = this.productDefinitionRepository.findAll();
+
+    productDefinitions.forEach(productDefinitionEntity -> {
+      if (this.accruableProduct(productDefinitionEntity)) {
+
+        final ArrayList<Double> accruedValues = new ArrayList<>();
+
+        final TermEntity term = this.termRepository.findByProductDefinition(productDefinitionEntity);
+        final CurrencyEntity currency = this.currencyRepository.findByProductDefinition(productDefinitionEntity);
+        final CurrencyUnit currencyUnit = Monetary.getCurrency(currency.getCode());
+
+        final List<ProductInstanceEntity> productInstances =
+            this.productInstanceRepository.findByProductDefinition(productDefinitionEntity);
+
+        final Money zero = Money.of(0.00D, currencyUnit);
+
+        productInstances.forEach(productInstanceEntity -> {
+          if (productInstanceEntity.getState().equals(ACTIVE)) {
+
+            final Account account = this.accountingService.findAccount(productInstanceEntity.getAccountIdentifier());
+
+            if (account.getBalance() > 0.00D) {
+              final Money balance = Money.of(account.getBalance(), currencyUnit);
+
+              final Rate rate = Rate.of(productDefinitionEntity.getInterest() / 100.00D);
+
+              final MonetaryAmount accruedInterest =
+                  AnnualPercentageYield
+                      .calculate(balance, rate, this.periodOfInterestPayable(term.getInterestPayable()))
+                      .divide(accrualDate.lengthOfYear());
+
+              if (accruedInterest.isGreaterThan(zero)) {
+                final Double doubleValue =
+                    BigDecimal.valueOf(accruedInterest.getNumber().doubleValue())
+                        .setScale(5, BigDecimal.ROUND_HALF_EVEN).doubleValue();
+
+                accruedValues.add(doubleValue);
+
+                final Optional<AccruedInterestEntity> optionalAccruedInterest =
+                    this.accruedInterestRepository.findByCustomerAccountIdentifier(account.getIdentifier());
+                if (optionalAccruedInterest.isPresent()) {
+                  final AccruedInterestEntity accruedInterestEntity = optionalAccruedInterest.get();
+                  accruedInterestEntity.setAmount(accruedInterestEntity.getAmount() + doubleValue);
+                  this.accruedInterestRepository.save(accruedInterestEntity);
+                } else {
+                  final AccruedInterestEntity accruedInterestEntity = new AccruedInterestEntity();
+                  accruedInterestEntity.setAccrueAccountIdentifier(productDefinitionEntity.getAccrueAccountIdentifier());
+                  accruedInterestEntity.setCustomerAccountIdentifier(account.getIdentifier());
+                  accruedInterestEntity.setAmount(doubleValue);
+                  this.accruedInterestRepository.save(accruedInterestEntity);
+                }
+              }
+            }
+          }
+        });
+
+        final String roundedAmount =
+            BigDecimal.valueOf(accruedValues.parallelStream().reduce(0.00D, Double::sum))
+                .setScale(2, BigDecimal.ROUND_HALF_EVEN).toString();
+
+        final JournalEntry cashToAccrueJournalEntry = new JournalEntry();
+        cashToAccrueJournalEntry.setTransactionIdentifier(RandomStringUtils.randomAlphanumeric(32));
+        cashToAccrueJournalEntry.setTransactionDate(DateConverter.toIsoString(LocalDateTime.now(Clock.systemUTC())));
+        cashToAccrueJournalEntry.setTransactionType("INTR");
+        cashToAccrueJournalEntry.setClerk(UserContextHolder.checkedGetUser());
+        cashToAccrueJournalEntry.setNote("Daily accrual for product " + productDefinitionEntity.getIdentifier() + ".");
+
+        final Debtor cashDebtor = new Debtor();
+        cashDebtor.setAccountNumber(productDefinitionEntity.getCashAccountIdentifier());
+        cashDebtor.setAmount(roundedAmount);
+        cashToAccrueJournalEntry.setDebtors(Sets.newHashSet(cashDebtor));
+
+        final Creditor accrueCreditor = new Creditor();
+        accrueCreditor.setAccountNumber(productDefinitionEntity.getAccrueAccountIdentifier());
+        accrueCreditor.setAmount(roundedAmount);
+        cashToAccrueJournalEntry.setCreditors(Sets.newHashSet(accrueCreditor));
+
+        this.accountingService.post(cashToAccrueJournalEntry);
+      }
+    });
+
+    return DateConverter.toIsoString(accrualDate);
+  }
+
+  @Transactional
+  @CommandHandler(logStart = CommandLogLevel.DEBUG, logFinish = CommandLogLevel.DEBUG)
+  @EventEmitter(selectorName = EventConstants.SELECTOR_NAME, selectorValue = EventConstants.INTEREST_PAYED)
+  public String process(final PayInterestCommand payInterestCommand) {
+    final List<ProductDefinitionEntity> productDefinitionEntities = this.productDefinitionRepository.findAll();
+
+    productDefinitionEntities.forEach(productDefinitionEntity -> {
+      if (productDefinitionEntity.getActive()
+          && !productDefinitionEntity.getType().equals(Type.SHARE.name())) {
+        final TermEntity term = this.termRepository.findByProductDefinition(productDefinitionEntity);
+        if (this.shouldPayInterest(term.getInterestPayable(), payInterestCommand.date())) {
+          final List<ProductInstanceEntity> productInstanceEntities =
+              this.productInstanceRepository.findByProductDefinition(productDefinitionEntity);
+
+          productInstanceEntities.forEach(productInstanceEntity -> {
+            if (productInstanceEntity.getState().equals(ACTIVE)) {
+              final Optional<AccruedInterestEntity> optionalAccruedInterestEntity =
+                  this.accruedInterestRepository.findByCustomerAccountIdentifier(productInstanceEntity.getAccountIdentifier());
+
+              if (optionalAccruedInterestEntity.isPresent()) {
+                final AccruedInterestEntity accruedInterestEntity = optionalAccruedInterestEntity.get();
+
+                final String roundedAmount =
+                    BigDecimal.valueOf(accruedInterestEntity.getAmount())
+                        .setScale(2, BigDecimal.ROUND_HALF_EVEN).toString();
+
+                final JournalEntry accrueToExpenseJournalEntry = new JournalEntry();
+                accrueToExpenseJournalEntry.setTransactionIdentifier(RandomStringUtils.randomAlphanumeric(32));
+                accrueToExpenseJournalEntry.setTransactionDate(DateConverter.toIsoString(LocalDateTime.now(Clock.systemUTC())));
+                accrueToExpenseJournalEntry.setTransactionType("INTR");
+                accrueToExpenseJournalEntry.setClerk(UserContextHolder.checkedGetUser());
+                accrueToExpenseJournalEntry.setNote("Interest paid.");
+
+                final Debtor accrueDebtor = new Debtor();
+                accrueDebtor.setAccountNumber(accruedInterestEntity.getAccrueAccountIdentifier());
+                accrueDebtor.setAmount(roundedAmount);
+                accrueToExpenseJournalEntry.setDebtors(Sets.newHashSet(accrueDebtor));
+
+                final Creditor expenseCreditor = new Creditor();
+                expenseCreditor.setAccountNumber(productDefinitionEntity.getExpenseAccountIdentifier());
+                expenseCreditor.setAmount(roundedAmount);
+                accrueToExpenseJournalEntry.setCreditors(Sets.newHashSet(expenseCreditor));
+
+                this.accruedInterestRepository.delete(accruedInterestEntity);
+
+                this.accountingService.post(accrueToExpenseJournalEntry);
+
+                this.payoutInterest(
+                    productDefinitionEntity.getExpenseAccountIdentifier(),
+                    accruedInterestEntity.getCustomerAccountIdentifier(),
+                    roundedAmount
+                );
+              }
+            }
+          });
+        }
+      }
+    });
+
+    return EventConstants.INTEREST_PAYED;
+  }
+
+  @Transactional
+  @CommandHandler(logStart = CommandLogLevel.DEBUG, logFinish = CommandLogLevel.DEBUG)
+  @EventEmitter(selectorName = EventConstants.SELECTOR_NAME, selectorValue = EventConstants.DIVIDEND_DISTRIBUTION)
+  public String process(final DividendDistributionCommand dividendDistributionCommand) {
+    final Optional<ProductDefinitionEntity> optionalProductDefinition =
+        this.productDefinitionRepository.findByIdentifier(dividendDistributionCommand.productDefinition());
+    if (optionalProductDefinition.isPresent()) {
+      final ProductDefinitionEntity productDefinitionEntity = optionalProductDefinition.get();
+      if (productDefinitionEntity.getActive()) {
+        final Rate rate = Rate.of(dividendDistributionCommand.rate());
+        final TermEntity term = this.termRepository.findByProductDefinition(productDefinitionEntity);
+        final List<String> dateRanges = this.dateRanges(dividendDistributionCommand.dueDate(), term.getInterestPayable());
+
+        final CurrencyEntity currency = this.currencyRepository.findByProductDefinition(productDefinitionEntity);
+        final CurrencyUnit currencyUnit = Monetary.getCurrency(currency.getCode());
+        final List<ProductInstanceEntity> productInstanceEntities =
+            this.productInstanceRepository.findByProductDefinition(productDefinitionEntity);
+        productInstanceEntities.forEach((ProductInstanceEntity productInstanceEntity) -> {
+          if (productInstanceEntity.getState().equals(ACTIVE)) {
+
+            final Account account =
+                this.accountingService.findAccount(productInstanceEntity.getAccountIdentifier());
+
+            final LocalDateTime startDate = dividendDistributionCommand.dueDate().plusDays(1).atStartOfDay();
+            final LocalDateTime now = LocalDateTime.now(Clock.systemUTC());
+
+            final String findCurrentEntries = DateConverter.toIsoString(startDate) + ".." + DateConverter.toIsoString(now);
+            final List<AccountEntry> currentAccountEntries =
+                this.accountingService.fetchEntries(account.getIdentifier(), findCurrentEntries, Sort.Direction.ASC.name());
+
+            final BalanceHolder balanceHolder;
+            if (currentAccountEntries.isEmpty()) {
+              balanceHolder = new BalanceHolder(account.getBalance());
+            } else {
+              final AccountEntry accountEntry = currentAccountEntries.get(0);
+              balanceHolder = new BalanceHolder(accountEntry.getBalance() - accountEntry.getAmount());
+            }
+
+            final DividendHolder dividendHolder = new DividendHolder(currencyUnit);
+            dateRanges.forEach(dateRange -> {
+              final List<AccountEntry> accountEntries =
+                  this.accountingService.fetchEntries(account.getIdentifier(), dateRange, Sort.Direction.DESC.name());
+              if (!accountEntries.isEmpty()) {
+                balanceHolder.setBalance(accountEntries.get(0).getBalance());
+              }
+
+              final Money currentBalance = Money.of(balanceHolder.getBalance(), currencyUnit);
+              dividendHolder.addAmount(
+                  AnnualPercentageYield
+                      .calculate(currentBalance, rate, 12)
+                      .divide(dividendDistributionCommand.dueDate().lengthOfYear()));
+            });
+
+            if (dividendHolder.getAmount().isGreaterThan(Money.of(0.00D, currencyUnit))) {
+
+              final String roundedAmount =
+                  BigDecimal.valueOf(dividendHolder.getAmount().getNumber().doubleValue())
+                      .setScale(2, BigDecimal.ROUND_HALF_EVEN).toString();
+
+              final JournalEntry cashToExpenseJournalEntry = new JournalEntry();
+              cashToExpenseJournalEntry.setTransactionIdentifier(RandomStringUtils.randomAlphanumeric(32));
+              cashToExpenseJournalEntry.setTransactionDate(DateConverter.toIsoString(now));
+              cashToExpenseJournalEntry.setTransactionType("INTR");
+              cashToExpenseJournalEntry.setClerk(UserContextHolder.checkedGetUser());
+              cashToExpenseJournalEntry.setNote("Dividend distribution.");
+
+              final Debtor cashDebtor = new Debtor();
+              cashDebtor.setAccountNumber(productDefinitionEntity.getCashAccountIdentifier());
+              cashDebtor.setAmount(roundedAmount);
+              cashToExpenseJournalEntry.setDebtors(Sets.newHashSet(cashDebtor));
+
+              final Creditor expenseCreditor = new Creditor();
+              expenseCreditor.setAccountNumber(productDefinitionEntity.getExpenseAccountIdentifier());
+              expenseCreditor.setAmount(roundedAmount);
+              cashToExpenseJournalEntry.setCreditors(Sets.newHashSet(expenseCreditor));
+
+              this.accountingService.post(cashToExpenseJournalEntry);
+
+              this.payoutInterest(
+                  productDefinitionEntity.getExpenseAccountIdentifier(),
+                  account.getIdentifier(),
+                  roundedAmount
+              );
+            }
+          }
+        });
+      }
+      final DividendDistributionEntity dividendDistributionEntity = new DividendDistributionEntity();
+
+      dividendDistributionEntity.setProductDefinition(productDefinitionEntity);
+      dividendDistributionEntity.setDueDate(Date.valueOf(dividendDistributionCommand.dueDate()));
+      dividendDistributionEntity.setRate(dividendDistributionCommand.rate());
+      dividendDistributionEntity.setCreatedOn(LocalDateTime.now(Clock.systemUTC()));
+      dividendDistributionEntity.setCreatedBy(UserContextHolder.checkedGetUser());
+
+      this.dividendDistributionRepository.save(dividendDistributionEntity);
+    }
+
+    return dividendDistributionCommand.productDefinition();
+  }
+
+  private int periodOfInterestPayable(final String interestPayable) {
+    switch (InterestPayable.valueOf(interestPayable)) {
+      case MONTHLY:
+        return 12;
+      case QUARTERLY:
+        return 4;
+      default:
+        return 1;
+    }
+  }
+
+  private boolean shouldPayInterest(final String interestPayable, final LocalDate date) {
+    switch (InterestPayable.valueOf(interestPayable)) {
+      case MONTHLY:
+        return date.equals(date.withDayOfMonth(date.lengthOfMonth()));
+      case QUARTERLY:
+        return date.equals(YearQuarter.from(date).atEndOfQuarter());
+      case ANNUALLY:
+        return date.getDayOfYear() == date.lengthOfYear();
+      default:
+        return false;
+    }
+  }
+
+  private List<String> dateRanges(final LocalDate dueDate, final String interestPayable) {
+    final int pastDays;
+    switch (InterestPayable.valueOf(interestPayable)) {
+      case MONTHLY:
+        pastDays = dueDate.lengthOfMonth();
+        break;
+      case QUARTERLY:
+        pastDays = YearQuarter.from(dueDate).lengthOfQuarter();
+        break;
+      default:
+        pastDays = dueDate.lengthOfYear();
+    }
+
+    return IntStream
+        .range(1, pastDays)
+        .mapToObj(value -> {
+          final LocalDate before = dueDate.minusDays(value);
+          return DateConverter.toIsoString(before) + ".." + DateConverter.toIsoString(dueDate.minusDays(value - 1));
+        }).collect(Collectors.toList());
+  }
+
+  private class BalanceHolder {
+    private Double balance;
+
+    private BalanceHolder(final Double balance) {
+      super();
+      this.balance = balance;
+    }
+
+    private Double getBalance() {
+      return this.balance;
+    }
+
+    private void setBalance(final Double balance) {
+      this.balance = balance;
+    }
+  }
+
+  private class DividendHolder {
+    private MonetaryAmount amount;
+
+    private DividendHolder(final CurrencyUnit currencyUnit) {
+      super();
+      this.amount = Money.of(0.00D, currencyUnit);
+    }
+
+    private void addAmount(final MonetaryAmount toAdd) {
+      this.amount = this.amount.add(toAdd);
+    }
+
+    private MonetaryAmount getAmount() {
+      return this.amount;
+    }
+  }
+
+  private boolean accruableProduct(final ProductDefinitionEntity productDefinitionEntity) {
+    return productDefinitionEntity.getActive()
+        && !productDefinitionEntity.getType().equals(Type.SHARE.name())
+        && productDefinitionEntity.getInterest() != null
+        && productDefinitionEntity.getInterest() > 0.00D;
+  }
+
+  private void payoutInterest(final String expenseAccount, final String customerAccount, final String amount) {
+    final JournalEntry expenseToCustomerJournalEntry = new JournalEntry();
+    expenseToCustomerJournalEntry.setTransactionIdentifier(RandomStringUtils.randomAlphanumeric(32));
+    expenseToCustomerJournalEntry.setTransactionDate(DateConverter.toIsoString(LocalDateTime.now(Clock.systemUTC())));
+    expenseToCustomerJournalEntry.setTransactionType("INTR");
+    expenseToCustomerJournalEntry.setClerk(UserContextHolder.checkedGetUser());
+    expenseToCustomerJournalEntry.setNote("Interest paid.");
+
+    final Debtor expenseDebtor = new Debtor();
+    expenseDebtor.setAccountNumber(expenseAccount);
+    expenseDebtor.setAmount(amount);
+    expenseToCustomerJournalEntry.setDebtors(Sets.newHashSet(expenseDebtor));
+
+    final Creditor customerCreditor = new Creditor();
+    customerCreditor.setAccountNumber(customerAccount);
+    customerCreditor.setAmount(amount);
+    expenseToCustomerJournalEntry.setCreditors(Sets.newHashSet(customerCreditor));
+
+    this.accountingService.post(expenseToCustomerJournalEntry);
+
+  }
+}
diff --git a/service/src/main/java/io/mifos/deposit/service/internal/mapper/DividendDistributionMapper.java b/service/src/main/java/io/mifos/deposit/service/internal/mapper/DividendDistributionMapper.java
new file mode 100644
index 0000000..7c01a8f
--- /dev/null
+++ b/service/src/main/java/io/mifos/deposit/service/internal/mapper/DividendDistributionMapper.java
@@ -0,0 +1,56 @@
+/*
+ * Copyright 2017 The Mifos Initiative.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package io.mifos.deposit.service.internal.mapper;
+
+import io.mifos.core.api.util.UserContextHolder;
+import io.mifos.core.lang.DateConverter;
+import io.mifos.deposit.api.v1.definition.domain.DividendDistribution;
+import io.mifos.deposit.service.internal.repository.DividendDistributionEntity;
+import io.mifos.deposit.service.internal.repository.ProductDefinitionEntity;
+
+import java.sql.Date;
+import java.time.Clock;
+import java.time.LocalDateTime;
+
+public class DividendDistributionMapper {
+
+  private DividendDistributionMapper() {
+    super();
+  }
+
+  public static DividendDistributionEntity map(final DividendDistribution dividendDistribution,
+                                               final ProductDefinitionEntity productDefinitionEntity) {
+    final DividendDistributionEntity dividendDistributionEntity = new DividendDistributionEntity();
+
+    dividendDistributionEntity.setProductDefinition(productDefinitionEntity);
+    final Date dueDate = Date.valueOf(DateConverter.dateFromIsoString(dividendDistribution.getDueDate()));
+    dividendDistributionEntity.setDueDate(dueDate);
+    dividendDistributionEntity.setRate(Double.valueOf(dividendDistribution.getDividendRate()));
+    dividendDistributionEntity.setCreatedOn(LocalDateTime.now(Clock.systemUTC()));
+    dividendDistributionEntity.setCreatedBy(UserContextHolder.checkedGetUser());
+
+    return dividendDistributionEntity;
+  }
+
+  public static DividendDistribution map(final DividendDistributionEntity dividendDistributionEntity) {
+    final DividendDistribution dividendDistribution = new DividendDistribution();
+
+    dividendDistribution.setDividendRate(dividendDistributionEntity.getRate().toString());
+    dividendDistribution.setDueDate(DateConverter.toIsoString(dividendDistributionEntity.getDueDate().toLocalDate()));
+
+    return dividendDistribution;
+  }
+}
diff --git a/service/src/main/java/io/mifos/deposit/service/internal/mapper/ProductDefinitionMapper.java b/service/src/main/java/io/mifos/deposit/service/internal/mapper/ProductDefinitionMapper.java
index 03165a7..f9fccd9 100644
--- a/service/src/main/java/io/mifos/deposit/service/internal/mapper/ProductDefinitionMapper.java
+++ b/service/src/main/java/io/mifos/deposit/service/internal/mapper/ProductDefinitionMapper.java
@@ -32,7 +32,9 @@ public class ProductDefinitionMapper {
     productDefinitionEntity.setDescription(productDefinition.getName());
     productDefinitionEntity.setMinimumBalance(productDefinition.getMinimumBalance());
     productDefinitionEntity.setEquityLedgerIdentifier(productDefinition.getEquityLedgerIdentifier());
+    productDefinitionEntity.setCashAccountIdentifier(productDefinition.getCashAccountIdentifier());
     productDefinitionEntity.setExpenseAccountIdentifier(productDefinition.getExpenseAccountIdentifier());
+    productDefinitionEntity.setAccrueAccountIdentifier(productDefinition.getAccrueAccountIdentifier());
     productDefinitionEntity.setInterest(productDefinition.getInterest());
     productDefinitionEntity.setFlexible(productDefinition.getFlexible());
 
@@ -47,7 +49,9 @@ public class ProductDefinitionMapper {
     productDefinition.setDescription(productDefinitionEntity.getName());
     productDefinition.setMinimumBalance(productDefinitionEntity.getMinimumBalance());
     productDefinition.setEquityLedgerIdentifier(productDefinitionEntity.getEquityLedgerIdentifier());
+    productDefinition.setCashAccountIdentifier(productDefinitionEntity.getCashAccountIdentifier());
     productDefinition.setExpenseAccountIdentifier(productDefinitionEntity.getExpenseAccountIdentifier());
+    productDefinition.setAccrueAccountIdentifier(productDefinitionEntity.getAccrueAccountIdentifier());
     productDefinition.setInterest(productDefinitionEntity.getInterest());
     productDefinition.setFlexible(productDefinitionEntity.getFlexible());
     productDefinition.setActive(productDefinitionEntity.getActive());
diff --git a/service/src/main/java/io/mifos/deposit/service/internal/repository/AccruedInterestEntity.java b/service/src/main/java/io/mifos/deposit/service/internal/repository/AccruedInterestEntity.java
new file mode 100644
index 0000000..dd0a60d
--- /dev/null
+++ b/service/src/main/java/io/mifos/deposit/service/internal/repository/AccruedInterestEntity.java
@@ -0,0 +1,75 @@
+/*
+ * Copyright 2017 The Mifos Initiative.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package io.mifos.deposit.service.internal.repository;
+
+import javax.persistence.Column;
+import javax.persistence.Entity;
+import javax.persistence.GeneratedValue;
+import javax.persistence.GenerationType;
+import javax.persistence.Id;
+import javax.persistence.Table;
+
+@Entity
+@Table(name = "shed_accrued_interests")
+public class AccruedInterestEntity {
+
+  @Id
+  @GeneratedValue(strategy = GenerationType.IDENTITY)
+  @Column(name = "id")
+  private Long id;
+  @Column(name = "accrue_account_identifier", nullable = false)
+  private String accrueAccountIdentifier;
+  @Column(name = "customer_account_identifier", nullable = false)
+  private String customerAccountIdentifier;
+  @Column(name = "amount", nullable = false)
+  private Double amount;
+
+  public AccruedInterestEntity() {
+    super();
+  }
+
+  public Long getId() {
+    return this.id;
+  }
+
+  public void setId(final Long id) {
+    this.id = id;
+  }
+
+  public String getAccrueAccountIdentifier() {
+    return this.accrueAccountIdentifier;
+  }
+
+  public void setAccrueAccountIdentifier(final String accrueAccountIdentifier) {
+    this.accrueAccountIdentifier = accrueAccountIdentifier;
+  }
+
+  public String getCustomerAccountIdentifier() {
+    return this.customerAccountIdentifier;
+  }
+
+  public void setCustomerAccountIdentifier(final String customerAccountIdentifier) {
+    this.customerAccountIdentifier = customerAccountIdentifier;
+  }
+
+  public Double getAmount() {
+    return this.amount;
+  }
+
+  public void setAmount(final Double amount) {
+    this.amount = amount;
+  }
+}
diff --git a/component-test/src/main/java/io/mifos/deposit/TestSuite.java b/service/src/main/java/io/mifos/deposit/service/internal/repository/AccruedInterestRepository.java
similarity index 59%
copy from component-test/src/main/java/io/mifos/deposit/TestSuite.java
copy to service/src/main/java/io/mifos/deposit/service/internal/repository/AccruedInterestRepository.java
index abb4cc2..1a12de1 100644
--- a/component-test/src/main/java/io/mifos/deposit/TestSuite.java
+++ b/service/src/main/java/io/mifos/deposit/service/internal/repository/AccruedInterestRepository.java
@@ -13,19 +13,15 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-package io.mifos.deposit;
+package io.mifos.deposit.service.internal.repository;
 
-import org.junit.runner.RunWith;
-import org.junit.runners.Suite;
+import org.springframework.data.jpa.repository.JpaRepository;
+import org.springframework.stereotype.Repository;
 
-/**
- * @author Myrle Krantz
- */
-@RunWith(Suite.class)
-@Suite.SuiteClasses({
-    TestActions.class,
-    TestProductDefinition.class,
-    TestProductInstance.class,
-})
-public class TestSuite extends SuiteTestEnvironment {
+import java.util.Optional;
+
+@Repository
+public interface AccruedInterestRepository extends JpaRepository<AccruedInterestEntity, Long> {
+
+  Optional<AccruedInterestEntity> findByCustomerAccountIdentifier(final String customerAccountIdentifier);
 }
diff --git a/service/src/main/java/io/mifos/deposit/service/internal/repository/DividendDistributionEntity.java b/service/src/main/java/io/mifos/deposit/service/internal/repository/DividendDistributionEntity.java
new file mode 100644
index 0000000..384e09e
--- /dev/null
+++ b/service/src/main/java/io/mifos/deposit/service/internal/repository/DividendDistributionEntity.java
@@ -0,0 +1,106 @@
+/*
+ * Copyright 2017 The Mifos Initiative.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package io.mifos.deposit.service.internal.repository;
+
+import io.mifos.core.mariadb.util.LocalDateTimeConverter;
+
+import javax.persistence.CascadeType;
+import javax.persistence.Column;
+import javax.persistence.Convert;
+import javax.persistence.Entity;
+import javax.persistence.FetchType;
+import javax.persistence.GeneratedValue;
+import javax.persistence.GenerationType;
+import javax.persistence.Id;
+import javax.persistence.JoinColumn;
+import javax.persistence.ManyToOne;
+import javax.persistence.Table;
+import java.sql.Date;
+import java.time.LocalDateTime;
+
+@Entity
+@Table(name = "shed_dividend_distributions")
+public class DividendDistributionEntity {
+
+  @Id
+  @GeneratedValue(strategy = GenerationType.IDENTITY)
+  @Column(name = "id", nullable = false)
+  private Long id;
+  @ManyToOne(fetch = FetchType.EAGER, optional = false, cascade = CascadeType.ALL)
+  @JoinColumn(name = "product_definition_id", nullable = false)
+  private ProductDefinitionEntity productDefinition;
+  @Column(name = "due_date")
+  private Date dueDate;
+  @Column(name = "rate")
+  private Double rate;
+  @Column(name = "created_by", nullable = false, length = 32)
+  private String createdBy;
+  @Convert(converter = LocalDateTimeConverter.class)
+  @Column(name = "created_on", nullable = false)
+  private LocalDateTime createdOn;
+
+  public DividendDistributionEntity() {
+    super();
+  }
+
+  public Long getId() {
+    return this.id;
+  }
+
+  public void setId(final Long id) {
+    this.id = id;
+  }
+
+  public ProductDefinitionEntity getProductDefinition() {
+    return this.productDefinition;
+  }
+
+  public void setProductDefinition(final ProductDefinitionEntity productDefinition) {
+    this.productDefinition = productDefinition;
+  }
+
+  public Date getDueDate() {
+    return this.dueDate;
+  }
+
+  public void setDueDate(final Date dueDate) {
+    this.dueDate = dueDate;
+  }
+
+  public Double getRate() {
+    return this.rate;
+  }
+
+  public void setRate(final Double rate) {
+    this.rate = rate;
+  }
+
+  public String getCreatedBy() {
+    return this.createdBy;
+  }
+
+  public void setCreatedBy(final String createdBy) {
+    this.createdBy = createdBy;
+  }
+
+  public LocalDateTime getCreatedOn() {
+    return this.createdOn;
+  }
+
+  public void setCreatedOn(final LocalDateTime createdOn) {
+    this.createdOn = createdOn;
+  }
+}
diff --git a/component-test/src/main/java/io/mifos/deposit/TestSuite.java b/service/src/main/java/io/mifos/deposit/service/internal/repository/DividendDistributionRepository.java
similarity index 61%
copy from component-test/src/main/java/io/mifos/deposit/TestSuite.java
copy to service/src/main/java/io/mifos/deposit/service/internal/repository/DividendDistributionRepository.java
index abb4cc2..754c7c4 100644
--- a/component-test/src/main/java/io/mifos/deposit/TestSuite.java
+++ b/service/src/main/java/io/mifos/deposit/service/internal/repository/DividendDistributionRepository.java
@@ -13,19 +13,13 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-package io.mifos.deposit;
+package io.mifos.deposit.service.internal.repository;
 
-import org.junit.runner.RunWith;
-import org.junit.runners.Suite;
+import org.springframework.data.jpa.repository.JpaRepository;
 
-/**
- * @author Myrle Krantz
- */
-@RunWith(Suite.class)
-@Suite.SuiteClasses({
-    TestActions.class,
-    TestProductDefinition.class,
-    TestProductInstance.class,
-})
-public class TestSuite extends SuiteTestEnvironment {
+import java.util.List;
+
+public interface DividendDistributionRepository extends JpaRepository<DividendDistributionEntity, Long> {
+
+  List<DividendDistributionEntity> findByProductDefinitionOrderByDueDateAsc(final ProductDefinitionEntity productDefinitionEntity);
 }
diff --git a/service/src/main/java/io/mifos/deposit/service/internal/repository/ProductDefinitionEntity.java b/service/src/main/java/io/mifos/deposit/service/internal/repository/ProductDefinitionEntity.java
index 802b067..37b5e93 100644
--- a/service/src/main/java/io/mifos/deposit/service/internal/repository/ProductDefinitionEntity.java
+++ b/service/src/main/java/io/mifos/deposit/service/internal/repository/ProductDefinitionEntity.java
@@ -46,8 +46,12 @@ public class ProductDefinitionEntity {
   private Double minimumBalance;
   @Column(name = "equity_ledger_identifier", nullable = false)
   private String equityLedgerIdentifier;
+  @Column(name = "cash_account_identifier", nullable = false)
+  private String cashAccountIdentifier;
   @Column(name = "expense_account_identifier", nullable = false)
   private String expenseAccountIdentifier;
+  @Column(name = "accrue_account_identifier", nullable = true)
+  private String accrueAccountIdentifier;
   @Column(name = "interest", nullable = true)
   private Double interest;
   @Column(name = "is_flexible", nullable = false)
@@ -125,6 +129,14 @@ public class ProductDefinitionEntity {
     this.equityLedgerIdentifier = equityLedgerIdentifier;
   }
 
+  public String getCashAccountIdentifier() {
+    return this.cashAccountIdentifier;
+  }
+
+  public void setCashAccountIdentifier(final String cashAccountIdentifier) {
+    this.cashAccountIdentifier = cashAccountIdentifier;
+  }
+
   public String getExpenseAccountIdentifier() {
     return this.expenseAccountIdentifier;
   }
@@ -133,6 +145,14 @@ public class ProductDefinitionEntity {
     this.expenseAccountIdentifier = expenseAccountIdentifier;
   }
 
+  public String getAccrueAccountIdentifier() {
+    return this.accrueAccountIdentifier;
+  }
+
+  public void setAccrueAccountIdentifier(final String accrueAccountIdentifier) {
+    this.accrueAccountIdentifier = accrueAccountIdentifier;
+  }
+
   public Double getInterest() {
     return this.interest;
   }
diff --git a/service/src/main/java/io/mifos/deposit/service/internal/repository/ProductInstanceRepository.java b/service/src/main/java/io/mifos/deposit/service/internal/repository/ProductInstanceRepository.java
index 0091204..cad0e15 100644
--- a/service/src/main/java/io/mifos/deposit/service/internal/repository/ProductInstanceRepository.java
+++ b/service/src/main/java/io/mifos/deposit/service/internal/repository/ProductInstanceRepository.java
@@ -26,8 +26,5 @@ public interface ProductInstanceRepository extends JpaRepository<ProductInstance
 
   List<ProductInstanceEntity> findByProductDefinition(final ProductDefinitionEntity productDefinitionEntity);
 
-  List<ProductInstanceEntity> findByProductDefinitionAndCustomerIdentifier(
-      final ProductDefinitionEntity productDefinitionEntity, final String customerIdentifier);
-
   Optional<ProductInstanceEntity> findByAccountIdentifier(final String identifier);
 }
diff --git a/service/src/main/java/io/mifos/deposit/service/internal/service/ProductDefinitionService.java b/service/src/main/java/io/mifos/deposit/service/internal/service/ProductDefinitionService.java
index 7430850..53d394e 100644
--- a/service/src/main/java/io/mifos/deposit/service/internal/service/ProductDefinitionService.java
+++ b/service/src/main/java/io/mifos/deposit/service/internal/service/ProductDefinitionService.java
@@ -15,17 +15,21 @@
  */
 package io.mifos.deposit.service.internal.service;
 
+import io.mifos.core.lang.ServiceException;
+import io.mifos.deposit.api.v1.definition.domain.DividendDistribution;
 import io.mifos.deposit.api.v1.definition.domain.ProductDefinition;
 import io.mifos.deposit.api.v1.definition.domain.ProductDefinitionCommand;
 import io.mifos.deposit.service.ServiceConstants;
 import io.mifos.deposit.service.internal.mapper.ChargeMapper;
 import io.mifos.deposit.service.internal.mapper.CurrencyMapper;
+import io.mifos.deposit.service.internal.mapper.DividendDistributionMapper;
 import io.mifos.deposit.service.internal.mapper.ProductDefinitionCommandMapper;
 import io.mifos.deposit.service.internal.mapper.ProductDefinitionMapper;
 import io.mifos.deposit.service.internal.mapper.TermMapper;
 import io.mifos.deposit.service.internal.repository.ActionRepository;
 import io.mifos.deposit.service.internal.repository.ChargeRepository;
 import io.mifos.deposit.service.internal.repository.CurrencyRepository;
+import io.mifos.deposit.service.internal.repository.DividendDistributionRepository;
 import io.mifos.deposit.service.internal.repository.ProductDefinitionCommandRepository;
 import io.mifos.deposit.service.internal.repository.ProductDefinitionEntity;
 import io.mifos.deposit.service.internal.repository.ProductDefinitionRepository;
@@ -50,6 +54,7 @@ public class ProductDefinitionService {
   private final ChargeRepository chargeRepository;
   private final CurrencyRepository currencyRepository;
   private final TermRepository termRepository;
+  private final DividendDistributionRepository dividendDistributionRepository;
 
   @Autowired
   public ProductDefinitionService(@Qualifier(ServiceConstants.LOGGER_NAME) final Logger logger,
@@ -58,7 +63,8 @@ public class ProductDefinitionService {
                                   final ActionRepository actionRepository,
                                   final ChargeRepository chargeRepository,
                                   final CurrencyRepository currencyRepository,
-                                  final TermRepository termRepository) {
+                                  final TermRepository termRepository,
+                                  final DividendDistributionRepository dividendDistributionRepository) {
     super();
     this.logger = logger;
     this.productDefinitionRepository = productDefinitionRepository;
@@ -67,6 +73,7 @@ public class ProductDefinitionService {
     this.chargeRepository = chargeRepository;
     this.currencyRepository = currencyRepository;
     this.termRepository = termRepository;
+    this.dividendDistributionRepository = dividendDistributionRepository;
   }
 
   public List<ProductDefinition> fetchProductDefinitions() {
@@ -106,4 +113,16 @@ public class ProductDefinitionService {
             .collect(Collectors.toList()))
         .orElseGet(Collections::emptyList);
   }
+
+  public List<DividendDistribution> fetchDividendDistributions(final String identifier) {
+    final Optional<ProductDefinitionEntity> optionalProductDefinition =
+        this.productDefinitionRepository.findByIdentifier(identifier);
+    if (optionalProductDefinition.isPresent()) {
+      return this.dividendDistributionRepository.findByProductDefinitionOrderByDueDateAsc(optionalProductDefinition.get())
+          .stream().map(DividendDistributionMapper::map)
+          .collect(Collectors.toList());
+    } else {
+      throw ServiceException.notFound("Product definition {0} not found", identifier);
+    }
+  }
 }
diff --git a/service/src/main/java/io/mifos/deposit/service/internal/service/helper/AccountingService.java b/service/src/main/java/io/mifos/deposit/service/internal/service/helper/AccountingService.java
index 6110e23..2229a03 100644
--- a/service/src/main/java/io/mifos/deposit/service/internal/service/helper/AccountingService.java
+++ b/service/src/main/java/io/mifos/deposit/service/internal/service/helper/AccountingService.java
@@ -19,6 +19,8 @@ import io.mifos.accounting.api.v1.client.AccountNotFoundException;
 import io.mifos.accounting.api.v1.client.LedgerManager;
 import io.mifos.accounting.api.v1.client.LedgerNotFoundException;
 import io.mifos.accounting.api.v1.domain.Account;
+import io.mifos.accounting.api.v1.domain.AccountEntry;
+import io.mifos.accounting.api.v1.domain.JournalEntry;
 import io.mifos.accounting.api.v1.domain.Ledger;
 import io.mifos.core.lang.ServiceException;
 import io.mifos.deposit.service.ServiceConstants;
@@ -32,6 +34,7 @@ import org.springframework.stereotype.Service;
 
 import java.util.Arrays;
 import java.util.HashSet;
+import java.util.List;
 
 @Service
 public class AccountingService {
@@ -86,4 +89,14 @@ public class AccountingService {
   public void updateAccount(final Account account) {
     this.ledgerManager.modifyAccount(account.getIdentifier(), account);
   }
+
+  public List<AccountEntry> fetchEntries(final String identifier, final String dateRange, final String direction) {
+    return this.ledgerManager
+        .fetchAccountEntries(identifier, dateRange, null, 0, 1, "transactionDate", direction)
+        .getAccountEntries();
+  }
+
+  public void post(final JournalEntry journalEntry) {
+    this.ledgerManager.createJournalEntry(journalEntry);
+  }
 }
diff --git a/service/src/main/java/io/mifos/deposit/service/rest/BeatListenerRestController.java b/service/src/main/java/io/mifos/deposit/service/rest/BeatListenerRestController.java
new file mode 100644
index 0000000..61a586f
--- /dev/null
+++ b/service/src/main/java/io/mifos/deposit/service/rest/BeatListenerRestController.java
@@ -0,0 +1,67 @@
+/*
+ * Copyright 2017 The Mifos Initiative.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package io.mifos.deposit.service.rest;
+
+import io.mifos.anubis.annotation.AcceptedTokenType;
+import io.mifos.anubis.annotation.Permittable;
+import io.mifos.core.command.gateway.CommandGateway;
+import io.mifos.deposit.service.ServiceConstants;
+import io.mifos.deposit.service.internal.command.BeatListenerCommand;
+import io.mifos.rhythm.spi.v1.client.BeatListener;
+import io.mifos.rhythm.spi.v1.domain.BeatPublish;
+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.RequestBody;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RequestMethod;
+import org.springframework.web.bind.annotation.ResponseBody;
+import org.springframework.web.bind.annotation.RestController;
+
+import javax.validation.Valid;
+
+@RestController
+@RequestMapping(BeatListener.PUBLISH_BEAT_PATH)
+public class BeatListenerRestController {
+
+  private final static String BEAT_PUBLISH_PERMISSION = "deposit__v1__khepri";
+
+  private final Logger logger;
+  private final CommandGateway commandGateway;
+
+  @Autowired
+  public BeatListenerRestController(@Qualifier(ServiceConstants.LOGGER_NAME) final Logger logger,
+                                    final CommandGateway commandGateway) {
+    super();
+    this.logger = logger;
+    this.commandGateway = commandGateway;
+  }
+
+  @Permittable(value = AcceptedTokenType.TENANT, groupId = BEAT_PUBLISH_PERMISSION)
+  @RequestMapping(
+      method = RequestMethod.POST,
+      consumes = MediaType.APPLICATION_JSON_VALUE,
+      produces = MediaType.APPLICATION_JSON_VALUE
+  )
+  public @ResponseBody
+  ResponseEntity<Void> publishBeat(@RequestBody @Valid final BeatPublish beatPublish)
+  {
+    this.commandGateway.process(new BeatListenerCommand(beatPublish));
+    return ResponseEntity.accepted().build();
+  }
+}
diff --git a/service/src/main/java/io/mifos/deposit/service/rest/ProductDefinitionRestController.java b/service/src/main/java/io/mifos/deposit/service/rest/ProductDefinitionRestController.java
index 05a6a43..7c8f875 100644
--- a/service/src/main/java/io/mifos/deposit/service/rest/ProductDefinitionRestController.java
+++ b/service/src/main/java/io/mifos/deposit/service/rest/ProductDefinitionRestController.java
@@ -18,16 +18,20 @@ package io.mifos.deposit.service.rest;
 import io.mifos.anubis.annotation.AcceptedTokenType;
 import io.mifos.anubis.annotation.Permittable;
 import io.mifos.core.command.gateway.CommandGateway;
+import io.mifos.core.lang.DateConverter;
 import io.mifos.core.lang.ServiceException;
 import io.mifos.deposit.api.v1.PermittableGroupIds;
+import io.mifos.deposit.api.v1.definition.domain.DividendDistribution;
 import io.mifos.deposit.api.v1.definition.domain.ProductDefinition;
 import io.mifos.deposit.api.v1.definition.domain.ProductDefinitionCommand;
+import io.mifos.deposit.api.v1.domain.Type;
 import io.mifos.deposit.api.v1.instance.domain.ProductInstance;
 import io.mifos.deposit.service.ServiceConstants;
 import io.mifos.deposit.service.internal.command.ActivateProductDefinitionCommand;
 import io.mifos.deposit.service.internal.command.CreateProductDefinitionCommand;
 import io.mifos.deposit.service.internal.command.DeactivateProductDefinitionCommand;
 import io.mifos.deposit.service.internal.command.DeleteProductDefinitionCommand;
+import io.mifos.deposit.service.internal.command.DividendDistributionCommand;
 import io.mifos.deposit.service.internal.command.UpdateProductDefinitionCommand;
 import io.mifos.deposit.service.internal.service.ProductDefinitionService;
 import io.mifos.deposit.service.internal.service.ProductInstanceService;
@@ -44,6 +48,7 @@ import org.springframework.web.bind.annotation.ResponseBody;
 import org.springframework.web.bind.annotation.RestController;
 
 import javax.validation.Valid;
+import java.time.LocalDate;
 import java.util.List;
 import java.util.Optional;
 
@@ -77,6 +82,11 @@ public class ProductDefinitionRestController {
   )
   @ResponseBody
   public ResponseEntity<Void> create(@RequestBody @Valid final ProductDefinition productDefinition) {
+    if (!productDefinition.getType().equals(Type.SHARE.name())
+        && productDefinition.getAccrueAccountIdentifier() == null) {
+      throw ServiceException.badRequest("Accrue account must be given.");
+    }
+
     if (this.productDefinitionService.findProductDefinition(productDefinition.getIdentifier()).isPresent()) {
       throw ServiceException.conflict("Product definition{0} already exists.", productDefinition.getIdentifier());
     } else {
@@ -227,4 +237,46 @@ public class ProductDefinitionRestController {
 
     return ResponseEntity.accepted().build();
   }
+
+  @Permittable(value = AcceptedTokenType.TENANT, groupId = PermittableGroupIds.DEFINITION_MANAGEMENT)
+  @RequestMapping(
+      value = "/{identifier}/dividends",
+      method = RequestMethod.POST,
+      consumes = MediaType.APPLICATION_JSON_VALUE,
+      produces = MediaType.APPLICATION_JSON_VALUE
+  )
+  @ResponseBody
+  ResponseEntity<Void> dividendDistribution(@PathVariable("identifier") final String identifier,
+                                            @RequestBody @Valid final DividendDistribution dividendDistribution) {
+    final Optional<ProductDefinition> optionalProductDefinition = this.productDefinitionService.findProductDefinition(identifier);
+    if (!optionalProductDefinition.isPresent()) {
+      throw ServiceException.notFound("Product definition {0} not found", identifier);
+    } else {
+      final ProductDefinition productDefinition = optionalProductDefinition.get();
+      if (!productDefinition.getType().equals(Type.SHARE.name())) {
+        throw ServiceException.badRequest("Product definition {0} is not a share product.", identifier);
+      }
+    }
+
+    final LocalDate dueDate = DateConverter.dateFromIsoString(dividendDistribution.getDueDate());
+    final Double amount = Double.valueOf(dividendDistribution.getDividendRate());
+
+    this.commandGateway.process(new DividendDistributionCommand(identifier, dueDate, amount));
+
+    return ResponseEntity.accepted().build();
+  }
+
+  @Permittable(value = AcceptedTokenType.TENANT, groupId = PermittableGroupIds.DEFINITION_MANAGEMENT)
+  @RequestMapping(
+      value = "/{identifier}/dividends",
+      method = RequestMethod.GET,
+      consumes = MediaType.ALL_VALUE,
+      produces = MediaType.APPLICATION_JSON_VALUE
+  )
+  @ResponseBody
+  ResponseEntity<List<DividendDistribution>> fetchDividendDistributions(@PathVariable("identifier") final String identifier) {
+    return ResponseEntity.ok(
+        this.productDefinitionService.fetchDividendDistributions(identifier)
+    );
+  }
 }
diff --git a/service/src/main/resources/db/migrations/mariadb/V5__interest_calculation.sql b/service/src/main/resources/db/migrations/mariadb/V5__interest_calculation.sql
new file mode 100644
index 0000000..786b24a
--- /dev/null
+++ b/service/src/main/resources/db/migrations/mariadb/V5__interest_calculation.sql
@@ -0,0 +1,40 @@
+--
+-- Copyright 2017 The Mifos Initiative.
+--
+-- Licensed under the Apache License, Version 2.0 (the "License");
+-- you may not use this file except in compliance with the License.
+-- You may obtain a copy of the License at
+--
+--    http://www.apache.org/licenses/LICENSE-2.0
+--
+-- Unless required by applicable law or agreed to in writing, software
+-- distributed under the License is distributed on an "AS IS" BASIS,
+-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+-- See the License for the specific language governing permissions and
+-- limitations under the License.
+--
+
+ALTER TABLE shed_product_definitions ADD COLUMN cash_account_identifier VARCHAR(34) NULL;
+ALTER TABLE shed_product_definitions ADD COLUMN accrue_account_identifier VARCHAR(34) NULL;
+ALTER TABLE shed_product_definitions MODIFY COLUMN equity_ledger_identifier VARCHAR(34) NOT NULL;
+ALTER TABLE shed_product_definitions MODIFY COLUMN expense_account_identifier VARCHAR(34) NOT NULL;
+
+CREATE TABLE shed_accrued_interests (
+  id                          BIGINT         NOT NULL AUTO_INCREMENT,
+  accrue_account_identifier   VARCHAR(34)    NOT NULL,
+  customer_account_identifier VARCHAR(34)    NOT NULL,
+  amount                      NUMERIC(15, 5) NOT NULL,
+  CONSTRAINT shed_accrued_interests_pk PRIMARY KEY (id),
+  CONSTRAINT shed_accrued_interests_uq UNIQUE (accrue_account_identifier, customer_account_identifier)
+);
+
+CREATE TABLE shed_dividend_distributions (
+  id                    BIGINT         NOT NULL AUTO_INCREMENT,
+  product_definition_id BIGINT         NOT NULL,
+  due_date              DATE           NOT NULL,
+  rate                  NUMERIC(15, 5) NOT NULL,
+  created_on            TIMESTAMP(3)   NOT NULL,
+  created_by            VARCHAR(32)    NOT NULL,
+  CONSTRAINT shed_dividend_distributions PRIMARY KEY (id),
+  CONSTRAINT shed_div_dist_prod_def_fk FOREIGN KEY (product_definition_id) REFERENCES shed_product_definitions (id)
+);
diff --git a/service/src/main/resources/logback.xml b/service/src/main/resources/logback.xml
index 25305f9..194618e 100644
--- a/service/src/main/resources/logback.xml
+++ b/service/src/main/resources/logback.xml
@@ -33,11 +33,11 @@
         </encoder>
     </appender>
 
-    <logger name="com" level="WARN">
+    <logger name="com" level="INFO">
         <appender-ref ref="STDOUT" />
     </logger>
 
-    <logger name="org" level="WARN">
+    <logger name="org" level="INFO">
         <appender-ref ref="STDOUT" />
     </logger>
 
@@ -45,11 +45,11 @@
         <appender-ref ref="STDOUT" />
     </logger>
 
-    <logger name="net" level="WARN">
+    <logger name="net" level="INFO">
         <appender-ref ref="STDOUT" />
     </logger>
 
-    <root level="INFO">
+    <root level="DEBUG">
         <appender-ref ref="FILE"/>
     </root>
 </configuration>
\ No newline at end of file
diff --git a/shared.gradle b/shared.gradle
index 8d20f5f..a456f78 100644
--- a/shared.gradle
+++ b/shared.gradle
@@ -11,6 +11,8 @@ ext.versions = [
         frameworktest     : '0.1.0-BUILD-SNAPSHOT',
         frameworkanubis   : '0.1.0-BUILD-SNAPSHOT',
         frameworkledger   : '0.1.0-BUILD-SNAPSHOT',
+        frameworkrhythm   : '0.1.0-BUILD-SNAPSHOT',
+        javamoneylib      : '0.9-SNAPSHOT',
         validator         : '5.3.0.Final'
 ]
 

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

[fineract-cn-deposit-account-management] 22/26: Merge pull request #8 from markusgeiss/develop

Posted by my...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

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

commit 102f0d7de9cead9a398a58b55bb42f00c26300c9
Merge: 5be1dbf 9680ecb
Author: Markus Geiss <ma...@kuelap.io>
AuthorDate: Tue Oct 24 13:02:27 2017 +0200

    Merge pull request #8 from markusgeiss/develop
    
    added time zone 'Z' handling to ease UI usage

 .../src/main/java/io/mifos/deposit/TestProductInstance.java   |  2 +-
 .../service/internal/mapper/ProductInstanceMapper.java        | 11 +++++++++--
 2 files changed, 10 insertions(+), 3 deletions(-)

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

[fineract-cn-deposit-account-management] 19/26: added opened on and last transaction date to product instance

Posted by my...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

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

commit 11a939cecdce8cccc8656b1e37a5c8cad4e79df3
Author: mgeiss <mg...@mifos.org>
AuthorDate: Sun Oct 22 09:00:35 2017 +0200

    added opened on and last transaction date to product instance
---
 .../io/mifos/deposit/api/v1/EventConstants.java    |  1 +
 .../api/v1/instance/domain/ProductInstance.java    | 18 +++++++++
 .../java/io/mifos/deposit/TestProductInstance.java | 47 +++++++++++++++++++++-
 .../command/TransactionProcessedCommand.java       | 30 ++++++++++++++
 .../command/handler/ProductInstanceAggregate.java  | 22 ++++++++++
 .../internal/mapper/ProductInstanceMapper.java     | 17 ++++++++
 .../internal/repository/ProductInstanceEntity.java | 24 +++++++++++
 .../rest/ProductInstanceRestController.java        |  4 ++
 ..._add_opened_on_last_transaction_to_instance.sql | 20 +++++++++
 9 files changed, 182 insertions(+), 1 deletion(-)

diff --git a/api/src/main/java/io/mifos/deposit/api/v1/EventConstants.java b/api/src/main/java/io/mifos/deposit/api/v1/EventConstants.java
index 7e63d55..a10c48f 100644
--- a/api/src/main/java/io/mifos/deposit/api/v1/EventConstants.java
+++ b/api/src/main/java/io/mifos/deposit/api/v1/EventConstants.java
@@ -49,6 +49,7 @@ public interface EventConstants {
 
   String ACTIVATE_PRODUCT_INSTANCE_COMMAND = "ACTIVATE";
   String CLOSE_PRODUCT_INSTANCE_COMMAND = "CLOSE";
+  String PRODUCT_INSTANCE_TRANSACTION = "TRANSACTION";
 
   String DIVIDEND_DISTRIBUTION = "dividend-distribution";
   String SELECTOR_DIVIDEND_DISTRIBUTION = SELECTOR_NAME + " = '" + DIVIDEND_DISTRIBUTION + "'";
diff --git a/api/src/main/java/io/mifos/deposit/api/v1/instance/domain/ProductInstance.java b/api/src/main/java/io/mifos/deposit/api/v1/instance/domain/ProductInstance.java
index 348543d..a37be73 100644
--- a/api/src/main/java/io/mifos/deposit/api/v1/instance/domain/ProductInstance.java
+++ b/api/src/main/java/io/mifos/deposit/api/v1/instance/domain/ProductInstance.java
@@ -28,6 +28,8 @@ public class ProductInstance {
   @ValidIdentifier(maxLength = 34, optional = true)
   private String accountIdentifier;
   private Set<String> beneficiaries;
+  private String openedOn;
+  private String lastTransactionDate;
   private String state;
   private Double balance;
 
@@ -67,6 +69,22 @@ public class ProductInstance {
     this.beneficiaries = beneficiaries;
   }
 
+  public String getOpenedOn() {
+    return this.openedOn;
+  }
+
+  public void setOpenedOn(final String openedOn) {
+    this.openedOn = openedOn;
+  }
+
+  public String getLastTransactionDate() {
+    return this.lastTransactionDate;
+  }
+
+  public void setLastTransactionDate(final String lastTransactionDate) {
+    this.lastTransactionDate = lastTransactionDate;
+  }
+
   public String getState() {
     return this.state;
   }
diff --git a/component-test/src/main/java/io/mifos/deposit/TestProductInstance.java b/component-test/src/main/java/io/mifos/deposit/TestProductInstance.java
index cb875e5..6018d94 100644
--- a/component-test/src/main/java/io/mifos/deposit/TestProductInstance.java
+++ b/component-test/src/main/java/io/mifos/deposit/TestProductInstance.java
@@ -90,17 +90,21 @@ public class TestProductInstance extends AbstractDepositAccountManagementTest {
     Assert.assertTrue(
         super.eventRecorder.wait(EventConstants.ACTIVATE_PRODUCT_INSTANCE,
             foundProductInstance.getAccountIdentifier()));
+
+    final ProductInstance activatedProductInstance = super.depositAccountManager.findProductInstance(foundProductInstance.getAccountIdentifier());
+    Assert.assertNotNull(activatedProductInstance.getOpenedOn());
   }
 
   @Test
   public void shouldCloseProductInstance() throws Exception {
     final ProductDefinition productDefinition = Fixture.productDefinition();
-
     super.depositAccountManager.create(productDefinition);
 
     super.eventRecorder.wait(EventConstants.POST_PRODUCT_DEFINITION, productDefinition.getIdentifier());
 
     final ProductInstance productInstance = Fixture.productInstance(productDefinition.getIdentifier());
+    final String openedOn = "2013-05-08Z";
+    productInstance.setOpenedOn(openedOn);
 
     super.depositAccountManager.create(productInstance);
 
@@ -110,6 +114,7 @@ public class TestProductInstance extends AbstractDepositAccountManagementTest {
     Assert.assertNotNull(productInstances);
     Assert.assertEquals(1, productInstances.size());
     final ProductInstance foundProductInstance = productInstances.get(0);
+    Assert.assertEquals(openedOn, foundProductInstance.getOpenedOn());
 
     super.depositAccountManager.postProductInstanceCommand(
         foundProductInstance.getAccountIdentifier(), EventConstants.CLOSE_PRODUCT_INSTANCE_COMMAND);
@@ -330,4 +335,44 @@ public class TestProductInstance extends AbstractDepositAccountManagementTest {
 
     Assert.assertTrue(expectedTransactionTypes.isEmpty());
   }
+
+  @Test
+  public void shouldAddTransactionDateProductInstance() throws Exception {
+    final ProductDefinition productDefinition = Fixture.productDefinition();
+
+    super.depositAccountManager.create(productDefinition);
+
+    super.eventRecorder.wait(EventConstants.POST_PRODUCT_DEFINITION, productDefinition.getIdentifier());
+
+    final ProductInstance productInstance = Fixture.productInstance(productDefinition.getIdentifier());
+
+    super.depositAccountManager.create(productInstance);
+
+    super.eventRecorder.wait(EventConstants.POST_PRODUCT_INSTANCE, productInstance.getCustomerIdentifier());
+
+    final List<ProductInstance> productInstances = super.depositAccountManager.findProductInstances(productDefinition.getIdentifier());
+    Assert.assertNotNull(productInstances);
+    Assert.assertEquals(1, productInstances.size());
+    final ProductInstance foundProductInstance = productInstances.get(0);
+
+    super.depositAccountManager.postProductInstanceCommand(
+        foundProductInstance.getAccountIdentifier(), EventConstants.ACTIVATE_PRODUCT_INSTANCE_COMMAND);
+
+    Assert.assertTrue(
+        super.eventRecorder.wait(EventConstants.ACTIVATE_PRODUCT_INSTANCE,
+            foundProductInstance.getAccountIdentifier()));
+
+    super.depositAccountManager.postProductInstanceCommand(
+        foundProductInstance.getAccountIdentifier(), EventConstants.PRODUCT_INSTANCE_TRANSACTION);
+
+    Assert.assertTrue(
+        super.eventRecorder.wait(EventConstants.PUT_PRODUCT_INSTANCE,
+            foundProductInstance.getAccountIdentifier()));
+
+    final List<ProductInstance> transactedProductInstances = super.depositAccountManager.findProductInstances(productDefinition.getIdentifier());
+    Assert.assertNotNull(transactedProductInstances);
+    Assert.assertEquals(1, transactedProductInstances.size());
+    final ProductInstance transactedProductInstance = transactedProductInstances.get(0);
+    Assert.assertNotNull(transactedProductInstance.getLastTransactionDate());
+  }
 }
diff --git a/service/src/main/java/io/mifos/deposit/service/internal/command/TransactionProcessedCommand.java b/service/src/main/java/io/mifos/deposit/service/internal/command/TransactionProcessedCommand.java
new file mode 100644
index 0000000..79950c9
--- /dev/null
+++ b/service/src/main/java/io/mifos/deposit/service/internal/command/TransactionProcessedCommand.java
@@ -0,0 +1,30 @@
+/*
+ * Copyright 2017 The Mifos Initiative.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package io.mifos.deposit.service.internal.command;
+
+public class TransactionProcessedCommand {
+
+  private final String accountIdentifier;
+
+  public TransactionProcessedCommand(final String accountIdentifier) {
+    super();
+    this.accountIdentifier = accountIdentifier;
+  }
+
+  public String accountIdentifier() {
+    return this.accountIdentifier;
+  }
+}
diff --git a/service/src/main/java/io/mifos/deposit/service/internal/command/handler/ProductInstanceAggregate.java b/service/src/main/java/io/mifos/deposit/service/internal/command/handler/ProductInstanceAggregate.java
index da6b8d7..29f188c 100644
--- a/service/src/main/java/io/mifos/deposit/service/internal/command/handler/ProductInstanceAggregate.java
+++ b/service/src/main/java/io/mifos/deposit/service/internal/command/handler/ProductInstanceAggregate.java
@@ -27,6 +27,7 @@ import io.mifos.deposit.service.ServiceConstants;
 import io.mifos.deposit.service.internal.command.ActivateProductInstanceCommand;
 import io.mifos.deposit.service.internal.command.CloseProductInstanceCommand;
 import io.mifos.deposit.service.internal.command.CreateProductInstanceCommand;
+import io.mifos.deposit.service.internal.command.TransactionProcessedCommand;
 import io.mifos.deposit.service.internal.command.UpdateProductInstanceCommand;
 import io.mifos.deposit.service.internal.mapper.ProductInstanceMapper;
 import io.mifos.deposit.service.internal.repository.ProductDefinitionEntity;
@@ -41,6 +42,7 @@ import org.springframework.beans.factory.annotation.Qualifier;
 import org.springframework.transaction.annotation.Transactional;
 
 import java.time.Clock;
+import java.time.LocalDate;
 import java.time.LocalDateTime;
 import java.util.Arrays;
 import java.util.HashSet;
@@ -120,6 +122,9 @@ public class ProductInstanceAggregate {
     if (optionalProductInstance.isPresent()) {
       final ProductInstanceEntity productInstanceEntity = optionalProductInstance.get();
       productInstanceEntity.setState("ACTIVE");
+      if (productInstanceEntity.getOpenedOn() == null) {
+        productInstanceEntity.setOpenedOn(LocalDate.now(Clock.systemUTC()));
+      }
       productInstanceEntity.setLastModifiedBy(UserContextHolder.checkedGetUser());
       productInstanceEntity.setLastModifiedOn(LocalDateTime.now(Clock.systemUTC()));
       this.productInstanceRepository.save(productInstanceEntity);
@@ -186,6 +191,23 @@ public class ProductInstanceAggregate {
     }
   }
 
+  @Transactional
+  @CommandHandler
+  @EventEmitter(selectorName = EventConstants.SELECTOR_NAME, selectorValue = EventConstants.PUT_PRODUCT_INSTANCE)
+  public String process(final TransactionProcessedCommand transactionProcessedCommand) {
+    final Optional<ProductInstanceEntity> optionalProductInstance =
+        this.productInstanceRepository.findByAccountIdentifier(transactionProcessedCommand.accountIdentifier());
+
+    final ProductInstanceEntity productInstanceEntity = optionalProductInstance.orElseThrow(() ->
+        ServiceException.notFound("Product instance {0} not found.", transactionProcessedCommand.accountIdentifier()));
+
+    productInstanceEntity.setLastTransactionDate(LocalDateTime.now(Clock.systemUTC()));
+    
+    this.productInstanceRepository.save(productInstanceEntity);
+
+    return transactionProcessedCommand.accountIdentifier();
+  }
+
   private boolean hasChanged(final ProductInstance productInstance, final ProductInstanceEntity productInstanceEntity) {
     if (productInstance.getBeneficiaries() != null) {
       if (productInstanceEntity.getBeneficiaries() == null) {
diff --git a/service/src/main/java/io/mifos/deposit/service/internal/mapper/ProductInstanceMapper.java b/service/src/main/java/io/mifos/deposit/service/internal/mapper/ProductInstanceMapper.java
index 68a31c3..a841833 100644
--- a/service/src/main/java/io/mifos/deposit/service/internal/mapper/ProductInstanceMapper.java
+++ b/service/src/main/java/io/mifos/deposit/service/internal/mapper/ProductInstanceMapper.java
@@ -16,6 +16,7 @@
 package io.mifos.deposit.service.internal.mapper;
 
 import io.mifos.accounting.api.v1.domain.Account;
+import io.mifos.core.lang.DateConverter;
 import io.mifos.core.lang.ServiceException;
 import io.mifos.deposit.api.v1.instance.domain.ProductInstance;
 import io.mifos.deposit.service.internal.repository.ProductDefinitionEntity;
@@ -49,6 +50,14 @@ public class ProductInstanceMapper {
             productInstance.getBeneficiaries().stream().collect(Collectors.joining(",")));
       }
 
+      if (productInstance.getOpenedOn() != null) {
+        productInstanceEntity.setOpenedOn(DateConverter.dateFromIsoString(productInstance.getOpenedOn()));
+      }
+
+      if (productInstance.getLastTransactionDate() != null) {
+        productInstanceEntity.setLastTransactionDate(DateConverter.fromIsoString(productInstance.getLastTransactionDate()));
+      }
+
       return productInstanceEntity;
     } else {
       throw ServiceException.notFound("Unable to assign product {0} to customer {1}, product not found.",
@@ -69,6 +78,14 @@ public class ProductInstanceMapper {
       ));
     }
 
+    if (productInstanceEntity.getOpenedOn() != null) {
+      productInstance.setOpenedOn(DateConverter.toIsoString(productInstanceEntity.getOpenedOn()));
+    }
+
+    if (productInstanceEntity.getLastTransactionDate() != null) {
+      productInstance.setLastTransactionDate(DateConverter.toIsoString(productInstanceEntity.getLastTransactionDate()));
+    }
+
     if (account != null && account.getBalance() != null) {
       productInstance.setBalance(account.getBalance());
     } else {
diff --git a/service/src/main/java/io/mifos/deposit/service/internal/repository/ProductInstanceEntity.java b/service/src/main/java/io/mifos/deposit/service/internal/repository/ProductInstanceEntity.java
index 53ad0bc..f95a8ea 100644
--- a/service/src/main/java/io/mifos/deposit/service/internal/repository/ProductInstanceEntity.java
+++ b/service/src/main/java/io/mifos/deposit/service/internal/repository/ProductInstanceEntity.java
@@ -15,6 +15,7 @@
  */
 package io.mifos.deposit.service.internal.repository;
 
+import io.mifos.core.mariadb.util.LocalDateConverter;
 import io.mifos.core.mariadb.util.LocalDateTimeConverter;
 
 import javax.persistence.CascadeType;
@@ -28,6 +29,7 @@ import javax.persistence.Id;
 import javax.persistence.JoinColumn;
 import javax.persistence.ManyToOne;
 import javax.persistence.Table;
+import java.time.LocalDate;
 import java.time.LocalDateTime;
 
 @Entity
@@ -47,6 +49,12 @@ public class ProductInstanceEntity {
   private String accountIdentifier;
   @Column(name = "beneficiaries", nullable = true, length = 256)
   private String beneficiaries;
+  @Convert(converter = LocalDateConverter.class)
+  @Column(name = "opened_on", nullable = false)
+  private LocalDate openedOn;
+  @Convert(converter = LocalDateTimeConverter.class)
+  @Column(name = "last_transaction_date", nullable = false)
+  private LocalDateTime lastTransactionDate;
   @Column(name = "a_state", nullable = false)
   private String state;
   @Column(name = "created_by", nullable = false, length = 32)
@@ -104,6 +112,22 @@ public class ProductInstanceEntity {
     this.beneficiaries = beneficiaries;
   }
 
+  public LocalDate getOpenedOn() {
+    return this.openedOn;
+  }
+
+  public void setOpenedOn(final LocalDate openedOn) {
+    this.openedOn = openedOn;
+  }
+
+  public LocalDateTime getLastTransactionDate() {
+    return this.lastTransactionDate;
+  }
+
+  public void setLastTransactionDate(final LocalDateTime lastTransactionDate) {
+    this.lastTransactionDate = lastTransactionDate;
+  }
+
   public String getState() {
     return this.state;
   }
diff --git a/service/src/main/java/io/mifos/deposit/service/rest/ProductInstanceRestController.java b/service/src/main/java/io/mifos/deposit/service/rest/ProductInstanceRestController.java
index 0d0deb4..e56bda8 100644
--- a/service/src/main/java/io/mifos/deposit/service/rest/ProductInstanceRestController.java
+++ b/service/src/main/java/io/mifos/deposit/service/rest/ProductInstanceRestController.java
@@ -27,6 +27,7 @@ import io.mifos.deposit.service.ServiceConstants;
 import io.mifos.deposit.service.internal.command.ActivateProductInstanceCommand;
 import io.mifos.deposit.service.internal.command.CloseProductInstanceCommand;
 import io.mifos.deposit.service.internal.command.CreateProductInstanceCommand;
+import io.mifos.deposit.service.internal.command.TransactionProcessedCommand;
 import io.mifos.deposit.service.internal.command.UpdateProductInstanceCommand;
 import io.mifos.deposit.service.internal.service.ProductInstanceService;
 import org.slf4j.Logger;
@@ -150,6 +151,9 @@ public class ProductInstanceRestController {
       case EventConstants.CLOSE_PRODUCT_INSTANCE_COMMAND:
         this.commandGateway.process(new CloseProductInstanceCommand(identifier));
         break;
+      case EventConstants.PRODUCT_INSTANCE_TRANSACTION:
+        this.commandGateway.process(new TransactionProcessedCommand(identifier));
+        break;
       default:
         throw ServiceException.badRequest("Unsupported command {0}", command);
     }
diff --git a/service/src/main/resources/db/migrations/mariadb/V6__add_opened_on_last_transaction_to_instance.sql b/service/src/main/resources/db/migrations/mariadb/V6__add_opened_on_last_transaction_to_instance.sql
new file mode 100644
index 0000000..89e2bef
--- /dev/null
+++ b/service/src/main/resources/db/migrations/mariadb/V6__add_opened_on_last_transaction_to_instance.sql
@@ -0,0 +1,20 @@
+--
+-- Copyright 2017 The Mifos Initiative.
+--
+-- Licensed under the Apache License, Version 2.0 (the "License");
+-- you may not use this file except in compliance with the License.
+-- You may obtain a copy of the License at
+--
+--    http://www.apache.org/licenses/LICENSE-2.0
+--
+-- Unless required by applicable law or agreed to in writing, software
+-- distributed under the License is distributed on an "AS IS" BASIS,
+-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+-- See the License for the specific language governing permissions and
+-- limitations under the License.
+--
+
+ALTER TABLE shed_product_instances ADD COLUMN opened_on DATE NULL;
+ALTER TABLE shed_product_instances ADD COLUMN last_transaction_date TIMESTAMP(3) NULL;
+
+UPDATE shed_product_instances set opened_on = CURDATE() WHERE a_state <> 'PENDING';
\ No newline at end of file

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

[fineract-cn-deposit-account-management] 05/26: Merge pull request #1 from markusgeiss/develop

Posted by my...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

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

commit caf9585ef24e63b98277c5bb7a7b67f16b9e17a2
Merge: 333cc52 adc669e
Author: Markus Geiss <ma...@kuelap.io>
AuthorDate: Thu Aug 10 18:14:23 2017 +0200

    Merge pull request #1 from markusgeiss/develop
    
    added ability to fetch available TX types for a customer

 .../api/v1/client/DepositAccountManager.java       | 14 ++++++
 .../instance/domain/AvailableTransactionType.java  | 51 ++++++++++++++++++++++
 .../java/io/mifos/deposit/TestProductInstance.java | 51 ++++++++++++++++++++++
 .../rest/ProductInstanceRestController.java        | 41 ++++++++++++++++-
 4 files changed, 156 insertions(+), 1 deletion(-)

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

[fineract-cn-deposit-account-management] 25/26: added proper alternative account and initial balance handling

Posted by my...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

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

commit 055b2fd18b4f7224b7de87d1c815b70e29e8f24a
Author: Markus Geiss <ma...@kuelap.io>
AuthorDate: Fri Nov 3 11:28:30 2017 +0100

    added proper alternative account and initial balance handling
---
 .../api/v1/instance/domain/ProductInstance.java    |  9 ++++++
 .../java/io/mifos/deposit/TestProductInstance.java | 34 ++++++++++++++++++++++
 .../command/handler/ProductInstanceAggregate.java  |  9 ++----
 .../internal/mapper/ProductInstanceMapper.java     | 12 ++++----
 .../internal/service/helper/AccountingService.java |  9 +++---
 5 files changed, 57 insertions(+), 16 deletions(-)

diff --git a/api/src/main/java/io/mifos/deposit/api/v1/instance/domain/ProductInstance.java b/api/src/main/java/io/mifos/deposit/api/v1/instance/domain/ProductInstance.java
index a37be73..5c9bd53 100644
--- a/api/src/main/java/io/mifos/deposit/api/v1/instance/domain/ProductInstance.java
+++ b/api/src/main/java/io/mifos/deposit/api/v1/instance/domain/ProductInstance.java
@@ -27,6 +27,7 @@ public class ProductInstance {
   private String productIdentifier;
   @ValidIdentifier(maxLength = 34, optional = true)
   private String accountIdentifier;
+  private String alternativeAccountNumber;
   private Set<String> beneficiaries;
   private String openedOn;
   private String lastTransactionDate;
@@ -61,6 +62,14 @@ public class ProductInstance {
     this.accountIdentifier = accountIdentifier;
   }
 
+  public String getAlternativeAccountNumber() {
+    return alternativeAccountNumber;
+  }
+
+  public void setAlternativeAccountNumber(String alternativeAccountNumber) {
+    this.alternativeAccountNumber = alternativeAccountNumber;
+  }
+
   public Set<String> getBeneficiaries() {
     return this.beneficiaries;
   }
diff --git a/component-test/src/main/java/io/mifos/deposit/TestProductInstance.java b/component-test/src/main/java/io/mifos/deposit/TestProductInstance.java
index d3442ec..e3854c7 100644
--- a/component-test/src/main/java/io/mifos/deposit/TestProductInstance.java
+++ b/component-test/src/main/java/io/mifos/deposit/TestProductInstance.java
@@ -27,6 +27,7 @@ import io.mifos.deposit.api.v1.instance.domain.ProductInstance;
 import org.apache.commons.lang3.RandomStringUtils;
 import org.junit.Assert;
 import org.junit.Test;
+import org.mockito.Matchers;
 import org.mockito.Mockito;
 
 import java.util.Arrays;
@@ -375,4 +376,37 @@ public class TestProductInstance extends AbstractDepositAccountManagementTest {
     final ProductInstance transactedProductInstance = transactedProductInstances.get(0);
     Assert.assertNotNull(transactedProductInstance.getLastTransactionDate());
   }
+
+  @Test
+  public void shouldSetAlternativeAccountAndBalanceProductInstance() throws Exception {
+    final ProductDefinition productDefinition = Fixture.productDefinition();
+
+    super.depositAccountManager.create(productDefinition);
+
+    super.eventRecorder.wait(EventConstants.POST_PRODUCT_DEFINITION, productDefinition.getIdentifier());
+
+    final ProductInstance productInstance = Fixture.productInstance(productDefinition.getIdentifier());
+    productInstance.setAlternativeAccountNumber("08154711");
+    productInstance.setBalance(1000.00D);
+
+    super.depositAccountManager.create(productInstance);
+
+    super.eventRecorder.wait(EventConstants.POST_PRODUCT_INSTANCE, productInstance.getCustomerIdentifier());
+
+    final Account dummy = new Account();
+    dummy.setAlternativeAccountNumber(productInstance.getAlternativeAccountNumber());
+    dummy.setBalance(productInstance.getBalance());
+    Mockito
+        .doAnswer(invocation -> dummy)
+        .when(super.accountingServiceSpy).findAccount(Matchers.anyString());
+
+    final List<ProductInstance> productInstances = super.depositAccountManager.findProductInstances(productDefinition.getIdentifier());
+    Assert.assertNotNull(productInstances);
+    Assert.assertEquals(1, productInstances.size());
+    final ProductInstance foundProductInstance = productInstances.get(0);
+    Assert.assertNotNull(foundProductInstance.getAccountIdentifier());
+    Assert.assertNotEquals(productInstance.getAlternativeAccountNumber(), foundProductInstance.getAccountIdentifier());
+    Assert.assertEquals(productInstance.getAlternativeAccountNumber(), foundProductInstance.getAlternativeAccountNumber());
+    Assert.assertEquals(productInstance.getBalance(), foundProductInstance.getBalance());
+  }
 }
diff --git a/service/src/main/java/io/mifos/deposit/service/internal/command/handler/ProductInstanceAggregate.java b/service/src/main/java/io/mifos/deposit/service/internal/command/handler/ProductInstanceAggregate.java
index 29f188c..3d41413 100644
--- a/service/src/main/java/io/mifos/deposit/service/internal/command/handler/ProductInstanceAggregate.java
+++ b/service/src/main/java/io/mifos/deposit/service/internal/command/handler/ProductInstanceAggregate.java
@@ -92,15 +92,12 @@ public class ProductInstanceAggregate {
               "." + productDefinitionEntity.getEquityLedgerIdentifier() +
               "." + String.format("%05d", accountSuffix);
 
-      if (productInstance.getAccountIdentifier() == null) {
-        productInstanceEntity.setAccountIdentifier(accountNumber);
-      } else {
-        productInstanceEntity.setAccountIdentifier(productInstance.getAccountIdentifier());
-      }
+      productInstanceEntity.setAccountIdentifier(accountNumber);
 
       this.accountingService.createAccount(productDefinitionEntity.getEquityLedgerIdentifier(),
           productDefinitionEntity.getName(), productInstanceEntity.getCustomerIdentifier(),
-          accountNumber, productInstance.getAccountIdentifier());
+          accountNumber, productInstance.getAlternativeAccountNumber(),
+          productInstance.getBalance());
     });
 
     productInstanceEntity.setCreatedBy(UserContextHolder.checkedGetUser());
diff --git a/service/src/main/java/io/mifos/deposit/service/internal/mapper/ProductInstanceMapper.java b/service/src/main/java/io/mifos/deposit/service/internal/mapper/ProductInstanceMapper.java
index 4073783..14f5a63 100644
--- a/service/src/main/java/io/mifos/deposit/service/internal/mapper/ProductInstanceMapper.java
+++ b/service/src/main/java/io/mifos/deposit/service/internal/mapper/ProductInstanceMapper.java
@@ -93,12 +93,14 @@ public class ProductInstanceMapper {
       productInstance.setLastTransactionDate(DateConverter.toIsoString(productInstanceEntity.getLastTransactionDate()));
     }
 
-    if (account != null && account.getBalance() != null) {
-      productInstance.setBalance(account.getBalance());
-    } else {
-      productInstance.setBalance(0.00D);
+    if (account != null) {
+      productInstance.setAlternativeAccountNumber(account.getAlternativeAccountNumber());
+      if (account.getBalance() != null) {
+        productInstance.setBalance(account.getBalance());
+      } else {
+        productInstance.setBalance(0.00D);
+      }
     }
-
     return productInstance;
   }
 }
diff --git a/service/src/main/java/io/mifos/deposit/service/internal/service/helper/AccountingService.java b/service/src/main/java/io/mifos/deposit/service/internal/service/helper/AccountingService.java
index f23c932..071de01 100644
--- a/service/src/main/java/io/mifos/deposit/service/internal/service/helper/AccountingService.java
+++ b/service/src/main/java/io/mifos/deposit/service/internal/service/helper/AccountingService.java
@@ -52,7 +52,8 @@ public class AccountingService {
                             final String productName,
                             final String customer,
                             final String accountNumber,
-                            final String alternativeAccountNumber) {
+                            final String alternativeAccountNumber,
+                            final Double balance) {
     try {
       final Ledger ledger = this.ledgerManager.findLedger(equityLedger);
       final Account account = new Account();
@@ -61,10 +62,8 @@ public class AccountingService {
       account.setLedger(equityLedger);
       account.setName(productName);
       account.setHolders(new HashSet<>(Lists.newArrayList(customer)));
-      account.setBalance(0.00D);
-      if (alternativeAccountNumber != null && !alternativeAccountNumber.equals(accountNumber)) {
-        account.setAlternativeAccountNumber(alternativeAccountNumber);
-      }
+      account.setBalance(balance != null ? balance : 0.00D);
+      account.setAlternativeAccountNumber(alternativeAccountNumber);
 
       this.ledgerManager.createAccount(account);
     } catch (final LedgerNotFoundException lnfex) {

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

[fineract-cn-deposit-account-management] 21/26: added time zone 'Z' handling to ease UI usage

Posted by my...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

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

commit 9680ecbb15747265d976c8fe6d8491f087c81b0a
Author: mgeiss <mg...@mifos.org>
AuthorDate: Tue Oct 24 07:00:47 2017 -0400

    added time zone 'Z' handling to ease UI usage
---
 .../src/main/java/io/mifos/deposit/TestProductInstance.java   |  2 +-
 .../service/internal/mapper/ProductInstanceMapper.java        | 11 +++++++++--
 2 files changed, 10 insertions(+), 3 deletions(-)

diff --git a/component-test/src/main/java/io/mifos/deposit/TestProductInstance.java b/component-test/src/main/java/io/mifos/deposit/TestProductInstance.java
index 6018d94..d3442ec 100644
--- a/component-test/src/main/java/io/mifos/deposit/TestProductInstance.java
+++ b/component-test/src/main/java/io/mifos/deposit/TestProductInstance.java
@@ -103,7 +103,7 @@ public class TestProductInstance extends AbstractDepositAccountManagementTest {
     super.eventRecorder.wait(EventConstants.POST_PRODUCT_DEFINITION, productDefinition.getIdentifier());
 
     final ProductInstance productInstance = Fixture.productInstance(productDefinition.getIdentifier());
-    final String openedOn = "2013-05-08Z";
+    final String openedOn = "2013-05-08";
     productInstance.setOpenedOn(openedOn);
 
     super.depositAccountManager.create(productInstance);
diff --git a/service/src/main/java/io/mifos/deposit/service/internal/mapper/ProductInstanceMapper.java b/service/src/main/java/io/mifos/deposit/service/internal/mapper/ProductInstanceMapper.java
index a841833..4073783 100644
--- a/service/src/main/java/io/mifos/deposit/service/internal/mapper/ProductInstanceMapper.java
+++ b/service/src/main/java/io/mifos/deposit/service/internal/mapper/ProductInstanceMapper.java
@@ -51,7 +51,13 @@ public class ProductInstanceMapper {
       }
 
       if (productInstance.getOpenedOn() != null) {
-        productInstanceEntity.setOpenedOn(DateConverter.dateFromIsoString(productInstance.getOpenedOn()));
+        final String editedOpenedDate;
+        if (!productInstance.getOpenedOn().endsWith("Z")) {
+          editedOpenedDate = productInstance.getOpenedOn() + "Z";
+        } else {
+          editedOpenedDate = productInstance.getOpenedOn();
+        }
+        productInstanceEntity.setOpenedOn(DateConverter.dateFromIsoString(editedOpenedDate));
       }
 
       if (productInstance.getLastTransactionDate() != null) {
@@ -79,7 +85,8 @@ public class ProductInstanceMapper {
     }
 
     if (productInstanceEntity.getOpenedOn() != null) {
-      productInstance.setOpenedOn(DateConverter.toIsoString(productInstanceEntity.getOpenedOn()));
+      final String editedOpenedDate = DateConverter.toIsoString(productInstanceEntity.getOpenedOn()).substring(0, 10);
+      productInstance.setOpenedOn(editedOpenedDate);
     }
 
     if (productInstanceEntity.getLastTransactionDate() != null) {

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

[fineract-cn-deposit-account-management] 04/26: added ability to fetch available TX types for a customer

Posted by my...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

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

commit adc669eb26bddd4f1f4f81f9e0a410c3a2d0e579
Author: mgeiss <mg...@mifos.org>
AuthorDate: Thu Aug 10 18:13:26 2017 +0200

    added ability to fetch available TX types for a customer
---
 .../api/v1/client/DepositAccountManager.java       | 14 ++++++
 .../instance/domain/AvailableTransactionType.java  | 51 ++++++++++++++++++++++
 .../java/io/mifos/deposit/TestProductInstance.java | 51 ++++++++++++++++++++++
 .../rest/ProductInstanceRestController.java        | 41 ++++++++++++++++-
 4 files changed, 156 insertions(+), 1 deletion(-)

diff --git a/api/src/main/java/io/mifos/deposit/api/v1/client/DepositAccountManager.java b/api/src/main/java/io/mifos/deposit/api/v1/client/DepositAccountManager.java
index aae77a7..b9c0c00 100644
--- a/api/src/main/java/io/mifos/deposit/api/v1/client/DepositAccountManager.java
+++ b/api/src/main/java/io/mifos/deposit/api/v1/client/DepositAccountManager.java
@@ -28,6 +28,7 @@ import io.mifos.deposit.api.v1.definition.domain.ProductDefinition;
 import io.mifos.deposit.api.v1.definition.domain.ProductDefinitionCommand;
 import io.mifos.deposit.api.v1.instance.ProductInstanceNotFoundException;
 import io.mifos.deposit.api.v1.instance.ProductInstanceValidationException;
+import io.mifos.deposit.api.v1.instance.domain.AvailableTransactionType;
 import io.mifos.deposit.api.v1.instance.domain.ProductInstance;
 import org.springframework.cloud.netflix.feign.FeignClient;
 import org.springframework.http.HttpStatus;
@@ -37,9 +38,11 @@ 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 javax.validation.Valid;
 import java.util.List;
+import java.util.Set;
 
 @SuppressWarnings("unused")
 @FeignClient(value = "deposit-v1", path = "/deposit/v1", configuration = CustomFeignClientsConfiguration.class)
@@ -133,6 +136,17 @@ public interface DepositAccountManager {
   List<ProductInstance> fetchProductInstances(@RequestParam(value = "customer", required = true) final String customer);
 
   @RequestMapping(
+      value = "/instances/transactiontypes",
+      method = RequestMethod.GET,
+      consumes = MediaType.APPLICATION_JSON_VALUE,
+      produces = MediaType.ALL_VALUE
+  )
+  @ResponseBody
+  Set<AvailableTransactionType> fetchPossibleTransactionTypes(
+      @RequestParam(value = "customer", required = true) final String customer
+  );
+
+  @RequestMapping(
       value = "/instances/{identifier}",
       method = RequestMethod.POST,
       consumes = MediaType.APPLICATION_JSON_VALUE,
diff --git a/api/src/main/java/io/mifos/deposit/api/v1/instance/domain/AvailableTransactionType.java b/api/src/main/java/io/mifos/deposit/api/v1/instance/domain/AvailableTransactionType.java
new file mode 100644
index 0000000..bd0a2d4
--- /dev/null
+++ b/api/src/main/java/io/mifos/deposit/api/v1/instance/domain/AvailableTransactionType.java
@@ -0,0 +1,51 @@
+/*
+ * Copyright 2017 The Mifos Initiative.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package io.mifos.deposit.api.v1.instance.domain;
+
+import org.hibernate.validator.constraints.NotEmpty;
+
+public class AvailableTransactionType {
+
+  @NotEmpty
+  private String transactionType;
+
+  public AvailableTransactionType() {
+    super();
+  }
+
+  public String getTransactionType() {
+    return this.transactionType;
+  }
+
+  public void setTransactionType(final String transactionType) {
+    this.transactionType = transactionType;
+  }
+
+  @Override
+  public boolean equals(final Object o) {
+    if (this == o) return true;
+    if (o == null || getClass() != o.getClass()) return false;
+
+    final AvailableTransactionType that = (AvailableTransactionType) o;
+
+    return transactionType.equals(that.transactionType);
+  }
+
+  @Override
+  public int hashCode() {
+    return transactionType.hashCode();
+  }
+}
diff --git a/component-test/src/main/java/io/mifos/deposit/TestProductInstance.java b/component-test/src/main/java/io/mifos/deposit/TestProductInstance.java
index be05a00..d023ee9 100644
--- a/component-test/src/main/java/io/mifos/deposit/TestProductInstance.java
+++ b/component-test/src/main/java/io/mifos/deposit/TestProductInstance.java
@@ -15,12 +15,14 @@
  */
 package io.mifos.deposit;
 
+import com.google.common.collect.Sets;
 import io.mifos.accounting.api.v1.domain.Account;
 import io.mifos.deposit.api.v1.EventConstants;
 import io.mifos.deposit.api.v1.definition.domain.Charge;
 import io.mifos.deposit.api.v1.definition.domain.ProductDefinition;
 import io.mifos.deposit.api.v1.instance.ProductInstanceNotFoundException;
 import io.mifos.deposit.api.v1.instance.ProductInstanceValidationException;
+import io.mifos.deposit.api.v1.instance.domain.AvailableTransactionType;
 import io.mifos.deposit.api.v1.instance.domain.ProductInstance;
 import org.apache.commons.lang3.RandomStringUtils;
 import org.junit.Assert;
@@ -30,6 +32,8 @@ import org.mockito.Mockito;
 import java.util.Arrays;
 import java.util.HashSet;
 import java.util.List;
+import java.util.Optional;
+import java.util.Set;
 
 public class TestProductInstance extends AbstractDepositAccountManagementTest {
 
@@ -279,4 +283,51 @@ public class TestProductInstance extends AbstractDepositAccountManagementTest {
         super.eventRecorder.wait(EventConstants.ACTIVATE_PRODUCT_INSTANCE,
             fetchedProductInstance.getAccountIdentifier()));
   }
+
+  @Test
+  public void shouldFindAvailableTransactionTypes() throws Exception {
+    final ProductDefinition productDefinition = Fixture.productDefinition();
+
+    super.depositAccountManager.create(productDefinition);
+
+    super.eventRecorder.wait(EventConstants.POST_PRODUCT_DEFINITION, productDefinition.getIdentifier());
+
+    final ProductInstance productInstance = Fixture.productInstance(productDefinition.getIdentifier());
+
+    super.depositAccountManager.create(productInstance);
+
+    super.eventRecorder.wait(EventConstants.POST_PRODUCT_INSTANCE, productInstance.getCustomerIdentifier());
+
+    final Set<AvailableTransactionType> availableTransactionTypesBeforeActivation =
+        super.depositAccountManager.fetchPossibleTransactionTypes(productInstance.getCustomerIdentifier());
+
+    Assert.assertFalse(availableTransactionTypesBeforeActivation.isEmpty());
+    Assert.assertTrue(availableTransactionTypesBeforeActivation.size() == 1);
+    final Optional<AvailableTransactionType> optionalTransactionType =
+        availableTransactionTypesBeforeActivation.stream().findFirst();
+    Assert.assertTrue(optionalTransactionType.isPresent());
+    Assert.assertEquals("ACCO", optionalTransactionType.get().getTransactionType());
+
+    final List<ProductInstance> productInstances = super.depositAccountManager.findProductInstances(productDefinition.getIdentifier());
+    Assert.assertNotNull(productInstances);
+    Assert.assertEquals(1, productInstances.size());
+    final ProductInstance foundProductInstance = productInstances.get(0);
+
+    super.depositAccountManager.postProductInstanceCommand(
+        foundProductInstance.getAccountIdentifier(), EventConstants.ACTIVATE_PRODUCT_INSTANCE_COMMAND);
+
+    super.eventRecorder.wait(EventConstants.ACTIVATE_PRODUCT_INSTANCE, foundProductInstance.getAccountIdentifier());
+
+    final Set<AvailableTransactionType> availableTransactionTypesAfterActivation =
+        super.depositAccountManager.fetchPossibleTransactionTypes(productInstance.getCustomerIdentifier());
+
+    Assert.assertFalse(availableTransactionTypesAfterActivation.isEmpty());
+    Assert.assertTrue(availableTransactionTypesAfterActivation.size() == 4);
+    final HashSet<String> expectedTransactionTypes = Sets.newHashSet("ACCC", "ACCT", "CDPT", "CWDL");
+    availableTransactionTypesAfterActivation.forEach(availableTransactionType ->
+        expectedTransactionTypes.remove(availableTransactionType.getTransactionType())
+    );
+
+    Assert.assertTrue(expectedTransactionTypes.isEmpty());
+  }
 }
diff --git a/service/src/main/java/io/mifos/deposit/service/rest/ProductInstanceRestController.java b/service/src/main/java/io/mifos/deposit/service/rest/ProductInstanceRestController.java
index 7470786..205fd91 100644
--- a/service/src/main/java/io/mifos/deposit/service/rest/ProductInstanceRestController.java
+++ b/service/src/main/java/io/mifos/deposit/service/rest/ProductInstanceRestController.java
@@ -21,6 +21,7 @@ import io.mifos.core.command.gateway.CommandGateway;
 import io.mifos.core.lang.ServiceException;
 import io.mifos.deposit.api.v1.EventConstants;
 import io.mifos.deposit.api.v1.PermittableGroupIds;
+import io.mifos.deposit.api.v1.instance.domain.AvailableTransactionType;
 import io.mifos.deposit.api.v1.instance.domain.ProductInstance;
 import io.mifos.deposit.service.ServiceConstants;
 import io.mifos.deposit.service.internal.command.ActivateProductInstanceCommand;
@@ -42,7 +43,9 @@ import org.springframework.web.bind.annotation.ResponseBody;
 import org.springframework.web.bind.annotation.RestController;
 
 import javax.validation.Valid;
+import java.util.HashSet;
 import java.util.List;
+import java.util.Set;
 
 @RestController
 @RequestMapping("/instances")
@@ -83,12 +86,48 @@ public class ProductInstanceRestController {
       produces = MediaType.APPLICATION_JSON_VALUE
   )
   @ResponseBody
-  public ResponseEntity<List<ProductInstance>> fetchProductInstances(@RequestParam(value = "customer", required = true) final String customerIdentifier) {
+  public ResponseEntity<List<ProductInstance>> fetchProductInstances(
+      @RequestParam(value = "customer", required = true) final String customerIdentifier) {
     return ResponseEntity.ok(this.productInstanceService.findByCustomer(customerIdentifier));
   }
 
   @Permittable(value = AcceptedTokenType.TENANT, groupId = PermittableGroupIds.INSTANCE_MANAGEMENT)
   @RequestMapping(
+      value = "/transactiontypes",
+      method = RequestMethod.GET,
+      consumes = MediaType.ALL_VALUE,
+      produces = MediaType.APPLICATION_JSON_VALUE
+  )
+  @ResponseBody
+  public ResponseEntity<Set<AvailableTransactionType>> fetchPossibleTransactionTypes(
+      @RequestParam(value = "customer", required = true) final String customerIdentifier) {
+    final HashSet<AvailableTransactionType> availableTransactionTypes = new HashSet<>();
+    final List<ProductInstance> productInstances = this.productInstanceService.findByCustomer(customerIdentifier);
+    productInstances.forEach(productInstance -> {
+      if (productInstance.getState().equals("PENDING")) {
+        final AvailableTransactionType actionOpen = new AvailableTransactionType();
+        actionOpen.setTransactionType("ACCO");
+        availableTransactionTypes.add(actionOpen);
+      } else if (productInstance.getState().equals("ACTIVE")) {
+        final AvailableTransactionType actionDeposit = new AvailableTransactionType();
+        actionDeposit.setTransactionType("CDPT");
+        availableTransactionTypes.add(actionDeposit);
+        final AvailableTransactionType actionWithdrawal = new AvailableTransactionType();
+        actionWithdrawal.setTransactionType("CWDL");
+        availableTransactionTypes.add(actionWithdrawal);
+        final AvailableTransactionType actionTransfer = new AvailableTransactionType();
+        actionTransfer.setTransactionType("ACCT");
+        availableTransactionTypes.add(actionTransfer);
+        final AvailableTransactionType actionClose = new AvailableTransactionType();
+        actionClose.setTransactionType("ACCC");
+        availableTransactionTypes.add(actionClose);
+      }
+    });
+    return ResponseEntity.ok(availableTransactionTypes);
+  }
+
+  @Permittable(value = AcceptedTokenType.TENANT, groupId = PermittableGroupIds.INSTANCE_MANAGEMENT)
+  @RequestMapping(
       value = "/{identifier}",
       method = RequestMethod.POST,
       consumes = MediaType.APPLICATION_JSON_VALUE,

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

[fineract-cn-deposit-account-management] 26/26: Merge pull request #10 from markusgeiss/develop

Posted by my...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

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

commit 9f00a397e08d46f553816910b503e7283ba3bd21
Merge: addc4cb 055b2fd
Author: Markus Geiss <ma...@kuelap.io>
AuthorDate: Fri Nov 3 11:29:08 2017 +0100

    Merge pull request #10 from markusgeiss/develop
    
    added proper alternative account and initial balance handling

 .../api/v1/instance/domain/ProductInstance.java    |  9 ++++++
 .../java/io/mifos/deposit/TestProductInstance.java | 34 ++++++++++++++++++++++
 .../command/handler/ProductInstanceAggregate.java  |  9 ++----
 .../internal/mapper/ProductInstanceMapper.java     | 12 ++++----
 .../internal/service/helper/AccountingService.java |  9 +++---
 5 files changed, 57 insertions(+), 16 deletions(-)

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

[fineract-cn-deposit-account-management] 15/26: added ability to use legacy account numbers

Posted by my...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

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

commit 7b202a3404bac48ebb942742a50b0678b1d80530
Author: mgeiss <mg...@mifos.org>
AuthorDate: Tue Oct 3 11:02:45 2017 +0200

    added ability to use legacy account numbers
---
 .../main/java/io/mifos/deposit/TestActions.java    |  2 +-
 .../command/handler/ProductInstanceAggregate.java  | 37 +++++++++--------
 .../mapper/DividendDistributionMapper.java         |  1 -
 .../repository/ProductDefinitionCommandEntity.java |  1 -
 .../internal/service/helper/AccountingService.java | 47 +++++++++++-----------
 .../internal/service/helper/RhythmService.java     | 15 +++++++
 .../rest/ProductDefinitionRestController.java      |  1 -
 7 files changed, 58 insertions(+), 46 deletions(-)

diff --git a/component-test/src/main/java/io/mifos/deposit/TestActions.java b/component-test/src/main/java/io/mifos/deposit/TestActions.java
index 98fa6c7..680128e 100644
--- a/component-test/src/main/java/io/mifos/deposit/TestActions.java
+++ b/component-test/src/main/java/io/mifos/deposit/TestActions.java
@@ -46,7 +46,7 @@ public class TestActions extends AbstractDepositAccountManagementTest {
   }
 
   @Test(expected = ActionAlreadyExistsException.class)
-  public void shouldNoCreateActionAlreadyExists() throws Exception {
+  public void shouldNotCreateActionAlreadyExists() throws Exception {
     final Action action = Fixture.action();
     super.depositAccountManager.create(action);
 
diff --git a/service/src/main/java/io/mifos/deposit/service/internal/command/handler/ProductInstanceAggregate.java b/service/src/main/java/io/mifos/deposit/service/internal/command/handler/ProductInstanceAggregate.java
index ac61c42..da6b8d7 100644
--- a/service/src/main/java/io/mifos/deposit/service/internal/command/handler/ProductInstanceAggregate.java
+++ b/service/src/main/java/io/mifos/deposit/service/internal/command/handler/ProductInstanceAggregate.java
@@ -76,31 +76,30 @@ public class ProductInstanceAggregate {
     final ProductInstanceEntity productInstanceEntity =
         ProductInstanceMapper.map(productInstance, this.productDefinitionRepository);
 
-    if (productInstance.getAccountIdentifier() == null) {
-      final Optional<ProductDefinitionEntity> optionalProductDefinition =
-          productDefinitionRepository.findByIdentifier(productInstance.getProductIdentifier());
+    final Optional<ProductDefinitionEntity> optionalProductDefinition =
+        productDefinitionRepository.findByIdentifier(productInstance.getProductIdentifier());
 
-      optionalProductDefinition.ifPresent(productDefinitionEntity -> {
+    optionalProductDefinition.ifPresent(productDefinitionEntity -> {
 
-        final List<ProductInstanceEntity> currentProductInstances =
-            this.productInstanceRepository.findByCustomerIdentifier(productInstance.getCustomerIdentifier());
+      final List<ProductInstanceEntity> currentProductInstances =
+          this.productInstanceRepository.findByCustomerIdentifier(productInstance.getCustomerIdentifier());
 
-        final int accountSuffix = currentProductInstances.size() + 1;
-
-        final StringBuilder stringBuilder = new StringBuilder();
-        final String accountNumber = stringBuilder
-            .append(productInstance.getCustomerIdentifier())
-            .append(".")
-            .append(productDefinitionEntity.getEquityLedgerIdentifier())
-            .append(".")
-            .append(String.format("%05d", accountSuffix))
-            .toString();
+      final int accountSuffix = currentProductInstances.size() + 1;
+      final String accountNumber =
+          productInstance.getCustomerIdentifier() +
+              "." + productDefinitionEntity.getEquityLedgerIdentifier() +
+              "." + String.format("%05d", accountSuffix);
 
+      if (productInstance.getAccountIdentifier() == null) {
         productInstanceEntity.setAccountIdentifier(accountNumber);
+      } else {
+        productInstanceEntity.setAccountIdentifier(productInstance.getAccountIdentifier());
+      }
 
-        this.accountingService.createAccount(productDefinitionEntity, productInstanceEntity);
-      });
-    }
+      this.accountingService.createAccount(productDefinitionEntity.getEquityLedgerIdentifier(),
+          productDefinitionEntity.getName(), productInstanceEntity.getCustomerIdentifier(),
+          accountNumber, productInstance.getAccountIdentifier());
+    });
 
     productInstanceEntity.setCreatedBy(UserContextHolder.checkedGetUser());
     productInstanceEntity.setCreatedOn(LocalDateTime.now(Clock.systemUTC()));
diff --git a/service/src/main/java/io/mifos/deposit/service/internal/mapper/DividendDistributionMapper.java b/service/src/main/java/io/mifos/deposit/service/internal/mapper/DividendDistributionMapper.java
index 6503836..1926606 100644
--- a/service/src/main/java/io/mifos/deposit/service/internal/mapper/DividendDistributionMapper.java
+++ b/service/src/main/java/io/mifos/deposit/service/internal/mapper/DividendDistributionMapper.java
@@ -16,7 +16,6 @@
 package io.mifos.deposit.service.internal.mapper;
 
 import io.mifos.core.api.util.UserContextHolder;
-import io.mifos.core.lang.DateConverter;
 import io.mifos.core.lang.DateOfBirth;
 import io.mifos.deposit.api.v1.definition.domain.DividendDistribution;
 import io.mifos.deposit.service.internal.repository.DividendDistributionEntity;
diff --git a/service/src/main/java/io/mifos/deposit/service/internal/repository/ProductDefinitionCommandEntity.java b/service/src/main/java/io/mifos/deposit/service/internal/repository/ProductDefinitionCommandEntity.java
index 42208d7..1021080 100644
--- a/service/src/main/java/io/mifos/deposit/service/internal/repository/ProductDefinitionCommandEntity.java
+++ b/service/src/main/java/io/mifos/deposit/service/internal/repository/ProductDefinitionCommandEntity.java
@@ -17,7 +17,6 @@ package io.mifos.deposit.service.internal.repository;
 
 import io.mifos.core.mariadb.util.LocalDateTimeConverter;
 
-import javax.persistence.CascadeType;
 import javax.persistence.Column;
 import javax.persistence.Convert;
 import javax.persistence.Entity;
diff --git a/service/src/main/java/io/mifos/deposit/service/internal/service/helper/AccountingService.java b/service/src/main/java/io/mifos/deposit/service/internal/service/helper/AccountingService.java
index 2229a03..f23c932 100644
--- a/service/src/main/java/io/mifos/deposit/service/internal/service/helper/AccountingService.java
+++ b/service/src/main/java/io/mifos/deposit/service/internal/service/helper/AccountingService.java
@@ -15,24 +15,22 @@
  */
 package io.mifos.deposit.service.internal.service.helper;
 
+import com.google.common.collect.Lists;
 import io.mifos.accounting.api.v1.client.AccountNotFoundException;
 import io.mifos.accounting.api.v1.client.LedgerManager;
 import io.mifos.accounting.api.v1.client.LedgerNotFoundException;
 import io.mifos.accounting.api.v1.domain.Account;
 import io.mifos.accounting.api.v1.domain.AccountEntry;
+import io.mifos.accounting.api.v1.domain.AccountPage;
 import io.mifos.accounting.api.v1.domain.JournalEntry;
 import io.mifos.accounting.api.v1.domain.Ledger;
 import io.mifos.core.lang.ServiceException;
 import io.mifos.deposit.service.ServiceConstants;
-import io.mifos.deposit.service.internal.repository.ProductDefinitionEntity;
-import io.mifos.deposit.service.internal.repository.ProductInstanceEntity;
-import org.apache.commons.lang.StringUtils;
 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.Arrays;
 import java.util.HashSet;
 import java.util.List;
 
@@ -50,31 +48,27 @@ public class AccountingService {
     this.ledgerManager = ledgerManager;
   }
 
-  public void createAccount(final ProductDefinitionEntity productDefinitionEntity,
-                            final ProductInstanceEntity productInstanceEntity) {
-    final String ledgerIdentifier = productDefinitionEntity.getEquityLedgerIdentifier();
+  public void createAccount(final String equityLedger,
+                            final String productName,
+                            final String customer,
+                            final String accountNumber,
+                            final String alternativeAccountNumber) {
     try {
-      final Ledger ledger = this.ledgerManager.findLedger(ledgerIdentifier);
+      final Ledger ledger = this.ledgerManager.findLedger(equityLedger);
       final Account account = new Account();
-      account.setIdentifier(productInstanceEntity.getAccountIdentifier());
+      account.setIdentifier(accountNumber);
       account.setType(ledger.getType());
-      account.setLedger(ledgerIdentifier);
-      account.setName(productDefinitionEntity.getName());
-
-      account.setHolders(new HashSet<>(
-          Arrays.asList(productInstanceEntity.getCustomerIdentifier()))
-      );
-
-      if (productInstanceEntity.getBeneficiaries() != null) {
-        account.setSignatureAuthorities(new HashSet<>(
-            Arrays.asList(StringUtils.split(productInstanceEntity.getBeneficiaries(), ","))
-        ));
+      account.setLedger(equityLedger);
+      account.setName(productName);
+      account.setHolders(new HashSet<>(Lists.newArrayList(customer)));
+      account.setBalance(0.00D);
+      if (alternativeAccountNumber != null && !alternativeAccountNumber.equals(accountNumber)) {
+        account.setAlternativeAccountNumber(alternativeAccountNumber);
       }
 
-      account.setBalance(0.00D);
       this.ledgerManager.createAccount(account);
     } catch (final LedgerNotFoundException lnfex) {
-      throw ServiceException.notFound("Ledger {0} not found.", ledgerIdentifier);
+      throw ServiceException.notFound("Ledger {0} not found.", equityLedger);
     }
   }
 
@@ -82,7 +76,14 @@ public class AccountingService {
     try {
       return this.ledgerManager.findAccount(identifier);
     } catch (final AccountNotFoundException anfex) {
-      throw ServiceException.notFound("Account {0} not found.", identifier);
+      final AccountPage accountPage = this.ledgerManager.fetchAccounts(true, identifier, null, true,
+          0, 10, null, null);
+
+      return accountPage.getAccounts()
+          .stream()
+          .filter(account -> account.getAlternativeAccountNumber().equals(identifier))
+          .findFirst()
+          .orElseThrow(() -> ServiceException.notFound("Account {0} not found.", identifier));
     }
   }
 
diff --git a/service/src/main/java/io/mifos/deposit/service/internal/service/helper/RhythmService.java b/service/src/main/java/io/mifos/deposit/service/internal/service/helper/RhythmService.java
index dfa7d18..67349a0 100644
--- a/service/src/main/java/io/mifos/deposit/service/internal/service/helper/RhythmService.java
+++ b/service/src/main/java/io/mifos/deposit/service/internal/service/helper/RhythmService.java
@@ -1,3 +1,18 @@
+/*
+ * Copyright 2017 The Mifos Initiative.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
 package io.mifos.deposit.service.internal.service.helper;
 
 import io.mifos.core.api.util.NotFoundException;
diff --git a/service/src/main/java/io/mifos/deposit/service/rest/ProductDefinitionRestController.java b/service/src/main/java/io/mifos/deposit/service/rest/ProductDefinitionRestController.java
index dfd1c1f..c925e43 100644
--- a/service/src/main/java/io/mifos/deposit/service/rest/ProductDefinitionRestController.java
+++ b/service/src/main/java/io/mifos/deposit/service/rest/ProductDefinitionRestController.java
@@ -18,7 +18,6 @@ package io.mifos.deposit.service.rest;
 import io.mifos.anubis.annotation.AcceptedTokenType;
 import io.mifos.anubis.annotation.Permittable;
 import io.mifos.core.command.gateway.CommandGateway;
-import io.mifos.core.lang.DateConverter;
 import io.mifos.core.lang.ServiceException;
 import io.mifos.deposit.api.v1.PermittableGroupIds;
 import io.mifos.deposit.api.v1.definition.domain.DividendDistribution;

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

[fineract-cn-deposit-account-management] 23/26: Add null check to prevent NPE when saving product definition without charges Add null check for flexible to prevent SQL exception

Posted by my...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

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

commit a646446245d4cf44c9108adaf6f1a38f4c4aa51e
Author: Mark <ma...@gmail.com>
AuthorDate: Wed Nov 1 18:46:29 2017 +0100

    Add null check to prevent NPE when saving product definition without charges
    Add null check for flexible to prevent SQL exception
---
 .../api/v1/definition/domain/ProductDefinition.java  |  1 +
 .../command/handler/ProductDefinitionAggregate.java  | 20 +++++++++++---------
 2 files changed, 12 insertions(+), 9 deletions(-)

diff --git a/api/src/main/java/io/mifos/deposit/api/v1/definition/domain/ProductDefinition.java b/api/src/main/java/io/mifos/deposit/api/v1/definition/domain/ProductDefinition.java
index 59d89c3..17ef7cd 100644
--- a/api/src/main/java/io/mifos/deposit/api/v1/definition/domain/ProductDefinition.java
+++ b/api/src/main/java/io/mifos/deposit/api/v1/definition/domain/ProductDefinition.java
@@ -50,6 +50,7 @@ public class ProductDefinition {
   private Term term;
   @Valid
   private Set<Charge> charges;
+  @NotNull
   private Boolean flexible;
   private Boolean active;
 
diff --git a/service/src/main/java/io/mifos/deposit/service/internal/command/handler/ProductDefinitionAggregate.java b/service/src/main/java/io/mifos/deposit/service/internal/command/handler/ProductDefinitionAggregate.java
index 788c4c4..b67ed48 100644
--- a/service/src/main/java/io/mifos/deposit/service/internal/command/handler/ProductDefinitionAggregate.java
+++ b/service/src/main/java/io/mifos/deposit/service/internal/command/handler/ProductDefinitionAggregate.java
@@ -228,15 +228,17 @@ public class ProductDefinitionAggregate {
     termEntity.setProductDefinition(savedProductEntity);
     this.termRepository.save(termEntity);
 
-    this.chargeRepository.save(productDefinition.getCharges()
-        .stream()
-        .map(charge -> {
-          final ChargeEntity chargeEntity = ChargeMapper.map(charge, this.actionRepository);
-          chargeEntity.setProductDefinition(savedProductEntity);
-          return chargeEntity;
-        })
-        .collect(Collectors.toSet())
-    );
+    if (productDefinition.getCharges() != null && !productDefinition.getCharges().isEmpty()) {
+      this.chargeRepository.save(productDefinition.getCharges()
+              .stream()
+              .map(charge -> {
+                final ChargeEntity chargeEntity = ChargeMapper.map(charge, this.actionRepository);
+                chargeEntity.setProductDefinition(savedProductEntity);
+                return chargeEntity;
+              })
+              .collect(Collectors.toSet())
+      );
+    }
   }
 
   void deleteDependingEntities(final ProductDefinitionEntity productDefinitionEntity) {

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

[fineract-cn-deposit-account-management] 01/26: Merge pull request #1 from myrle-krantz/develop

Posted by my...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

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

commit 22b1f49e157c0bfd80bb1a9622a051f5bd43779a
Merge: 223b4cf bcdf82e
Author: Myrle Krantz <my...@apache.org>
AuthorDate: Tue Jul 11 12:05:16 2017 +0200

    Merge pull request #1 from myrle-krantz/develop
    
    Added TestSuite to make running all the component tests faster.

 .../AbstractDepositAccountManagementTest.java      | 20 ++---------
 .../io/mifos/deposit/SuiteTestEnvironment.java     | 41 ++++++++++++++++++++++
 .../src/main/java/io/mifos/deposit/TestSuite.java  | 31 ++++++++++++++++
 3 files changed, 74 insertions(+), 18 deletions(-)

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

[fineract-cn-deposit-account-management] 12/26: Merge pull request #3 from markusgeiss/develop

Posted by my...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

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

commit 0362703be50757b77c55322e4dc9059f57541808
Merge: 9b93726 ebda8e9
Author: Markus Geiss <ma...@kuelap.io>
AuthorDate: Thu Sep 7 11:27:42 2017 +0200

    Merge pull request #3 from markusgeiss/develop
    
    fixed bug while closing an unused product

 .../AbstractDepositAccountManagementTest.java      |  4 +++
 .../io/mifos/deposit/TestProductDefinition.java    | 29 ++++++++++++++++++++++
 .../repository/ProductDefinitionCommandEntity.java |  2 +-
 3 files changed, 34 insertions(+), 1 deletion(-)

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

[fineract-cn-deposit-account-management] 18/26: Merge pull request #6 from markusgeiss/develop

Posted by my...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

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

commit 30bc082b7fc64dc14c04e1089a9b048a6050fd5e
Merge: afe6c8f 72e80f6
Author: Markus Geiss <ma...@kuelap.io>
AuthorDate: Wed Oct 18 06:54:37 2017 +0200

    Merge pull request #6 from markusgeiss/develop
    
    fix date range only use dates

 .../deposit/service/internal/command/handler/InterestCalculator.java  | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

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

[fineract-cn-deposit-account-management] 20/26: Merge pull request #7 from markusgeiss/develop

Posted by my...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

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

commit 5be1dbf04693676e05cd51e6db5cfe779201d9f3
Merge: 30bc082 11a939c
Author: Markus Geiss <ma...@kuelap.io>
AuthorDate: Sun Oct 22 09:01:09 2017 +0200

    Merge pull request #7 from markusgeiss/develop
    
    added opened on and last transaction date to product instance

 .../io/mifos/deposit/api/v1/EventConstants.java    |  1 +
 .../api/v1/instance/domain/ProductInstance.java    | 18 +++++++++
 .../java/io/mifos/deposit/TestProductInstance.java | 47 +++++++++++++++++++++-
 .../command/TransactionProcessedCommand.java       | 30 ++++++++++++++
 .../command/handler/ProductInstanceAggregate.java  | 22 ++++++++++
 .../internal/mapper/ProductInstanceMapper.java     | 17 ++++++++
 .../internal/repository/ProductInstanceEntity.java | 24 +++++++++++
 .../rest/ProductInstanceRestController.java        |  4 ++
 ..._add_opened_on_last_transaction_to_instance.sql | 20 +++++++++
 9 files changed, 182 insertions(+), 1 deletion(-)

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

[fineract-cn-deposit-account-management] 17/26: fix date range only use dates

Posted by my...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

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

commit 72e80f60e01f6931ef9bfc19c3e15b0bb9890e5b
Author: mgeiss <mg...@mifos.org>
AuthorDate: Wed Oct 18 06:53:47 2017 +0200

    fix date range only use dates
---
 .../deposit/service/internal/command/handler/InterestCalculator.java  | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/service/src/main/java/io/mifos/deposit/service/internal/command/handler/InterestCalculator.java b/service/src/main/java/io/mifos/deposit/service/internal/command/handler/InterestCalculator.java
index 8f8ffd4..f9bd630 100644
--- a/service/src/main/java/io/mifos/deposit/service/internal/command/handler/InterestCalculator.java
+++ b/service/src/main/java/io/mifos/deposit/service/internal/command/handler/InterestCalculator.java
@@ -278,8 +278,8 @@ public class InterestCalculator {
             final Account account =
                 this.accountingService.findAccount(productInstanceEntity.getAccountIdentifier());
 
-            final LocalDateTime startDate = dividendDistributionCommand.dueDate().plusDays(1).atStartOfDay();
-            final LocalDateTime now = LocalDateTime.now(Clock.systemUTC());
+            final LocalDate startDate = dividendDistributionCommand.dueDate().plusDays(1);
+            final LocalDate now = LocalDate.now(Clock.systemUTC());
 
             final String findCurrentEntries = DateConverter.toIsoString(startDate) + ".." + DateConverter.toIsoString(now);
             final List<AccountEntry> currentAccountEntries =

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