private Collection<SavingsProductData> retrieveSavingsProducts(
     Collection<JLGGroupData> groupsWithSavingsData) {
   List<SavingsProductData> savingsProducts = new ArrayList<>();
   for (JLGGroupData groupSavingsData : groupsWithSavingsData) {
     Collection<JLGClientData> clientsSavingsData = groupSavingsData.getClients();
     for (JLGClientData clientSavingsData : clientsSavingsData) {
       Collection<SavingsDueData> savingsDatas = clientSavingsData.getSavings();
       for (SavingsDueData savingsDueData : savingsDatas) {
         final SavingsProductData savingsProduct =
             SavingsProductData.lookup(savingsDueData.productId(), savingsDueData.productName());
         if (!savingsProducts.contains(savingsProduct)) {
           savingsProducts.add(savingsProduct);
         }
       }
     }
   }
   return savingsProducts;
 }
  private void mergeGroup(
      final JLGGroupData groupSavingsData, final List<JLGGroupData> groupsWithLoanData) {
    final int index = groupsWithLoanData.indexOf(groupSavingsData);

    if (index < 0) return;

    JLGGroupData groupLoanData = groupsWithLoanData.get(index);
    List<JLGClientData> clientsLoanData = (List<JLGClientData>) groupLoanData.getClients();
    List<JLGClientData> clientsSavingsData = (List<JLGClientData>) groupSavingsData.getClients();

    for (JLGClientData clientSavingsData : clientsSavingsData) {
      if (clientsLoanData.contains(clientSavingsData)) {
        mergeClient(clientSavingsData, clientsLoanData);
      } else {
        clientsLoanData.add(clientSavingsData);
      }
    }
  }
    @Override
    public JLGGroupData mapRow(ResultSet rs, @SuppressWarnings("unused") int rowNum)
        throws SQLException {

      final String groupName = rs.getString("groupName");
      final Long groupId = JdbcSupport.getLong(rs, "groupId");
      final Long staffId = JdbcSupport.getLong(rs, "staffId");
      final String staffName = rs.getString("staffName");
      final Long levelId = JdbcSupport.getLong(rs, "levelId");
      final String levelName = rs.getString("levelName");
      return JLGGroupData.instance(groupId, groupName, staffId, staffName, levelId, levelName);
    }
    public JLGGroupData mapRowData(ResultSet rs, int rowNum) throws SQLException {
      final List<JLGClientData> clients = new ArrayList<>();
      final JLGGroupData group = this.mapRow(rs, rowNum);
      final Long previousGroupId = group.getGroupId();

      // first client row of new group
      JLGClientData client = clientSavingsDataMapper.mapRowData(rs, rowNum);
      clients.add(client);

      // if its not after last row loop
      while (!rs.isAfterLast()) {
        final Long groupId = JdbcSupport.getLong(rs, "groupId");
        if (previousGroupId != null && groupId.compareTo(previousGroupId) != 0) {
          // return for next group details
          return JLGGroupData.withClients(group, clients);
        }
        client = clientSavingsDataMapper.mapRowData(rs, rowNum);
        clients.add(client);
      }

      return JLGGroupData.withClients(group, clients);
    }
  /*
   * Reads all the loans which are due for disbursement or collection and
   * builds hierarchical data structure for collections sheet with hierarchy
   * Groups >> Clients >> Loans.
   */
  @SuppressWarnings("null")
  private JLGCollectionSheetData buildJLGCollectionSheet(
      final LocalDate dueDate,
      final Collection<JLGCollectionSheetFlatData> jlgCollectionSheetFlatData) {

    boolean firstTime = true;
    Long prevGroupId = null;
    Long prevClientId = null;

    final List<JLGGroupData> jlgGroupsData = new ArrayList<>();
    List<JLGClientData> clientsData = new ArrayList<>();
    List<LoanDueData> loansDueData = new ArrayList<>();

    JLGCollectionSheetData jlgCollectionSheetData = null;
    JLGCollectionSheetFlatData prevCollectioSheetFlatData = null;
    JLGCollectionSheetFlatData corrCollectioSheetFlatData = null;
    final Set<LoanProductData> loanProducts = new HashSet<>();
    if (jlgCollectionSheetFlatData != null) {

      for (final JLGCollectionSheetFlatData collectionSheetFlatData : jlgCollectionSheetFlatData) {

        if (collectionSheetFlatData.getProductId() != null) {
          loanProducts.add(
              LoanProductData.lookupWithCurrency(
                  collectionSheetFlatData.getProductId(),
                  collectionSheetFlatData.getProductShortName(),
                  collectionSheetFlatData.getCurrency()));
        }
        corrCollectioSheetFlatData = collectionSheetFlatData;

        if (firstTime || collectionSheetFlatData.getGroupId().equals(prevGroupId)) {
          if (firstTime || collectionSheetFlatData.getClientId().equals(prevClientId)) {
            if (collectionSheetFlatData.getLoanId() != null) {
              loansDueData.add(collectionSheetFlatData.getLoanDueData());
            }
          } else {
            final JLGClientData clientData = prevCollectioSheetFlatData.getClientData();
            clientData.setLoans(loansDueData);
            clientsData.add(clientData);
            loansDueData = new ArrayList<>();

            if (collectionSheetFlatData.getLoanId() != null) {
              loansDueData.add(collectionSheetFlatData.getLoanDueData());
            }
          }
        } else {

          final JLGClientData clientData = prevCollectioSheetFlatData.getClientData();
          clientData.setLoans(loansDueData);
          clientsData.add(clientData);

          final JLGGroupData jlgGroupData = prevCollectioSheetFlatData.getJLGGroupData();
          jlgGroupData.setClients(clientsData);

          jlgGroupsData.add(jlgGroupData);

          loansDueData = new ArrayList<>();
          clientsData = new ArrayList<>();

          if (collectionSheetFlatData.getLoanId() != null) {
            loansDueData.add(collectionSheetFlatData.getLoanDueData());
          }
        }

        prevClientId = collectionSheetFlatData.getClientId();
        prevGroupId = collectionSheetFlatData.getGroupId();
        prevCollectioSheetFlatData = collectionSheetFlatData;
        firstTime = false;
      }

      // FIXME Need to check last loan is added under previous
      // client/group or new client / previous group or new client / new
      // group
      if (corrCollectioSheetFlatData != null) {
        final JLGClientData lastClientData = corrCollectioSheetFlatData.getClientData();
        lastClientData.setLoans(loansDueData);
        clientsData.add(lastClientData);

        final JLGGroupData jlgGroupData = corrCollectioSheetFlatData.getJLGGroupData();
        jlgGroupData.setClients(clientsData);
        jlgGroupsData.add(jlgGroupData);
      }

      jlgCollectionSheetData =
          JLGCollectionSheetData.instance(
              dueDate,
              loanProducts,
              jlgGroupsData,
              this.attendanceDropdownReadPlatformService.retrieveAttendanceTypeOptions());
    }

    return jlgCollectionSheetData;
  }