@Override
  public JLGCollectionSheetData generateCenterCollectionSheet(
      final Long centerId, final JsonQuery query) {

    this.collectionSheetGenerateCommandFromApiJsonDeserializer.validateForGenerateCollectionSheet(
        query.json());

    final AppUser currentUser = this.context.authenticatedUser();
    final String hierarchy = currentUser.getOffice().getHierarchy();
    final String officeHierarchy = hierarchy + "%";

    final CenterData center = this.centerReadPlatformService.retrieveOne(centerId);

    final LocalDate transactionDate =
        query.localDateValueOfParameterNamed(transactionDateParamName);
    final DateFormat df = new SimpleDateFormat("yyyy-MM-dd");
    final String dueDateStr = df.format(transactionDate.toDate());

    final JLGCollectionSheetFaltDataMapper mapper = new JLGCollectionSheetFaltDataMapper();

    StringBuilder sql = new StringBuilder(mapper.collectionSheetSchema(true));

    final SqlParameterSource namedParameters =
        new MapSqlParameterSource()
            .addValue("dueDate", dueDateStr)
            .addValue("centerId", center.getId())
            .addValue("officeHierarchy", officeHierarchy)
            .addValue("entityTypeId", CalendarEntityType.CENTERS.getValue());

    final Collection<JLGCollectionSheetFlatData> collectionSheetFlatDatas =
        this.namedParameterjdbcTemplate.query(sql.toString(), namedParameters, mapper);

    // loan data for collection sheet
    JLGCollectionSheetData collectionSheetData =
        buildJLGCollectionSheet(transactionDate, collectionSheetFlatDatas);

    // mandatory savings data for collection sheet
    Collection<JLGGroupData> groupsWithSavingsData =
        this.namedParameterjdbcTemplate.query(
            mandatorySavingsExtractor.collectionSheetSchema(true),
            namedParameters,
            mandatorySavingsExtractor);

    // merge savings data into loan data
    mergeSavingsGroupDataIntoCollectionsheetData(groupsWithSavingsData, collectionSheetData);

    collectionSheetData =
        JLGCollectionSheetData.withSavingsProducts(
            collectionSheetData, retrieveSavingsProducts(groupsWithSavingsData));

    return collectionSheetData;
  }
  @Override
  public JLGCollectionSheetData generateGroupCollectionSheet(
      final Long groupId, final JsonQuery query) {

    this.collectionSheetGenerateCommandFromApiJsonDeserializer.validateForGenerateCollectionSheet(
        query.json());

    final Long calendarId = query.longValueOfParameterNamed(calendarIdParamName);
    final LocalDate transactionDate =
        query.localDateValueOfParameterNamed(transactionDateParamName);
    final DateFormat df = new SimpleDateFormat("yyyy-MM-dd");
    final String transactionDateStr = df.format(transactionDate.toDate());

    final Calendar calendar =
        this.calendarRepositoryWrapper.findOneWithNotFoundDetection(calendarId);
    // check if transaction against calendar effective from date

    if (!calendar.isValidRecurringDate(transactionDate)) {
      throw new NotValidRecurringDateException(
          "collectionsheet",
          "The date '" + transactionDate + "' is not a valid meeting date.",
          transactionDate);
    }

    final AppUser currentUser = this.context.authenticatedUser();
    final String hierarchy = currentUser.getOffice().getHierarchy();
    final String officeHierarchy = hierarchy + "%";

    final GroupGeneralData group = this.groupReadPlatformService.retrieveOne(groupId);

    final JLGCollectionSheetFaltDataMapper mapper = new JLGCollectionSheetFaltDataMapper();

    // entityType should be center if it's within a center
    final CalendarEntityType entityType =
        (group.isChildGroup()) ? CalendarEntityType.CENTERS : CalendarEntityType.GROUPS;

    final SqlParameterSource namedParameters =
        new MapSqlParameterSource()
            .addValue("dueDate", transactionDateStr)
            .addValue("groupId", group.getId())
            .addValue("officeHierarchy", officeHierarchy)
            .addValue("entityTypeId", entityType.getValue());

    final Collection<JLGCollectionSheetFlatData> collectionSheetFlatDatas =
        this.namedParameterjdbcTemplate.query(
            mapper.collectionSheetSchema(false), namedParameters, mapper);

    // loan data for collection sheet
    JLGCollectionSheetData collectionSheetData =
        buildJLGCollectionSheet(transactionDate, collectionSheetFlatDatas);

    // mandatory savings data for collection sheet
    Collection<JLGGroupData> groupsWithSavingsData =
        this.namedParameterjdbcTemplate.query(
            mandatorySavingsExtractor.collectionSheetSchema(false),
            namedParameters,
            mandatorySavingsExtractor);

    // merge savings data into loan data
    mergeSavingsGroupDataIntoCollectionsheetData(groupsWithSavingsData, collectionSheetData);

    collectionSheetData =
        JLGCollectionSheetData.withSavingsProducts(
            collectionSheetData, retrieveSavingsProducts(groupsWithSavingsData));

    return collectionSheetData;
  }