diff --git a/mifosng-provider/src/main/java/org/mifosplatform/commands/service/CommandWrapperBuilder.java b/mifosng-provider/src/main/java/org/mifosplatform/commands/service/CommandWrapperBuilder.java index 430387fd9..76996c137 100644 --- a/mifosng-provider/src/main/java/org/mifosplatform/commands/service/CommandWrapperBuilder.java +++ b/mifosng-provider/src/main/java/org/mifosplatform/commands/service/CommandWrapperBuilder.java @@ -6,6 +6,7 @@ package org.mifosplatform.commands.service; import org.mifosplatform.commands.domain.CommandWrapper; +import org.mifosplatform.portfolio.calendar.domain.CalendarEntityType; public class CommandWrapperBuilder { @@ -1016,6 +1017,8 @@ public class CommandWrapperBuilder { this.entityName = "GROUP"; this.entityId = groupId; this.groupId = groupId; + this.supportedEntityId = groupId; + this.supportedEntityType = CalendarEntityType.GROUPS.name(); this.href = "/groups/" + groupId + "?command=saveCollectionSheet"; return this; } @@ -1145,6 +1148,8 @@ public class CommandWrapperBuilder { this.actionName = "SAVECOLLECTIONSHEET"; this.entityName = "CENTER"; this.entityId = centerId; + this.supportedEntityId = centerId; + this.supportedEntityType = CalendarEntityType.CENTERS.name(); this.href = "/centers/" + centerId + "?command=saveCollectionSheet"; return this; } diff --git a/mifosng-provider/src/main/java/org/mifosplatform/portfolio/calendar/data/CalendarData.java b/mifosng-provider/src/main/java/org/mifosplatform/portfolio/calendar/data/CalendarData.java index ffd205f61..8bdcf2071 100644 --- a/mifosng-provider/src/main/java/org/mifosplatform/portfolio/calendar/data/CalendarData.java +++ b/mifosng-provider/src/main/java/org/mifosplatform/portfolio/calendar/data/CalendarData.java @@ -37,6 +37,7 @@ public class CalendarData { private final Collection recurringDates; private final Collection nextTenRecurringDates; private final String humanReadable; + private final LocalDate recentEligibleMeetingDate; private final LocalDate createdDate; private final LocalDate lastUpdatedDate; @@ -53,7 +54,7 @@ public class CalendarData { public CalendarData(final Long id, final Long entityId, final EnumOptionData entityType, final String title, final String description, final String location, final LocalDate startDate, final LocalDate endDate, final Integer duration, final EnumOptionData type, final boolean repeating, final String recurrence, final EnumOptionData remindBy, final Integer firstReminder, - final Integer secondReminder, final String humanReadable, final LocalDate createdDate, final LocalDate lastUpdatedDate, + final Integer secondReminder, final String humanReadable, final LocalDate recentEligibleMeetingDate, final LocalDate createdDate, final LocalDate lastUpdatedDate, final Long createdByUserId, final String createdByUsername, final Long lastUpdatedByUserId, final String lastUpdatedByUsername) { this.id = id; @@ -77,6 +78,7 @@ public class CalendarData { this.recurringDates = null; this.nextTenRecurringDates = null; this.humanReadable = humanReadable; + this.recentEligibleMeetingDate = recentEligibleMeetingDate; this.createdDate = createdDate; this.lastUpdatedDate = lastUpdatedDate; @@ -109,6 +111,7 @@ public class CalendarData { this.recurringDates = calendarData.recurringDates; this.nextTenRecurringDates = calendarData.nextTenRecurringDates; this.humanReadable = calendarData.humanReadable; + this.recentEligibleMeetingDate = calendarData.recentEligibleMeetingDate; this.createdDate = calendarData.createdDate; this.lastUpdatedDate = calendarData.lastUpdatedDate; this.createdByUserId = calendarData.createdByUserId; @@ -117,7 +120,7 @@ public class CalendarData { this.lastUpdatedByUsername = calendarData.lastUpdatedByUsername; } - public CalendarData(final CalendarData calendarData, final Collection recurringDates, final Collection nextTenRecurringDates) { + public CalendarData(final CalendarData calendarData, final Collection recurringDates, final Collection nextTenRecurringDates, final LocalDate recentEligibleMeetingDate) { this.id = calendarData.id; this.entityId = calendarData.entityId; this.entityType = calendarData.entityType; @@ -139,6 +142,7 @@ public class CalendarData { this.recurringDates = recurringDates; this.nextTenRecurringDates = nextTenRecurringDates; this.humanReadable = calendarData.humanReadable; + this.recentEligibleMeetingDate = recentEligibleMeetingDate; this.createdDate = calendarData.createdDate; this.lastUpdatedDate = calendarData.lastUpdatedDate; this.createdByUserId = calendarData.createdByUserId; @@ -165,9 +169,18 @@ public class CalendarData { final Integer firstReminder = new Integer(0); final Integer secondReminder = new Integer(0); final String humanReadable = null; + final LocalDate recentEligibleMeetingDate = null; + + final LocalDate createdDate = null; + final LocalDate lastUpdatedDate = null; + final Long createdByUserId = null; + final String createdByUsername = null; + final Long lastUpdatedByUserId = null; + final String lastUpdatedByUsername = null; return new CalendarData(id, entityId, entityType, title, description, location, startDate, endDate, duration, type, repeating, - recurrence, remindBy, firstReminder, secondReminder, humanReadable, null, null, null, null, null, null); + recurrence, remindBy, firstReminder, secondReminder, humanReadable, recentEligibleMeetingDate, createdDate, + lastUpdatedDate, createdByUserId, createdByUsername, lastUpdatedByUserId, lastUpdatedByUsername); } public Long getId() { diff --git a/mifosng-provider/src/main/java/org/mifosplatform/portfolio/calendar/domain/CalendarRepositoryWrapper.java b/mifosng-provider/src/main/java/org/mifosplatform/portfolio/calendar/domain/CalendarRepositoryWrapper.java new file mode 100644 index 000000000..4356292fb --- /dev/null +++ b/mifosng-provider/src/main/java/org/mifosplatform/portfolio/calendar/domain/CalendarRepositoryWrapper.java @@ -0,0 +1,51 @@ +/** + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this file, + * You can obtain one at http://mozilla.org/MPL/2.0/. + */ +package org.mifosplatform.portfolio.calendar.domain; + +import org.mifosplatform.portfolio.calendar.exception.CalendarNotFoundException; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; + +/** + *

+ * Wrapper for {@link CalendarRepository} that is responsible for checking + * if {@link Calendar} is returned when using findOne + * repository method and throwing an appropriate not found exception. + *

+ * + *

+ * This is to avoid need for checking and throwing in multiple areas of code + * base where {@link CalendarRepository} is required. + *

+ */ +@Service +public class CalendarRepositoryWrapper { + + private final CalendarRepository repository; + + @Autowired + public CalendarRepositoryWrapper(final CalendarRepository repository) { + this.repository = repository; + } + + public Calendar findOneWithNotFoundDetection(final Long calendarId) { + final Calendar calendar = this.repository.findOne(calendarId); + if (calendar == null) { throw new CalendarNotFoundException(calendarId); } + return calendar; + } + + public void save(final Calendar calendar) { + this.repository.save(calendar); + } + + public void delete(final Calendar calendar) { + this.repository.delete(calendar); + } + + public void saveAndFlush(final Calendar calendar) { + this.repository.saveAndFlush(calendar); + } +} \ No newline at end of file diff --git a/mifosng-provider/src/main/java/org/mifosplatform/portfolio/calendar/service/CalendarReadPlatformServiceImpl.java b/mifosng-provider/src/main/java/org/mifosplatform/portfolio/calendar/service/CalendarReadPlatformServiceImpl.java index d82d58677..126a07962 100644 --- a/mifosng-provider/src/main/java/org/mifosplatform/portfolio/calendar/service/CalendarReadPlatformServiceImpl.java +++ b/mifosng-provider/src/main/java/org/mifosplatform/portfolio/calendar/service/CalendarReadPlatformServiceImpl.java @@ -81,9 +81,11 @@ public class CalendarReadPlatformServiceImpl implements CalendarReadPlatformServ final String createdByUserName = rs.getString("creatingUserName"); final Long lastUpdatedByUserId = rs.getLong("updatingUserId"); final String lastUpdatedByUserName = rs.getString("updatingUserName"); + + final LocalDate recentEligibleMeetingDate = null; return new CalendarData(id, entityId, entityType, title, description, location, startDate, endDate, duration, type, repeating, - recurrence, remindBy, firstReminder, secondReminder, humanReadable, createdDate, lastUpdatedDate, createdByUserId, + recurrence, remindBy, firstReminder, secondReminder, humanReadable, recentEligibleMeetingDate, createdDate, lastUpdatedDate, createdByUserId, createdByUserName, lastUpdatedByUserId, lastUpdatedByUserName); } } @@ -207,7 +209,8 @@ public class CalendarReadPlatformServiceImpl implements CalendarReadPlatformServ final Collection recurringDates = CalendarUtils.getRecurringDates(rrule, seedDate, startDate, endDate, -1); final Collection nextTenRecurringDates = CalendarUtils.getRecurringDates(rrule, seedDate, endDate); - return new CalendarData(calendarData, recurringDates, nextTenRecurringDates); + final LocalDate recentEligibleMeetingDate = CalendarUtils.getRecentEligibleMeetingDate(rrule, seedDate); + return new CalendarData(calendarData, recurringDates, nextTenRecurringDates, recentEligibleMeetingDate); } diff --git a/mifosng-provider/src/main/java/org/mifosplatform/portfolio/calendar/service/CalendarUtils.java b/mifosng-provider/src/main/java/org/mifosplatform/portfolio/calendar/service/CalendarUtils.java index a02cc61fa..a3b27ee19 100644 --- a/mifosng-provider/src/main/java/org/mifosplatform/portfolio/calendar/service/CalendarUtils.java +++ b/mifosng-provider/src/main/java/org/mifosplatform/portfolio/calendar/service/CalendarUtils.java @@ -415,4 +415,26 @@ public class CalendarUtils { sqlCalendarTypeOptions += calendarTypeOptions.get(size - 1).toString(); return sqlCalendarTypeOptions; } + + public static LocalDate getRecentEligibleMeetingDate(final String recurringRule, final LocalDate seedDate){ + LocalDate currentDate = DateUtils.getLocalDateOfTenant(); + final Recur recur = CalendarUtils.getICalRecur(recurringRule); + if (recur == null) { return null; } + + if(isValidRecurringDate(recur, seedDate, currentDate)){ + return currentDate; + } + + if(recur.getFrequency().equals(Recur.DAILY)){ + currentDate = currentDate.plusDays(recur.getInterval()); + }else if(recur.getFrequency().equals(Recur.WEEKLY)){ + currentDate = currentDate.plusWeeks(recur.getInterval()); + }else if(recur.getFrequency().equals(Recur.MONTHLY)){ + currentDate = currentDate.plusMonths(recur.getInterval()); + }else if(recur.getFrequency().equals(Recur.YEARLY)){ + currentDate = currentDate.plusYears(recur.getInterval()); + } + + return getNextRecurringDate(recur, seedDate, currentDate); + } } diff --git a/mifosng-provider/src/main/java/org/mifosplatform/portfolio/collectionsheet/CollectionSheetConstants.java b/mifosng-provider/src/main/java/org/mifosplatform/portfolio/collectionsheet/CollectionSheetConstants.java new file mode 100644 index 000000000..63b8361f6 --- /dev/null +++ b/mifosng-provider/src/main/java/org/mifosplatform/portfolio/collectionsheet/CollectionSheetConstants.java @@ -0,0 +1,37 @@ +/** + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this file, + * You can obtain one at http://mozilla.org/MPL/2.0/. + */ +package org.mifosplatform.portfolio.collectionsheet; + +import java.util.Arrays; +import java.util.HashSet; +import java.util.Set; + +public class CollectionSheetConstants { + + public static final String COLLECTIONSHEET_RESOURCE_NAME = "collectionsheet"; + + public static final String localeParamName = "locale"; + public static final String dateFormatParamName = "dateFormat"; + + public static final String transactionDateParamName = "transactionDate"; + public static final String actualDisbursementDateParamName = "actualDisbursementDate"; + public static final String bulkRepaymentTransactionsParamName = "bulkRepaymentTransactions"; + public static final String bulkDisbursementTransactionsParamName = "bulkDisbursementTransactions"; + public static final String noteParamName = "note"; + public static final String calendarIdParamName = "calendarId"; + + // attendance parameters + public static final String clientsAttendanceParamName = "clientsAttendance"; + public static final String clientIdParamName = "clientId"; + public static final String attendanceTypeParamName = "attendanceType"; + + public static final String loanIdParamName = "loanId"; + public static final String transactionAmountParamName = "transactionAmount"; + + public static final Set COLLECTIONSHEET_REQUEST_DATA_PARAMETERS = new HashSet(Arrays.asList(localeParamName, + dateFormatParamName, transactionDateParamName, actualDisbursementDateParamName, bulkRepaymentTransactionsParamName, + bulkDisbursementTransactionsParamName, noteParamName, calendarIdParamName, clientsAttendanceParamName)); +} \ No newline at end of file diff --git a/mifosng-provider/src/main/java/org/mifosplatform/portfolio/collectionsheet/data/CollectionSheetTransactionDataValidator.java b/mifosng-provider/src/main/java/org/mifosplatform/portfolio/collectionsheet/data/CollectionSheetTransactionDataValidator.java new file mode 100644 index 000000000..f1464e75b --- /dev/null +++ b/mifosng-provider/src/main/java/org/mifosplatform/portfolio/collectionsheet/data/CollectionSheetTransactionDataValidator.java @@ -0,0 +1,154 @@ +/** + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this file, + * You can obtain one at http://mozilla.org/MPL/2.0/. + */ +package org.mifosplatform.portfolio.collectionsheet.data; + +import static org.mifosplatform.portfolio.collectionsheet.CollectionSheetConstants.COLLECTIONSHEET_REQUEST_DATA_PARAMETERS; +import static org.mifosplatform.portfolio.collectionsheet.CollectionSheetConstants.COLLECTIONSHEET_RESOURCE_NAME; +import static org.mifosplatform.portfolio.collectionsheet.CollectionSheetConstants.attendanceTypeParamName; +import static org.mifosplatform.portfolio.collectionsheet.CollectionSheetConstants.bulkDisbursementTransactionsParamName; +import static org.mifosplatform.portfolio.collectionsheet.CollectionSheetConstants.bulkRepaymentTransactionsParamName; +import static org.mifosplatform.portfolio.collectionsheet.CollectionSheetConstants.calendarIdParamName; +import static org.mifosplatform.portfolio.collectionsheet.CollectionSheetConstants.clientIdParamName; +import static org.mifosplatform.portfolio.collectionsheet.CollectionSheetConstants.clientsAttendanceParamName; +import static org.mifosplatform.portfolio.collectionsheet.CollectionSheetConstants.loanIdParamName; +import static org.mifosplatform.portfolio.collectionsheet.CollectionSheetConstants.noteParamName; +import static org.mifosplatform.portfolio.collectionsheet.CollectionSheetConstants.transactionAmountParamName; +import static org.mifosplatform.portfolio.collectionsheet.CollectionSheetConstants.transactionDateParamName; + +import java.lang.reflect.Type; +import java.math.BigDecimal; +import java.util.ArrayList; +import java.util.List; +import java.util.Locale; +import java.util.Map; + +import org.apache.commons.lang.StringUtils; +import org.joda.time.LocalDate; +import org.mifosplatform.infrastructure.core.api.JsonCommand; +import org.mifosplatform.infrastructure.core.data.ApiParameterError; +import org.mifosplatform.infrastructure.core.data.DataValidatorBuilder; +import org.mifosplatform.infrastructure.core.exception.InvalidJsonException; +import org.mifosplatform.infrastructure.core.exception.PlatformApiDataValidationException; +import org.mifosplatform.infrastructure.core.serialization.FromJsonHelper; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Component; + +import com.google.gson.JsonArray; +import com.google.gson.JsonElement; +import com.google.gson.JsonObject; +import com.google.gson.reflect.TypeToken; + +@Component +public class CollectionSheetTransactionDataValidator { + + private final FromJsonHelper fromApiJsonHelper; + + @Autowired + public CollectionSheetTransactionDataValidator(final FromJsonHelper fromApiJsonHelper) { + this.fromApiJsonHelper = fromApiJsonHelper; + } + + public void validateTransaction(final JsonCommand command) { + final String json = command.json(); + if (StringUtils.isBlank(json)) { throw new InvalidJsonException(); } + + final Type typeOfMap = new TypeToken>() {}.getType(); + fromApiJsonHelper.checkForUnsupportedParameters(typeOfMap, json, COLLECTIONSHEET_REQUEST_DATA_PARAMETERS); + + final List dataValidationErrors = new ArrayList(); + final DataValidatorBuilder baseDataValidator = new DataValidatorBuilder(dataValidationErrors) + .resource(COLLECTIONSHEET_RESOURCE_NAME); + + final JsonElement element = fromApiJsonHelper.parse(json); + + final LocalDate transactionDate = fromApiJsonHelper.extractLocalDateNamed(transactionDateParamName, element); + baseDataValidator.reset().parameter(transactionDateParamName).value(transactionDate).notNull(); + + final String note = fromApiJsonHelper.extractStringNamed(noteParamName, element); + if (StringUtils.isNotBlank(note)) { + baseDataValidator.reset().parameter(noteParamName).value(note).notExceedingLengthOf(1000); + } + + final Long calendarId = this.fromApiJsonHelper.extractLongNamed(calendarIdParamName, element); + baseDataValidator.reset().parameter(calendarIdParamName).value(calendarId).notNull(); + + validateAttendanceDetails(element, baseDataValidator); + + validateDisbursementTransactions(element, baseDataValidator); + + validateRepaymentTransactions(element, baseDataValidator); + + throwExceptionIfValidationWarningsExist(dataValidationErrors); + } + + private void validateAttendanceDetails(final JsonElement element, final DataValidatorBuilder baseDataValidator) { + final JsonObject topLevelJsonElement = element.getAsJsonObject(); + if (element.isJsonObject()) { + if (topLevelJsonElement.has(clientsAttendanceParamName) && topLevelJsonElement.get(clientsAttendanceParamName).isJsonArray()) { + final JsonArray array = topLevelJsonElement.get(clientsAttendanceParamName).getAsJsonArray(); + for (int i = 0; i < array.size(); i++) { + final JsonObject attendanceElement = array.get(i).getAsJsonObject(); + final Long clientId = this.fromApiJsonHelper.extractLongNamed(clientIdParamName, attendanceElement); + final Long attendanceType = this.fromApiJsonHelper.extractLongNamed(attendanceTypeParamName, attendanceElement); + baseDataValidator.reset().parameter(clientsAttendanceParamName + "[" + i + "]." + clientIdParamName).value(clientId) + .notNull().integerGreaterThanZero(); + baseDataValidator.reset().parameter(clientsAttendanceParamName + "[" + i + "]." + attendanceTypeParamName) + .value(attendanceType).notNull().integerGreaterThanZero(); + } + } + } + } + + private void validateDisbursementTransactions(final JsonElement element, final DataValidatorBuilder baseDataValidator) { + final JsonObject topLevelJsonElement = element.getAsJsonObject(); + final Locale locale = this.fromApiJsonHelper.extractLocaleParameter(topLevelJsonElement); + if (element.isJsonObject()) { + if (topLevelJsonElement.has(bulkDisbursementTransactionsParamName) + && topLevelJsonElement.get(bulkDisbursementTransactionsParamName).isJsonArray()) { + final JsonArray array = topLevelJsonElement.get(bulkDisbursementTransactionsParamName).getAsJsonArray(); + + for (int i = 0; i < array.size(); i++) { + final JsonObject loanTransactionElement = array.get(i).getAsJsonObject(); + final Long loanId = this.fromApiJsonHelper.extractLongNamed(loanIdParamName, loanTransactionElement); + final BigDecimal disbursementAmount = this.fromApiJsonHelper.extractBigDecimalNamed(transactionAmountParamName, + loanTransactionElement, locale); + + baseDataValidator.reset().parameter("bulktransaction" + "[" + i + "].loan.id").value(loanId).notNull() + .integerGreaterThanZero(); + baseDataValidator.reset().parameter("bulktransaction" + "[" + i + "].disbursement.amount").value(disbursementAmount) + .notNull().zeroOrPositiveAmount(); + } + } + } + } + + private void validateRepaymentTransactions(final JsonElement element, final DataValidatorBuilder baseDataValidator) { + final JsonObject topLevelJsonElement = element.getAsJsonObject(); + final Locale locale = this.fromApiJsonHelper.extractLocaleParameter(topLevelJsonElement); + if (element.isJsonObject()) { + if (topLevelJsonElement.has(bulkRepaymentTransactionsParamName) + && topLevelJsonElement.get(bulkRepaymentTransactionsParamName).isJsonArray()) { + final JsonArray array = topLevelJsonElement.get(bulkRepaymentTransactionsParamName).getAsJsonArray(); + + for (int i = 0; i < array.size(); i++) { + final JsonObject loanTransactionElement = array.get(i).getAsJsonObject(); + final Long loanId = this.fromApiJsonHelper.extractLongNamed(loanIdParamName, loanTransactionElement); + final BigDecimal disbursementAmount = this.fromApiJsonHelper.extractBigDecimalNamed(transactionAmountParamName, + loanTransactionElement, locale); + + baseDataValidator.reset().parameter("bulktransaction" + "[" + i + "].loan.id").value(loanId).notNull() + .integerGreaterThanZero(); + baseDataValidator.reset().parameter("bulktransaction" + "[" + i + "].disbursement.amount").value(disbursementAmount) + .notNull().zeroOrPositiveAmount(); + } + } + } + } + + private void throwExceptionIfValidationWarningsExist(final List dataValidationErrors) { + if (!dataValidationErrors.isEmpty()) { throw new PlatformApiDataValidationException(dataValidationErrors); } + } +} \ No newline at end of file diff --git a/mifosng-provider/src/main/java/org/mifosplatform/portfolio/collectionsheet/data/ClientLoansData.java b/mifosng-provider/src/main/java/org/mifosplatform/portfolio/collectionsheet/data/JLGClientData.java similarity index 67% rename from mifosng-provider/src/main/java/org/mifosplatform/portfolio/collectionsheet/data/ClientLoansData.java rename to mifosng-provider/src/main/java/org/mifosplatform/portfolio/collectionsheet/data/JLGClientData.java index 7abebaba9..cd9775903 100644 --- a/mifosng-provider/src/main/java/org/mifosplatform/portfolio/collectionsheet/data/ClientLoansData.java +++ b/mifosng-provider/src/main/java/org/mifosplatform/portfolio/collectionsheet/data/JLGClientData.java @@ -7,25 +7,30 @@ package org.mifosplatform.portfolio.collectionsheet.data; import java.util.Collection; +import org.mifosplatform.infrastructure.core.data.EnumOptionData; + /** * Immutable data object for clients with loans due for disbursement or collection. */ -public class ClientLoansData { +public class JLGClientData { private final Long clientId; private final String clientName; private Collection loans; + private final EnumOptionData attendanceType; - public ClientLoansData(final Long clientId, final String clientName, final Collection loans) { + public JLGClientData(final Long clientId, final String clientName, final Collection loans, final EnumOptionData attendanceType) { this.clientId = clientId; this.clientName = clientName; this.loans = loans; + this.attendanceType = attendanceType; } - public ClientLoansData(final Long clientId, final String clientName) { + public JLGClientData(final Long clientId, final String clientName, final EnumOptionData attendanceType) { this.clientId = clientId; this.clientName = clientName; this.loans = null; + this.attendanceType = attendanceType; } public Long getClientId() { diff --git a/mifosng-provider/src/main/java/org/mifosplatform/portfolio/collectionsheet/data/JLGCollectionSheetData.java b/mifosng-provider/src/main/java/org/mifosplatform/portfolio/collectionsheet/data/JLGCollectionSheetData.java index f7e96af96..77917ac3a 100644 --- a/mifosng-provider/src/main/java/org/mifosplatform/portfolio/collectionsheet/data/JLGCollectionSheetData.java +++ b/mifosng-provider/src/main/java/org/mifosplatform/portfolio/collectionsheet/data/JLGCollectionSheetData.java @@ -6,8 +6,10 @@ package org.mifosplatform.portfolio.collectionsheet.data; import java.util.Collection; +import java.util.List; import org.joda.time.LocalDate; +import org.mifosplatform.infrastructure.core.data.EnumOptionData; import org.mifosplatform.portfolio.loanproduct.data.LoanProductData; /** @@ -17,19 +19,23 @@ public class JLGCollectionSheetData { private final LocalDate dueDate; private final Collection loanProducts; - private final Collection groups; + private final Collection groups; + @SuppressWarnings("unused") + private final List attendanceTypeOptions; - public JLGCollectionSheetData(final LocalDate date, final Collection loanProducts, final Collection groups) { + public JLGCollectionSheetData(final LocalDate date, final Collection loanProducts, + final Collection groups, final List attendanceTypeOptions) { this.dueDate = date; this.loanProducts = loanProducts; this.groups = groups; + this.attendanceTypeOptions = attendanceTypeOptions; } public LocalDate getDate() { return this.dueDate; } - public Collection getGroups() { + public Collection getGroups() { return this.groups; } diff --git a/mifosng-provider/src/main/java/org/mifosplatform/portfolio/collectionsheet/data/JLGCollectionSheetFlatData.java b/mifosng-provider/src/main/java/org/mifosplatform/portfolio/collectionsheet/data/JLGCollectionSheetFlatData.java index 399fb00a3..f87f217f6 100644 --- a/mifosng-provider/src/main/java/org/mifosplatform/portfolio/collectionsheet/data/JLGCollectionSheetFlatData.java +++ b/mifosng-provider/src/main/java/org/mifosplatform/portfolio/collectionsheet/data/JLGCollectionSheetFlatData.java @@ -7,6 +7,7 @@ package org.mifosplatform.portfolio.collectionsheet.data; import java.math.BigDecimal; +import org.mifosplatform.infrastructure.core.data.EnumOptionData; import org.mifosplatform.organisation.monetary.data.CurrencyData; /** @@ -34,12 +35,13 @@ public class JLGCollectionSheetFlatData { private BigDecimal interestDue = BigDecimal.ZERO; private BigDecimal interestPaid = BigDecimal.ZERO; private BigDecimal chargesDue = BigDecimal.ZERO; + private final EnumOptionData attendanceType; public JLGCollectionSheetFlatData(final String groupName, final Long groupId, final Long staffId, final String staffName, final Long levelId, final String levelName, final String clientName, final Long clientId, final Long loanId, final String accountId, final Integer accountStatusId, final String productShortName, final Long productId, final CurrencyData currency, final BigDecimal disbursementAmount, final BigDecimal principalDue, - final BigDecimal principalPaid, final BigDecimal interestDue, final BigDecimal interestPaid, final BigDecimal chargesDue) { + final BigDecimal principalPaid, final BigDecimal interestDue, final BigDecimal interestPaid, final BigDecimal chargesDue, final EnumOptionData attendanceType) { this.groupName = groupName; this.groupId = groupId; this.staffId = staffId; @@ -60,6 +62,7 @@ public class JLGCollectionSheetFlatData { this.interestDue = interestDue; this.interestPaid = interestPaid; this.chargesDue = chargesDue; + this.attendanceType = attendanceType; } public String getGroupName() { @@ -147,13 +150,13 @@ public class JLGCollectionSheetFlatData { this.disbursementAmount, this.principalDue, this.principalPaid, this.interestDue, this.interestPaid, this.chargesDue); } - public ClientLoansData getClientLoansData() { - return new ClientLoansData(this.clientId, this.clientName); + public JLGClientData getClientData() { + return new JLGClientData(this.clientId, this.clientName, this.attendanceType); } - public JLGClientsData getJLGClientsData() { + public JLGGroupData getJLGGroupData() { - return new JLGClientsData(this.groupId, this.groupName, this.staffId, this.staffName, this.levelId, this.levelName); + return new JLGGroupData(this.groupId, this.groupName, this.staffId, this.staffName, this.levelId, this.levelName); } } \ No newline at end of file diff --git a/mifosng-provider/src/main/java/org/mifosplatform/portfolio/collectionsheet/data/JLGClientsData.java b/mifosng-provider/src/main/java/org/mifosplatform/portfolio/collectionsheet/data/JLGGroupData.java similarity index 79% rename from mifosng-provider/src/main/java/org/mifosplatform/portfolio/collectionsheet/data/JLGClientsData.java rename to mifosng-provider/src/main/java/org/mifosplatform/portfolio/collectionsheet/data/JLGGroupData.java index 1214007ee..4c341e9a0 100644 --- a/mifosng-provider/src/main/java/org/mifosplatform/portfolio/collectionsheet/data/JLGClientsData.java +++ b/mifosng-provider/src/main/java/org/mifosplatform/portfolio/collectionsheet/data/JLGGroupData.java @@ -10,7 +10,7 @@ import java.util.Collection; /** * Immutable data object for groups with clients due for disbursement or collection. */ -public class JLGClientsData { +public class JLGGroupData { private final Long groupId; private final String groupName; @@ -18,9 +18,9 @@ public class JLGClientsData { private final String staffName; private final Long levelId; private final String levelName; - private Collection clients; + private Collection clients; - public JLGClientsData(final Long groupId, final String groupName, final Long staffId, final String staffName, final Long levelId, + public JLGGroupData(final Long groupId, final String groupName, final Long staffId, final String staffName, final Long levelId, final String levelName) { this.groupId = groupId; this.groupName = groupName; @@ -54,11 +54,11 @@ public class JLGClientsData { return this.levelName; } - public Collection getCutomers() { + public Collection getClients() { return this.clients; } - public void setClients(final Collection clients) { + public void setClients(final Collection clients) { this.clients = clients; } } \ No newline at end of file diff --git a/mifosng-provider/src/main/java/org/mifosplatform/portfolio/collectionsheet/serialization/CollectionSheetBulkDisbursalCommandFromApiJsonDeserializer.java b/mifosng-provider/src/main/java/org/mifosplatform/portfolio/collectionsheet/serialization/CollectionSheetBulkDisbursalCommandFromApiJsonDeserializer.java index af5af12e0..4ce3161d2 100644 --- a/mifosng-provider/src/main/java/org/mifosplatform/portfolio/collectionsheet/serialization/CollectionSheetBulkDisbursalCommandFromApiJsonDeserializer.java +++ b/mifosng-provider/src/main/java/org/mifosplatform/portfolio/collectionsheet/serialization/CollectionSheetBulkDisbursalCommandFromApiJsonDeserializer.java @@ -5,22 +5,12 @@ */ package org.mifosplatform.portfolio.collectionsheet.serialization; -import java.lang.reflect.Type; import java.math.BigDecimal; -import java.util.ArrayList; -import java.util.Arrays; -import java.util.HashSet; -import java.util.List; import java.util.Locale; -import java.util.Map; -import java.util.Set; import org.apache.commons.lang.StringUtils; import org.joda.time.LocalDate; -import org.mifosplatform.infrastructure.core.data.ApiParameterError; -import org.mifosplatform.infrastructure.core.data.DataValidatorBuilder; import org.mifosplatform.infrastructure.core.exception.InvalidJsonException; -import org.mifosplatform.infrastructure.core.exception.PlatformApiDataValidationException; import org.mifosplatform.infrastructure.core.serialization.AbstractFromApiJsonDeserializer; import org.mifosplatform.infrastructure.core.serialization.FromApiJsonDeserializer; import org.mifosplatform.infrastructure.core.serialization.FromJsonHelper; @@ -32,7 +22,6 @@ import org.springframework.stereotype.Component; import com.google.gson.JsonArray; import com.google.gson.JsonElement; import com.google.gson.JsonObject; -import com.google.gson.reflect.TypeToken; /** * Implementation of {@link FromApiJsonDeserializer} for @@ -52,21 +41,12 @@ public final class CollectionSheetBulkDisbursalCommandFromApiJsonDeserializer ex public CollectionSheetBulkDisbursalCommand commandFromApiJson(final String json) { if (StringUtils.isBlank(json)) { throw new InvalidJsonException(); } - final Type typeOfMap = new TypeToken>() {}.getType(); - //TODO: AA need to refactor transactionDate and actualDisbursementDate - //actualDisbursementDate used in Loan.disburse() - final Set supportedParameters = new HashSet(Arrays.asList("transactionDate", "actualDisbursementDate", "bulkRepaymentTransactions", "bulkDisbursementTransactions", "note", - "locale", "dateFormat")); - this.fromApiJsonHelper.checkForUnsupportedParameters(typeOfMap, json, supportedParameters); - final JsonElement element = this.fromApiJsonHelper.parse(json); - - final LocalDate transactionDate = fromApiJsonHelper.extractLocalDateNamed("transactionDate", element); - - final String note = fromApiJsonHelper.extractStringNamed("note", element); - final JsonObject topLevelJsonElement = element.getAsJsonObject(); + final Locale locale = this.fromApiJsonHelper.extractLocaleParameter(topLevelJsonElement); + final LocalDate transactionDate = fromApiJsonHelper.extractLocalDateNamed("transactionDate", element); + final String note = fromApiJsonHelper.extractStringNamed("note", element); SingleDisbursalCommand[] loanDisbursementTransactions = null; @@ -86,33 +66,4 @@ public final class CollectionSheetBulkDisbursalCommandFromApiJsonDeserializer ex } return new CollectionSheetBulkDisbursalCommand(note, transactionDate, loanDisbursementTransactions); } - - public void validateBulkDisbursalTransaction(final CollectionSheetBulkDisbursalCommand bulkDisburseCommand) { - - final List dataValidationErrors = new ArrayList(); - final DataValidatorBuilder baseDataValidator = new DataValidatorBuilder(dataValidationErrors).resource("loan.bulk.disbursement.transaction"); - - baseDataValidator.reset().parameter("transactionDate").value(bulkDisburseCommand.getTransactionDate()).notNull(); - - if (StringUtils.isNotBlank(bulkDisburseCommand.getNote())) { - baseDataValidator.reset().parameter("note").value(bulkDisburseCommand.getNote()).notExceedingLengthOf(1000); - } - final SingleDisbursalCommand[] loanDisbursements = bulkDisburseCommand.getDisburseTransactions(); - if (loanDisbursements != null) { - for (int i = 0; i < loanDisbursements.length; i++) { - SingleDisbursalCommand singleLoanDisburseCommand = loanDisbursements[i]; - - baseDataValidator.reset().parameter("bulktransaction" + "[" + i + "].loan.id").value(singleLoanDisburseCommand.getLoanId()) - .notNull().integerGreaterThanZero(); - baseDataValidator.reset().parameter("bulktransaction" + "[" + i + "].disbursement.amount") - .value(singleLoanDisburseCommand.getTransactionAmount()).notNull().zeroOrPositiveAmount(); - } - } - throwExceptionIfValidationWarningsExist(dataValidationErrors); - } - - private void throwExceptionIfValidationWarningsExist(final List dataValidationErrors) { - if (!dataValidationErrors.isEmpty()) { throw new PlatformApiDataValidationException("validation.msg.validation.errors.exist", - "Validation errors exist.", dataValidationErrors); } - } } \ No newline at end of file diff --git a/mifosng-provider/src/main/java/org/mifosplatform/portfolio/collectionsheet/serialization/CollectionSheetBulkRepaymentCommandFromApiJsonDeserializer.java b/mifosng-provider/src/main/java/org/mifosplatform/portfolio/collectionsheet/serialization/CollectionSheetBulkRepaymentCommandFromApiJsonDeserializer.java index ae26e034a..7b93f9817 100644 --- a/mifosng-provider/src/main/java/org/mifosplatform/portfolio/collectionsheet/serialization/CollectionSheetBulkRepaymentCommandFromApiJsonDeserializer.java +++ b/mifosng-provider/src/main/java/org/mifosplatform/portfolio/collectionsheet/serialization/CollectionSheetBulkRepaymentCommandFromApiJsonDeserializer.java @@ -5,22 +5,12 @@ */ package org.mifosplatform.portfolio.collectionsheet.serialization; -import java.lang.reflect.Type; import java.math.BigDecimal; -import java.util.ArrayList; -import java.util.Arrays; -import java.util.HashSet; -import java.util.List; import java.util.Locale; -import java.util.Map; -import java.util.Set; import org.apache.commons.lang.StringUtils; import org.joda.time.LocalDate; -import org.mifosplatform.infrastructure.core.data.ApiParameterError; -import org.mifosplatform.infrastructure.core.data.DataValidatorBuilder; import org.mifosplatform.infrastructure.core.exception.InvalidJsonException; -import org.mifosplatform.infrastructure.core.exception.PlatformApiDataValidationException; import org.mifosplatform.infrastructure.core.serialization.AbstractFromApiJsonDeserializer; import org.mifosplatform.infrastructure.core.serialization.FromApiJsonDeserializer; import org.mifosplatform.infrastructure.core.serialization.FromJsonHelper; @@ -32,7 +22,6 @@ import org.springframework.stereotype.Component; import com.google.gson.JsonArray; import com.google.gson.JsonElement; import com.google.gson.JsonObject; -import com.google.gson.reflect.TypeToken; /** * Implementation of {@link FromApiJsonDeserializer} for @@ -52,11 +41,6 @@ public final class CollectionSheetBulkRepaymentCommandFromApiJsonDeserializer ex public CollectionSheetBulkRepaymentCommand commandFromApiJson(final String json) { if (StringUtils.isBlank(json)) { throw new InvalidJsonException(); } - final Type typeOfMap = new TypeToken>() {}.getType(); - final Set supportedParameters = new HashSet(Arrays.asList("transactionDate", "actualDisbursementDate", "bulkRepaymentTransactions", "bulkDisbursementTransactions", "note", - "locale", "dateFormat")); - this.fromApiJsonHelper.checkForUnsupportedParameters(typeOfMap, json, supportedParameters); - final JsonElement element = this.fromApiJsonHelper.parse(json); final LocalDate transactionDate = fromApiJsonHelper.extractLocalDateNamed("transactionDate", element); @@ -84,33 +68,5 @@ public final class CollectionSheetBulkRepaymentCommandFromApiJsonDeserializer ex } return new CollectionSheetBulkRepaymentCommand(note, transactionDate, loanRepaymentTransactions); } - - public void validateBulkRepaymentTransaction(final CollectionSheetBulkRepaymentCommand bulkRepaymentCommand) { - final List dataValidationErrors = new ArrayList(); - final DataValidatorBuilder baseDataValidator = new DataValidatorBuilder(dataValidationErrors).resource("loan.bulk.repayment.transaction"); - - baseDataValidator.reset().parameter("transactionDate").value(bulkRepaymentCommand.getTransactionDate()).notNull(); - - if (StringUtils.isNotBlank(bulkRepaymentCommand.getNote())) { - baseDataValidator.reset().parameter("note").value(bulkRepaymentCommand.getNote()).notExceedingLengthOf(1000); - } - - final SingleRepaymentCommand[] loanRepayments = bulkRepaymentCommand.getLoanTransactions(); - if (loanRepayments != null) { - for (int i = 0; i < loanRepayments.length; i++) { - SingleRepaymentCommand singleLoanRepaymentCommand = loanRepayments[i]; - baseDataValidator.reset().parameter("bulktransaction" + "[" + i + "].loan.id") - .value(singleLoanRepaymentCommand.getLoanId()).notNull().integerGreaterThanZero(); - baseDataValidator.reset().parameter("bulktransaction" + "[" + i + "].transaction.amount") - .value(singleLoanRepaymentCommand.getTransactionAmount()).notNull().zeroOrPositiveAmount(); - } - } - throwExceptionIfValidationWarningsExist(dataValidationErrors); - } - - private void throwExceptionIfValidationWarningsExist(final List dataValidationErrors) { - if (!dataValidationErrors.isEmpty()) { throw new PlatformApiDataValidationException("validation.msg.validation.errors.exist", - "Validation errors exist.", dataValidationErrors); } - } } \ No newline at end of file diff --git a/mifosng-provider/src/main/java/org/mifosplatform/portfolio/collectionsheet/serialization/CollectionSheetGenerateCommandFromApiJsonDeserializer.java b/mifosng-provider/src/main/java/org/mifosplatform/portfolio/collectionsheet/serialization/CollectionSheetGenerateCommandFromApiJsonDeserializer.java index 8076ffe3f..cad90abe1 100644 --- a/mifosng-provider/src/main/java/org/mifosplatform/portfolio/collectionsheet/serialization/CollectionSheetGenerateCommandFromApiJsonDeserializer.java +++ b/mifosng-provider/src/main/java/org/mifosplatform/portfolio/collectionsheet/serialization/CollectionSheetGenerateCommandFromApiJsonDeserializer.java @@ -13,6 +13,11 @@ import java.util.List; import java.util.Map; import java.util.Set; +import static org.mifosplatform.portfolio.collectionsheet.CollectionSheetConstants.localeParamName; +import static org.mifosplatform.portfolio.collectionsheet.CollectionSheetConstants.dateFormatParamName; +import static org.mifosplatform.portfolio.collectionsheet.CollectionSheetConstants.calendarIdParamName; +import static org.mifosplatform.portfolio.collectionsheet.CollectionSheetConstants.transactionDateParamName; + import org.apache.commons.lang.StringUtils; import org.joda.time.LocalDate; import org.mifosplatform.infrastructure.core.data.ApiParameterError; @@ -32,7 +37,8 @@ public class CollectionSheetGenerateCommandFromApiJsonDeserializer { /** * The parameters supported for this command. */ - final Set supportedParameters = new HashSet(Arrays.asList("dueDate", "locale", "dateFormat")); + final Set supportedParameters = new HashSet(Arrays.asList(transactionDateParamName, localeParamName, + dateFormatParamName, calendarIdParamName)); private final FromJsonHelper fromApiJsonHelper; @@ -53,15 +59,17 @@ public class CollectionSheetGenerateCommandFromApiJsonDeserializer { final DataValidatorBuilder baseDataValidator = new DataValidatorBuilder(dataValidationErrors).resource("collectionsheet"); - final String dueDateParameterName = "dueDate"; - final String dueDateStr = this.fromApiJsonHelper.extractStringNamed(dueDateParameterName, element); - baseDataValidator.reset().parameter(dueDateParameterName).value(dueDateStr).notBlank(); + final String transactionDateStr = this.fromApiJsonHelper.extractStringNamed(transactionDateParamName, element); + baseDataValidator.reset().parameter(transactionDateParamName).value(transactionDateStr).notBlank(); - if(!StringUtils.isBlank(dueDateStr)){ - final LocalDate dueDate = this.fromApiJsonHelper.extractLocalDateNamed(dueDateParameterName, element); - baseDataValidator.reset().parameter(dueDateParameterName).value(dueDate).notNull(); + if (!StringUtils.isBlank(transactionDateStr)) { + final LocalDate dueDate = this.fromApiJsonHelper.extractLocalDateNamed(transactionDateParamName, element); + baseDataValidator.reset().parameter(transactionDateParamName).value(dueDate).notNull(); } + final Long calendarId = this.fromApiJsonHelper.extractLongNamed(calendarIdParamName, element); + baseDataValidator.reset().parameter(calendarIdParamName).value(calendarId).notNull(); + if (!dataValidationErrors.isEmpty()) { throw new PlatformApiDataValidationException("validation.msg.validation.errors.exist", "Validation errors exist.", dataValidationErrors); } } diff --git a/mifosng-provider/src/main/java/org/mifosplatform/portfolio/collectionsheet/service/CollectionSheetReadPlatformServiceImpl.java b/mifosng-provider/src/main/java/org/mifosplatform/portfolio/collectionsheet/service/CollectionSheetReadPlatformServiceImpl.java index 64d7f8386..ec76b88b7 100644 --- a/mifosng-provider/src/main/java/org/mifosplatform/portfolio/collectionsheet/service/CollectionSheetReadPlatformServiceImpl.java +++ b/mifosng-provider/src/main/java/org/mifosplatform/portfolio/collectionsheet/service/CollectionSheetReadPlatformServiceImpl.java @@ -5,6 +5,9 @@ */ package org.mifosplatform.portfolio.collectionsheet.service; +import static org.mifosplatform.portfolio.collectionsheet.CollectionSheetConstants.calendarIdParamName; +import static org.mifosplatform.portfolio.collectionsheet.CollectionSheetConstants.transactionDateParamName; + import java.math.BigDecimal; import java.sql.ResultSet; import java.sql.SQLException; @@ -18,14 +21,20 @@ import java.util.Set; import org.joda.time.LocalDate; import org.mifosplatform.infrastructure.core.api.JsonQuery; +import org.mifosplatform.infrastructure.core.data.EnumOptionData; import org.mifosplatform.infrastructure.core.domain.JdbcSupport; import org.mifosplatform.infrastructure.core.service.RoutingDataSource; import org.mifosplatform.infrastructure.security.service.PlatformSecurityContext; import org.mifosplatform.organisation.monetary.data.CurrencyData; -import org.mifosplatform.portfolio.collectionsheet.data.ClientLoansData; -import org.mifosplatform.portfolio.collectionsheet.data.JLGClientsData; +import org.mifosplatform.portfolio.calendar.domain.Calendar; +import org.mifosplatform.portfolio.calendar.domain.CalendarEntityType; +import org.mifosplatform.portfolio.calendar.domain.CalendarRepositoryWrapper; +import org.mifosplatform.portfolio.calendar.exception.NotValidRecurringDateException; +import org.mifosplatform.portfolio.calendar.service.CalendarUtils; +import org.mifosplatform.portfolio.collectionsheet.data.JLGClientData; import org.mifosplatform.portfolio.collectionsheet.data.JLGCollectionSheetData; import org.mifosplatform.portfolio.collectionsheet.data.JLGCollectionSheetFlatData; +import org.mifosplatform.portfolio.collectionsheet.data.JLGGroupData; import org.mifosplatform.portfolio.collectionsheet.data.LoanDueData; import org.mifosplatform.portfolio.collectionsheet.serialization.CollectionSheetGenerateCommandFromApiJsonDeserializer; import org.mifosplatform.portfolio.group.data.CenterData; @@ -33,6 +42,8 @@ import org.mifosplatform.portfolio.group.data.GroupGeneralData; import org.mifosplatform.portfolio.group.service.CenterReadPlatformService; import org.mifosplatform.portfolio.group.service.GroupReadPlatformService; import org.mifosplatform.portfolio.loanproduct.data.LoanProductData; +import org.mifosplatform.portfolio.meeting.attendance.service.AttendanceDropdownReadPlatformService; +import org.mifosplatform.portfolio.meeting.attendance.service.AttendanceEnumerations; import org.mifosplatform.useradministration.domain.AppUser; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.jdbc.core.RowMapper; @@ -49,16 +60,22 @@ public class CollectionSheetReadPlatformServiceImpl implements CollectionSheetRe private final CenterReadPlatformService centerReadPlatformService; private final GroupReadPlatformService groupReadPlatformService; private final CollectionSheetGenerateCommandFromApiJsonDeserializer collectionSheetGenerateCommandFromApiJsonDeserializer; + private final CalendarRepositoryWrapper calendarRepositoryWrapper; + private final AttendanceDropdownReadPlatformService attendanceDropdownReadPlatformService; @Autowired public CollectionSheetReadPlatformServiceImpl(final PlatformSecurityContext context, final RoutingDataSource dataSource, final CenterReadPlatformService centerReadPlatformService, final GroupReadPlatformService groupReadPlatformService, - final CollectionSheetGenerateCommandFromApiJsonDeserializer collectionSheetGenerateCommandFromApiJsonDeserializer) { + final CollectionSheetGenerateCommandFromApiJsonDeserializer collectionSheetGenerateCommandFromApiJsonDeserializer, + final CalendarRepositoryWrapper calendarRepositoryWrapper, + final AttendanceDropdownReadPlatformService attendanceDropdownReadPlatformService) { this.context = context; this.centerReadPlatformService = centerReadPlatformService; this.namedParameterjdbcTemplate = new NamedParameterJdbcTemplate(dataSource); this.collectionSheetGenerateCommandFromApiJsonDeserializer = collectionSheetGenerateCommandFromApiJsonDeserializer; this.groupReadPlatformService = groupReadPlatformService; + this.calendarRepositoryWrapper = calendarRepositoryWrapper; + this.attendanceDropdownReadPlatformService = attendanceDropdownReadPlatformService; } @Override @@ -92,9 +109,9 @@ public class CollectionSheetReadPlatformServiceImpl implements CollectionSheetRe Long prevGroupId = null; Long prevClientId = null; - final List jlgClientsDatas = new ArrayList(); - List clientLoansDatas = new ArrayList(); - List loanDueDatas = new ArrayList(); + final List jlgGroupsData = new ArrayList(); + List clientsData = new ArrayList(); + List loansDueData = new ArrayList(); JLGCollectionSheetData jlgCollectionSheetData = null; JLGCollectionSheetFlatData prevCollectioSheetFlatData = null; @@ -113,35 +130,35 @@ public class CollectionSheetReadPlatformServiceImpl implements CollectionSheetRe if (firstTime || collectionSheetFlatData.getGroupId().equals(prevGroupId)) { if (firstTime || collectionSheetFlatData.getClientId().equals(prevClientId)) { if (collectionSheetFlatData.getLoanId() != null) { - loanDueDatas.add(collectionSheetFlatData.getLoanDueData()); + loansDueData.add(collectionSheetFlatData.getLoanDueData()); } } else { - final ClientLoansData clientLoansData = prevCollectioSheetFlatData.getClientLoansData(); - clientLoansData.setLoans(loanDueDatas); - clientLoansDatas.add(clientLoansData); - loanDueDatas = new ArrayList(); + final JLGClientData clientData = prevCollectioSheetFlatData.getClientData(); + clientData.setLoans(loansDueData); + clientsData.add(clientData); + loansDueData = new ArrayList(); if (collectionSheetFlatData.getLoanId() != null) { - loanDueDatas.add(collectionSheetFlatData.getLoanDueData()); + loansDueData.add(collectionSheetFlatData.getLoanDueData()); } } } else { - final ClientLoansData clientLoansData = prevCollectioSheetFlatData.getClientLoansData(); - clientLoansData.setLoans(loanDueDatas); - clientLoansDatas.add(clientLoansData); + final JLGClientData clientData = prevCollectioSheetFlatData.getClientData(); + clientData.setLoans(loansDueData); + clientsData.add(clientData); - final JLGClientsData jlgClientsData = prevCollectioSheetFlatData.getJLGClientsData(); - jlgClientsData.setClients(clientLoansDatas); + final JLGGroupData jlgGroupData = prevCollectioSheetFlatData.getJLGGroupData(); + jlgGroupData.setClients(clientsData); - jlgClientsDatas.add(jlgClientsData); + jlgGroupsData.add(jlgGroupData); - loanDueDatas = new ArrayList(); - clientLoansDatas = new ArrayList(); + loansDueData = new ArrayList(); + clientsData = new ArrayList(); if (collectionSheetFlatData.getLoanId() != null) { - loanDueDatas.add(collectionSheetFlatData.getLoanDueData()); + loansDueData.add(collectionSheetFlatData.getLoanDueData()); } } @@ -155,16 +172,17 @@ public class CollectionSheetReadPlatformServiceImpl implements CollectionSheetRe // client/group or new client / previous group or new client / new // group if (corrCollectioSheetFlatData != null) { - final ClientLoansData lastClientLoansData = corrCollectioSheetFlatData.getClientLoansData(); - lastClientLoansData.setLoans(loanDueDatas); - clientLoansDatas.add(lastClientLoansData); + final JLGClientData lastClientData = corrCollectioSheetFlatData.getClientData(); + lastClientData.setLoans(loansDueData); + clientsData.add(lastClientData); - final JLGClientsData jlgClientsData = corrCollectioSheetFlatData.getJLGClientsData(); - jlgClientsData.setClients(clientLoansDatas); - jlgClientsDatas.add(jlgClientsData); + final JLGGroupData jlgGroupData = corrCollectioSheetFlatData.getJLGGroupData(); + jlgGroupData.setClients(clientsData); + jlgGroupsData.add(jlgGroupData); } - jlgCollectionSheetData = new JLGCollectionSheetData(dueDate, loanProducts, jlgClientsDatas); + jlgCollectionSheetData = new JLGCollectionSheetData(dueDate, loanProducts, jlgGroupsData, + attendanceDropdownReadPlatformService.retrieveAttendanceTypeOptions()); } return jlgCollectionSheetData; @@ -206,7 +224,8 @@ public class CollectionSheetReadPlatformServiceImpl implements CollectionSheetRe + "ln.principal_repaid_derived As principalPaid, " + "sum(ifnull(if(ln.loan_status_id = 300, ls.interest_amount, 0.0), 0.0) - ifnull(if(ln.loan_status_id = 300, ls.interest_completed_derived, 0.0), 0.0)) As interestDue, " + "ln.interest_repaid_derived As interestPaid, " - + "sum(if(ln.loan_status_id = 300, lc.amount_outstanding_derived, 0.0)) as chargesDue " + + "sum(if(ln.loan_status_id = 300, lc.amount_outstanding_derived, 0.0)) as chargesDue, " + + "ca.attendance_type_enum as attendanceTypeId " + "FROM m_group gp " + "LEFT JOIN m_office of ON of.id = gp.office_id AND of.hierarchy like :officeHierarchy " // + "LEFT JOIN m_office of ON of.id = gp.office_id " @@ -218,7 +237,10 @@ public class CollectionSheetReadPlatformServiceImpl implements CollectionSheetRe + "LEFT JOIN m_product_loan pl ON pl.id = ln.product_id " + "LEFT JOIN m_currency rc on rc.`code` = ln.currency_code " + "LEFT JOIN m_loan_repayment_schedule ls ON ls.loan_id = ln.id AND ls.completed_derived = 0 AND ls.duedate <= :dueDate " - + "LEFT JOIN m_loan_charge lc ON lc.loan_id = ln.id AND lc.is_paid_derived = 0 AND ( lc.due_for_collection_as_of_date <= :dueDate OR lc.charge_time_enum = 1) "; + + "LEFT JOIN m_loan_charge lc ON lc.loan_id = ln.id AND lc.is_paid_derived = 0 AND ( lc.due_for_collection_as_of_date <= :dueDate OR lc.charge_time_enum = 1) " + + "left join m_calendar_instance ci on gp.parent_id = ci.entity_id and ci.entity_type_enum =:entityTypeId " + + "left join m_meeting mt on ci.id = mt.calendar_instance_id and mt.meeting_date =:dueDate " + + "left join m_client_attendance ca on ca.meeting_id=mt.id and ca.client_id=cl.id "; // + "WHERE gp.hierarchy like :hierarchy " + // "GROUP BY gp.id ,cl.id , ln.id " + @@ -261,9 +283,12 @@ public class CollectionSheetReadPlatformServiceImpl implements CollectionSheetRe final BigDecimal interestPaid = rs.getBigDecimal("interestPaid"); final BigDecimal chargesDue = rs.getBigDecimal("chargesDue"); + final Integer attendanceTypeId = rs.getInt("attendanceTypeId"); + final EnumOptionData attendanceType = AttendanceEnumerations.attendanceType(attendanceTypeId); + return new JLGCollectionSheetFlatData(groupName, groupId, staffId, staffName, levelId, levelName, clientName, clientId, loanId, accountId, accountStatusId, productShortName, productId, currencyData, disbursementAmount, principalDue, principalPaid, - interestDue, interestPaid, chargesDue); + interestDue, interestPaid, chargesDue, attendanceType); } } @@ -273,28 +298,34 @@ public class CollectionSheetReadPlatformServiceImpl implements CollectionSheetRe 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); + if (!CalendarUtils.isValidRedurringDate(calendar.getRecurrence(), calendar.getStartDateLocalDate(), 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 LocalDate dueDate = query.localDateValueOfParameterNamed("dueDate"); - final DateFormat df = new SimpleDateFormat("yyyy-MM-dd"); - final String dueDateStr = df.format(dueDate.toDate()); - final JLGCollectionSheetFaltDataMapper mapper = new JLGCollectionSheetFaltDataMapper(); - String sql = mapper.collectionSheetSchema(); - sql += "WHERE gp.id = :groupId GROUP BY gp.id ,cl.id , ln.id ORDER BY gp.id , cl.id , ln.id"; + StringBuilder sql = new StringBuilder(mapper.collectionSheetSchema()); + sql.append(" WHERE gp.id = :groupId GROUP BY gp.id ,cl.id , ln.id ORDER BY gp.id , cl.id , ln.id "); - final SqlParameterSource namedParameters = new MapSqlParameterSource().addValue("dueDate", dueDateStr) - .addValue("groupId", group.getId()).addValue("officeHierarchy", officeHierarchy); + final SqlParameterSource namedParameters = new MapSqlParameterSource().addValue("dueDate", transactionDateStr) + .addValue("groupId", group.getId()).addValue("officeHierarchy", officeHierarchy) + .addValue("entityTypeId", CalendarEntityType.CENTERS.getValue()); - final Collection collectionSheetFlatDatas = this.namedParameterjdbcTemplate.query(sql, namedParameters, - mapper); + final Collection collectionSheetFlatDatas = this.namedParameterjdbcTemplate.query(sql.toString(), + namedParameters, mapper); - return buildJLGCollectionSheet(dueDate, collectionSheetFlatDatas); + return buildJLGCollectionSheet(transactionDate, collectionSheetFlatDatas); } @Override @@ -308,9 +339,9 @@ public class CollectionSheetReadPlatformServiceImpl implements CollectionSheetRe final CenterData center = this.centerReadPlatformService.retrieveOne(centerId); - final LocalDate dueDate = query.localDateValueOfParameterNamed("dueDate"); + final LocalDate transactionDate = query.localDateValueOfParameterNamed(transactionDateParamName); final DateFormat df = new SimpleDateFormat("yyyy-MM-dd"); - final String dueDateStr = df.format(dueDate.toDate()); + final String dueDateStr = df.format(transactionDate.toDate()); final JLGCollectionSheetFaltDataMapper mapper = new JLGCollectionSheetFaltDataMapper(); @@ -318,12 +349,13 @@ public class CollectionSheetReadPlatformServiceImpl implements CollectionSheetRe sql += "WHERE gp.parent_id = :centerId GROUP BY gp.id ,cl.id , ln.id ORDER BY gp.id , cl.id , ln.id"; final SqlParameterSource namedParameters = new MapSqlParameterSource().addValue("dueDate", dueDateStr) - .addValue("centerId", center.getId()).addValue("officeHierarchy", officeHierarchy); + .addValue("centerId", center.getId()).addValue("officeHierarchy", officeHierarchy) + .addValue("entityTypeId", CalendarEntityType.CENTERS.getValue()); final Collection collectionSheetFlatDatas = this.namedParameterjdbcTemplate.query(sql, namedParameters, mapper); - return buildJLGCollectionSheet(dueDate, collectionSheetFlatDatas); + return buildJLGCollectionSheet(transactionDate, collectionSheetFlatDatas); } } diff --git a/mifosng-provider/src/main/java/org/mifosplatform/portfolio/collectionsheet/service/CollectionSheetWritePlatformServiceJpaRepositoryImpl.java b/mifosng-provider/src/main/java/org/mifosplatform/portfolio/collectionsheet/service/CollectionSheetWritePlatformServiceJpaRepositoryImpl.java index e37c099c3..2907520da 100644 --- a/mifosng-provider/src/main/java/org/mifosplatform/portfolio/collectionsheet/service/CollectionSheetWritePlatformServiceJpaRepositoryImpl.java +++ b/mifosng-provider/src/main/java/org/mifosplatform/portfolio/collectionsheet/service/CollectionSheetWritePlatformServiceJpaRepositoryImpl.java @@ -14,9 +14,11 @@ import org.mifosplatform.infrastructure.core.data.CommandProcessingResult; import org.mifosplatform.infrastructure.core.data.CommandProcessingResultBuilder; import org.mifosplatform.portfolio.collectionsheet.command.CollectionSheetBulkDisbursalCommand; import org.mifosplatform.portfolio.collectionsheet.command.CollectionSheetBulkRepaymentCommand; +import org.mifosplatform.portfolio.collectionsheet.data.CollectionSheetTransactionDataValidator; import org.mifosplatform.portfolio.collectionsheet.serialization.CollectionSheetBulkDisbursalCommandFromApiJsonDeserializer; import org.mifosplatform.portfolio.collectionsheet.serialization.CollectionSheetBulkRepaymentCommandFromApiJsonDeserializer; import org.mifosplatform.portfolio.loanaccount.service.LoanWritePlatformService; +import org.mifosplatform.portfolio.meeting.service.MeetingWritePlatformService; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; @@ -25,21 +27,27 @@ public class CollectionSheetWritePlatformServiceJpaRepositoryImpl implements Col private final LoanWritePlatformService loanWritePlatformService; private final CollectionSheetBulkRepaymentCommandFromApiJsonDeserializer bulkRepaymentCommandFromApiJsonDeserializer; - private final CollectionSheetBulkDisbursalCommandFromApiJsonDeserializer bulkDisbursalCommandFromApiJsonDeserializer; + private final CollectionSheetBulkDisbursalCommandFromApiJsonDeserializer bulkDisbursalCommandFromApiJsonDeserializer; + private final CollectionSheetTransactionDataValidator transactionDataValidator; + private final MeetingWritePlatformService meetingWritePlatformService; @Autowired public CollectionSheetWritePlatformServiceJpaRepositoryImpl(LoanWritePlatformService loanWritePlatformService, CollectionSheetBulkRepaymentCommandFromApiJsonDeserializer bulkRepaymentCommandFromApiJsonDeserializer, - CollectionSheetBulkDisbursalCommandFromApiJsonDeserializer bulkDisbursalCommandFromApiJsonDeserializer) { + CollectionSheetBulkDisbursalCommandFromApiJsonDeserializer bulkDisbursalCommandFromApiJsonDeserializer, + final CollectionSheetTransactionDataValidator transactionDataValidator, final MeetingWritePlatformService meetingWritePlatformService) { this.loanWritePlatformService = loanWritePlatformService; this.bulkRepaymentCommandFromApiJsonDeserializer = bulkRepaymentCommandFromApiJsonDeserializer; this.bulkDisbursalCommandFromApiJsonDeserializer = bulkDisbursalCommandFromApiJsonDeserializer; + this.transactionDataValidator = transactionDataValidator; + this.meetingWritePlatformService = meetingWritePlatformService; } - @Override public CommandProcessingResult updateCollectionSheet(JsonCommand command) { + this.transactionDataValidator.validateTransaction(command); + Map changes = new HashMap(); changes.put("locale", command.locale()); changes.put("dateFormat", command.dateFormat()); @@ -52,6 +60,8 @@ public class CollectionSheetWritePlatformServiceJpaRepositoryImpl implements Col changes.putAll(updateBulkReapayments(command)); changes.putAll(updateBulkDisbursals(command)); + + this.meetingWritePlatformService.updateCollectionSheetAttendance(command); return new CommandProcessingResultBuilder() // .withCommandId(command.commandId()) // @@ -64,7 +74,6 @@ public class CollectionSheetWritePlatformServiceJpaRepositoryImpl implements Col private Map updateBulkReapayments(JsonCommand command) { Map changes = new HashMap(); final CollectionSheetBulkRepaymentCommand bulkRepaymentCommand = this.bulkRepaymentCommandFromApiJsonDeserializer.commandFromApiJson(command.json()); - this.bulkRepaymentCommandFromApiJsonDeserializer.validateBulkRepaymentTransaction(bulkRepaymentCommand); changes.putAll(this.loanWritePlatformService.makeLoanBulkRepayment(bulkRepaymentCommand)); return changes; } @@ -72,7 +81,6 @@ public class CollectionSheetWritePlatformServiceJpaRepositoryImpl implements Col private Map updateBulkDisbursals(JsonCommand command) { Map changes = new HashMap(); final CollectionSheetBulkDisbursalCommand bulkDisbursalCommand = this.bulkDisbursalCommandFromApiJsonDeserializer.commandFromApiJson(command.json()); - this.bulkDisbursalCommandFromApiJsonDeserializer.validateBulkDisbursalTransaction(bulkDisbursalCommand); changes.putAll(this.loanWritePlatformService.bulkLoanDisbursal(command, bulkDisbursalCommand)); return changes; } diff --git a/mifosng-provider/src/main/java/org/mifosplatform/portfolio/group/api/CentersApiResource.java b/mifosng-provider/src/main/java/org/mifosplatform/portfolio/group/api/CentersApiResource.java index 70dca5147..8d9c8aa8e 100644 --- a/mifosng-provider/src/main/java/org/mifosplatform/portfolio/group/api/CentersApiResource.java +++ b/mifosng-provider/src/main/java/org/mifosplatform/portfolio/group/api/CentersApiResource.java @@ -150,6 +150,9 @@ public class CentersApiResource { if (associationParameters.contains("collectionMeetingCalendar")) { collectionMeetingCalendar = this.calendarReadPlatformService.retrieveCollctionCalendarByEntity(centerId, CalendarEntityType.CENTERS.getValue()); + if(collectionMeetingCalendar != null){ + collectionMeetingCalendar = this.calendarReadPlatformService.generateRecurringDate(collectionMeetingCalendar); + } } center = CenterData.withAssociations(center, groups, collectionMeetingCalendar); diff --git a/mifosng-provider/src/main/java/org/mifosplatform/portfolio/group/api/GroupsApiResource.java b/mifosng-provider/src/main/java/org/mifosplatform/portfolio/group/api/GroupsApiResource.java index 684c2d700..3c2b8a5e6 100644 --- a/mifosng-provider/src/main/java/org/mifosplatform/portfolio/group/api/GroupsApiResource.java +++ b/mifosng-provider/src/main/java/org/mifosplatform/portfolio/group/api/GroupsApiResource.java @@ -203,7 +203,7 @@ public class GroupsApiResource { groupRoles = null; } } - if (associationParameters.contains("calendars")) { + if (associationParameters.contains("parentCalendars")) { final List calendarTypeOptions = CalendarUtils.createIntegerListFromQueryParameter("all"); calendars = this.calendarReadPlatformService.retrieveParentCalendarsByEntity(groupId, CalendarEntityType.GROUPS.getValue(), calendarTypeOptions); if (CollectionUtils.isEmpty(calendars)) { @@ -211,7 +211,14 @@ public class GroupsApiResource { } } if (associationParameters.contains("collectionMeetingCalendar")) { - collectionMeetingCalendar = this.calendarReadPlatformService.retrieveCollctionCalendarByEntity(groupId, CalendarEntityType.GROUPS.getValue()); + if(group.isChildGroup()){ + collectionMeetingCalendar = this.calendarReadPlatformService.retrieveCollctionCalendarByEntity(group.getParentId(), CalendarEntityType.CENTERS.getValue()); + }else { + collectionMeetingCalendar = this.calendarReadPlatformService.retrieveCollctionCalendarByEntity(groupId, CalendarEntityType.GROUPS.getValue()); + } + if(collectionMeetingCalendar != null){ + collectionMeetingCalendar = this.calendarReadPlatformService.generateRecurringDate(collectionMeetingCalendar); + } } group = GroupGeneralData.withAssocations(group, membersOfGroup, groupRoles, calendars, collectionMeetingCalendar); diff --git a/mifosng-provider/src/main/java/org/mifosplatform/portfolio/group/data/GroupGeneralData.java b/mifosng-provider/src/main/java/org/mifosplatform/portfolio/group/data/GroupGeneralData.java index 722d84d1e..5c78d5c3b 100644 --- a/mifosng-provider/src/main/java/org/mifosplatform/portfolio/group/data/GroupGeneralData.java +++ b/mifosng-provider/src/main/java/org/mifosplatform/portfolio/group/data/GroupGeneralData.java @@ -168,7 +168,16 @@ public class GroupGeneralData { public String getHierarchy() { return this.hierarchy; } + + public boolean isChildGroup(){ + return this.centerId == null ? false : true; + } + public Long getParentId(){ + return this.centerId; + } + + public static GroupGeneralData updateSelectedRole(final GroupGeneralData grouping, final GroupRoleData selectedRole) { return new GroupGeneralData(grouping.id, grouping.name, grouping.externalId, grouping.status, grouping.activationDate, grouping.officeId, grouping.officeName, grouping.centerId, grouping.centerName, grouping.staffId, grouping.staffName, diff --git a/mifosng-provider/src/main/java/org/mifosplatform/portfolio/meeting/domain/Meeting.java b/mifosng-provider/src/main/java/org/mifosplatform/portfolio/meeting/domain/Meeting.java index 1dcabee46..b4dff3b83 100644 --- a/mifosng-provider/src/main/java/org/mifosplatform/portfolio/meeting/domain/Meeting.java +++ b/mifosng-provider/src/main/java/org/mifosplatform/portfolio/meeting/domain/Meeting.java @@ -67,16 +67,15 @@ public class Meeting extends AbstractPersistable { } public static Meeting createNew(final CalendarInstance calendarInstance, final Date meetingDate) { - - if(!isValidMeetingDate(calendarInstance, meetingDate)){ - throw new NotValidRecurringDateException("meeting", "The date '" + meetingDate + "' is not a valid meeting date.", meetingDate); - } + + if (!isValidMeetingDate(calendarInstance, meetingDate)) { throw new NotValidRecurringDateException("meeting", "The date '" + + meetingDate + "' is not a valid meeting date.", meetingDate); } return new Meeting(calendarInstance, meetingDate); } public void associateClientsAttendance(final Collection clientsAttendance) { - //do not allow to capture attendance in advance. - if(isMeetingDateAfter(DateUtils.getLocalDateOfTenant())){ + // do not allow to capture attendance in advance. + if (isMeetingDateAfter(DateUtils.getLocalDateOfTenant())) { final String errorMessage = "Attendance cannot be in the future."; throw new MeetingDateException("cannot.be.a.future.date", errorMessage, getMeetingDateLocalDate()); } @@ -95,11 +94,10 @@ public class Meeting extends AbstractPersistable { actualChanges.put("dateFormat", dateFormatAsInput); actualChanges.put("locale", localeAsInput); this.meetingDate = newValue.toDate(); - - if(!isValidMeetingDate(this.calendarInstance, this.meetingDate)){ - throw new NotValidRecurringDateException("meeting", "Not a valid meeting date", meetingDate); - } - + + if (!isValidMeetingDate(this.calendarInstance, this.meetingDate)) { throw new NotValidRecurringDateException("meeting", + "Not a valid meeting date", meetingDate); } + } return actualChanges; @@ -108,12 +106,15 @@ public class Meeting extends AbstractPersistable { public Map updateAttendance(final Collection clientsAttendance) { final Map actualChanges = new LinkedHashMap(1); final Map clientAttendanceChanges = new LinkedHashMap(clientsAttendance.size()); - + updateAttendanceLoop: for (ClientAttendance clientAttendance : clientsAttendance) { + if (this.clientsAttendance == null) { + this.clientsAttendance = new HashSet(); + } for (ClientAttendance clientAttendanceOriginal : this.clientsAttendance) { if (clientAttendanceOriginal.clientId().equals(clientAttendance.clientId())) { - final Integer newValue = clientAttendance.getAttendanceTypeId(); - if(!newValue.equals(clientAttendanceOriginal.getAttendanceTypeId())){ + final Integer newValue = clientAttendance.getAttendanceTypeId(); + if (!newValue.equals(clientAttendanceOriginal.getAttendanceTypeId())) { clientAttendanceOriginal.updateAttendanceTypeId(newValue); final Map clientAttendanceChange = new LinkedHashMap(2); clientAttendanceChange.put(clientIdParamName, clientAttendanceOriginal.clientId()); @@ -123,32 +124,32 @@ public class Meeting extends AbstractPersistable { continue updateAttendanceLoop; } } - + final Map clientAttendanceChange = new LinkedHashMap(); clientAttendanceChange.put(clientIdParamName, clientAttendance.clientId()); clientAttendanceChange.put(attendanceTypeParamName, clientAttendance.getAttendanceTypeId()); clientAttendanceChanges.put(clientAttendance.clientId().toString(), clientAttendanceChange); - //New attendance record + // New attendance record this.clientsAttendance.add(clientAttendance); } - + actualChanges.put(clientsAttendanceParamName, clientAttendanceChanges); - + return actualChanges; } public Long entityId() { return calendarInstance.getEntityId(); } - - public boolean isCenterEntity(){ + + public boolean isCenterEntity() { return CalendarEntityType.isCenter(calendarInstance.getEntityTypeId()); } - public boolean isGroupEntity(){ + public boolean isGroupEntity() { return CalendarEntityType.isGroup(calendarInstance.getEntityTypeId()); } - + public LocalDate getMeetingDateLocalDate() { LocalDate meetingDateLocalDate = null; if (this.meetingDate != null) { @@ -156,8 +157,8 @@ public class Meeting extends AbstractPersistable { } return meetingDateLocalDate; } - - public Date getMeetingDate(){ + + public Date getMeetingDate() { return this.meetingDate; } @@ -165,24 +166,23 @@ public class Meeting extends AbstractPersistable { return (this.meetingDate != null && newStartDate != null && getMeetingDateLocalDate().isBefore(newStartDate)) ? true : false; } - private static boolean isValidMeetingDate(final CalendarInstance calendarInstance, final Date meetingDate ){ + private static boolean isValidMeetingDate(final CalendarInstance calendarInstance, final Date meetingDate) { final Calendar calendar = calendarInstance.getCalendar(); - LocalDate meetingDateLocalDate = null; + LocalDate meetingDateLocalDate = null; if (meetingDate != null) { meetingDateLocalDate = LocalDate.fromDateFields(meetingDate); - } - if(meetingDateLocalDate == null || !CalendarUtils.isValidRedurringDate(calendar.getRecurrence(), calendar.getStartDateLocalDate(), meetingDateLocalDate)){ - return false; } + if (meetingDateLocalDate == null + || !CalendarUtils.isValidRedurringDate(calendar.getRecurrence(), calendar.getStartDateLocalDate(), meetingDateLocalDate)) { return false; } return true; } - - private boolean isMeetingDateAfter(final LocalDate date){ + + private boolean isMeetingDateAfter(final LocalDate date) { return getMeetingDateLocalDate().isAfter(date); } - + public Collection getClientsAttendance() { return this.clientsAttendance; } - + } diff --git a/mifosng-provider/src/main/java/org/mifosplatform/portfolio/meeting/domain/MeetingRepository.java b/mifosng-provider/src/main/java/org/mifosplatform/portfolio/meeting/domain/MeetingRepository.java index d13b66970..74547ad8a 100644 --- a/mifosng-provider/src/main/java/org/mifosplatform/portfolio/meeting/domain/MeetingRepository.java +++ b/mifosng-provider/src/main/java/org/mifosplatform/portfolio/meeting/domain/MeetingRepository.java @@ -5,9 +5,11 @@ */ package org.mifosplatform.portfolio.meeting.domain; +import java.util.Date; + import org.springframework.data.jpa.repository.JpaRepository; import org.springframework.data.jpa.repository.JpaSpecificationExecutor; public interface MeetingRepository extends JpaRepository, JpaSpecificationExecutor { - + Meeting findByCalendarInstanceIdAndMeetingDate(Long calendarInstanceId, Date meetingDate); } diff --git a/mifosng-provider/src/main/java/org/mifosplatform/portfolio/meeting/service/MeetingWritePlatformService.java b/mifosng-provider/src/main/java/org/mifosplatform/portfolio/meeting/service/MeetingWritePlatformService.java index 5d7ac4952..f423b9586 100644 --- a/mifosng-provider/src/main/java/org/mifosplatform/portfolio/meeting/service/MeetingWritePlatformService.java +++ b/mifosng-provider/src/main/java/org/mifosplatform/portfolio/meeting/service/MeetingWritePlatformService.java @@ -11,6 +11,8 @@ import org.mifosplatform.infrastructure.core.data.CommandProcessingResult; public interface MeetingWritePlatformService { CommandProcessingResult createMeeting(JsonCommand command); + + void updateCollectionSheetAttendance(JsonCommand command); CommandProcessingResult updateMeeting(JsonCommand command); diff --git a/mifosng-provider/src/main/java/org/mifosplatform/portfolio/meeting/service/MeetingWritePlatformServiceJpaRepositoryImpl.java b/mifosng-provider/src/main/java/org/mifosplatform/portfolio/meeting/service/MeetingWritePlatformServiceJpaRepositoryImpl.java index f4b39854c..9736fc3e5 100644 --- a/mifosng-provider/src/main/java/org/mifosplatform/portfolio/meeting/service/MeetingWritePlatformServiceJpaRepositoryImpl.java +++ b/mifosng-provider/src/main/java/org/mifosplatform/portfolio/meeting/service/MeetingWritePlatformServiceJpaRepositoryImpl.java @@ -10,12 +10,14 @@ import static org.mifosplatform.portfolio.meeting.MeetingApiConstants.calendarId import static org.mifosplatform.portfolio.meeting.MeetingApiConstants.clientIdParamName; import static org.mifosplatform.portfolio.meeting.MeetingApiConstants.clientsAttendanceParamName; import static org.mifosplatform.portfolio.meeting.MeetingApiConstants.meetingDateParamName; +import static org.mifosplatform.portfolio.collectionsheet.CollectionSheetConstants.transactionDateParamName; import java.util.ArrayList; import java.util.Collection; import java.util.Date; import java.util.Map; +import org.joda.time.LocalDate; import org.mifosplatform.infrastructure.core.api.JsonCommand; import org.mifosplatform.infrastructure.core.data.CommandProcessingResult; import org.mifosplatform.infrastructure.core.data.CommandProcessingResultBuilder; @@ -36,6 +38,7 @@ import org.mifosplatform.portfolio.group.exception.ClientNotInGroupException; import org.mifosplatform.portfolio.meeting.attendance.domain.ClientAttendance; import org.mifosplatform.portfolio.meeting.data.MeetingDataValidator; import org.mifosplatform.portfolio.meeting.domain.Meeting; +import org.mifosplatform.portfolio.meeting.domain.MeetingRepository; import org.mifosplatform.portfolio.meeting.domain.MeetingRepositoryWrapper; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.dao.DataIntegrityViolationException; @@ -48,7 +51,8 @@ import com.google.gson.JsonObject; @Service public class MeetingWritePlatformServiceJpaRepositoryImpl implements MeetingWritePlatformService { - private final MeetingRepositoryWrapper meetingRepository; + private final MeetingRepositoryWrapper meetingRepositoryWrapper; + private final MeetingRepository meetingRepository; private final MeetingDataValidator meetingDataValidator; private final CalendarInstanceRepository calendarInstanceRepository; private final CalendarRepository calendarRepository; @@ -57,10 +61,11 @@ public class MeetingWritePlatformServiceJpaRepositoryImpl implements MeetingWrit private final FromJsonHelper fromApiJsonHelper; @Autowired - public MeetingWritePlatformServiceJpaRepositoryImpl(MeetingRepositoryWrapper meetingRepository, - MeetingDataValidator meetingDataValidator, CalendarInstanceRepository calendarInstanceRepository, - CalendarRepository calendarRepository, final ClientRepository clientRepository, final GroupRepository groupRepository, - final FromJsonHelper fromApiJsonHelper) { + public MeetingWritePlatformServiceJpaRepositoryImpl(final MeetingRepositoryWrapper meetingRepositoryWrapper, + final MeetingRepository meetingRepository, final MeetingDataValidator meetingDataValidator, + final CalendarInstanceRepository calendarInstanceRepository, final CalendarRepository calendarRepository, + final ClientRepository clientRepository, final GroupRepository groupRepository, final FromJsonHelper fromApiJsonHelper) { + this.meetingRepositoryWrapper = meetingRepositoryWrapper; this.meetingRepository = meetingRepository; this.meetingDataValidator = meetingDataValidator; this.calendarInstanceRepository = calendarInstanceRepository; @@ -71,7 +76,7 @@ public class MeetingWritePlatformServiceJpaRepositoryImpl implements MeetingWrit } @Override - public CommandProcessingResult createMeeting(JsonCommand command) { + public CommandProcessingResult createMeeting(final JsonCommand command) { this.meetingDataValidator.validateForCreate(command); @@ -87,13 +92,13 @@ public class MeetingWritePlatformServiceJpaRepositoryImpl implements MeetingWrit newMeeting.associateClientsAttendance(clientsAttendance); } // save meeting details - this.meetingRepository.save(newMeeting); + this.meetingRepositoryWrapper.save(newMeeting); final Long groupId = newMeeting.isGroupEntity() ? newMeeting.entityId() : null; return new CommandProcessingResultBuilder() // .withEntityId(newMeeting.getId()) // .withGroupId(groupId).build(); - } catch (DataIntegrityViolationException dve) { + } catch (final DataIntegrityViolationException dve) { handleMeetingDataIntegrityIssues(meetingDate, dve); return new CommandProcessingResultBuilder() // .build(); @@ -107,11 +112,12 @@ public class MeetingWritePlatformServiceJpaRepositoryImpl implements MeetingWrit if (calendarForUpdate == null) { throw new CalendarNotFoundException(calendarId); } final Integer entityTypeId = CalendarEntityType.valueOf(command.getSupportedEntityType().toUpperCase()).getValue(); - final CalendarInstance calendarInstance = calendarInstanceRepository.findByCalendarIdAndEntityIdAndEntityTypeId( + final CalendarInstance calendarInstance = this.calendarInstanceRepository.findByCalendarIdAndEntityIdAndEntityTypeId( calendarForUpdate.getId(), entityId, entityTypeId); - if(calendarInstance == null) { + if (calendarInstance == null) { final String postFix = "for." + command.getSupportedEntityType() + "not.found"; - final String defaultUserMessage = "No Calendar Instance details found for group with identifier " + entityId + " and calendar with identifier " + calendarId; + final String defaultUserMessage = "No Calendar Instance details found for group with identifier " + entityId + + " and calendar with identifier " + calendarId; throw new CalendarInstanceNotFoundException(postFix, defaultUserMessage, entityId, calendarId); } return calendarInstance; @@ -144,16 +150,17 @@ public class MeetingWritePlatformServiceJpaRepositoryImpl implements MeetingWrit } else if (meeting.isCenterEntity()) { if (childGroups != null && !childGroups.isEmpty()) { boolean isChildClient = false; - for (Group group : childGroups) { - if (group.isChildClient(clientId)){ + for (final Group group : childGroups) { + if (group.isChildClient(clientId)) { isChildClient = true; break; } } - if(!isChildClient){ + if (!isChildClient) { final String defaultUserMessage = "Client with identifier " + clientId + " is not in center " + meeting.entityId(); - throw new ClientNotInGroupException("client.not.in.center", defaultUserMessage, clientId, meeting.entityId()); + throw new ClientNotInGroupException("client.not.in.center", defaultUserMessage, clientId, + meeting.entityId()); } } } @@ -167,17 +174,17 @@ public class MeetingWritePlatformServiceJpaRepositoryImpl implements MeetingWrit } @Override - public CommandProcessingResult updateMeeting(JsonCommand command) { + public CommandProcessingResult updateMeeting(final JsonCommand command) { this.meetingDataValidator.validateForUpdate(command); - final Meeting meetingForUpdate = this.meetingRepository.findOneWithNotFoundDetection(command.entityId()); + final Meeting meetingForUpdate = this.meetingRepositoryWrapper.findOneWithNotFoundDetection(command.entityId()); final Map changes = meetingForUpdate.update(command); try { if (!changes.isEmpty()) { - this.meetingRepository.saveAndFlush(meetingForUpdate); + this.meetingRepositoryWrapper.saveAndFlush(meetingForUpdate); } - } catch (DataIntegrityViolationException dve) { + } catch (final DataIntegrityViolationException dve) { handleMeetingDataIntegrityIssues(meetingForUpdate.getMeetingDate(), dve); return new CommandProcessingResultBuilder() // .build(); @@ -191,23 +198,23 @@ public class MeetingWritePlatformServiceJpaRepositoryImpl implements MeetingWrit } @Override - public CommandProcessingResult deleteMeeting(Long meetingId) { - final Meeting meetingForDelete = this.meetingRepository.findOneWithNotFoundDetection(meetingId); - this.meetingRepository.delete(meetingForDelete); + public CommandProcessingResult deleteMeeting(final Long meetingId) { + final Meeting meetingForDelete = this.meetingRepositoryWrapper.findOneWithNotFoundDetection(meetingId); + this.meetingRepositoryWrapper.delete(meetingForDelete); return new CommandProcessingResultBuilder() // .withEntityId(meetingId) // .build(); } @Override - public CommandProcessingResult saveOrUpdateAttendance(JsonCommand command) { + public CommandProcessingResult saveOrUpdateAttendance(final JsonCommand command) { this.meetingDataValidator.validateForUpdateAttendance(command); - final Meeting meetingForUpdate = this.meetingRepository.findOneWithNotFoundDetection(command.entityId()); + final Meeting meetingForUpdate = this.meetingRepositoryWrapper.findOneWithNotFoundDetection(command.entityId()); final Collection clientsAttendance = getClientsAttendance(meetingForUpdate, command); final Map changes = meetingForUpdate.updateAttendance(clientsAttendance); - this.meetingRepository.saveAndFlush(meetingForUpdate); + this.meetingRepositoryWrapper.saveAndFlush(meetingForUpdate); final Long groupId = meetingForUpdate.isGroupEntity() ? meetingForUpdate.entityId() : null; return new CommandProcessingResultBuilder() // .withEntityId(meetingForUpdate.getId()) // @@ -219,11 +226,35 @@ public class MeetingWritePlatformServiceJpaRepositoryImpl implements MeetingWrit private void handleMeetingDataIntegrityIssues(final Date meetingDate, final DataIntegrityViolationException dve) { final Throwable realCause = dve.getMostSpecificCause(); if (realCause.getMessage().contains("unique_calendar_instance_id_meeting_date")) { - - throw new PlatformDataIntegrityException("error.msg.meeting.duplicate", "A meeting with date '" + meetingDate + "' already exists", - meetingDateParamName, meetingDate); } + final LocalDate meetingDateLocal = LocalDate.fromDateFields(meetingDate); + throw new PlatformDataIntegrityException("error.msg.meeting.duplicate", "A meeting with date '" + meetingDateLocal + "' already exists", + meetingDateParamName, meetingDateLocal); } throw new PlatformDataIntegrityException("error.msg.meeting.unknown.data.integrity.issue", "Unknown data integrity issue with resource: " + realCause.getMessage()); } + + @Override + public void updateCollectionSheetAttendance(final JsonCommand command) { + final Date meetingDate = command.DateValueOfParameterNamed(transactionDateParamName); + + try { + final CalendarInstance calendarInstance = getCalendarInstance(command); + final Meeting meeting = this.meetingRepository.findByCalendarInstanceIdAndMeetingDate(calendarInstance.getId(), meetingDate); + + // create new meeting + final Meeting newMeeting = (meeting != null) ? meeting : Meeting.createNew(calendarInstance, meetingDate); + + final Collection clientsAttendance = getClientsAttendance(newMeeting, command); + if (clientsAttendance != null && !clientsAttendance.isEmpty()) { + newMeeting.updateAttendance(clientsAttendance); + } + // save meeting details + this.meetingRepositoryWrapper.save(newMeeting); + } catch (final DataIntegrityViolationException dve) { + handleMeetingDataIntegrityIssues(meetingDate, dve); + } + + } + }