Implemented waiting for ledger creation before proceeding to account creation.
diff --git a/component-test/src/main/java/io/mifos/portfolio/AbstractPortfolioTest.java b/component-test/src/main/java/io/mifos/portfolio/AbstractPortfolioTest.java
index 68461f4..2aedaa3 100644
--- a/component-test/src/main/java/io/mifos/portfolio/AbstractPortfolioTest.java
+++ b/component-test/src/main/java/io/mifos/portfolio/AbstractPortfolioTest.java
@@ -31,6 +31,7 @@
 import io.mifos.portfolio.api.v1.domain.*;
 import io.mifos.portfolio.api.v1.events.*;
 import io.mifos.portfolio.service.config.PortfolioServiceConfiguration;
+import io.mifos.portfolio.service.internal.util.AccountingListener;
 import io.mifos.portfolio.service.internal.util.RhythmAdapter;
 import org.junit.*;
 import org.junit.runner.RunWith;
@@ -41,6 +42,7 @@
 import org.springframework.beans.factory.annotation.Qualifier;
 import org.springframework.boot.test.context.SpringBootTest;
 import org.springframework.boot.test.mock.mockito.MockBean;
+import org.springframework.boot.test.mock.mockito.SpyBean;
 import org.springframework.cloud.netflix.feign.EnableFeignClients;
 import org.springframework.cloud.netflix.ribbon.RibbonClient;
 import org.springframework.context.annotation.Bean;
@@ -124,6 +126,9 @@
   @MockBean
   CustomerManager customerManager;
 
+  @SpyBean
+  AccountingListener accountingListener;
+
   @SuppressWarnings("SpringAutowiredFieldsWarningInspection")
   @Autowired
   @Qualifier(LOGGER_NAME)
@@ -132,7 +137,7 @@
   @Before
   public void prepTest() {
     userContext = this.tenantApplicationSecurityEnvironment.createAutoUserContext(TEST_USER);
-    AccountingFixture.mockAccountingPrereqs(ledgerManager);
+    AccountingFixture.mockAccountingPrereqs(ledgerManager, accountingListener);
     Mockito.doReturn(true).when(customerManager).isCustomerInGoodStanding(Fixture.CUSTOMER_IDENTIFIER);
   }
 
diff --git a/component-test/src/main/java/io/mifos/portfolio/AccountingFixture.java b/component-test/src/main/java/io/mifos/portfolio/AccountingFixture.java
index feaee49..eb00848 100644
--- a/component-test/src/main/java/io/mifos/portfolio/AccountingFixture.java
+++ b/component-test/src/main/java/io/mifos/portfolio/AccountingFixture.java
@@ -19,7 +19,9 @@
 import io.mifos.accounting.api.v1.domain.*;
 import io.mifos.core.api.util.NotFoundException;
 import io.mifos.core.lang.DateConverter;
+import io.mifos.core.lang.TenantContextHolder;
 import io.mifos.individuallending.api.v1.domain.workflow.Action;
+import io.mifos.portfolio.service.internal.util.AccountingListener;
 import org.hamcrest.Description;
 import org.junit.Assert;
 import org.mockito.AdditionalMatchers;
@@ -477,10 +479,17 @@
   }
 
   private static class CreateLedgerAnswer implements Answer {
+    private final AccountingListener accountingListener;
+
+    public CreateLedgerAnswer(AccountingListener accountingListener) {
+      this.accountingListener = accountingListener;
+    }
+
     @Override
     public Void answer(final InvocationOnMock invocation) throws Throwable {
       final Ledger ledger = invocation.getArgumentAt(0, Ledger.class);
       makeLedgerResponsive(ledger, (LedgerManager) invocation.getMock());
+      accountingListener.onPostLedger(TenantContextHolder.checkedGetIdentifier(), ledger.getIdentifier());
       return null;
     }
   }
@@ -512,7 +521,7 @@
     }
   }
 
-  static void mockAccountingPrereqs(final LedgerManager ledgerManagerMock) {
+  static void mockAccountingPrereqs(final LedgerManager ledgerManagerMock, final AccountingListener accountingListener) {
     makeAccountResponsive(loanFundsSourceAccount(), universalCreationDate, ledgerManagerMock);
     makeAccountResponsive(loanOriginationFeesIncomeAccount(), universalCreationDate, ledgerManagerMock);
     makeAccountResponsive(processingFeeIncomeAccount(), universalCreationDate, ledgerManagerMock);
@@ -536,7 +545,7 @@
     Mockito.doAnswer(new FindAccountAnswer()).when(ledgerManagerMock).findAccount(Matchers.anyString());
     Mockito.doAnswer(new CreateAccountAnswer()).when(ledgerManagerMock).createAccount(Matchers.any());
     Mockito.doAnswer(new CreateJournalEntryAnswer()).when(ledgerManagerMock).createJournalEntry(Matchers.any(JournalEntry.class));
-    Mockito.doAnswer(new CreateLedgerAnswer()).when(ledgerManagerMock).createLedger(Matchers.any(Ledger.class));
+    Mockito.doAnswer(new CreateLedgerAnswer(accountingListener)).when(ledgerManagerMock).createLedger(Matchers.any(Ledger.class));
   }
 
   static void mockBalance(final String accountIdentifier, final BigDecimal balance) {
diff --git a/service/src/main/java/io/mifos/individuallending/internal/command/handler/IndividualLoanCommandHandler.java b/service/src/main/java/io/mifos/individuallending/internal/command/handler/IndividualLoanCommandHandler.java
index 5caf2ea..c42f31f 100644
--- a/service/src/main/java/io/mifos/individuallending/internal/command/handler/IndividualLoanCommandHandler.java
+++ b/service/src/main/java/io/mifos/individuallending/internal/command/handler/IndividualLoanCommandHandler.java
@@ -152,12 +152,26 @@
     return new IndividualLoanCommandEvent(productIdentifier, caseIdentifier, DateConverter.toIsoString(today));
   }
 
+  static class InterruptedInALambdaException extends RuntimeException {
+
+    private final InterruptedException interruptedException;
+
+    InterruptedInALambdaException(InterruptedException e) {
+      interruptedException = e;
+    }
+
+    void throwWrappedException() throws InterruptedException {
+      throw interruptedException;
+    }
+  }
+
   @Transactional
   @CommandHandler(logStart = CommandLogLevel.INFO, logFinish = CommandLogLevel.INFO)
   @EventEmitter(
       selectorName = EventConstants.SELECTOR_NAME,
       selectorValue = IndividualLoanEventConstants.APPROVE_INDIVIDUALLOAN_CASE)
-  public IndividualLoanCommandEvent process(final ApproveCommand command) {
+  public IndividualLoanCommandEvent process(final ApproveCommand command) throws InterruptedException
+  {
     final String productIdentifier = command.getProductIdentifier();
     final String caseIdentifier = command.getCaseIdentifier();
     final DataContextOfAction dataContextOfAction = dataContextService.checkedGetDataContext(
@@ -170,14 +184,25 @@
             = new DesignatorToAccountIdentifierMapper(dataContextOfAction);
 
     //Create the needed account assignments for groups and persist them for the case.
-    designatorToAccountIdentifierMapper.getGroupsNeedingLedgers()
-        .map(groupNeedingLedger -> new AccountAssignment(groupNeedingLedger.getGroupName(),
-            accountingAdapter.createLedger(
-                dataContextOfAction.getCaseParametersEntity().getCustomerIdentifier(),
-                groupNeedingLedger.getGroupName(),
-                groupNeedingLedger.getParentLedger())))
-        .map(accountAssignment -> CaseMapper.map(accountAssignment, dataContextOfAction.getCustomerCaseEntity()))
-        .forEach(caseAccountAssignmentEntity -> dataContextOfAction.getCustomerCaseEntity().getAccountAssignments().add(caseAccountAssignmentEntity));
+    try {
+      designatorToAccountIdentifierMapper.getGroupsNeedingLedgers()
+          .map(groupNeedingLedger -> {
+            try {
+              final String createdLedgerIdentifier = accountingAdapter.createLedger(
+                  dataContextOfAction.getCaseParametersEntity().getCustomerIdentifier(),
+                  groupNeedingLedger.getGroupName(),
+                  groupNeedingLedger.getParentLedger());
+              return new AccountAssignment(groupNeedingLedger.getGroupName(), createdLedgerIdentifier);
+            } catch (InterruptedException e) {
+              throw new InterruptedInALambdaException(e);
+            }
+          })
+          .map(accountAssignment -> CaseMapper.map(accountAssignment, dataContextOfAction.getCustomerCaseEntity()))
+          .forEach(caseAccountAssignmentEntity -> dataContextOfAction.getCustomerCaseEntity().getAccountAssignments().add(caseAccountAssignmentEntity));
+    }
+    catch (final InterruptedInALambdaException e) {
+      e.throwWrappedException();
+    }
 
     //Create the needed account assignments and persist them for the case.
     designatorToAccountIdentifierMapper.getLedgersNeedingAccounts()
diff --git a/service/src/main/java/io/mifos/portfolio/service/internal/util/AccountingAdapter.java b/service/src/main/java/io/mifos/portfolio/service/internal/util/AccountingAdapter.java
index d305e43..217f1eb 100644
--- a/service/src/main/java/io/mifos/portfolio/service/internal/util/AccountingAdapter.java
+++ b/service/src/main/java/io/mifos/portfolio/service/internal/util/AccountingAdapter.java
@@ -24,6 +24,7 @@
 import io.mifos.core.lang.DateConverter;
 import io.mifos.core.lang.DateRange;
 import io.mifos.core.lang.ServiceException;
+import io.mifos.core.lang.listening.EventExpectation;
 import io.mifos.portfolio.api.v1.domain.AccountAssignment;
 import io.mifos.portfolio.api.v1.domain.ChargeDefinition;
 import io.mifos.portfolio.service.ServiceConstants;
@@ -39,6 +40,7 @@
 import java.time.LocalDateTime;
 import java.time.ZoneId;
 import java.util.*;
+import java.util.concurrent.TimeUnit;
 import java.util.stream.Collectors;
 import java.util.stream.Stream;
 
@@ -54,12 +56,15 @@
   public enum IdentifierType {LEDGER, ACCOUNT}
 
   private final LedgerManager ledgerManager;
+  private final AccountingListener accountingListener;
   private final Logger logger;
 
   @Autowired
   public AccountingAdapter(@SuppressWarnings("SpringJavaAutowiringInspection") final LedgerManager ledgerManager,
+                           final AccountingListener accountingListener,
                            @Qualifier(ServiceConstants.LOGGER_NAME) final Logger logger) {
     this.ledgerManager = ledgerManager;
+    this.accountingListener = accountingListener;
     this.logger = logger;
   }
 
@@ -170,7 +175,12 @@
      throw ServiceException.internalError("Could not find the account with identifier ''{0}''", accountIdentifier);
     }
   }
-  public String createLedger(final String customerIdentifier, final String groupName, final String parentLedger) {
+
+  public String createLedger(
+      final String customerIdentifier,
+      final String groupName,
+      final String parentLedger) throws InterruptedException
+  {
     final Ledger ledger = ledgerManager.findLedger(parentLedger);
     final List<Ledger> subLedgers = ledger.getSubLedgers() == null ? Collections.emptyList() : ledger.getSubLedgers();
 
@@ -185,7 +195,13 @@
 
     logger.info("Creating ledger with identifier '{}'", ledgerIdentifer);
 
-    ledgerManager.createLedger(generatedLedger); //TODO: wait?
+    final EventExpectation expectation = accountingListener.expectLedgerCreation(generatedLedger.getIdentifier());
+    ledgerManager.createLedger(generatedLedger);
+    final boolean ledgerCreationDetected = expectation.waitForOccurrence(5, TimeUnit.SECONDS);
+    if (!ledgerCreationDetected)
+      logger.warn("Waited 5 seconds for creation of ledger '{}', but it was not detected. This could cause subsequent " +
+              "account creations to fail. Is there something wrong with the accounting service? Is ActiveMQ setup properly?",
+          generatedLedger.getIdentifier());
     return ledgerIdentifer;
   }
 
diff --git a/service/src/main/java/io/mifos/portfolio/service/internal/util/AccountingListener.java b/service/src/main/java/io/mifos/portfolio/service/internal/util/AccountingListener.java
new file mode 100644
index 0000000..034510a
--- /dev/null
+++ b/service/src/main/java/io/mifos/portfolio/service/internal/util/AccountingListener.java
@@ -0,0 +1,49 @@
+/*
+ * Copyright 2017 Kuelap, Inc.
+ *
+ * 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.portfolio.service.internal.util;
+
+import io.mifos.accounting.api.v1.EventConstants;
+import io.mifos.core.lang.TenantContextHolder;
+import io.mifos.core.lang.config.TenantHeaderFilter;
+import io.mifos.core.lang.listening.EventExpectation;
+import io.mifos.core.lang.listening.EventKey;
+import io.mifos.core.lang.listening.TenantedEventListener;
+import org.springframework.jms.annotation.JmsListener;
+import org.springframework.messaging.handler.annotation.Header;
+import org.springframework.stereotype.Component;
+
+/**
+ * @author Myrle Krantz
+ */
+@Component
+public class AccountingListener {
+  private final TenantedEventListener eventListener = new TenantedEventListener();
+
+  @JmsListener(
+      destination = EventConstants.DESTINATION,
+      selector = EventConstants.SELECTOR_POST_LEDGER,
+      subscription = EventConstants.DESTINATION
+  )
+  public void onPostLedger(@Header(TenantHeaderFilter.TENANT_HEADER) final String tenant,
+                           final String payload) {
+    this.eventListener.notify(new EventKey(tenant, EventConstants.POST_LEDGER, payload));
+  }
+
+
+  EventExpectation expectLedgerCreation(final String ledgerIdentifier) {
+    return eventListener.expect(new EventKey(TenantContextHolder.checkedGetIdentifier(), EventConstants.POST_LEDGER, ledgerIdentifier));
+  }
+}
diff --git a/service/src/test/java/io/mifos/individuallending/internal/service/PaymentBuilderTest.java b/service/src/test/java/io/mifos/individuallending/internal/service/PaymentBuilderTest.java
index b113d50..b98742b 100644
--- a/service/src/test/java/io/mifos/individuallending/internal/service/PaymentBuilderTest.java
+++ b/service/src/test/java/io/mifos/individuallending/internal/service/PaymentBuilderTest.java
@@ -1,3 +1,18 @@
+/*
+ * Copyright 2017 Kuelap, Inc.
+ *
+ * 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.individuallending.internal.service;
 
 import io.mifos.individuallending.api.v1.domain.product.AccountDesignators;