merge 1.14.0 release into master
This commit is contained in:
+9
-4
@@ -8,6 +8,8 @@ import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
|
||||
import com.google.gson.Gson;
|
||||
import com.jayway.restassured.specification.RequestSpecification;
|
||||
import com.jayway.restassured.specification.ResponseSpecification;
|
||||
@@ -74,13 +76,15 @@ public class GroupHelper {
|
||||
map.put("officeId", "1");
|
||||
map.put("name", randomNameGenerator("Group_Name_", 5));
|
||||
map.put("externalId", randomIDGenerator("ID_", 7));
|
||||
if (active == true) {
|
||||
map.put("dateFormat", "dd MMMM yyyy");
|
||||
map.put("locale", "en");
|
||||
if (active) {
|
||||
map.put("active", "true");
|
||||
map.put("dateFormat", "dd MMMM yyyy");
|
||||
map.put("locale", "en");
|
||||
map.put("activationDate", activationDate);
|
||||
} else {
|
||||
map.put("active", "false");
|
||||
map.put("submittedOnDate", "04 March 2011");
|
||||
System.out.println("defaulting to inactive group: 04 March 2011");
|
||||
}
|
||||
|
||||
System.out.println("map : " + map);
|
||||
@@ -100,10 +104,11 @@ public class GroupHelper {
|
||||
final HashMap<String, String> map = new HashMap<String, String>();
|
||||
map.put("dateFormat", "dd MMMM yyyy");
|
||||
map.put("locale", "en");
|
||||
if (activationDate != "") {
|
||||
if (StringUtils.isNotEmpty(activationDate)) {
|
||||
map.put("activationDate", activationDate);
|
||||
} else {
|
||||
map.put("activationDate", "04 March 2011");
|
||||
System.out.println("defaulting to fixed date: 04 March 2011");
|
||||
}
|
||||
System.out.println("map : " + map);
|
||||
return new Gson().toJson(map);
|
||||
|
||||
+9
-9
@@ -267,10 +267,10 @@ public class JournalEntryWritePlatformServiceJpaRepositoryImpl implements Journa
|
||||
.getTransactionId());
|
||||
|
||||
if (journalEntries.size() <= 1) { throw new JournalEntriesNotFoundException(command.getTransactionId()); }
|
||||
Long officeId = journalEntries.get(0).getOffice().getId();
|
||||
final Long officeId = journalEntries.get(0).getOffice().getId();
|
||||
final String reversalTransactionId = generateTransactionId(officeId);
|
||||
final boolean manualEntry = true;
|
||||
|
||||
|
||||
for (final JournalEntry journalEntry : journalEntries) {
|
||||
JournalEntry reversalJournalEntry;
|
||||
final String reversalComment = "Reversal entry for Journal Entry with Entry Id :" + journalEntry.getId()
|
||||
@@ -330,7 +330,7 @@ public class JournalEntryWritePlatformServiceJpaRepositoryImpl implements Journa
|
||||
private void validateBusinessRulesForJournalEntries(final JournalEntryCommand command) {
|
||||
/** check if date of Journal entry is valid ***/
|
||||
final LocalDate entryLocalDate = command.getTransactionDate();
|
||||
final Date transactionDate = entryLocalDate.toDateMidnight().toDate();
|
||||
final Date transactionDate = entryLocalDate.toDateTimeAtStartOfDay().toDate();
|
||||
// shouldn't be in the future
|
||||
final Date todaysDate = new Date();
|
||||
if (transactionDate.after(todaysDate)) { throw new JournalEntryInvalidException(GL_JOURNAL_ENTRY_INVALID_REASON.FUTURE_DATE,
|
||||
@@ -347,7 +347,7 @@ public class JournalEntryWritePlatformServiceJpaRepositoryImpl implements Journa
|
||||
final SingleDebitOrCreditEntryCommand[] debits = command.getDebits();
|
||||
|
||||
// atleast one debit or credit must be present
|
||||
if ((credits == null || credits.length <= 0) || (debits == null || debits.length <= 0)) { throw new JournalEntryInvalidException(
|
||||
if (credits == null || credits.length <= 0 || debits == null || debits.length <= 0) { throw new JournalEntryInvalidException(
|
||||
GL_JOURNAL_ENTRY_INVALID_REASON.NO_DEBITS_OR_CREDITS, null, null, null); }
|
||||
|
||||
checkDebitAndCreditAmounts(credits, debits);
|
||||
@@ -381,11 +381,11 @@ public class JournalEntryWritePlatformServiceJpaRepositoryImpl implements Journa
|
||||
* TODO: Need a better implementation with guaranteed uniqueness (but not a
|
||||
* long UUID)...maybe something tied to system clock..
|
||||
*/
|
||||
private String generateTransactionId(Long officeId) {
|
||||
AppUser user = this.context.authenticatedUser();
|
||||
Long time = System.currentTimeMillis();
|
||||
String uniqueVal = String.valueOf(time) + user.getId() + officeId;
|
||||
String transactionId = Long.toHexString(Long.parseLong(uniqueVal));
|
||||
private String generateTransactionId(final Long officeId) {
|
||||
final AppUser user = this.context.authenticatedUser();
|
||||
final Long time = System.currentTimeMillis();
|
||||
final String uniqueVal = String.valueOf(time) + user.getId() + officeId;
|
||||
final String transactionId = Long.toHexString(Long.parseLong(uniqueVal));
|
||||
return transactionId;
|
||||
}
|
||||
|
||||
|
||||
+11
-3
@@ -143,7 +143,7 @@ public class CommandWrapper {
|
||||
public String getTransactionId() {
|
||||
return this.transactionId;
|
||||
}
|
||||
|
||||
|
||||
public Long getTemplateId() {
|
||||
return this.templateId;
|
||||
}
|
||||
@@ -230,6 +230,10 @@ public class CommandWrapper {
|
||||
return this.entityName.equalsIgnoreCase("CURRENCY");
|
||||
}
|
||||
|
||||
public boolean isSmsResource() {
|
||||
return this.entityName.equalsIgnoreCase("SMS");
|
||||
}
|
||||
|
||||
public boolean isCodeResource() {
|
||||
return this.entityName.equalsIgnoreCase("CODE");
|
||||
}
|
||||
@@ -265,7 +269,7 @@ public class CommandWrapper {
|
||||
public boolean isUpdateRunningbalance() {
|
||||
return this.actionName.equalsIgnoreCase("UPDATERUNNINGBALANCE") && this.entityName.equalsIgnoreCase("JOURNALENTRY");
|
||||
}
|
||||
|
||||
|
||||
public boolean isFundResource() {
|
||||
return this.entityName.equalsIgnoreCase("FUND");
|
||||
}
|
||||
@@ -329,7 +333,7 @@ public class CommandWrapper {
|
||||
public boolean isCollateralResource() {
|
||||
return this.entityName.equalsIgnoreCase("COLLATERAL");
|
||||
}
|
||||
|
||||
|
||||
public boolean isTemplateRessource() {
|
||||
return this.entityName.equalsIgnoreCase("Template");
|
||||
}
|
||||
@@ -588,6 +592,10 @@ public class CommandWrapper {
|
||||
public boolean isHolidayResource() {
|
||||
return this.entityName.equalsIgnoreCase("HOLIDAY");
|
||||
}
|
||||
|
||||
public boolean isHolidayActivation() {
|
||||
return this.entityName.equalsIgnoreCase("HOLIDAY") && this.actionName.equalsIgnoreCase("ACTIVATE") && this.entityId != null;
|
||||
}
|
||||
|
||||
public boolean isAccountingRuleResource() {
|
||||
return this.entityName.equalsIgnoreCase("ACCOUNTINGRULE");
|
||||
|
||||
+50
-2
@@ -238,6 +238,30 @@ public class CommandWrapperBuilder {
|
||||
return this;
|
||||
}
|
||||
|
||||
public CommandWrapperBuilder createSms() {
|
||||
this.actionName = "CREATE";
|
||||
this.entityName = "SMS";
|
||||
this.entityId = null;
|
||||
this.href = "/sms/template";
|
||||
return this;
|
||||
}
|
||||
|
||||
public CommandWrapperBuilder updateSms(final Long resourceId) {
|
||||
this.actionName = "UPDATE";
|
||||
this.entityName = "SMS";
|
||||
this.entityId = resourceId;
|
||||
this.href = "/sms/" + resourceId;
|
||||
return this;
|
||||
}
|
||||
|
||||
public CommandWrapperBuilder deleteSms(final Long resourceId) {
|
||||
this.actionName = "DELETE";
|
||||
this.entityName = "SMS";
|
||||
this.entityId = resourceId;
|
||||
this.href = "/sms/" + resourceId;
|
||||
return this;
|
||||
}
|
||||
|
||||
public CommandWrapperBuilder createCode() {
|
||||
this.actionName = "CREATE";
|
||||
this.entityName = "CODE";
|
||||
@@ -362,7 +386,7 @@ public class CommandWrapperBuilder {
|
||||
this.href = "/clientId/" + clientId + "?command=proposeTransfer";
|
||||
return this;
|
||||
}
|
||||
|
||||
|
||||
public CommandWrapperBuilder proposeAndAcceptClientTransfer(final Long clientId) {
|
||||
this.actionName = "PROPOSEANDACCEPTTRANSFER";
|
||||
this.entityName = "CLIENT";
|
||||
@@ -773,7 +797,7 @@ public class CommandWrapperBuilder {
|
||||
this.href = "/journalentries/" + transactionId;
|
||||
return this;
|
||||
}
|
||||
|
||||
|
||||
public CommandWrapperBuilder updateRunningBalanceForJournalEntry() {
|
||||
this.actionName = "UPDATERUNNINGBALANCE";
|
||||
this.entityName = "JOURNALENTRY";
|
||||
@@ -1287,6 +1311,30 @@ public class CommandWrapperBuilder {
|
||||
this.href = "/holidays/template";
|
||||
return this;
|
||||
}
|
||||
|
||||
public CommandWrapperBuilder activateHoliday(final Long holidayId) {
|
||||
this.actionName = "ACTIVATE";
|
||||
this.entityName = "HOLIDAY";
|
||||
this.entityId = holidayId;
|
||||
this.href = "/holidays/" + holidayId + "command=activate";
|
||||
return this;
|
||||
}
|
||||
|
||||
public CommandWrapperBuilder updateHoliday(final Long holidayId) {
|
||||
this.actionName = "UPDATE";
|
||||
this.entityName = "HOLIDAY";
|
||||
this.entityId = holidayId;
|
||||
this.href = "/holidays/" + holidayId ;
|
||||
return this;
|
||||
}
|
||||
|
||||
public CommandWrapperBuilder deleteHoliday(final Long holidayId) {
|
||||
this.actionName = "DELETE";
|
||||
this.entityName = "HOLIDAY";
|
||||
this.entityId = holidayId;
|
||||
this.href = "/holidays/" + holidayId + "command=delete";
|
||||
return this;
|
||||
}
|
||||
|
||||
public CommandWrapperBuilder assignRole(final Long groupId) {
|
||||
this.actionName = "ASSIGNROLE";
|
||||
|
||||
+18
@@ -254,6 +254,16 @@ public class SynchronousCommandProcessingService implements CommandProcessingSer
|
||||
} else {
|
||||
throw new UnsupportedCommandException(wrapper.commandName());
|
||||
}
|
||||
} else if (wrapper.isSmsResource()) {
|
||||
if (wrapper.isCreate()) {
|
||||
handler = this.applicationContext.getBean("createSmsCommandHandler", NewCommandSourceHandler.class);
|
||||
} else if (wrapper.isUpdate()) {
|
||||
handler = this.applicationContext.getBean("updateSmsCommandHandler", NewCommandSourceHandler.class);
|
||||
} else if (wrapper.isDelete()) {
|
||||
handler = this.applicationContext.getBean("deleteSmsCommandHandler", NewCommandSourceHandler.class);
|
||||
} else {
|
||||
throw new UnsupportedCommandException(wrapper.commandName());
|
||||
}
|
||||
} else if (wrapper.isCurrencyResource()) {
|
||||
handler = this.applicationContext.getBean("updateCurrencyCommandHandler", NewCommandSourceHandler.class);
|
||||
} else if (wrapper.isFundResource()) {
|
||||
@@ -538,6 +548,14 @@ public class SynchronousCommandProcessingService implements CommandProcessingSer
|
||||
} else if (wrapper.isHolidayResource()) {
|
||||
if (wrapper.isCreate()) {
|
||||
handler = this.applicationContext.getBean("createHolidayCommandHandler", NewCommandSourceHandler.class);
|
||||
} else if (wrapper.isHolidayActivation()) {
|
||||
handler = this.applicationContext.getBean("activateHolidayCommandHandler", NewCommandSourceHandler.class);
|
||||
} else if (wrapper.isUpdate()) {
|
||||
handler = this.applicationContext.getBean("updateHolidayCommandHandler", NewCommandSourceHandler.class);
|
||||
} else if (wrapper.isDelete()) {
|
||||
handler = this.applicationContext.getBean("deleteHolidayCommandHandler", NewCommandSourceHandler.class);
|
||||
} else {
|
||||
throw new UnsupportedCommandException(wrapper.commandName());
|
||||
}
|
||||
} else if (wrapper.isProductMixResource()) {
|
||||
if (wrapper.isCreate()) {
|
||||
|
||||
+2
-2
@@ -28,7 +28,7 @@ import com.google.gson.reflect.TypeToken;
|
||||
|
||||
/**
|
||||
* Immutable representation of a command.
|
||||
*
|
||||
*
|
||||
* Wraps the provided JSON with convenience functions for extracting parameter
|
||||
* values and checking for changes against an existing value.
|
||||
*/
|
||||
@@ -295,7 +295,7 @@ public final class JsonCommand {
|
||||
public Date DateValueOfParameterNamed(final String parameterName) {
|
||||
final LocalDate localDate = this.fromApiJsonHelper.extractLocalDateNamed(parameterName, this.parsedCommand);
|
||||
if (localDate == null) { return null; }
|
||||
return localDate.toDateMidnight().toDate();
|
||||
return localDate.toDateTimeAtStartOfDay().toDate();
|
||||
}
|
||||
|
||||
public boolean isChangeInStringParameterNamed(final String parameterName, final String existingValue) {
|
||||
|
||||
+31
@@ -0,0 +1,31 @@
|
||||
/**
|
||||
* 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.infrastructure.core.api;
|
||||
|
||||
import java.util.Set;
|
||||
|
||||
import com.google.gson.ExclusionStrategy;
|
||||
import com.google.gson.FieldAttributes;
|
||||
|
||||
public class ParameterListInclusionStrategy implements ExclusionStrategy {
|
||||
|
||||
private final Set<String> parameterNamesToInclude;
|
||||
|
||||
public ParameterListInclusionStrategy(final Set<String> parameterNamesToSkip) {
|
||||
this.parameterNamesToInclude = parameterNamesToSkip;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean shouldSkipField(final FieldAttributes f) {
|
||||
return !this.parameterNamesToInclude.contains(f.getName());
|
||||
}
|
||||
|
||||
@SuppressWarnings("unused")
|
||||
@Override
|
||||
public boolean shouldSkipClass(final Class<?> clazz) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
+27
@@ -80,6 +80,24 @@ public final class DefaultToApiJsonSerializer<T> implements ToApiJsonSerializer<
|
||||
return serializeWithSettings(delegatedSerializer, settings, singleObject);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String serialize(final ApiRequestJsonSerializationSettings settings, final Collection<T> collection) {
|
||||
final Gson delegatedSerializer = findAppropriateSerializer(settings);
|
||||
return serializeWithSettings(delegatedSerializer, settings, collection.toArray());
|
||||
}
|
||||
|
||||
@Override
|
||||
public String serialize(final ApiRequestJsonSerializationSettings settings, final T singleObject) {
|
||||
final Gson delegatedSerializer = findAppropriateSerializer(settings);
|
||||
return serializeWithSettings(delegatedSerializer, settings, singleObject);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String serialize(final ApiRequestJsonSerializationSettings settings, final Page<T> singleObject) {
|
||||
final Gson delegatedSerializer = findAppropriateSerializer(settings);
|
||||
return serializeWithSettings(delegatedSerializer, settings, singleObject);
|
||||
}
|
||||
|
||||
private String serializeWithSettings(final Gson gson, final ApiRequestJsonSerializationSettings settings, final Object[] dataObject) {
|
||||
String json = null;
|
||||
if (gson != null) {
|
||||
@@ -116,4 +134,13 @@ public final class DefaultToApiJsonSerializer<T> implements ToApiJsonSerializer<
|
||||
}
|
||||
return gson;
|
||||
}
|
||||
|
||||
private Gson findAppropriateSerializer(final ApiRequestJsonSerializationSettings settings) {
|
||||
Gson gson = null;
|
||||
if (settings.isPartialResponseRequired()) {
|
||||
gson = this.helper.createGsonBuilderForPartialResponseFiltering(settings.isPrettyPrint(),
|
||||
settings.getParametersForPartialResponse());
|
||||
}
|
||||
return gson;
|
||||
}
|
||||
}
|
||||
+15
@@ -16,6 +16,7 @@ import org.mifosplatform.infrastructure.core.api.JodaDateTimeAdapter;
|
||||
import org.mifosplatform.infrastructure.core.api.JodaLocalDateAdapter;
|
||||
import org.mifosplatform.infrastructure.core.api.JodaMonthDayAdapter;
|
||||
import org.mifosplatform.infrastructure.core.api.ParameterListExclusionStrategy;
|
||||
import org.mifosplatform.infrastructure.core.api.ParameterListInclusionStrategy;
|
||||
import org.mifosplatform.infrastructure.core.exception.UnsupportedParameterException;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
@@ -40,6 +41,20 @@ public final class GoogleGsonSerializerHelper {
|
||||
return builder.create();
|
||||
}
|
||||
|
||||
public Gson createGsonBuilderForPartialResponseFiltering(final boolean prettyPrint, final Set<String> responseParameters) {
|
||||
|
||||
final ExclusionStrategy strategy = new ParameterListInclusionStrategy(responseParameters);
|
||||
|
||||
final GsonBuilder builder = new GsonBuilder().addSerializationExclusionStrategy(strategy);
|
||||
builder.registerTypeAdapter(LocalDate.class, new JodaLocalDateAdapter());
|
||||
builder.registerTypeAdapter(DateTime.class, new JodaDateTimeAdapter());
|
||||
builder.registerTypeAdapter(MonthDay.class, new JodaMonthDayAdapter());
|
||||
if (prettyPrint) {
|
||||
builder.setPrettyPrinting();
|
||||
}
|
||||
return builder.create();
|
||||
}
|
||||
|
||||
public Gson createGsonBuilderWithParameterExclusionSerializationStrategy(final Set<String> supportedParameters,
|
||||
final boolean prettyPrint, final Set<String> responseParameters) {
|
||||
|
||||
|
||||
+11
@@ -18,6 +18,17 @@ public interface ToApiJsonSerializer<T> {
|
||||
|
||||
String serializeResult(Object object);
|
||||
|
||||
String serialize(ApiRequestJsonSerializationSettings settings, Collection<T> collection);
|
||||
|
||||
String serialize(ApiRequestJsonSerializationSettings settings, T single);
|
||||
|
||||
String serialize(ApiRequestJsonSerializationSettings settings, Page<T> singleObject);
|
||||
|
||||
// TODO: TECHDEBT - bottom three will be deprecated going forward to remove
|
||||
// need for people to pass full list of supported parameters. It was only
|
||||
// used in cases where the partial response features was used (fields=x,y,x)
|
||||
// to report error if incorrect field was passed. From now on it will just
|
||||
// ignore unknown fields and fail silently
|
||||
String serialize(ApiRequestJsonSerializationSettings settings, Collection<T> collection, Set<String> supportedResponseParameters);
|
||||
|
||||
String serialize(ApiRequestJsonSerializationSettings settings, T single, Set<String> supportedResponseParameters);
|
||||
|
||||
+2
-2
@@ -23,7 +23,7 @@ import org.mifosplatform.infrastructure.core.exception.PlatformApiDataValidation
|
||||
public class DateUtils {
|
||||
|
||||
public static Date getDateOfTenant() {
|
||||
return getLocalDateOfTenant().toDateMidnight().toDate();
|
||||
return getLocalDateOfTenant().toDateTimeAtStartOfDay().toDate();
|
||||
}
|
||||
|
||||
public static LocalDate getLocalDateOfTenant() {
|
||||
@@ -63,7 +63,7 @@ public class DateUtils {
|
||||
final String formattedSqlDate = df.format(date);
|
||||
return formattedSqlDate;
|
||||
}
|
||||
|
||||
|
||||
public static boolean isDateInTheFuture(final LocalDate localDate){
|
||||
return localDate.isAfter(getLocalDateOfTenant());
|
||||
}
|
||||
|
||||
+3
-12
@@ -34,6 +34,8 @@ import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
@Path("/jobs")
|
||||
@Consumes({ MediaType.APPLICATION_JSON })
|
||||
@Produces({ MediaType.APPLICATION_JSON })
|
||||
@Component
|
||||
public class SchedulerJobApiResource {
|
||||
|
||||
@@ -59,8 +61,6 @@ public class SchedulerJobApiResource {
|
||||
}
|
||||
|
||||
@GET
|
||||
@Consumes({ MediaType.APPLICATION_JSON })
|
||||
@Produces({ MediaType.APPLICATION_JSON })
|
||||
public String retrieveAll(@Context final UriInfo uriInfo) {
|
||||
final List<JobDetailData> jobDetailDatas = this.schedulerJobRunnerReadService.findAllJobDeatils();
|
||||
final ApiRequestJsonSerializationSettings settings = this.apiRequestParameterHelper.process(uriInfo.getQueryParameters());
|
||||
@@ -69,8 +69,6 @@ public class SchedulerJobApiResource {
|
||||
|
||||
@GET
|
||||
@Path("{" + SchedulerJobApiConstants.JOB_ID + "}")
|
||||
@Consumes({ MediaType.APPLICATION_JSON })
|
||||
@Produces({ MediaType.APPLICATION_JSON })
|
||||
public String retrieveOne(@PathParam(SchedulerJobApiConstants.JOB_ID) final Long jobId, @Context final UriInfo uriInfo) {
|
||||
final JobDetailData jobDetailData = this.schedulerJobRunnerReadService.retrieveOne(jobId);
|
||||
final ApiRequestJsonSerializationSettings settings = this.apiRequestParameterHelper.process(uriInfo.getQueryParameters());
|
||||
@@ -79,8 +77,6 @@ public class SchedulerJobApiResource {
|
||||
|
||||
@GET
|
||||
@Path("{" + SchedulerJobApiConstants.JOB_ID + "}/" + SchedulerJobApiConstants.JOB_RUN_HISTORY)
|
||||
@Consumes({ MediaType.APPLICATION_JSON })
|
||||
@Produces({ MediaType.APPLICATION_JSON })
|
||||
public String retrieveHistory(@Context final UriInfo uriInfo, @PathParam(SchedulerJobApiConstants.JOB_ID) final Long jobId,
|
||||
@QueryParam("offset") final Integer offset, @QueryParam("limit") final Integer limit,
|
||||
@QueryParam("orderBy") final String orderBy, @QueryParam("sortOrder") final String sortOrder) {
|
||||
@@ -94,8 +90,6 @@ public class SchedulerJobApiResource {
|
||||
|
||||
@POST
|
||||
@Path("{" + SchedulerJobApiConstants.JOB_ID + "}")
|
||||
@Consumes({ MediaType.APPLICATION_JSON })
|
||||
@Produces({ MediaType.APPLICATION_JSON })
|
||||
public Response executeJob(@PathParam(SchedulerJobApiConstants.JOB_ID) final Long jobId,
|
||||
@QueryParam(SchedulerJobApiConstants.COMMAND) final String commandParam) {
|
||||
Response response = Response.status(400).build();
|
||||
@@ -110,8 +104,6 @@ public class SchedulerJobApiResource {
|
||||
|
||||
@PUT
|
||||
@Path("{" + SchedulerJobApiConstants.JOB_ID + "}")
|
||||
@Consumes({ MediaType.APPLICATION_JSON })
|
||||
@Produces({ MediaType.APPLICATION_JSON })
|
||||
public String updateJobDetail(@PathParam(SchedulerJobApiConstants.JOB_ID) final Long jobId, final String jsonRequestBody) {
|
||||
|
||||
final CommandWrapper commandRequest = new CommandWrapperBuilder() //
|
||||
@@ -130,5 +122,4 @@ public class SchedulerJobApiResource {
|
||||
private boolean is(final String commandParam, final String commandValue) {
|
||||
return StringUtils.isNotBlank(commandParam) && commandParam.trim().equalsIgnoreCase(commandValue);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
Regular → Executable
+12
-7
@@ -2,15 +2,20 @@ package org.mifosplatform.infrastructure.jobs.service;
|
||||
|
||||
public enum JobName {
|
||||
|
||||
UPDATE_LOAN_SUMMARY("Update loan Summary"), UPDATE_LOAN_ARREARS_AGEING("Update Loan Arrears Ageing"), UPDATE_LOAN_PAID_IN_ADVANCE(
|
||||
"Update Loan Paid In Advance"), APPLY_ANNUAL_FEE_FOR_SAVINGS("Apply Annual Fee For Savings"), APPLY_HOLIDAYS_TO_LOANS(
|
||||
"Apply Holidays To Loans"), POST_INTEREST_FOR_SAVINGS("Post Interest For Savings"), TRANSFER_FEE_CHARGE_FOR_LOANS(
|
||||
"Transfer Fee For Loans From Savings"), ACCOUNTING_RUNNING_BALANCE_UPDATE("Update Accounting Running Balances"), PAY_DUE_SAVINGS_CHARGES(
|
||||
"Pay Due Savings Charges");
|
||||
UPDATE_LOAN_SUMMARY("Update loan Summary"), //
|
||||
UPDATE_LOAN_ARREARS_AGEING("Update Loan Arrears Ageing"), //
|
||||
UPDATE_LOAN_PAID_IN_ADVANCE("Update Loan Paid In Advance"), //
|
||||
APPLY_ANNUAL_FEE_FOR_SAVINGS("Apply Annual Fee For Savings"), //
|
||||
APPLY_HOLIDAYS_TO_LOANS("Apply Holidays To Loans"), //
|
||||
POST_INTEREST_FOR_SAVINGS("Post Interest For Savings"), //
|
||||
TRANSFER_FEE_CHARGE_FOR_LOANS("Transfer Fee For Loans From Savings"), //
|
||||
ACCOUNTING_RUNNING_BALANCE_UPDATE("Update Accounting Running Balances"), //
|
||||
PAY_DUE_SAVINGS_CHARGES("Pay Due Savings Charges"), //
|
||||
APPLY_CHARGE_TO_OVERDUE_LOAN_INSTALLMENT("Apply penalty to overdue loans");
|
||||
|
||||
private final String name;
|
||||
|
||||
JobName(final String name) {
|
||||
private JobName(final String name) {
|
||||
this.name = name;
|
||||
}
|
||||
|
||||
@@ -18,4 +23,4 @@ public enum JobName {
|
||||
public String toString() {
|
||||
return this.name;
|
||||
}
|
||||
}
|
||||
}
|
||||
+1
-5
@@ -38,7 +38,7 @@ import org.springframework.stereotype.Service;
|
||||
* Service class to create and load batch jobs to Scheduler using
|
||||
* {@link SchedulerFactoryBean} ,{@link MethodInvokingJobDetailFactoryBean} and
|
||||
* {@link CronTriggerFactoryBean}
|
||||
*
|
||||
*
|
||||
*/
|
||||
@Service
|
||||
public class JobRegisterServiceImpl implements JobRegisterService {
|
||||
@@ -351,10 +351,6 @@ public class JobRegisterServiceImpl implements JobRegisterService {
|
||||
return cronTriggerFactoryBean.getObject();
|
||||
}
|
||||
|
||||
/**
|
||||
* @param throwable
|
||||
* @return
|
||||
*/
|
||||
private String getStackTraceAsString(final Throwable throwable) {
|
||||
final StackTraceElement[] stackTraceElements = throwable.getStackTrace();
|
||||
final StringBuffer sb = new StringBuffer(throwable.toString());
|
||||
|
||||
+1
-1
@@ -13,5 +13,5 @@ public interface PlatformSecurityContext {
|
||||
|
||||
void validateAccessRights(String resourceOfficeHierarchy);
|
||||
|
||||
String OfficeHierarchy();
|
||||
String officeHierarchy();
|
||||
}
|
||||
+1
-1
@@ -48,7 +48,7 @@ public class SpringSecurityPlatformSecurityContext implements PlatformSecurityCo
|
||||
}
|
||||
|
||||
@Override
|
||||
public String OfficeHierarchy() {
|
||||
public String officeHierarchy() {
|
||||
return authenticatedUser().getOffice().getHierarchy();
|
||||
}
|
||||
}
|
||||
|
||||
+35
@@ -0,0 +1,35 @@
|
||||
/**
|
||||
* 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.infrastructure.sms;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.HashSet;
|
||||
import java.util.Set;
|
||||
|
||||
public class SmsApiConstants {
|
||||
|
||||
public static final String RESOURCE_NAME = "sms";
|
||||
|
||||
// general
|
||||
public static final String localeParamName = "locale";
|
||||
public static final String dateFormatParamName = "dateFormat";
|
||||
|
||||
// request parameters
|
||||
public static final String idParamName = "id";
|
||||
public static final String groupIdParamName = "groupId";
|
||||
public static final String clientIdParamName = "clientId";
|
||||
public static final String staffIdParamName = "staffId";
|
||||
public static final String messageParamName = "message";
|
||||
|
||||
// response parameters
|
||||
public static final String statusParamName = "status";
|
||||
|
||||
public static final Set<String> CREATE_REQUEST_DATA_PARAMETERS = new HashSet<String>(Arrays.asList(localeParamName,
|
||||
dateFormatParamName, groupIdParamName, clientIdParamName, staffIdParamName, messageParamName));
|
||||
|
||||
public static final Set<String> UPDATE_REQUEST_DATA_PARAMETERS = new HashSet<String>(Arrays.asList(messageParamName));
|
||||
|
||||
}
|
||||
+114
@@ -0,0 +1,114 @@
|
||||
/**
|
||||
* 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.infrastructure.sms.api;
|
||||
|
||||
import java.util.Collection;
|
||||
|
||||
import javax.ws.rs.Consumes;
|
||||
import javax.ws.rs.DELETE;
|
||||
import javax.ws.rs.GET;
|
||||
import javax.ws.rs.POST;
|
||||
import javax.ws.rs.PUT;
|
||||
import javax.ws.rs.Path;
|
||||
import javax.ws.rs.PathParam;
|
||||
import javax.ws.rs.Produces;
|
||||
import javax.ws.rs.core.Context;
|
||||
import javax.ws.rs.core.MediaType;
|
||||
import javax.ws.rs.core.UriInfo;
|
||||
|
||||
import org.mifosplatform.commands.domain.CommandWrapper;
|
||||
import org.mifosplatform.commands.service.CommandWrapperBuilder;
|
||||
import org.mifosplatform.commands.service.PortfolioCommandSourceWritePlatformService;
|
||||
import org.mifosplatform.infrastructure.core.api.ApiRequestParameterHelper;
|
||||
import org.mifosplatform.infrastructure.core.data.CommandProcessingResult;
|
||||
import org.mifosplatform.infrastructure.core.serialization.ApiRequestJsonSerializationSettings;
|
||||
import org.mifosplatform.infrastructure.core.serialization.DefaultToApiJsonSerializer;
|
||||
import org.mifosplatform.infrastructure.security.service.PlatformSecurityContext;
|
||||
import org.mifosplatform.infrastructure.sms.data.SmsData;
|
||||
import org.mifosplatform.infrastructure.sms.service.SmsReadPlatformService;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.context.annotation.Scope;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
@Path("/sms")
|
||||
@Consumes({ MediaType.APPLICATION_JSON })
|
||||
@Produces({ MediaType.APPLICATION_JSON })
|
||||
@Component
|
||||
@Scope("singleton")
|
||||
public class SmsApiResource {
|
||||
|
||||
private final String resourceNameForPermissions = "SMS";
|
||||
|
||||
private final PlatformSecurityContext context;
|
||||
private final SmsReadPlatformService readPlatformService;
|
||||
private final DefaultToApiJsonSerializer<SmsData> toApiJsonSerializer;
|
||||
private final ApiRequestParameterHelper apiRequestParameterHelper;
|
||||
private final PortfolioCommandSourceWritePlatformService commandsSourceWritePlatformService;
|
||||
|
||||
@Autowired
|
||||
public SmsApiResource(final PlatformSecurityContext context, final SmsReadPlatformService readPlatformService,
|
||||
final DefaultToApiJsonSerializer<SmsData> toApiJsonSerializer, final ApiRequestParameterHelper apiRequestParameterHelper,
|
||||
final PortfolioCommandSourceWritePlatformService commandsSourceWritePlatformService) {
|
||||
this.context = context;
|
||||
this.readPlatformService = readPlatformService;
|
||||
this.toApiJsonSerializer = toApiJsonSerializer;
|
||||
this.apiRequestParameterHelper = apiRequestParameterHelper;
|
||||
this.commandsSourceWritePlatformService = commandsSourceWritePlatformService;
|
||||
}
|
||||
|
||||
@GET
|
||||
public String retrieveAll(@Context final UriInfo uriInfo) {
|
||||
|
||||
this.context.authenticatedUser().validateHasReadPermission(this.resourceNameForPermissions);
|
||||
|
||||
final Collection<SmsData> smsMessages = this.readPlatformService.retrieveAll();
|
||||
|
||||
final ApiRequestJsonSerializationSettings settings = this.apiRequestParameterHelper.process(uriInfo.getQueryParameters());
|
||||
return this.toApiJsonSerializer.serialize(settings, smsMessages);
|
||||
}
|
||||
|
||||
@POST
|
||||
public String create(final String apiRequestBodyAsJson) {
|
||||
|
||||
final CommandWrapper commandRequest = new CommandWrapperBuilder().createSms().withJson(apiRequestBodyAsJson).build();
|
||||
|
||||
final CommandProcessingResult result = this.commandsSourceWritePlatformService.logCommandSource(commandRequest);
|
||||
|
||||
return this.toApiJsonSerializer.serialize(result);
|
||||
}
|
||||
|
||||
@GET
|
||||
@Path("{resourceId}")
|
||||
public String retrieveOne(@PathParam("resourceId") final Long resourceId, @Context final UriInfo uriInfo) {
|
||||
|
||||
final SmsData smsMessage = this.readPlatformService.retrieveOne(resourceId);
|
||||
|
||||
final ApiRequestJsonSerializationSettings settings = this.apiRequestParameterHelper.process(uriInfo.getQueryParameters());
|
||||
return this.toApiJsonSerializer.serialize(settings, smsMessage);
|
||||
}
|
||||
|
||||
@PUT
|
||||
@Path("{resourceId}")
|
||||
public String update(@PathParam("resourceId") final Long resourceId, final String apiRequestBodyAsJson) {
|
||||
|
||||
final CommandWrapper commandRequest = new CommandWrapperBuilder().updateSms(resourceId).withJson(apiRequestBodyAsJson).build();
|
||||
|
||||
final CommandProcessingResult result = this.commandsSourceWritePlatformService.logCommandSource(commandRequest);
|
||||
|
||||
return this.toApiJsonSerializer.serialize(result);
|
||||
}
|
||||
|
||||
@DELETE
|
||||
@Path("{resourceId}")
|
||||
public String delete(@PathParam("resourceId") final Long resourceId) {
|
||||
|
||||
final CommandWrapper commandRequest = new CommandWrapperBuilder().deleteSms(resourceId).build();
|
||||
|
||||
final CommandProcessingResult result = this.commandsSourceWritePlatformService.logCommandSource(commandRequest);
|
||||
|
||||
return this.toApiJsonSerializer.serialize(result);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,45 @@
|
||||
/**
|
||||
* 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.infrastructure.sms.data;
|
||||
|
||||
import org.mifosplatform.infrastructure.core.data.EnumOptionData;
|
||||
|
||||
/**
|
||||
* Immutable data object representing a SMS message.
|
||||
*/
|
||||
public class SmsData {
|
||||
|
||||
@SuppressWarnings("unused")
|
||||
private final Long id;
|
||||
@SuppressWarnings("unused")
|
||||
private final Long groupId;
|
||||
@SuppressWarnings("unused")
|
||||
private final Long clientId;
|
||||
@SuppressWarnings("unused")
|
||||
private final Long staffId;
|
||||
@SuppressWarnings("unused")
|
||||
private final EnumOptionData status;
|
||||
@SuppressWarnings("unused")
|
||||
private final String mobileNo;
|
||||
@SuppressWarnings("unused")
|
||||
private final String message;
|
||||
|
||||
public static SmsData instance(final Long id, final Long groupId, final Long clientId, final Long staffId, final EnumOptionData status,
|
||||
final String mobileNo, final String message) {
|
||||
return new SmsData(id, groupId, clientId, staffId, status, mobileNo, message);
|
||||
}
|
||||
|
||||
private SmsData(final Long id, final Long groupId, final Long clientId, final Long staffId, final EnumOptionData status,
|
||||
final String mobileNo, final String message) {
|
||||
this.id = id;
|
||||
this.groupId = groupId;
|
||||
this.clientId = clientId;
|
||||
this.staffId = staffId;
|
||||
this.status = status;
|
||||
this.mobileNo = mobileNo;
|
||||
this.message = message;
|
||||
}
|
||||
}
|
||||
+124
@@ -0,0 +1,124 @@
|
||||
/**
|
||||
* 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.infrastructure.sms.data;
|
||||
|
||||
import java.lang.reflect.Type;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import org.apache.commons.lang.StringUtils;
|
||||
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.mifosplatform.infrastructure.sms.SmsApiConstants;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
import com.google.gson.JsonElement;
|
||||
import com.google.gson.reflect.TypeToken;
|
||||
|
||||
@Component
|
||||
public final class SmsDataValidator {
|
||||
|
||||
private final FromJsonHelper fromApiJsonHelper;
|
||||
|
||||
@Autowired
|
||||
public SmsDataValidator(final FromJsonHelper fromApiJsonHelper) {
|
||||
this.fromApiJsonHelper = fromApiJsonHelper;
|
||||
}
|
||||
|
||||
public void validateForCreate(final String json) {
|
||||
|
||||
if (StringUtils.isBlank(json)) { throw new InvalidJsonException(); }
|
||||
|
||||
final Type typeOfMap = new TypeToken<Map<String, Object>>() {}.getType();
|
||||
this.fromApiJsonHelper.checkForUnsupportedParameters(typeOfMap, json, SmsApiConstants.CREATE_REQUEST_DATA_PARAMETERS);
|
||||
final JsonElement element = this.fromApiJsonHelper.parse(json);
|
||||
|
||||
final List<ApiParameterError> dataValidationErrors = new ArrayList<ApiParameterError>();
|
||||
|
||||
final DataValidatorBuilder baseDataValidator = new DataValidatorBuilder(dataValidationErrors)
|
||||
.resource(SmsApiConstants.RESOURCE_NAME);
|
||||
|
||||
if (this.fromApiJsonHelper.parameterExists(SmsApiConstants.groupIdParamName, element)) {
|
||||
final Long groupId = this.fromApiJsonHelper.extractLongNamed(SmsApiConstants.groupIdParamName, element);
|
||||
baseDataValidator.reset().parameter(SmsApiConstants.groupIdParamName).value(groupId).notNull().integerGreaterThanZero();
|
||||
|
||||
// ensure clientId and staffId are not passed
|
||||
if (this.fromApiJsonHelper.parameterExists(SmsApiConstants.clientIdParamName, element)) {
|
||||
baseDataValidator.reset().parameter(SmsApiConstants.clientIdParamName).failWithCode("cannot.be.passed.with.groupId");
|
||||
}
|
||||
|
||||
if (this.fromApiJsonHelper.parameterExists(SmsApiConstants.staffIdParamName, element)) {
|
||||
baseDataValidator.reset().parameter(SmsApiConstants.staffIdParamName).failWithCode("cannot.be.passed.with.groupId");
|
||||
}
|
||||
} else if (this.fromApiJsonHelper.parameterExists(SmsApiConstants.clientIdParamName, element)) {
|
||||
final Long clientId = this.fromApiJsonHelper.extractLongNamed(SmsApiConstants.clientIdParamName, element);
|
||||
baseDataValidator.reset().parameter(SmsApiConstants.clientIdParamName).value(clientId).notNull().integerGreaterThanZero();
|
||||
|
||||
// ensure groupId and staffId are not passed
|
||||
if (this.fromApiJsonHelper.parameterExists(SmsApiConstants.groupIdParamName, element)) {
|
||||
baseDataValidator.reset().parameter(SmsApiConstants.groupIdParamName).failWithCode("cannot.be.passed.with.clientId");
|
||||
}
|
||||
|
||||
if (this.fromApiJsonHelper.parameterExists(SmsApiConstants.staffIdParamName, element)) {
|
||||
baseDataValidator.reset().parameter(SmsApiConstants.staffIdParamName).failWithCode("cannot.be.passed.with.clientId");
|
||||
}
|
||||
} else if (this.fromApiJsonHelper.parameterExists(SmsApiConstants.staffIdParamName, element)) {
|
||||
final Long staffId = this.fromApiJsonHelper.extractLongNamed(SmsApiConstants.staffIdParamName, element);
|
||||
baseDataValidator.reset().parameter(SmsApiConstants.staffIdParamName).value(staffId).ignoreIfNull().longGreaterThanZero();
|
||||
|
||||
// ensure groupId and clientId are not passed
|
||||
if (this.fromApiJsonHelper.parameterExists(SmsApiConstants.groupIdParamName, element)) {
|
||||
baseDataValidator.reset().parameter(SmsApiConstants.groupIdParamName).failWithCode("cannot.be.passed.with.staffId");
|
||||
}
|
||||
|
||||
if (this.fromApiJsonHelper.parameterExists(SmsApiConstants.clientIdParamName, element)) {
|
||||
baseDataValidator.reset().parameter(SmsApiConstants.clientIdParamName).failWithCode("cannot.be.passed.with.staffId");
|
||||
}
|
||||
}
|
||||
|
||||
if (!this.fromApiJsonHelper.parameterExists(SmsApiConstants.groupIdParamName, element)
|
||||
&& !this.fromApiJsonHelper.parameterExists(SmsApiConstants.clientIdParamName, element)
|
||||
&& !this.fromApiJsonHelper.parameterExists(SmsApiConstants.staffIdParamName, element)) {
|
||||
baseDataValidator.reset().parameter(SmsApiConstants.staffIdParamName)
|
||||
.failWithCodeNoParameterAddedToErrorCode("no.entity.provided");
|
||||
}
|
||||
|
||||
final String message = this.fromApiJsonHelper.extractStringNamed(SmsApiConstants.messageParamName, element);
|
||||
baseDataValidator.reset().parameter(SmsApiConstants.messageParamName).value(message).notBlank().notExceedingLengthOf(1000);
|
||||
|
||||
throwExceptionIfValidationWarningsExist(dataValidationErrors);
|
||||
}
|
||||
|
||||
public void validateForUpdate(final String json) {
|
||||
|
||||
if (StringUtils.isBlank(json)) { throw new InvalidJsonException(); }
|
||||
|
||||
final Type typeOfMap = new TypeToken<Map<String, Object>>() {}.getType();
|
||||
this.fromApiJsonHelper.checkForUnsupportedParameters(typeOfMap, json, SmsApiConstants.UPDATE_REQUEST_DATA_PARAMETERS);
|
||||
final JsonElement element = this.fromApiJsonHelper.parse(json);
|
||||
|
||||
final List<ApiParameterError> dataValidationErrors = new ArrayList<ApiParameterError>();
|
||||
|
||||
final DataValidatorBuilder baseDataValidator = new DataValidatorBuilder(dataValidationErrors)
|
||||
.resource(SmsApiConstants.RESOURCE_NAME);
|
||||
|
||||
if (this.fromApiJsonHelper.parameterExists(SmsApiConstants.messageParamName, element)) {
|
||||
final String message = this.fromApiJsonHelper.extractStringNamed(SmsApiConstants.messageParamName, element);
|
||||
baseDataValidator.reset().parameter(SmsApiConstants.messageParamName).value(message).notBlank().notExceedingLengthOf(1000);
|
||||
}
|
||||
|
||||
throwExceptionIfValidationWarningsExist(dataValidationErrors);
|
||||
}
|
||||
|
||||
private void throwExceptionIfValidationWarningsExist(final List<ApiParameterError> dataValidationErrors) {
|
||||
if (!dataValidationErrors.isEmpty()) { throw new PlatformApiDataValidationException(dataValidationErrors); }
|
||||
}
|
||||
}
|
||||
+81
@@ -0,0 +1,81 @@
|
||||
/**
|
||||
* 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.infrastructure.sms.domain;
|
||||
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.Map;
|
||||
|
||||
import javax.persistence.Column;
|
||||
import javax.persistence.Entity;
|
||||
import javax.persistence.JoinColumn;
|
||||
import javax.persistence.ManyToOne;
|
||||
import javax.persistence.Table;
|
||||
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
import org.mifosplatform.infrastructure.core.api.JsonCommand;
|
||||
import org.mifosplatform.infrastructure.sms.SmsApiConstants;
|
||||
import org.mifosplatform.organisation.staff.domain.Staff;
|
||||
import org.mifosplatform.portfolio.client.domain.Client;
|
||||
import org.mifosplatform.portfolio.group.domain.Group;
|
||||
import org.springframework.data.jpa.domain.AbstractPersistable;
|
||||
|
||||
@Entity
|
||||
@Table(name = "sms_messages_outbound")
|
||||
public class SmsMessage extends AbstractPersistable<Long> {
|
||||
|
||||
@ManyToOne
|
||||
@JoinColumn(name = "group_id", nullable = true)
|
||||
private Group group;
|
||||
|
||||
@ManyToOne
|
||||
@JoinColumn(name = "client_id", nullable = true)
|
||||
private Client client;
|
||||
|
||||
@ManyToOne
|
||||
@JoinColumn(name = "staff_id", nullable = true)
|
||||
private Staff staff;
|
||||
|
||||
@Column(name = "status_enum", nullable = false)
|
||||
private Integer statusType;
|
||||
|
||||
@Column(name = "mobile_no", nullable = false, length=50)
|
||||
private String mobileNo;
|
||||
|
||||
@Column(name = "message", nullable = false)
|
||||
private String message;
|
||||
|
||||
public static SmsMessage pendingSms(final Group group, final Client client, final Staff staff, final String message,
|
||||
final String mobileNo) {
|
||||
return new SmsMessage(group, client, staff, SmsMessageStatusType.PENDING, message, mobileNo);
|
||||
}
|
||||
|
||||
protected SmsMessage() {
|
||||
//
|
||||
}
|
||||
|
||||
private SmsMessage(final Group group, final Client client, final Staff staff, final SmsMessageStatusType statusType,
|
||||
final String message, final String mobileNo) {
|
||||
this.group = group;
|
||||
this.client = client;
|
||||
this.staff = staff;
|
||||
this.statusType = statusType.getValue();
|
||||
this.mobileNo = mobileNo;
|
||||
this.message = message;
|
||||
}
|
||||
|
||||
public Map<String, Object> update(final JsonCommand command) {
|
||||
|
||||
final Map<String, Object> actualChanges = new LinkedHashMap<String, Object>(1);
|
||||
|
||||
if (command.isChangeInStringParameterNamed(SmsApiConstants.messageParamName, this.message)) {
|
||||
final String newValue = command.stringValueOfParameterNamed(SmsApiConstants.messageParamName);
|
||||
actualChanges.put(SmsApiConstants.messageParamName, newValue);
|
||||
this.message = StringUtils.defaultIfEmpty(newValue, null);
|
||||
}
|
||||
|
||||
return actualChanges;
|
||||
}
|
||||
}
|
||||
+81
@@ -0,0 +1,81 @@
|
||||
/**
|
||||
* 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.infrastructure.sms.domain;
|
||||
|
||||
import org.mifosplatform.infrastructure.core.api.JsonCommand;
|
||||
import org.mifosplatform.infrastructure.core.serialization.FromJsonHelper;
|
||||
import org.mifosplatform.infrastructure.sms.SmsApiConstants;
|
||||
import org.mifosplatform.infrastructure.sms.exception.SmsNotFoundException;
|
||||
import org.mifosplatform.organisation.staff.domain.Staff;
|
||||
import org.mifosplatform.organisation.staff.domain.StaffRepositoryWrapper;
|
||||
import org.mifosplatform.portfolio.client.domain.Client;
|
||||
import org.mifosplatform.portfolio.client.domain.ClientRepositoryWrapper;
|
||||
import org.mifosplatform.portfolio.group.domain.Group;
|
||||
import org.mifosplatform.portfolio.group.domain.GroupRepositoryWrapper;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
import com.google.gson.JsonElement;
|
||||
|
||||
@Component
|
||||
public class SmsMessageAssembler {
|
||||
|
||||
private final SmsMessageRepository smsMessageRepository;
|
||||
private final GroupRepositoryWrapper groupRepository;
|
||||
private final ClientRepositoryWrapper clientRepository;
|
||||
private final StaffRepositoryWrapper staffRepository;
|
||||
private final FromJsonHelper fromApiJsonHelper;
|
||||
|
||||
@Autowired
|
||||
public SmsMessageAssembler(final SmsMessageRepository smsMessageRepository,
|
||||
final GroupRepositoryWrapper groupRepositoryWrapper,
|
||||
final ClientRepositoryWrapper clientRepository,
|
||||
final StaffRepositoryWrapper staffRepository,
|
||||
final FromJsonHelper fromApiJsonHelper) {
|
||||
this.smsMessageRepository = smsMessageRepository;
|
||||
this.groupRepository = groupRepositoryWrapper;
|
||||
this.clientRepository = clientRepository;
|
||||
this.staffRepository = staffRepository;
|
||||
this.fromApiJsonHelper = fromApiJsonHelper;
|
||||
}
|
||||
|
||||
public SmsMessage assembleFromJson(final JsonCommand command) {
|
||||
|
||||
final JsonElement element = command.parsedJson();
|
||||
|
||||
String mobileNo = null;
|
||||
|
||||
Group group = null;
|
||||
if (this.fromApiJsonHelper.parameterExists(SmsApiConstants.groupIdParamName, element)) {
|
||||
final Long groupId = this.fromApiJsonHelper.extractLongNamed(SmsApiConstants.groupIdParamName, element);
|
||||
group = this.groupRepository.findOneWithNotFoundDetection(groupId);
|
||||
}
|
||||
|
||||
Client client = null;
|
||||
if (this.fromApiJsonHelper.parameterExists(SmsApiConstants.clientIdParamName, element)) {
|
||||
final Long clientId = this.fromApiJsonHelper.extractLongNamed(SmsApiConstants.clientIdParamName, element);
|
||||
client = this.clientRepository.findOneWithNotFoundDetection(clientId);
|
||||
mobileNo = client.mobileNo();
|
||||
}
|
||||
|
||||
Staff staff = null;
|
||||
if (this.fromApiJsonHelper.parameterExists(SmsApiConstants.staffIdParamName, element)) {
|
||||
final Long staffId = this.fromApiJsonHelper.extractLongNamed(SmsApiConstants.staffIdParamName, element);
|
||||
staff = this.staffRepository.findOneWithNotFoundDetection(staffId);
|
||||
mobileNo = staff.mobileNo();
|
||||
}
|
||||
|
||||
final String message = this.fromApiJsonHelper.extractStringNamed(SmsApiConstants.messageParamName, element);
|
||||
|
||||
return SmsMessage.pendingSms(group, client, staff, message, mobileNo);
|
||||
}
|
||||
|
||||
public SmsMessage assembleFromResourceId(final Long resourceId) {
|
||||
final SmsMessage sms = this.smsMessageRepository.findOne(resourceId);
|
||||
if (sms == null) { throw new SmsNotFoundException(resourceId); }
|
||||
return sms;
|
||||
}
|
||||
}
|
||||
+40
@@ -0,0 +1,40 @@
|
||||
/**
|
||||
* 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.infrastructure.sms.domain;
|
||||
|
||||
import org.mifosplatform.infrastructure.core.data.EnumOptionData;
|
||||
|
||||
public class SmsMessageEnumerations {
|
||||
|
||||
public static EnumOptionData status(final Integer statusId) {
|
||||
return status(SmsMessageStatusType.fromInt(statusId));
|
||||
}
|
||||
|
||||
public static EnumOptionData status(final SmsMessageStatusType status) {
|
||||
EnumOptionData optionData = new EnumOptionData(SmsMessageStatusType.INVALID.getValue().longValue(), SmsMessageStatusType.INVALID.getCode(),
|
||||
"Invalid");
|
||||
switch (status) {
|
||||
case INVALID:
|
||||
optionData = new EnumOptionData(SmsMessageStatusType.INVALID.getValue().longValue(), SmsMessageStatusType.INVALID.getCode(), "Invalid");
|
||||
break;
|
||||
case PENDING:
|
||||
optionData = new EnumOptionData(SmsMessageStatusType.PENDING.getValue().longValue(), SmsMessageStatusType.PENDING.getCode(), "Pending");
|
||||
break;
|
||||
case SENT:
|
||||
optionData = new EnumOptionData(SmsMessageStatusType.SENT.getValue().longValue(), SmsMessageStatusType.SENT.getCode(), "Sent");
|
||||
break;
|
||||
case DELIVERED:
|
||||
optionData = new EnumOptionData(SmsMessageStatusType.DELIVERED.getValue().longValue(), SmsMessageStatusType.DELIVERED.getCode(), "Delivered");
|
||||
break;
|
||||
case FAILED:
|
||||
optionData = new EnumOptionData(SmsMessageStatusType.FAILED.getValue().longValue(), SmsMessageStatusType.FAILED.getCode(), "Failed");
|
||||
break;
|
||||
|
||||
}
|
||||
|
||||
return optionData;
|
||||
}
|
||||
}
|
||||
+13
@@ -0,0 +1,13 @@
|
||||
/**
|
||||
* 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.infrastructure.sms.domain;
|
||||
|
||||
import org.springframework.data.jpa.repository.JpaRepository;
|
||||
import org.springframework.data.jpa.repository.JpaSpecificationExecutor;
|
||||
|
||||
public interface SmsMessageRepository extends JpaRepository<SmsMessage, Long>, JpaSpecificationExecutor<SmsMessage> {
|
||||
// no extra behaviour
|
||||
}
|
||||
+46
@@ -0,0 +1,46 @@
|
||||
package org.mifosplatform.infrastructure.sms.domain;
|
||||
|
||||
public enum SmsMessageStatusType {
|
||||
|
||||
INVALID(0, "smsMessageStatusType.invalid"), //
|
||||
PENDING(100, "smsMessageStatusType.pending"), //
|
||||
SENT(200, "smsMessageStatusType.sent"), //
|
||||
DELIVERED(300, "smsMessageStatusType.delivered"), //
|
||||
FAILED(400, "smsMessageStatusType.failed");
|
||||
|
||||
private final Integer value;
|
||||
private final String code;
|
||||
|
||||
public static SmsMessageStatusType fromInt(final Integer statusValue) {
|
||||
|
||||
SmsMessageStatusType enumeration = SmsMessageStatusType.INVALID;
|
||||
switch (statusValue) {
|
||||
case 100:
|
||||
enumeration = SmsMessageStatusType.PENDING;
|
||||
break;
|
||||
case 200:
|
||||
enumeration = SmsMessageStatusType.SENT;
|
||||
break;
|
||||
case 300:
|
||||
enumeration = SmsMessageStatusType.DELIVERED;
|
||||
break;
|
||||
case 400:
|
||||
enumeration = SmsMessageStatusType.FAILED;
|
||||
break;
|
||||
}
|
||||
return enumeration;
|
||||
}
|
||||
|
||||
private SmsMessageStatusType(final Integer value, final String code) {
|
||||
this.value = value;
|
||||
this.code = code;
|
||||
}
|
||||
|
||||
public Integer getValue() {
|
||||
return this.value;
|
||||
}
|
||||
|
||||
public String getCode() {
|
||||
return this.code;
|
||||
}
|
||||
}
|
||||
+18
@@ -0,0 +1,18 @@
|
||||
/**
|
||||
* 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.infrastructure.sms.exception;
|
||||
|
||||
import org.mifosplatform.infrastructure.core.exception.AbstractPlatformResourceNotFoundException;
|
||||
|
||||
/**
|
||||
* A {@link RuntimeException} thrown when a code is not found.
|
||||
*/
|
||||
public class SmsNotFoundException extends AbstractPlatformResourceNotFoundException {
|
||||
|
||||
public SmsNotFoundException(final Long resourceId) {
|
||||
super("error.msg.sms.identifier.not.found", "SMS with identifier `" + resourceId + "` does not exist", resourceId);
|
||||
}
|
||||
}
|
||||
+32
@@ -0,0 +1,32 @@
|
||||
/**
|
||||
* 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.infrastructure.sms.handler;
|
||||
|
||||
import org.mifosplatform.commands.handler.NewCommandSourceHandler;
|
||||
import org.mifosplatform.infrastructure.core.api.JsonCommand;
|
||||
import org.mifosplatform.infrastructure.core.data.CommandProcessingResult;
|
||||
import org.mifosplatform.infrastructure.sms.service.SmsWritePlatformService;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.stereotype.Service;
|
||||
import org.springframework.transaction.annotation.Transactional;
|
||||
|
||||
@Service
|
||||
public class CreateSmsCommandHandler implements NewCommandSourceHandler {
|
||||
|
||||
private final SmsWritePlatformService writePlatformService;
|
||||
|
||||
@Autowired
|
||||
public CreateSmsCommandHandler(final SmsWritePlatformService writePlatformService) {
|
||||
this.writePlatformService = writePlatformService;
|
||||
}
|
||||
|
||||
@Transactional
|
||||
@Override
|
||||
public CommandProcessingResult processCommand(final JsonCommand command) {
|
||||
|
||||
return this.writePlatformService.create(command);
|
||||
}
|
||||
}
|
||||
+32
@@ -0,0 +1,32 @@
|
||||
/**
|
||||
* 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.infrastructure.sms.handler;
|
||||
|
||||
import org.mifosplatform.commands.handler.NewCommandSourceHandler;
|
||||
import org.mifosplatform.infrastructure.core.api.JsonCommand;
|
||||
import org.mifosplatform.infrastructure.core.data.CommandProcessingResult;
|
||||
import org.mifosplatform.infrastructure.sms.service.SmsWritePlatformService;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.stereotype.Service;
|
||||
import org.springframework.transaction.annotation.Transactional;
|
||||
|
||||
@Service
|
||||
public class DeleteSmsCommandHandler implements NewCommandSourceHandler {
|
||||
|
||||
private final SmsWritePlatformService writePlatformService;
|
||||
|
||||
@Autowired
|
||||
public DeleteSmsCommandHandler(final SmsWritePlatformService writePlatformService) {
|
||||
this.writePlatformService = writePlatformService;
|
||||
}
|
||||
|
||||
@Transactional
|
||||
@Override
|
||||
public CommandProcessingResult processCommand(final JsonCommand command) {
|
||||
|
||||
return this.writePlatformService.delete(command.entityId());
|
||||
}
|
||||
}
|
||||
+32
@@ -0,0 +1,32 @@
|
||||
/**
|
||||
* 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.infrastructure.sms.handler;
|
||||
|
||||
import org.mifosplatform.commands.handler.NewCommandSourceHandler;
|
||||
import org.mifosplatform.infrastructure.core.api.JsonCommand;
|
||||
import org.mifosplatform.infrastructure.core.data.CommandProcessingResult;
|
||||
import org.mifosplatform.infrastructure.sms.service.SmsWritePlatformService;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.stereotype.Service;
|
||||
import org.springframework.transaction.annotation.Transactional;
|
||||
|
||||
@Service
|
||||
public class UpdateSmsCommandHandler implements NewCommandSourceHandler {
|
||||
|
||||
private final SmsWritePlatformService writePlatformService;
|
||||
|
||||
@Autowired
|
||||
public UpdateSmsCommandHandler(final SmsWritePlatformService writePlatformService) {
|
||||
this.writePlatformService = writePlatformService;
|
||||
}
|
||||
|
||||
@Transactional
|
||||
@Override
|
||||
public CommandProcessingResult processCommand(final JsonCommand command) {
|
||||
|
||||
return this.writePlatformService.update(command.entityId(), command);
|
||||
}
|
||||
}
|
||||
+17
@@ -0,0 +1,17 @@
|
||||
/**
|
||||
* 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.infrastructure.sms.service;
|
||||
|
||||
import java.util.Collection;
|
||||
|
||||
import org.mifosplatform.infrastructure.sms.data.SmsData;
|
||||
|
||||
public interface SmsReadPlatformService {
|
||||
|
||||
Collection<SmsData> retrieveAll();
|
||||
|
||||
SmsData retrieveOne(Long resourceId);
|
||||
}
|
||||
+94
@@ -0,0 +1,94 @@
|
||||
/**
|
||||
* 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.infrastructure.sms.service;
|
||||
|
||||
import java.sql.ResultSet;
|
||||
import java.sql.SQLException;
|
||||
import java.util.Collection;
|
||||
|
||||
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.sms.data.SmsData;
|
||||
import org.mifosplatform.infrastructure.sms.domain.SmsMessageEnumerations;
|
||||
import org.mifosplatform.infrastructure.sms.exception.SmsNotFoundException;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.dao.EmptyResultDataAccessException;
|
||||
import org.springframework.jdbc.core.JdbcTemplate;
|
||||
import org.springframework.jdbc.core.RowMapper;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
@Service
|
||||
public class SmsReadPlatformServiceImpl implements SmsReadPlatformService {
|
||||
|
||||
private final JdbcTemplate jdbcTemplate;
|
||||
private final SmsMapper smsRowMapper;
|
||||
|
||||
@Autowired
|
||||
public SmsReadPlatformServiceImpl(final RoutingDataSource dataSource) {
|
||||
this.jdbcTemplate = new JdbcTemplate(dataSource);
|
||||
this.smsRowMapper = new SmsMapper();
|
||||
}
|
||||
|
||||
private static final class SmsMapper implements RowMapper<SmsData> {
|
||||
|
||||
final String schema;
|
||||
|
||||
public SmsMapper() {
|
||||
final StringBuilder sql = new StringBuilder(300);
|
||||
sql.append("smo.id as id, ");
|
||||
sql.append("smo.group_id as groupId, ");
|
||||
sql.append("smo.client_id as clientId, ");
|
||||
sql.append("smo.staff_id as staffId, ");
|
||||
sql.append("smo.status_enum as statusId, ");
|
||||
sql.append("smo.mobile_no as mobileNo, ");
|
||||
sql.append("smo.message as message ");
|
||||
sql.append("from sms_messages_outbound smo");
|
||||
|
||||
this.schema = sql.toString();
|
||||
}
|
||||
|
||||
public String schema() {
|
||||
return this.schema;
|
||||
}
|
||||
|
||||
@Override
|
||||
public SmsData mapRow(final ResultSet rs, @SuppressWarnings("unused") final int rowNum) throws SQLException {
|
||||
|
||||
final Long id = JdbcSupport.getLong(rs, "id");
|
||||
final Long groupId = JdbcSupport.getLong(rs, "groupId");
|
||||
final Long clientId = JdbcSupport.getLong(rs, "clientId");
|
||||
final Long staffId = JdbcSupport.getLong(rs, "staffId");
|
||||
|
||||
final String mobileNo = rs.getString("mobileNo");
|
||||
final String message = rs.getString("message");
|
||||
|
||||
final Integer statusId = JdbcSupport.getInteger(rs, "statusId");
|
||||
final EnumOptionData status = SmsMessageEnumerations.status(statusId);
|
||||
|
||||
return SmsData.instance(id, groupId, clientId, staffId, status, mobileNo, message);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public Collection<SmsData> retrieveAll() {
|
||||
|
||||
final String sql = "select " + this.smsRowMapper.schema();
|
||||
|
||||
return this.jdbcTemplate.query(sql, this.smsRowMapper, new Object[] {});
|
||||
}
|
||||
|
||||
@Override
|
||||
public SmsData retrieveOne(final Long resourceId) {
|
||||
try {
|
||||
final String sql = "select " + this.smsRowMapper.schema() + " where smo.id = ?";
|
||||
|
||||
return this.jdbcTemplate.queryForObject(sql, this.smsRowMapper, new Object[] { resourceId });
|
||||
} catch (final EmptyResultDataAccessException e) {
|
||||
throw new SmsNotFoundException(resourceId);
|
||||
}
|
||||
}
|
||||
}
|
||||
+18
@@ -0,0 +1,18 @@
|
||||
/**
|
||||
* 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.infrastructure.sms.service;
|
||||
|
||||
import org.mifosplatform.infrastructure.core.api.JsonCommand;
|
||||
import org.mifosplatform.infrastructure.core.data.CommandProcessingResult;
|
||||
|
||||
public interface SmsWritePlatformService {
|
||||
|
||||
CommandProcessingResult create(JsonCommand command);
|
||||
|
||||
CommandProcessingResult update(Long resourceId, JsonCommand command);
|
||||
|
||||
CommandProcessingResult delete(Long resourceId);
|
||||
}
|
||||
+119
@@ -0,0 +1,119 @@
|
||||
/**
|
||||
* 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.infrastructure.sms.service;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
import org.mifosplatform.infrastructure.core.api.JsonCommand;
|
||||
import org.mifosplatform.infrastructure.core.data.CommandProcessingResult;
|
||||
import org.mifosplatform.infrastructure.core.data.CommandProcessingResultBuilder;
|
||||
import org.mifosplatform.infrastructure.core.exception.PlatformDataIntegrityException;
|
||||
import org.mifosplatform.infrastructure.sms.data.SmsDataValidator;
|
||||
import org.mifosplatform.infrastructure.sms.domain.SmsMessage;
|
||||
import org.mifosplatform.infrastructure.sms.domain.SmsMessageAssembler;
|
||||
import org.mifosplatform.infrastructure.sms.domain.SmsMessageRepository;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.dao.DataIntegrityViolationException;
|
||||
import org.springframework.stereotype.Service;
|
||||
import org.springframework.transaction.annotation.Transactional;
|
||||
|
||||
@Service
|
||||
public class SmsWritePlatformServiceJpaRepositoryImpl implements SmsWritePlatformService {
|
||||
|
||||
private final static Logger logger = LoggerFactory.getLogger(SmsWritePlatformServiceJpaRepositoryImpl.class);
|
||||
|
||||
private final SmsMessageAssembler assembler;
|
||||
private final SmsMessageRepository repository;
|
||||
private final SmsDataValidator validator;
|
||||
|
||||
@Autowired
|
||||
public SmsWritePlatformServiceJpaRepositoryImpl(final SmsMessageAssembler assembler, final SmsMessageRepository repository,
|
||||
final SmsDataValidator validator) {
|
||||
this.assembler = assembler;
|
||||
this.repository = repository;
|
||||
this.validator = validator;
|
||||
}
|
||||
|
||||
@Transactional
|
||||
@Override
|
||||
public CommandProcessingResult create(final JsonCommand command) {
|
||||
|
||||
try {
|
||||
this.validator.validateForCreate(command.json());
|
||||
|
||||
final SmsMessage message = this.assembler.assembleFromJson(command);
|
||||
|
||||
// TODO: at this point we also want to fire off request using third party service to send SMS.
|
||||
// TODO: decision to be made on wheter we 'wait' for response or use 'future/promise' to capture response and update the SmsMessage table
|
||||
this.repository.save(message);
|
||||
|
||||
return new CommandProcessingResultBuilder() //
|
||||
.withCommandId(command.commandId()) //
|
||||
.withEntityId(message.getId()) //
|
||||
.build();
|
||||
} catch (final DataIntegrityViolationException dve) {
|
||||
handleDataIntegrityIssues(command, dve);
|
||||
return CommandProcessingResult.empty();
|
||||
}
|
||||
}
|
||||
|
||||
@Transactional
|
||||
@Override
|
||||
public CommandProcessingResult update(final Long resourceId, final JsonCommand command) {
|
||||
|
||||
try {
|
||||
this.validator.validateForUpdate(command.json());
|
||||
|
||||
final SmsMessage message = this.assembler.assembleFromResourceId(resourceId);
|
||||
final Map<String, Object> changes = message.update(command);
|
||||
if (!changes.isEmpty()) {
|
||||
this.repository.save(message);
|
||||
}
|
||||
|
||||
return new CommandProcessingResultBuilder() //
|
||||
.withCommandId(command.commandId()) //
|
||||
.withEntityId(resourceId) //
|
||||
.with(changes) //
|
||||
.build();
|
||||
} catch (final DataIntegrityViolationException dve) {
|
||||
handleDataIntegrityIssues(command, dve);
|
||||
return CommandProcessingResult.empty();
|
||||
}
|
||||
}
|
||||
|
||||
@Transactional
|
||||
@Override
|
||||
public CommandProcessingResult delete(final Long resourceId) {
|
||||
|
||||
try {
|
||||
final SmsMessage message = this.assembler.assembleFromResourceId(resourceId);
|
||||
this.repository.delete(message);
|
||||
this.repository.flush();
|
||||
} catch (final DataIntegrityViolationException dve) {
|
||||
handleDataIntegrityIssues(null, dve);
|
||||
return CommandProcessingResult.empty();
|
||||
}
|
||||
return new CommandProcessingResultBuilder().withEntityId(resourceId).build();
|
||||
}
|
||||
|
||||
/*
|
||||
* Guaranteed to throw an exception no matter what the data integrity issue
|
||||
* is.
|
||||
*/
|
||||
private void handleDataIntegrityIssues(@SuppressWarnings("unused") final JsonCommand command, final DataIntegrityViolationException dve) {
|
||||
final Throwable realCause = dve.getMostSpecificCause();
|
||||
|
||||
if (realCause.getMessage().contains("mobile_no")) {
|
||||
throw new PlatformDataIntegrityException("error.msg.sms.no.mobile.no.exists", "The group, client or staff provided has no mobile no.", "id");
|
||||
}
|
||||
|
||||
logger.error(dve.getMessage(), dve);
|
||||
throw new PlatformDataIntegrityException("error.msg.sms.unknown.data.integrity.issue",
|
||||
"Unknown data integrity issue with resource: " + realCause.getMessage());
|
||||
}
|
||||
}
|
||||
+13
-12
@@ -13,18 +13,19 @@ public class HolidayApiConstants {
|
||||
public static final String dateFormatParamName = "dateFormat";
|
||||
|
||||
// request parameters
|
||||
public static final String name = "name";
|
||||
public static final String fromDate = "fromDate";
|
||||
public static final String toDate = "toDate";
|
||||
public static final String description = "description";
|
||||
public static final String offices = "offices";
|
||||
public static final String officeId = "officeId";
|
||||
public static final String repaymentsRescheduledTo = "repaymentsRescheduledTo";
|
||||
public static final String idParamName = "id";
|
||||
public static final String nameParamName = "name";
|
||||
public static final String fromDateParamName = "fromDate";
|
||||
public static final String toDateParamName = "toDate";
|
||||
public static final String descriptionParamName = "description";
|
||||
public static final String officesParamName = "offices";
|
||||
public static final String officeIdParamName = "officeId";
|
||||
public static final String repaymentsRescheduledToParamName = "repaymentsRescheduledTo";
|
||||
public static final String processed = "processed";
|
||||
|
||||
public static final Set<String> HOLIDAY_CREATE_REQUEST_DATA_PARAMETERS = new HashSet<String>(Arrays.asList(localeParamName,
|
||||
dateFormatParamName, name, fromDate, toDate, description, offices, repaymentsRescheduledTo));
|
||||
|
||||
public static final Set<String> HOLIDAY_REQUEST_DATA_PARAMETERS = new HashSet<String>(Arrays.asList(localeParamName,
|
||||
dateFormatParamName, name, fromDate, toDate, repaymentsRescheduledTo));
|
||||
public static final Set<String> HOLIDAY_CREATE_OR_UPDATE_REQUEST_DATA_PARAMETERS = new HashSet<String>(Arrays.asList(localeParamName,
|
||||
dateFormatParamName, nameParamName, fromDateParamName, toDateParamName, descriptionParamName, officesParamName, repaymentsRescheduledToParamName));
|
||||
|
||||
public static final Set<String> HOLIDAY_RESPONSE_DATA_PARAMETERS = new HashSet<String>(Arrays.asList(idParamName, nameParamName,
|
||||
fromDateParamName, descriptionParamName, toDateParamName, repaymentsRescheduledToParamName, localeParamName, dateFormatParamName));
|
||||
}
|
||||
|
||||
+80
-6
@@ -1,24 +1,32 @@
|
||||
package org.mifosplatform.organisation.holiday.api;
|
||||
|
||||
import static org.mifosplatform.organisation.holiday.api.HolidayApiConstants.HOLIDAY_RESOURCE_NAME;
|
||||
import static org.mifosplatform.organisation.holiday.api.HolidayApiConstants.HOLIDAY_RESPONSE_DATA_PARAMETERS;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.Date;
|
||||
|
||||
import javax.ws.rs.Consumes;
|
||||
import javax.ws.rs.DELETE;
|
||||
import javax.ws.rs.GET;
|
||||
import javax.ws.rs.POST;
|
||||
import javax.ws.rs.PUT;
|
||||
import javax.ws.rs.Path;
|
||||
import javax.ws.rs.PathParam;
|
||||
import javax.ws.rs.Produces;
|
||||
import javax.ws.rs.QueryParam;
|
||||
import javax.ws.rs.core.Context;
|
||||
import javax.ws.rs.core.MediaType;
|
||||
import javax.ws.rs.core.UriInfo;
|
||||
|
||||
import org.apache.commons.lang.StringUtils;
|
||||
import org.mifosplatform.accounting.journalentry.api.DateParam;
|
||||
import org.mifosplatform.commands.domain.CommandWrapper;
|
||||
import org.mifosplatform.commands.service.CommandWrapperBuilder;
|
||||
import org.mifosplatform.commands.service.PortfolioCommandSourceWritePlatformService;
|
||||
import org.mifosplatform.infrastructure.core.api.ApiRequestParameterHelper;
|
||||
import org.mifosplatform.infrastructure.core.data.CommandProcessingResult;
|
||||
import org.mifosplatform.infrastructure.core.exception.UnrecognizedQueryParamException;
|
||||
import org.mifosplatform.infrastructure.core.serialization.ApiRequestJsonSerializationSettings;
|
||||
import org.mifosplatform.infrastructure.core.serialization.DefaultToApiJsonSerializer;
|
||||
import org.mifosplatform.infrastructure.security.service.PlatformSecurityContext;
|
||||
@@ -33,8 +41,6 @@ import org.springframework.stereotype.Component;
|
||||
@Scope("singleton")
|
||||
public class HolidaysApiResource {
|
||||
|
||||
private final String resourceNameForPermissions = "HOLIDAY";
|
||||
|
||||
private final DefaultToApiJsonSerializer<HolidayData> toApiJsonSerializer;
|
||||
private final PortfolioCommandSourceWritePlatformService commandsSourceWritePlatformService;
|
||||
private final PlatformSecurityContext context;
|
||||
@@ -64,15 +70,84 @@ public class HolidaysApiResource {
|
||||
|
||||
return this.toApiJsonSerializer.serialize(result);
|
||||
}
|
||||
|
||||
@POST
|
||||
@Path("{holidayId}")
|
||||
@Consumes({ MediaType.APPLICATION_JSON })
|
||||
@Produces({ MediaType.APPLICATION_JSON })
|
||||
public String handleCommands(@PathParam("holidayId") final Long holidayId, @QueryParam("command") final String commandParam,
|
||||
final String apiRequestBodyAsJson) {
|
||||
|
||||
String jsonApiRequest = apiRequestBodyAsJson;
|
||||
if (StringUtils.isBlank(jsonApiRequest)) {
|
||||
jsonApiRequest = "{}";
|
||||
}
|
||||
|
||||
final CommandWrapperBuilder builder = new CommandWrapperBuilder().withJson(jsonApiRequest);
|
||||
|
||||
CommandProcessingResult result = null;
|
||||
if (is(commandParam, "activate")) {
|
||||
final CommandWrapper commandRequest = builder.activateHoliday(holidayId).build();
|
||||
result = this.commandsSourceWritePlatformService.logCommandSource(commandRequest);
|
||||
}
|
||||
|
||||
if (result == null) { throw new UnrecognizedQueryParamException("command", commandParam, new Object[] { "activate" }); }
|
||||
|
||||
return this.toApiJsonSerializer.serialize(result);
|
||||
}
|
||||
|
||||
@GET
|
||||
@Path("{holidayId}")
|
||||
@Consumes({ MediaType.APPLICATION_JSON })
|
||||
@Produces({ MediaType.APPLICATION_JSON })
|
||||
public String retrieveOne(@PathParam("holidayId") final Long holidayId, @Context final UriInfo uriInfo) {
|
||||
|
||||
this.context.authenticatedUser().validateHasReadPermission(HOLIDAY_RESOURCE_NAME);
|
||||
|
||||
final HolidayData holidayData = this.holidayReadPlatformService.retrieveHoliday(holidayId);
|
||||
|
||||
final ApiRequestJsonSerializationSettings settings = this.apiRequestParameterHelper.process(uriInfo.getQueryParameters());
|
||||
|
||||
|
||||
return this.toApiJsonSerializer.serialize(settings, holidayData, HOLIDAY_RESPONSE_DATA_PARAMETERS);
|
||||
}
|
||||
|
||||
@PUT
|
||||
@Path("{holidayId}")
|
||||
@Consumes({ MediaType.APPLICATION_JSON })
|
||||
@Produces({ MediaType.APPLICATION_JSON })
|
||||
public String update(@PathParam("holidayId") final Long holidayId, final String jsonRequestBody) {
|
||||
|
||||
final CommandWrapper commandRequest = new CommandWrapperBuilder().updateHoliday(holidayId)
|
||||
.withJson(jsonRequestBody).build();
|
||||
|
||||
final CommandProcessingResult result = this.commandsSourceWritePlatformService.logCommandSource(commandRequest);
|
||||
|
||||
return this.toApiJsonSerializer.serialize(result);
|
||||
}
|
||||
|
||||
@DELETE
|
||||
@Path("{holidayId}")
|
||||
@Consumes({ MediaType.APPLICATION_JSON })
|
||||
@Produces({ MediaType.APPLICATION_JSON })
|
||||
public String delete(@PathParam("holidayId") final Long holidayId) {
|
||||
final CommandWrapper commandRequest = new CommandWrapperBuilder().deleteHoliday(holidayId).build();
|
||||
final CommandProcessingResult result = this.commandsSourceWritePlatformService.logCommandSource(commandRequest);
|
||||
return this.toApiJsonSerializer.serialize(result);
|
||||
}
|
||||
|
||||
private boolean is(final String commandParam, final String commandValue) {
|
||||
return StringUtils.isNotBlank(commandParam) && commandParam.trim().equalsIgnoreCase(commandValue);
|
||||
}
|
||||
|
||||
@GET
|
||||
@Consumes({ MediaType.APPLICATION_JSON })
|
||||
@Produces({ MediaType.APPLICATION_JSON })
|
||||
public String retrieveAllLoanProducts(@Context final UriInfo uriInfo, @QueryParam("officeId") final Long officeId,
|
||||
public String retrieveAllHolidays(@Context final UriInfo uriInfo, @QueryParam("officeId") final Long officeId,
|
||||
@QueryParam("fromDate") final DateParam fromDateParam, @QueryParam("toDate") final DateParam toDateParam,
|
||||
@QueryParam("locale") final String locale, @QueryParam("dateFormat") final String dateFormat) {
|
||||
|
||||
this.context.authenticatedUser().validateHasReadPermission(this.resourceNameForPermissions);
|
||||
this.context.authenticatedUser().validateHasReadPermission(HOLIDAY_RESOURCE_NAME);
|
||||
|
||||
Date fromDate = null;
|
||||
if (fromDateParam != null) {
|
||||
@@ -87,7 +162,6 @@ public class HolidaysApiResource {
|
||||
toDate);
|
||||
|
||||
final ApiRequestJsonSerializationSettings settings = this.apiRequestParameterHelper.process(uriInfo.getQueryParameters());
|
||||
return this.toApiJsonSerializer.serialize(settings, holidays, HolidayApiConstants.HOLIDAY_REQUEST_DATA_PARAMETERS);
|
||||
return this.toApiJsonSerializer.serialize(settings, holidays, HOLIDAY_RESPONSE_DATA_PARAMETERS);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
+3
-3
@@ -13,17 +13,17 @@ public class HolidayData {
|
||||
@SuppressWarnings("unused")
|
||||
private final LocalDate toDate;
|
||||
@SuppressWarnings("unused")
|
||||
private final LocalDate repaymentsScheduleTO;
|
||||
private final LocalDate repaymentsRescheduledTo;
|
||||
@SuppressWarnings("unused")
|
||||
private final Long officeId;
|
||||
|
||||
public HolidayData(final Long id, final String name, final LocalDate fromDate, final LocalDate toDate,
|
||||
final LocalDate repaymentsScheduleTO) {
|
||||
final LocalDate repaymentsRescheduledTo) {
|
||||
this.id = id;
|
||||
this.name = name;
|
||||
this.fromDate = fromDate;
|
||||
this.toDate = toDate;
|
||||
this.repaymentsScheduleTO = repaymentsScheduleTO;
|
||||
this.repaymentsRescheduledTo = repaymentsRescheduledTo;
|
||||
this.officeId = null;
|
||||
|
||||
}
|
||||
|
||||
+70
-14
@@ -38,7 +38,7 @@ public class HolidayDataValidator {
|
||||
if (StringUtils.isBlank(json)) { throw new InvalidJsonException(); }
|
||||
|
||||
final Type typeOfMap = new TypeToken<Map<String, Object>>() {}.getType();
|
||||
this.fromApiJsonHelper.checkForUnsupportedParameters(typeOfMap, json, HolidayApiConstants.HOLIDAY_CREATE_REQUEST_DATA_PARAMETERS);
|
||||
this.fromApiJsonHelper.checkForUnsupportedParameters(typeOfMap, json, HolidayApiConstants.HOLIDAY_CREATE_OR_UPDATE_REQUEST_DATA_PARAMETERS);
|
||||
final JsonElement element = this.fromApiJsonHelper.parse(json);
|
||||
|
||||
final List<ApiParameterError> dataValidationErrors = new ArrayList<ApiParameterError>();
|
||||
@@ -46,38 +46,94 @@ public class HolidayDataValidator {
|
||||
final DataValidatorBuilder baseDataValidator = new DataValidatorBuilder(dataValidationErrors)
|
||||
.resource(HolidayApiConstants.HOLIDAY_RESOURCE_NAME);
|
||||
|
||||
final String name = this.fromApiJsonHelper.extractStringNamed(HolidayApiConstants.name, element);
|
||||
baseDataValidator.reset().parameter(HolidayApiConstants.name).value(name).notNull().notExceedingLengthOf(100);
|
||||
final String name = this.fromApiJsonHelper.extractStringNamed(HolidayApiConstants.nameParamName, element);
|
||||
baseDataValidator.reset().parameter(HolidayApiConstants.nameParamName).value(name).notNull().notExceedingLengthOf(100);
|
||||
|
||||
final LocalDate fromDate = this.fromApiJsonHelper.extractLocalDateNamed(HolidayApiConstants.fromDate, element);
|
||||
baseDataValidator.reset().parameter(HolidayApiConstants.fromDate).value(fromDate).notNull();
|
||||
final LocalDate fromDate = this.fromApiJsonHelper.extractLocalDateNamed(HolidayApiConstants.fromDateParamName, element);
|
||||
baseDataValidator.reset().parameter(HolidayApiConstants.fromDateParamName).value(fromDate).notNull();
|
||||
|
||||
final LocalDate toDate = this.fromApiJsonHelper.extractLocalDateNamed(HolidayApiConstants.toDate, element);
|
||||
baseDataValidator.reset().parameter(HolidayApiConstants.toDate).value(toDate).notNull();
|
||||
final LocalDate toDate = this.fromApiJsonHelper.extractLocalDateNamed(HolidayApiConstants.toDateParamName, element);
|
||||
baseDataValidator.reset().parameter(HolidayApiConstants.toDateParamName).value(toDate).notNull();
|
||||
|
||||
final LocalDate repaymentsRescheduledTo = this.fromApiJsonHelper.extractLocalDateNamed(HolidayApiConstants.repaymentsRescheduledTo,
|
||||
final LocalDate repaymentsRescheduledTo = this.fromApiJsonHelper.extractLocalDateNamed(HolidayApiConstants.repaymentsRescheduledToParamName,
|
||||
element);
|
||||
baseDataValidator.reset().parameter(HolidayApiConstants.repaymentsRescheduledTo).value(repaymentsRescheduledTo).notNull();
|
||||
baseDataValidator.reset().parameter(HolidayApiConstants.repaymentsRescheduledToParamName).value(repaymentsRescheduledTo).notNull();
|
||||
|
||||
Set<Long> offices = null;
|
||||
final JsonObject topLevelJsonElement = element.getAsJsonObject();
|
||||
|
||||
if (topLevelJsonElement.has(HolidayApiConstants.offices) && topLevelJsonElement.get(HolidayApiConstants.offices).isJsonArray()) {
|
||||
if (topLevelJsonElement.has(HolidayApiConstants.officesParamName) && topLevelJsonElement.get(HolidayApiConstants.officesParamName).isJsonArray()) {
|
||||
|
||||
final JsonArray array = topLevelJsonElement.get(HolidayApiConstants.offices).getAsJsonArray();
|
||||
final JsonArray array = topLevelJsonElement.get(HolidayApiConstants.officesParamName).getAsJsonArray();
|
||||
if (array.size() > 0) {
|
||||
offices = new HashSet<Long>(array.size());
|
||||
for (int i = 0; i < array.size(); i++) {
|
||||
final JsonObject officeElement = array.get(i).getAsJsonObject();
|
||||
final Long officeId = this.fromApiJsonHelper.extractLongNamed(HolidayApiConstants.officeId, officeElement);
|
||||
baseDataValidator.reset().parameter(HolidayApiConstants.offices).value(officeId).notNull();
|
||||
final Long officeId = this.fromApiJsonHelper.extractLongNamed(HolidayApiConstants.officeIdParamName, officeElement);
|
||||
baseDataValidator.reset().parameter(HolidayApiConstants.officesParamName).value(officeId).notNull();
|
||||
offices.add(officeId);
|
||||
}
|
||||
}
|
||||
}
|
||||
baseDataValidator.reset().parameter(HolidayApiConstants.offices).value(offices).notNull();
|
||||
baseDataValidator.reset().parameter(HolidayApiConstants.officesParamName).value(offices).notNull();
|
||||
throwExceptionIfValidationWarningsExist(dataValidationErrors);
|
||||
}
|
||||
|
||||
public void validateForUpdate(final String json) {
|
||||
|
||||
if (StringUtils.isBlank(json)) { throw new InvalidJsonException(); }
|
||||
|
||||
final Type typeOfMap = new TypeToken<Map<String, Object>>() {}.getType();
|
||||
this.fromApiJsonHelper.checkForUnsupportedParameters(typeOfMap, json,
|
||||
HolidayApiConstants.HOLIDAY_CREATE_OR_UPDATE_REQUEST_DATA_PARAMETERS);
|
||||
final JsonElement element = this.fromApiJsonHelper.parse(json);
|
||||
|
||||
final List<ApiParameterError> dataValidationErrors = new ArrayList<ApiParameterError>();
|
||||
|
||||
final DataValidatorBuilder baseDataValidator = new DataValidatorBuilder(dataValidationErrors)
|
||||
.resource(HolidayApiConstants.HOLIDAY_RESOURCE_NAME);
|
||||
|
||||
if (this.fromApiJsonHelper.parameterExists(HolidayApiConstants.nameParamName, element)) {
|
||||
final String name = this.fromApiJsonHelper.extractStringNamed(HolidayApiConstants.nameParamName, element);
|
||||
baseDataValidator.reset().parameter(HolidayApiConstants.nameParamName).value(name).notNull().notExceedingLengthOf(100);
|
||||
}
|
||||
|
||||
if (this.fromApiJsonHelper.parameterExists(HolidayApiConstants.fromDateParamName, element)) {
|
||||
final LocalDate fromDate = this.fromApiJsonHelper.extractLocalDateNamed(HolidayApiConstants.fromDateParamName, element);
|
||||
baseDataValidator.reset().parameter(HolidayApiConstants.fromDateParamName).value(fromDate).notNull();
|
||||
}
|
||||
|
||||
if (this.fromApiJsonHelper.parameterExists(HolidayApiConstants.toDateParamName, element)) {
|
||||
final LocalDate toDate = this.fromApiJsonHelper.extractLocalDateNamed(HolidayApiConstants.toDateParamName, element);
|
||||
baseDataValidator.reset().parameter(HolidayApiConstants.toDateParamName).value(toDate).notNull();
|
||||
}
|
||||
|
||||
if (this.fromApiJsonHelper.parameterExists(HolidayApiConstants.repaymentsRescheduledToParamName, element)) {
|
||||
final LocalDate repaymentsRescheduledTo = this.fromApiJsonHelper.extractLocalDateNamed(
|
||||
HolidayApiConstants.repaymentsRescheduledToParamName, element);
|
||||
baseDataValidator.reset().parameter(HolidayApiConstants.repaymentsRescheduledToParamName).value(repaymentsRescheduledTo).notNull();
|
||||
}
|
||||
|
||||
Set<Long> offices = null;
|
||||
final JsonObject topLevelJsonElement = element.getAsJsonObject();
|
||||
if (this.fromApiJsonHelper.parameterExists(HolidayApiConstants.officesParamName, element)) {
|
||||
if (topLevelJsonElement.has(HolidayApiConstants.officesParamName) && topLevelJsonElement.get(HolidayApiConstants.officesParamName).isJsonArray()) {
|
||||
|
||||
final JsonArray array = topLevelJsonElement.get(HolidayApiConstants.officesParamName).getAsJsonArray();
|
||||
if (array.size() > 0) {
|
||||
offices = new HashSet<Long>(array.size());
|
||||
for (int i = 0; i < array.size(); i++) {
|
||||
final JsonObject officeElement = array.get(i).getAsJsonObject();
|
||||
final Long officeId = this.fromApiJsonHelper.extractLongNamed(HolidayApiConstants.officeIdParamName, officeElement);
|
||||
baseDataValidator.reset().parameter(HolidayApiConstants.officesParamName).value(officeId).notNull();
|
||||
offices.add(officeId);
|
||||
}
|
||||
}
|
||||
}
|
||||
baseDataValidator.reset().parameter(HolidayApiConstants.officesParamName).value(offices).notNull();
|
||||
throwExceptionIfValidationWarningsExist(dataValidationErrors);
|
||||
}
|
||||
}
|
||||
|
||||
private void throwExceptionIfValidationWarningsExist(final List<ApiParameterError> dataValidationErrors) {
|
||||
if (!dataValidationErrors.isEmpty()) {
|
||||
|
||||
+159
-7
@@ -5,7 +5,21 @@
|
||||
*/
|
||||
package org.mifosplatform.organisation.holiday.domain;
|
||||
|
||||
import static org.mifosplatform.organisation.holiday.api.HolidayApiConstants.descriptionParamName;
|
||||
import static org.mifosplatform.organisation.holiday.api.HolidayApiConstants.fromDateParamName;
|
||||
import static org.mifosplatform.organisation.holiday.api.HolidayApiConstants.nameParamName;
|
||||
import static org.mifosplatform.organisation.holiday.api.HolidayApiConstants.officesParamName;
|
||||
import static org.mifosplatform.organisation.holiday.api.HolidayApiConstants.repaymentsRescheduledToParamName;
|
||||
import static org.mifosplatform.organisation.holiday.api.HolidayApiConstants.toDateParamName;
|
||||
import static org.mifosplatform.portfolio.savings.SavingsApiConstants.dateFormatParamName;
|
||||
import static org.mifosplatform.portfolio.savings.SavingsApiConstants.localeParamName;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Date;
|
||||
import java.util.HashSet;
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
|
||||
import javax.persistence.Column;
|
||||
@@ -22,10 +36,15 @@ import javax.persistence.UniqueConstraint;
|
||||
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.PlatformApiDataValidationException;
|
||||
import org.mifosplatform.organisation.holiday.api.HolidayApiConstants;
|
||||
import org.mifosplatform.organisation.office.domain.Office;
|
||||
import org.springframework.data.jpa.domain.AbstractPersistable;
|
||||
|
||||
import com.google.gson.JsonArray;
|
||||
|
||||
@Entity
|
||||
@Table(name = "m_holiday", uniqueConstraints = { @UniqueConstraint(columnNames = { "name" }, name = "holiday_name") })
|
||||
public class Holiday extends AbstractPersistable<Long> {
|
||||
@@ -45,6 +64,9 @@ public class Holiday extends AbstractPersistable<Long> {
|
||||
@Temporal(TemporalType.DATE)
|
||||
private Date repaymentsRescheduledTo;
|
||||
|
||||
@Column(name = "status_enum", nullable = false)
|
||||
private Integer status;
|
||||
|
||||
@Column(name = "processed", nullable = false)
|
||||
private boolean processed;
|
||||
|
||||
@@ -56,18 +78,121 @@ public class Holiday extends AbstractPersistable<Long> {
|
||||
private Set<Office> offices;
|
||||
|
||||
public static Holiday createNew(final Set<Office> offices, final JsonCommand command) {
|
||||
final String name = command.stringValueOfParameterNamed(HolidayApiConstants.name);
|
||||
final LocalDate fromDate = command.localDateValueOfParameterNamed(HolidayApiConstants.fromDate);
|
||||
final LocalDate toDate = command.localDateValueOfParameterNamed(HolidayApiConstants.toDate);
|
||||
final LocalDate repaymentsRescheduledTo = command.localDateValueOfParameterNamed(HolidayApiConstants.repaymentsRescheduledTo);
|
||||
final String name = command.stringValueOfParameterNamed(HolidayApiConstants.nameParamName);
|
||||
final LocalDate fromDate = command.localDateValueOfParameterNamed(HolidayApiConstants.fromDateParamName);
|
||||
final LocalDate toDate = command.localDateValueOfParameterNamed(HolidayApiConstants.toDateParamName);
|
||||
final LocalDate repaymentsRescheduledTo = command.localDateValueOfParameterNamed(HolidayApiConstants.repaymentsRescheduledToParamName);
|
||||
final Integer status = HolidayStatusType.PENDING_FOR_ACTIVATION.getValue();
|
||||
final boolean processed = false;// default it to false. Only batch job
|
||||
// should update this field.
|
||||
final String description = command.stringValueOfParameterNamed(HolidayApiConstants.description);
|
||||
return new Holiday(name, fromDate, toDate, repaymentsRescheduledTo, processed, description, offices);
|
||||
final String description = command.stringValueOfParameterNamed(HolidayApiConstants.descriptionParamName);
|
||||
return new Holiday(name, fromDate, toDate, repaymentsRescheduledTo, status, processed, description, offices);
|
||||
}
|
||||
|
||||
public Map<String, Object> update(final JsonCommand command) {
|
||||
final Map<String, Object> actualChanges = new LinkedHashMap<String, Object>(7);
|
||||
|
||||
final List<ApiParameterError> dataValidationErrors = new ArrayList<ApiParameterError>();
|
||||
final DataValidatorBuilder baseDataValidator = new DataValidatorBuilder(dataValidationErrors)
|
||||
.resource("holiday" + ".update");
|
||||
|
||||
final HolidayStatusType currentStatus = HolidayStatusType.fromInt(this.status);
|
||||
|
||||
final String dateFormatAsInput = command.dateFormat();
|
||||
final String localeAsInput = command.locale();
|
||||
|
||||
if (command.isChangeInStringParameterNamed(nameParamName, this.name)) {
|
||||
final String newValue = command.stringValueOfParameterNamed(nameParamName);
|
||||
actualChanges.put(nameParamName, newValue);
|
||||
this.name = StringUtils.defaultIfEmpty(newValue, null);
|
||||
}
|
||||
|
||||
if (command.isChangeInStringParameterNamed(descriptionParamName, this.description)) {
|
||||
final String newValue = command.stringValueOfParameterNamed(descriptionParamName);
|
||||
actualChanges.put(descriptionParamName, newValue);
|
||||
this.description = StringUtils.defaultIfEmpty(newValue, null);
|
||||
}
|
||||
|
||||
if (currentStatus.isPendingActivation()) {
|
||||
if (command.isChangeInLocalDateParameterNamed(fromDateParamName, getFromDateLocalDate())) {
|
||||
final String valueAsInput = command.stringValueOfParameterNamed(fromDateParamName);
|
||||
actualChanges.put(fromDateParamName, valueAsInput);
|
||||
actualChanges.put(dateFormatParamName, dateFormatAsInput);
|
||||
actualChanges.put(localeParamName, localeAsInput);
|
||||
final LocalDate newValue = command.localDateValueOfParameterNamed(fromDateParamName);
|
||||
this.fromDate = newValue.toDate();
|
||||
}
|
||||
|
||||
if (command.isChangeInLocalDateParameterNamed(toDateParamName, getToDateLocalDate())) {
|
||||
final String valueAsInput = command.stringValueOfParameterNamed(toDateParamName);
|
||||
actualChanges.put(toDateParamName, valueAsInput);
|
||||
actualChanges.put(dateFormatParamName, dateFormatAsInput);
|
||||
actualChanges.put(localeParamName, localeAsInput);
|
||||
|
||||
final LocalDate newValue = command.localDateValueOfParameterNamed(toDateParamName);
|
||||
this.toDate = newValue.toDate();
|
||||
}
|
||||
|
||||
if (command.isChangeInLocalDateParameterNamed(repaymentsRescheduledToParamName, getRepaymentsRescheduledToLocalDate())) {
|
||||
final String valueAsInput = command.stringValueOfParameterNamed(repaymentsRescheduledToParamName);
|
||||
actualChanges.put(repaymentsRescheduledToParamName, valueAsInput);
|
||||
actualChanges.put(dateFormatParamName, dateFormatAsInput);
|
||||
actualChanges.put(localeParamName, localeAsInput);
|
||||
|
||||
final LocalDate newValue = command.localDateValueOfParameterNamed(repaymentsRescheduledToParamName);
|
||||
this.repaymentsRescheduledTo = newValue.toDate();
|
||||
}
|
||||
|
||||
if (command.hasParameter(officesParamName)) {
|
||||
final JsonArray jsonArray = command.arrayOfParameterNamed(officesParamName);
|
||||
if (jsonArray != null) {
|
||||
actualChanges.put(officesParamName, command.jsonFragment(officesParamName));
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if (command.isChangeInLocalDateParameterNamed(fromDateParamName, getFromDateLocalDate())) {
|
||||
baseDataValidator.reset().parameter(fromDateParamName).failWithCode("cannot.edit.holiday.in.active.state");
|
||||
}
|
||||
|
||||
if (command.isChangeInLocalDateParameterNamed(toDateParamName, getToDateLocalDate())) {
|
||||
baseDataValidator.reset().parameter(toDateParamName).failWithCode("cannot.edit.holiday.in.active.state");
|
||||
}
|
||||
|
||||
if (command.isChangeInLocalDateParameterNamed(repaymentsRescheduledToParamName, getRepaymentsRescheduledToLocalDate())) {
|
||||
baseDataValidator.reset().parameter(repaymentsRescheduledToParamName).failWithCode("cannot.edit.holiday.in.active.state");
|
||||
}
|
||||
|
||||
if (command.hasParameter(officesParamName)) {
|
||||
baseDataValidator.reset().parameter(repaymentsRescheduledToParamName).failWithCode("cannot.edit.holiday.in.active.state");
|
||||
}
|
||||
|
||||
if (!dataValidationErrors.isEmpty()) { throw new PlatformApiDataValidationException(dataValidationErrors); }
|
||||
}
|
||||
|
||||
return actualChanges;
|
||||
}
|
||||
|
||||
public boolean update(final Set<Office> newOffices) {
|
||||
if (newOffices == null) { return false; }
|
||||
|
||||
boolean updated = false;
|
||||
if (this.offices != null) {
|
||||
final Set<Office> currentSetOfOffices = new HashSet<Office>(this.offices);
|
||||
final Set<Office> newSetOfOffices = new HashSet<Office>(newOffices);
|
||||
|
||||
if (!(currentSetOfOffices.equals(newSetOfOffices))) {
|
||||
updated = true;
|
||||
this.offices = newOffices;
|
||||
}
|
||||
} else {
|
||||
updated = true;
|
||||
this.offices = newOffices;
|
||||
}
|
||||
return updated;
|
||||
}
|
||||
|
||||
private Holiday(final String name, final LocalDate fromDate, final LocalDate toDate, final LocalDate repaymentsRescheduledTo,
|
||||
final boolean processed, final String description, final Set<Office> offices) {
|
||||
final Integer status, final boolean processed, final String description, final Set<Office> offices) {
|
||||
if (StringUtils.isNotBlank(name)) {
|
||||
this.name = name.trim();
|
||||
}
|
||||
@@ -84,6 +209,7 @@ public class Holiday extends AbstractPersistable<Long> {
|
||||
this.repaymentsRescheduledTo = repaymentsRescheduledTo.toDate();
|
||||
}
|
||||
|
||||
this.status = status;
|
||||
this.processed = processed;
|
||||
|
||||
if (StringUtils.isNotBlank(name)) {
|
||||
@@ -134,4 +260,30 @@ public class Holiday extends AbstractPersistable<Long> {
|
||||
public void processed() {
|
||||
this.processed = true;
|
||||
}
|
||||
|
||||
public void activate() {
|
||||
final List<ApiParameterError> dataValidationErrors = new ArrayList<ApiParameterError>();
|
||||
final DataValidatorBuilder baseDataValidator = new DataValidatorBuilder(dataValidationErrors)
|
||||
.resource("holiday" + ".activate");
|
||||
|
||||
final HolidayStatusType currentStatus = HolidayStatusType.fromInt(this.status);
|
||||
if (!currentStatus.isPendingActivation()) {
|
||||
baseDataValidator.reset().failWithCodeNoParameterAddedToErrorCode("not.in.pending.for.activation.state");
|
||||
if (!dataValidationErrors.isEmpty()) { throw new PlatformApiDataValidationException(dataValidationErrors); }
|
||||
}
|
||||
|
||||
this.status = HolidayStatusType.ACTIVE.getValue();
|
||||
}
|
||||
|
||||
public void delete() {
|
||||
final List<ApiParameterError> dataValidationErrors = new ArrayList<ApiParameterError>();
|
||||
final DataValidatorBuilder baseDataValidator = new DataValidatorBuilder(dataValidationErrors).resource("holiday" + ".delete");
|
||||
|
||||
final HolidayStatusType currentStatus = HolidayStatusType.fromInt(this.status);
|
||||
if (currentStatus.isDeleted()) {
|
||||
baseDataValidator.reset().failWithCodeNoParameterAddedToErrorCode("already.in.deleted.state");
|
||||
if (!dataValidationErrors.isEmpty()) { throw new PlatformApiDataValidationException(dataValidationErrors); }
|
||||
}
|
||||
this.status = HolidayStatusType.DELETED.getValue();
|
||||
}
|
||||
}
|
||||
|
||||
+4
-4
@@ -15,9 +15,9 @@ import org.springframework.data.repository.query.Param;
|
||||
|
||||
public interface HolidayRepository extends JpaRepository<Holiday, Long>, JpaSpecificationExecutor<Holiday> {
|
||||
|
||||
@Query("select holiday from Holiday holiday, IN(holiday.offices) office where (holiday.fromDate >= :date OR :date <= holiday.toDate) and office.id = :officeId")
|
||||
List<Holiday> findByOfficeIdAndGreaterThanDate(@Param("officeId") Long officeId, @Param("date") Date date);
|
||||
@Query("select holiday from Holiday holiday, IN(holiday.offices) office where (holiday.fromDate >= :date OR :date <= holiday.toDate) and holiday.status = :status and office.id = :officeId")
|
||||
List<Holiday> findByOfficeIdAndGreaterThanDate(@Param("officeId") Long officeId, @Param("date") Date date, @Param("status") Integer status);
|
||||
|
||||
@Query("from Holiday holiday where holiday.processed = false")
|
||||
List<Holiday> findUnprocessed();
|
||||
@Query("from Holiday holiday where holiday.processed = false and holiday.status = :status")
|
||||
List<Holiday> findUnprocessed(@Param("status") Integer status);
|
||||
}
|
||||
|
||||
+60
@@ -0,0 +1,60 @@
|
||||
/**
|
||||
* 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.organisation.holiday.domain;
|
||||
|
||||
import java.util.Date;
|
||||
import java.util.List;
|
||||
|
||||
import org.mifosplatform.organisation.holiday.exception.HolidayNotFoundException;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
/**
|
||||
* <p>
|
||||
* Wrapper for {@link HolidayRepository} that adds NULL checking and Error
|
||||
* handling capabilities
|
||||
* </p>
|
||||
*/
|
||||
@Service
|
||||
public class HolidayRepositoryWrapper {
|
||||
|
||||
private final HolidayRepository repository;
|
||||
|
||||
@Autowired
|
||||
public HolidayRepositoryWrapper(final HolidayRepository repository) {
|
||||
this.repository = repository;
|
||||
}
|
||||
|
||||
public Holiday findOneWithNotFoundDetection(final Long id) {
|
||||
final Holiday holiday = this.repository.findOne(id);
|
||||
if (holiday == null) { throw new HolidayNotFoundException(id); }
|
||||
return holiday;
|
||||
}
|
||||
|
||||
public void save(final Holiday holiday) {
|
||||
this.repository.save(holiday);
|
||||
}
|
||||
|
||||
public void save(final Iterable<Holiday> holidays){
|
||||
this.repository.save(holidays);
|
||||
}
|
||||
|
||||
public void saveAndFlush(final Holiday holiday) {
|
||||
this.repository.saveAndFlush(holiday);
|
||||
}
|
||||
|
||||
public void delete(final Holiday holiday) {
|
||||
this.repository.delete(holiday);
|
||||
}
|
||||
|
||||
public List<Holiday> findByOfficeIdAndGreaterThanDate(final Long officeId, final Date date) {
|
||||
return this.repository.findByOfficeIdAndGreaterThanDate(officeId, date, HolidayStatusType.ACTIVE.getValue());
|
||||
}
|
||||
|
||||
public List<Holiday> findUnprocessed() {
|
||||
return this.repository.findUnprocessed(HolidayStatusType.ACTIVE.getValue());
|
||||
}
|
||||
}
|
||||
+66
@@ -0,0 +1,66 @@
|
||||
/**
|
||||
* 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.organisation.holiday.domain;
|
||||
|
||||
|
||||
/**
|
||||
* Enum representation of {@link Holiday} status states.
|
||||
*/
|
||||
public enum HolidayStatusType {
|
||||
|
||||
INVALID(0, "holidayStatusType.invalid"), //
|
||||
PENDING_FOR_ACTIVATION(100, "holidayStatusType.pending.for.activation"), //
|
||||
ACTIVE(300, "holidayStatusType.active"), //
|
||||
DELETED(600, "savingsAccountStatusType.transfer.in.progress");
|
||||
|
||||
private final Integer value;
|
||||
private final String code;
|
||||
|
||||
public static HolidayStatusType fromInt(final Integer type) {
|
||||
HolidayStatusType enumeration = HolidayStatusType.INVALID;
|
||||
switch (type) {
|
||||
case 100:
|
||||
enumeration = HolidayStatusType.PENDING_FOR_ACTIVATION;
|
||||
break;
|
||||
case 300:
|
||||
enumeration = HolidayStatusType.ACTIVE;
|
||||
break;
|
||||
case 600:
|
||||
enumeration = HolidayStatusType.DELETED;
|
||||
break;
|
||||
}
|
||||
return enumeration;
|
||||
}
|
||||
|
||||
private HolidayStatusType(final Integer value, final String code) {
|
||||
this.value = value;
|
||||
this.code = code;
|
||||
}
|
||||
|
||||
public boolean hasStateOf(final HolidayStatusType state) {
|
||||
return this.value.equals(state.getValue());
|
||||
}
|
||||
|
||||
public Integer getValue() {
|
||||
return this.value;
|
||||
}
|
||||
|
||||
public String getCode() {
|
||||
return this.code;
|
||||
}
|
||||
|
||||
public boolean isPendingActivation() {
|
||||
return this.value.equals(HolidayStatusType.PENDING_FOR_ACTIVATION.getValue());
|
||||
}
|
||||
|
||||
public boolean isActive() {
|
||||
return this.value.equals(HolidayStatusType.ACTIVE.getValue());
|
||||
}
|
||||
|
||||
public boolean isDeleted() {
|
||||
return this.value.equals(HolidayStatusType.DELETED.getValue());
|
||||
}
|
||||
}
|
||||
+18
@@ -0,0 +1,18 @@
|
||||
/**
|
||||
* 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.organisation.holiday.exception;
|
||||
|
||||
import org.mifosplatform.infrastructure.core.exception.AbstractPlatformResourceNotFoundException;
|
||||
|
||||
/**
|
||||
* A {@link RuntimeException} thrown when holiday resources are not found.
|
||||
*/
|
||||
public class HolidayNotFoundException extends AbstractPlatformResourceNotFoundException {
|
||||
|
||||
public HolidayNotFoundException(final Long id) {
|
||||
super("error.msg.holiday.id.invalid", "Holiday with identifier " + id + " does not exist", id);
|
||||
}
|
||||
}
|
||||
+26
@@ -0,0 +1,26 @@
|
||||
package org.mifosplatform.organisation.holiday.handler;
|
||||
|
||||
import org.mifosplatform.commands.handler.NewCommandSourceHandler;
|
||||
import org.mifosplatform.infrastructure.core.api.JsonCommand;
|
||||
import org.mifosplatform.infrastructure.core.data.CommandProcessingResult;
|
||||
import org.mifosplatform.organisation.holiday.service.HolidayWritePlatformService;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.stereotype.Service;
|
||||
import org.springframework.transaction.annotation.Transactional;
|
||||
|
||||
@Service
|
||||
public class ActivateHolidayCommandHandler implements NewCommandSourceHandler {
|
||||
|
||||
private final HolidayWritePlatformService holidayWritePlatformService;
|
||||
|
||||
@Autowired
|
||||
public ActivateHolidayCommandHandler(final HolidayWritePlatformService holidayWritePlatformService) {
|
||||
this.holidayWritePlatformService = holidayWritePlatformService;
|
||||
}
|
||||
|
||||
@Transactional
|
||||
@Override
|
||||
public CommandProcessingResult processCommand(final JsonCommand command) {
|
||||
return this.holidayWritePlatformService.activateHoliday(command.entityId());
|
||||
}
|
||||
}
|
||||
+26
@@ -0,0 +1,26 @@
|
||||
package org.mifosplatform.organisation.holiday.handler;
|
||||
|
||||
import org.mifosplatform.commands.handler.NewCommandSourceHandler;
|
||||
import org.mifosplatform.infrastructure.core.api.JsonCommand;
|
||||
import org.mifosplatform.infrastructure.core.data.CommandProcessingResult;
|
||||
import org.mifosplatform.organisation.holiday.service.HolidayWritePlatformService;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.stereotype.Service;
|
||||
import org.springframework.transaction.annotation.Transactional;
|
||||
|
||||
@Service
|
||||
public class DeleteHolidayCommandHandler implements NewCommandSourceHandler {
|
||||
|
||||
private final HolidayWritePlatformService holidayWritePlatformService;
|
||||
|
||||
@Autowired
|
||||
public DeleteHolidayCommandHandler(final HolidayWritePlatformService holidayWritePlatformService) {
|
||||
this.holidayWritePlatformService = holidayWritePlatformService;
|
||||
}
|
||||
|
||||
@Transactional
|
||||
@Override
|
||||
public CommandProcessingResult processCommand(final JsonCommand command) {
|
||||
return this.holidayWritePlatformService.deleteHoliday(command.entityId());
|
||||
}
|
||||
}
|
||||
+26
@@ -0,0 +1,26 @@
|
||||
package org.mifosplatform.organisation.holiday.handler;
|
||||
|
||||
import org.mifosplatform.commands.handler.NewCommandSourceHandler;
|
||||
import org.mifosplatform.infrastructure.core.api.JsonCommand;
|
||||
import org.mifosplatform.infrastructure.core.data.CommandProcessingResult;
|
||||
import org.mifosplatform.organisation.holiday.service.HolidayWritePlatformService;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.stereotype.Service;
|
||||
import org.springframework.transaction.annotation.Transactional;
|
||||
|
||||
@Service
|
||||
public class UpdateHolidayCommandHandler implements NewCommandSourceHandler {
|
||||
|
||||
private final HolidayWritePlatformService holidayWritePlatformService;
|
||||
|
||||
@Autowired
|
||||
public UpdateHolidayCommandHandler(final HolidayWritePlatformService holidayWritePlatformService) {
|
||||
this.holidayWritePlatformService = holidayWritePlatformService;
|
||||
}
|
||||
|
||||
@Transactional
|
||||
@Override
|
||||
public CommandProcessingResult processCommand(final JsonCommand command) {
|
||||
return this.holidayWritePlatformService.updateHoliday(command);
|
||||
}
|
||||
}
|
||||
+37
@@ -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.organisation.holiday.service;
|
||||
|
||||
import org.mifosplatform.infrastructure.core.data.EnumOptionData;
|
||||
import org.mifosplatform.organisation.holiday.domain.HolidayStatusType;
|
||||
|
||||
public class HolidayEnumerations {
|
||||
|
||||
public static EnumOptionData holidayStatusType(final int id) {
|
||||
return holidayStatusType(HolidayStatusType.fromInt(id));
|
||||
}
|
||||
|
||||
public static EnumOptionData holidayStatusType(final HolidayStatusType type) {
|
||||
EnumOptionData optionData = null;
|
||||
switch (type) {
|
||||
case INVALID:
|
||||
optionData = new EnumOptionData(HolidayStatusType.INVALID.getValue().longValue(), HolidayStatusType.INVALID.getCode(),
|
||||
"Invalid");
|
||||
break;
|
||||
case PENDING_FOR_ACTIVATION:
|
||||
optionData = new EnumOptionData(HolidayStatusType.PENDING_FOR_ACTIVATION.getValue().longValue(),
|
||||
HolidayStatusType.PENDING_FOR_ACTIVATION.getCode(), "Pending for activation");
|
||||
break;
|
||||
case ACTIVE:
|
||||
optionData = new EnumOptionData(HolidayStatusType.ACTIVE.getValue().longValue(), HolidayStatusType.ACTIVE.getCode(), "Active");
|
||||
break;
|
||||
case DELETED:
|
||||
optionData = new EnumOptionData(HolidayStatusType.DELETED.getValue().longValue(), HolidayStatusType.DELETED.getCode(), "Deleted");
|
||||
break;
|
||||
}
|
||||
return optionData;
|
||||
}
|
||||
}
|
||||
+2
@@ -8,4 +8,6 @@ import org.mifosplatform.organisation.holiday.data.HolidayData;
|
||||
public interface HolidayReadPlatformService {
|
||||
|
||||
Collection<HolidayData> retrieveAllHolidaysBySearchParamerters(final Long officeId, Date fromDate, Date toDate);
|
||||
|
||||
HolidayData retrieveHoliday(final Long holidayId);
|
||||
}
|
||||
|
||||
+17
-2
@@ -13,7 +13,9 @@ 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.holiday.data.HolidayData;
|
||||
import org.mifosplatform.organisation.holiday.exception.HolidayNotFoundException;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.dao.EmptyResultDataAccessException;
|
||||
import org.springframework.jdbc.core.JdbcTemplate;
|
||||
import org.springframework.jdbc.core.RowMapper;
|
||||
import org.springframework.stereotype.Service;
|
||||
@@ -38,7 +40,7 @@ public class HolidayReadPlatformServiceImpl implements HolidayReadPlatformServic
|
||||
final StringBuilder sqlBuilder = new StringBuilder(200);
|
||||
sqlBuilder.append("h.id as id, h.name as name, h.from_date as fromDate, h.to_date as toDate, ");
|
||||
sqlBuilder.append("h.repayments_rescheduled_to as repaymentsScheduleTO ");
|
||||
sqlBuilder.append("from m_holiday h join m_holiday_office hf on h.id = hf.holiday_id and ");
|
||||
sqlBuilder.append("from m_holiday h ");
|
||||
this.schema = sqlBuilder.toString();
|
||||
}
|
||||
|
||||
@@ -69,7 +71,7 @@ public class HolidayReadPlatformServiceImpl implements HolidayReadPlatformServic
|
||||
int arrayPos = 0;
|
||||
|
||||
final HolidayMapper rm = new HolidayMapper();
|
||||
String sql = "select " + rm.schema() + " hf.office_id = ? ";
|
||||
String sql = "select " + rm.schema() + " join m_holiday_office hf on h.id = hf.holiday_id and hf.office_id = ? ";
|
||||
|
||||
objectArray[arrayPos] = officeId;
|
||||
arrayPos = arrayPos + 1;
|
||||
@@ -97,4 +99,17 @@ public class HolidayReadPlatformServiceImpl implements HolidayReadPlatformServic
|
||||
return this.jdbcTemplate.query(sql, rm, finalObjectArray);
|
||||
}
|
||||
|
||||
@Override
|
||||
public HolidayData retrieveHoliday(Long holidayId) {
|
||||
try {
|
||||
final HolidayMapper rm = new HolidayMapper();
|
||||
|
||||
final String sql = rm.schema() + " where h.id = ?";
|
||||
|
||||
return this.jdbcTemplate.queryForObject(sql, rm, new Object[] { holidayId });
|
||||
} catch (final EmptyResultDataAccessException e) {
|
||||
throw new HolidayNotFoundException(holidayId);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
+6
@@ -8,6 +8,12 @@ public interface HolidayWritePlatformService {
|
||||
|
||||
CommandProcessingResult createHoliday(JsonCommand command);
|
||||
|
||||
CommandProcessingResult updateHoliday(JsonCommand command);
|
||||
|
||||
CommandProcessingResult activateHoliday(final Long holidayId);
|
||||
|
||||
CommandProcessingResult deleteHoliday(final Long holidayId);
|
||||
|
||||
boolean isHoliday(Long officeId, LocalDate transactionDate);
|
||||
|
||||
boolean isTransactionAllowedOnHoliday();
|
||||
|
||||
+69
-9
@@ -1,7 +1,10 @@
|
||||
package org.mifosplatform.organisation.holiday.service;
|
||||
|
||||
import static org.mifosplatform.organisation.holiday.api.HolidayApiConstants.officesParamName;
|
||||
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
|
||||
import org.joda.time.LocalDate;
|
||||
@@ -15,7 +18,7 @@ import org.mifosplatform.infrastructure.security.service.PlatformSecurityContext
|
||||
import org.mifosplatform.organisation.holiday.api.HolidayApiConstants;
|
||||
import org.mifosplatform.organisation.holiday.data.HolidayDataValidator;
|
||||
import org.mifosplatform.organisation.holiday.domain.Holiday;
|
||||
import org.mifosplatform.organisation.holiday.domain.HolidayRepository;
|
||||
import org.mifosplatform.organisation.holiday.domain.HolidayRepositoryWrapper;
|
||||
import org.mifosplatform.organisation.holiday.exception.HolidayDateException;
|
||||
import org.mifosplatform.organisation.office.domain.Office;
|
||||
import org.mifosplatform.organisation.office.domain.OfficeRepository;
|
||||
@@ -39,7 +42,7 @@ public class HolidayWritePlatformServiceJpaRepositoryImpl implements HolidayWrit
|
||||
private final static Logger logger = LoggerFactory.getLogger(HolidayWritePlatformServiceJpaRepositoryImpl.class);
|
||||
|
||||
private final HolidayDataValidator fromApiJsonDeserializer;
|
||||
private final HolidayRepository holidayRepository;
|
||||
private final HolidayRepositoryWrapper holidayRepository;
|
||||
private final WorkingDaysRepositoryWrapper daysRepositoryWrapper;
|
||||
private final ConfigurationDomainService configurationDomainService;
|
||||
private final PlatformSecurityContext context;
|
||||
@@ -48,7 +51,7 @@ public class HolidayWritePlatformServiceJpaRepositoryImpl implements HolidayWrit
|
||||
|
||||
@Autowired
|
||||
public HolidayWritePlatformServiceJpaRepositoryImpl(final HolidayDataValidator fromApiJsonDeserializer,
|
||||
final HolidayRepository holidayRepository, final PlatformSecurityContext context, final OfficeRepository officeRepository,
|
||||
final HolidayRepositoryWrapper holidayRepository, final PlatformSecurityContext context, final OfficeRepository officeRepository,
|
||||
final FromJsonHelper fromApiJsonHelper, final WorkingDaysRepositoryWrapper daysRepositoryWrapper, final ConfigurationDomainService configurationDomainService) {
|
||||
this.fromApiJsonDeserializer = fromApiJsonDeserializer;
|
||||
this.holidayRepository = holidayRepository;
|
||||
@@ -81,17 +84,70 @@ public class HolidayWritePlatformServiceJpaRepositoryImpl implements HolidayWrit
|
||||
return CommandProcessingResult.empty();
|
||||
}
|
||||
}
|
||||
|
||||
@Transactional
|
||||
@Override
|
||||
public CommandProcessingResult updateHoliday(final JsonCommand command) {
|
||||
|
||||
try {
|
||||
this.context.authenticatedUser();
|
||||
this.fromApiJsonDeserializer.validateForUpdate(command.json());
|
||||
|
||||
final Holiday holiday = this.holidayRepository.findOneWithNotFoundDetection(command.entityId());
|
||||
Map<String, Object> changes = holiday.update(command);
|
||||
|
||||
validateInputDates(holiday.getFromDateLocalDate(), holiday.getToDateLocalDate(), holiday.getRepaymentsRescheduledToLocalDate());
|
||||
|
||||
if (changes.containsKey(officesParamName)) {
|
||||
final Set<Office> offices = getSelectedOffices(command);
|
||||
final boolean updated = holiday.update(offices);
|
||||
if (!updated) {
|
||||
changes.remove(officesParamName);
|
||||
}
|
||||
}
|
||||
|
||||
this.holidayRepository.saveAndFlush(holiday);
|
||||
|
||||
return new CommandProcessingResultBuilder().withEntityId(holiday.getId()).with(changes).build();
|
||||
} catch (final DataIntegrityViolationException dve) {
|
||||
handleDataIntegrityIssues(command, dve);
|
||||
return CommandProcessingResult.empty();
|
||||
}
|
||||
}
|
||||
|
||||
@Transactional
|
||||
@Override
|
||||
public CommandProcessingResult activateHoliday(final Long holidayId) {
|
||||
this.context.authenticatedUser();
|
||||
final Holiday holiday = this.holidayRepository.findOneWithNotFoundDetection(holidayId);
|
||||
|
||||
holiday.activate();
|
||||
this.holidayRepository.saveAndFlush(holiday);
|
||||
return new CommandProcessingResultBuilder()
|
||||
.withEntityId(holiday.getId()).build();
|
||||
}
|
||||
|
||||
@Transactional
|
||||
@Override
|
||||
public CommandProcessingResult deleteHoliday(final Long holidayId) {
|
||||
this.context.authenticatedUser();
|
||||
final Holiday holiday = this.holidayRepository.findOneWithNotFoundDetection(holidayId);
|
||||
holiday.delete();
|
||||
this.holidayRepository.saveAndFlush(holiday);
|
||||
return new CommandProcessingResultBuilder()
|
||||
.withEntityId(holidayId).build();
|
||||
}
|
||||
|
||||
private Set<Office> getSelectedOffices(final JsonCommand command) {
|
||||
Set<Office> offices = null;
|
||||
final JsonObject topLevelJsonElement = this.fromApiJsonHelper.parse(command.json()).getAsJsonObject();
|
||||
if (topLevelJsonElement.has(HolidayApiConstants.offices) && topLevelJsonElement.get(HolidayApiConstants.offices).isJsonArray()) {
|
||||
if (topLevelJsonElement.has(HolidayApiConstants.officesParamName) && topLevelJsonElement.get(HolidayApiConstants.officesParamName).isJsonArray()) {
|
||||
|
||||
final JsonArray array = topLevelJsonElement.get(HolidayApiConstants.offices).getAsJsonArray();
|
||||
final JsonArray array = topLevelJsonElement.get(HolidayApiConstants.officesParamName).getAsJsonArray();
|
||||
offices = new HashSet<Office>(array.size());
|
||||
for (int i = 0; i < array.size(); i++) {
|
||||
final JsonObject officeElement = array.get(i).getAsJsonObject();
|
||||
final Long officeId = this.fromApiJsonHelper.extractLongNamed(HolidayApiConstants.officeId, officeElement);
|
||||
final Long officeId = this.fromApiJsonHelper.extractLongNamed(HolidayApiConstants.officeIdParamName, officeElement);
|
||||
final Office office = this.officeRepository.findOne(officeId);
|
||||
if (office == null) { throw new OfficeNotFoundException(officeId); }
|
||||
offices.add(office);
|
||||
@@ -114,9 +170,13 @@ public class HolidayWritePlatformServiceJpaRepositoryImpl implements HolidayWrit
|
||||
}
|
||||
|
||||
private void validateInputDates(final JsonCommand command) {
|
||||
final LocalDate fromDate = command.localDateValueOfParameterNamed(HolidayApiConstants.fromDate);
|
||||
final LocalDate toDate = command.localDateValueOfParameterNamed(HolidayApiConstants.toDate);
|
||||
final LocalDate repaymentsRescheduledTo = command.localDateValueOfParameterNamed(HolidayApiConstants.repaymentsRescheduledTo);
|
||||
final LocalDate fromDate = command.localDateValueOfParameterNamed(HolidayApiConstants.fromDateParamName);
|
||||
final LocalDate toDate = command.localDateValueOfParameterNamed(HolidayApiConstants.toDateParamName);
|
||||
final LocalDate repaymentsRescheduledTo = command.localDateValueOfParameterNamed(HolidayApiConstants.repaymentsRescheduledToParamName);
|
||||
this.validateInputDates(fromDate, toDate, repaymentsRescheduledTo);
|
||||
}
|
||||
private void validateInputDates(final LocalDate fromDate, final LocalDate toDate, final LocalDate repaymentsRescheduledTo) {
|
||||
|
||||
String defaultUserMessage = "";
|
||||
|
||||
if (toDate.isBefore(fromDate)) {
|
||||
|
||||
+1
-1
@@ -76,7 +76,7 @@ public class Office extends AbstractPersistable<Long> {
|
||||
|
||||
private Office(final Office parent, final String name, final LocalDate openingDate, final String externalId) {
|
||||
this.parent = parent;
|
||||
this.openingDate = openingDate.toDateMidnight().toDate();
|
||||
this.openingDate = openingDate.toDateTimeAtStartOfDay().toDate();
|
||||
if (parent != null) {
|
||||
this.parent.addChild(this);
|
||||
}
|
||||
|
||||
+1
-1
@@ -49,7 +49,7 @@ public class StaffApiResource {
|
||||
* {@link StaffData}.
|
||||
*/
|
||||
private final Set<String> RESPONSE_DATA_PARAMETERS = new HashSet<String>(Arrays.asList("id", "firstname", "lastname", "displayName",
|
||||
"officeId", "officeName", "loanOfficerFlag", "externalId", "allowedOffices"));
|
||||
"officeId", "officeName", "loanOfficerFlag", "externalId", "mobileNo", "allowedOffices"));
|
||||
|
||||
private final String resourceNameForPermissions = "STAFF";
|
||||
|
||||
|
||||
+11
-6
@@ -15,33 +15,37 @@ import org.mifosplatform.organisation.office.data.OfficeData;
|
||||
public class StaffData {
|
||||
|
||||
private final Long id;
|
||||
private final String externalId;
|
||||
|
||||
private final String firstname;
|
||||
private final String lastname;
|
||||
private final String displayName;
|
||||
private final String mobileNo;
|
||||
|
||||
private final Long officeId;
|
||||
private final String officeName;
|
||||
private final Boolean isLoanOfficer;
|
||||
private final String externalId;
|
||||
|
||||
@SuppressWarnings("unused")
|
||||
private final Collection<OfficeData> allowedOffices;
|
||||
|
||||
public static StaffData templateData(final StaffData staff, final Collection<OfficeData> allowedOffices) {
|
||||
return new StaffData(staff.id, staff.firstname, staff.lastname, staff.displayName, staff.officeId, staff.officeName,
|
||||
staff.isLoanOfficer, staff.externalId, allowedOffices);
|
||||
staff.isLoanOfficer, staff.externalId, staff.mobileNo, allowedOffices);
|
||||
}
|
||||
|
||||
public static StaffData lookup(final Long id, final String displayName) {
|
||||
return new StaffData(id, null, null, displayName, null, null, null, null, null);
|
||||
return new StaffData(id, null, null, displayName, null, null, null, null, null, null);
|
||||
}
|
||||
|
||||
public static StaffData instance(final Long id, final String firstname, final String lastname, final String displayName,
|
||||
final Long officeId, final String officeName, final Boolean isLoanOfficer, final String externalId) {
|
||||
return new StaffData(id, firstname, lastname, displayName, officeId, officeName, isLoanOfficer, externalId, null);
|
||||
final Long officeId, final String officeName, final Boolean isLoanOfficer, final String externalId, final String mobileNo) {
|
||||
return new StaffData(id, firstname, lastname, displayName, officeId, officeName, isLoanOfficer, externalId, mobileNo, null);
|
||||
}
|
||||
|
||||
private StaffData(final Long id, final String firstname, final String lastname, final String displayName, final Long officeId,
|
||||
final String officeName, final Boolean isLoanOfficer, final String externalId, final Collection<OfficeData> allowedOffices) {
|
||||
final String officeName, final Boolean isLoanOfficer, final String externalId, final String mobileNo,
|
||||
final Collection<OfficeData> allowedOffices) {
|
||||
this.id = id;
|
||||
this.firstname = firstname;
|
||||
this.lastname = lastname;
|
||||
@@ -50,6 +54,7 @@ public class StaffData {
|
||||
this.isLoanOfficer = isLoanOfficer;
|
||||
this.externalId = externalId;
|
||||
this.officeId = officeId;
|
||||
this.mobileNo = mobileNo;
|
||||
this.allowedOffices = allowedOffices;
|
||||
}
|
||||
|
||||
|
||||
+23
-11
@@ -23,7 +23,8 @@ import org.springframework.data.jpa.domain.AbstractPersistable;
|
||||
|
||||
@Entity
|
||||
@Table(name = "m_staff", uniqueConstraints = { @UniqueConstraint(columnNames = { "display_name" }, name = "display_name"),
|
||||
@UniqueConstraint(columnNames = { "external_id" }, name = "external_id_UNIQUE") })
|
||||
@UniqueConstraint(columnNames = { "external_id" }, name = "external_id_UNIQUE"),
|
||||
@UniqueConstraint(columnNames = { "mobile_no" }, name = "mobile_no_UNIQUE") })
|
||||
public class Staff extends AbstractPersistable<Long> {
|
||||
|
||||
@Column(name = "firstname", length = 50)
|
||||
@@ -35,15 +36,16 @@ public class Staff extends AbstractPersistable<Long> {
|
||||
@Column(name = "display_name", length = 100)
|
||||
private String displayName;
|
||||
|
||||
@Column(name = "mobile_no", length = 50, nullable = false, unique = true)
|
||||
private String mobileNo;
|
||||
|
||||
@Column(name = "external_id", length = 100, nullable = true, unique = true)
|
||||
private String externalId;
|
||||
|
||||
// Office to which this employee belongs
|
||||
@ManyToOne
|
||||
@JoinColumn(name = "office_id", nullable = false)
|
||||
private Office office;
|
||||
|
||||
// Flag determines if employee is a loan Officer
|
||||
@Column(name = "is_loan_officer ", nullable = false)
|
||||
private boolean loanOfficer;
|
||||
|
||||
@@ -65,27 +67,26 @@ public class Staff extends AbstractPersistable<Long> {
|
||||
final String externalIdParamName = "externalId";
|
||||
final String externalId = command.stringValueOfParameterNamedAllowingNull(externalIdParamName);
|
||||
|
||||
final String mobileNoParamName = "mobileNo";
|
||||
final String mobileNo = command.stringValueOfParameterNamedAllowingNull(mobileNoParamName);
|
||||
|
||||
final String isLoanOfficerParamName = "isLoanOfficer";
|
||||
final boolean isLoanOfficer = command.booleanPrimitiveValueOfParameterNamed(isLoanOfficerParamName);
|
||||
|
||||
return new Staff(staffOffice, firstname, lastname, externalId, isLoanOfficer);
|
||||
}
|
||||
|
||||
public static Staff createNew(final Office staffOffice, final String firstname, final String lastname, final String externalId,
|
||||
final boolean isLoanOfficer) {
|
||||
return new Staff(staffOffice, firstname, lastname, externalId, isLoanOfficer);
|
||||
return new Staff(staffOffice, firstname, lastname, externalId, mobileNo, isLoanOfficer);
|
||||
}
|
||||
|
||||
protected Staff() {
|
||||
//
|
||||
}
|
||||
|
||||
private Staff(final Office staffOffice, final String firstname, final String lastname, final String externalId,
|
||||
private Staff(final Office staffOffice, final String firstname, final String lastname, final String externalId, final String mobileNo,
|
||||
final boolean isLoanOfficer) {
|
||||
this.office = staffOffice;
|
||||
this.firstname = StringUtils.defaultIfEmpty(firstname, null);
|
||||
this.lastname = StringUtils.defaultIfEmpty(lastname, null);
|
||||
this.externalId = externalId;
|
||||
this.externalId = StringUtils.defaultIfEmpty(externalId, null);
|
||||
this.mobileNo = StringUtils.defaultIfEmpty(mobileNo, null);
|
||||
this.loanOfficer = isLoanOfficer;
|
||||
deriveDisplayName(firstname);
|
||||
}
|
||||
@@ -141,6 +142,13 @@ public class Staff extends AbstractPersistable<Long> {
|
||||
this.externalId = newValue;
|
||||
}
|
||||
|
||||
final String mobileNoParamName = "mobileNo";
|
||||
if (command.isChangeInStringParameterNamed(mobileNoParamName, this.mobileNo)) {
|
||||
final String newValue = command.stringValueOfParameterNamed(mobileNoParamName);
|
||||
actualChanges.put(mobileNoParamName, newValue);
|
||||
this.mobileNo = StringUtils.defaultIfEmpty(newValue, null);
|
||||
}
|
||||
|
||||
final String isLoanOfficerParamName = "isLoanOfficer";
|
||||
if (command.isChangeInBooleanParameterNamed(isLoanOfficerParamName, this.loanOfficer)) {
|
||||
final boolean newValue = command.booleanPrimitiveValueOfParameterNamed(isLoanOfficerParamName);
|
||||
@@ -179,6 +187,10 @@ public class Staff extends AbstractPersistable<Long> {
|
||||
return this.displayName;
|
||||
}
|
||||
|
||||
public String mobileNo() {
|
||||
return this.mobileNo;
|
||||
}
|
||||
|
||||
public Office office() {
|
||||
return this.office;
|
||||
}
|
||||
|
||||
+13
-1
@@ -19,6 +19,7 @@ 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.mifosplatform.portfolio.client.api.ClientApiConstants;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
@@ -32,7 +33,7 @@ public final class StaffCommandFromApiJsonDeserializer {
|
||||
* The parameters supported for this command.
|
||||
*/
|
||||
private final Set<String> supportedParameters = new HashSet<String>(Arrays.asList("firstname", "lastname", "officeId", "externalId",
|
||||
"isLoanOfficer"));
|
||||
"mobileNo", "isLoanOfficer"));
|
||||
|
||||
private final FromJsonHelper fromApiJsonHelper;
|
||||
|
||||
@@ -61,6 +62,12 @@ public final class StaffCommandFromApiJsonDeserializer {
|
||||
final String lastname = this.fromApiJsonHelper.extractStringNamed("lastname", element);
|
||||
baseDataValidator.reset().parameter("lastname").value(lastname).notBlank().notExceedingLengthOf(50);
|
||||
|
||||
if (this.fromApiJsonHelper.parameterExists(ClientApiConstants.mobileNoParamName, element)) {
|
||||
final String mobileNo = this.fromApiJsonHelper.extractStringNamed(ClientApiConstants.mobileNoParamName, element);
|
||||
baseDataValidator.reset().parameter(ClientApiConstants.mobileNoParamName).value(mobileNo).ignoreIfNull()
|
||||
.notExceedingLengthOf(50);
|
||||
}
|
||||
|
||||
if (this.fromApiJsonHelper.parameterExists("isLoanOfficer", element)) {
|
||||
final Boolean loanOfficerFlag = this.fromApiJsonHelper.extractBooleanNamed("isLoanOfficer", element);
|
||||
baseDataValidator.reset().parameter("isLoanOfficer").value(loanOfficerFlag).notNull();
|
||||
@@ -94,6 +101,11 @@ public final class StaffCommandFromApiJsonDeserializer {
|
||||
baseDataValidator.reset().parameter("lastname").value(lastname).notBlank().notExceedingLengthOf(50);
|
||||
}
|
||||
|
||||
if (this.fromApiJsonHelper.parameterExists(ClientApiConstants.mobileNoParamName, element)) {
|
||||
final String mobileNo = this.fromApiJsonHelper.extractStringNamed(ClientApiConstants.mobileNoParamName, element);
|
||||
baseDataValidator.reset().parameter(ClientApiConstants.mobileNoParamName).value(mobileNo).notExceedingLengthOf(50);
|
||||
}
|
||||
|
||||
if (this.fromApiJsonHelper.parameterExists("isLoanOfficer", element)) {
|
||||
final Boolean loanOfficerFlag = this.fromApiJsonHelper.extractBooleanNamed("isLoanOfficer", element);
|
||||
baseDataValidator.reset().parameter("isLoanOfficer").value(loanOfficerFlag).notNull();
|
||||
|
||||
+7
-6
@@ -38,7 +38,7 @@ public class StaffReadPlatformServiceImpl implements StaffReadPlatformService {
|
||||
|
||||
public String schema() {
|
||||
return " s.id as id,s.office_id as officeId, o.name as officeName, s.firstname as firstname, s.lastname as lastname,"
|
||||
+ " s.display_name as displayName, s.is_loan_officer as isLoanOfficer, s.external_id as externalId from m_staff s "
|
||||
+ " s.display_name as displayName, s.is_loan_officer as isLoanOfficer, s.external_id as externalId, s.mobile_no as mobileNo from m_staff s "
|
||||
+ " join m_office o on o.id = s.office_id";
|
||||
}
|
||||
|
||||
@@ -53,8 +53,9 @@ public class StaffReadPlatformServiceImpl implements StaffReadPlatformService {
|
||||
final boolean isLoanOfficer = rs.getBoolean("isLoanOfficer");
|
||||
final String officeName = rs.getString("officeName");
|
||||
final String externalId = rs.getString("externalId");
|
||||
final String mobileNo = rs.getString("mobileNo");
|
||||
|
||||
return StaffData.instance(id, firstname, lastname, displayName, officeId, officeName, isLoanOfficer, externalId);
|
||||
return StaffData.instance(id, firstname, lastname, displayName, officeId, officeName, isLoanOfficer, externalId, mobileNo);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -65,7 +66,8 @@ public class StaffReadPlatformServiceImpl implements StaffReadPlatformService {
|
||||
final StringBuilder sqlBuilder = new StringBuilder(200);
|
||||
sqlBuilder.append("s.id as id, s.office_id as officeId, ohierarchy.name as officeName,");
|
||||
sqlBuilder.append("s.firstname as firstname, s.lastname as lastname,");
|
||||
sqlBuilder.append("s.display_name as displayName, s.is_loan_officer as isLoanOfficer, s.external_id as externalId ");
|
||||
sqlBuilder
|
||||
.append("s.display_name as displayName, s.is_loan_officer as isLoanOfficer, s.external_id as externalId, s.mobile_no as mobileNo ");
|
||||
sqlBuilder.append("from m_office o ");
|
||||
sqlBuilder.append("join m_office ohierarchy on o.hierarchy like concat(ohierarchy.hierarchy, '%') ");
|
||||
sqlBuilder.append("join m_staff s on s.office_id = ohierarchy.id ");
|
||||
@@ -90,8 +92,9 @@ public class StaffReadPlatformServiceImpl implements StaffReadPlatformService {
|
||||
final String officeName = rs.getString("officeName");
|
||||
final boolean isLoanOfficer = rs.getBoolean("isLoanOfficer");
|
||||
final String externalId = rs.getString("externalId");
|
||||
final String mobileNo = rs.getString("mobileNo");
|
||||
|
||||
return StaffData.instance(id, firstname, lastname, displayName, officeId, officeName, isLoanOfficer, externalId);
|
||||
return StaffData.instance(id, firstname, lastname, displayName, officeId, officeName, isLoanOfficer, externalId, mobileNo);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -149,8 +152,6 @@ public class StaffReadPlatformServiceImpl implements StaffReadPlatformService {
|
||||
public StaffData retrieveStaff(final Long staffId) {
|
||||
|
||||
try {
|
||||
this.context.authenticatedUser();
|
||||
|
||||
final StaffMapper rm = new StaffMapper();
|
||||
final String sql = "select " + rm.schema() + " where s.id = ?";
|
||||
|
||||
|
||||
+2
-10
@@ -12,7 +12,6 @@ import org.mifosplatform.infrastructure.core.api.JsonCommand;
|
||||
import org.mifosplatform.infrastructure.core.data.CommandProcessingResult;
|
||||
import org.mifosplatform.infrastructure.core.data.CommandProcessingResultBuilder;
|
||||
import org.mifosplatform.infrastructure.core.exception.PlatformDataIntegrityException;
|
||||
import org.mifosplatform.infrastructure.security.service.PlatformSecurityContext;
|
||||
import org.mifosplatform.organisation.office.domain.Office;
|
||||
import org.mifosplatform.organisation.office.domain.OfficeRepository;
|
||||
import org.mifosplatform.organisation.office.exception.OfficeNotFoundException;
|
||||
@@ -32,16 +31,13 @@ public class StaffWritePlatformServiceJpaRepositoryImpl implements StaffWritePla
|
||||
|
||||
private final static Logger logger = LoggerFactory.getLogger(StaffWritePlatformServiceJpaRepositoryImpl.class);
|
||||
|
||||
private final PlatformSecurityContext context;
|
||||
private final StaffCommandFromApiJsonDeserializer fromApiJsonDeserializer;
|
||||
private final StaffRepository staffRepository;
|
||||
private final OfficeRepository officeRepository;
|
||||
|
||||
@Autowired
|
||||
public StaffWritePlatformServiceJpaRepositoryImpl(final PlatformSecurityContext context,
|
||||
final StaffCommandFromApiJsonDeserializer fromApiJsonDeserializer, final StaffRepository staffRepository,
|
||||
final OfficeRepository officeRepository) {
|
||||
this.context = context;
|
||||
public StaffWritePlatformServiceJpaRepositoryImpl(final StaffCommandFromApiJsonDeserializer fromApiJsonDeserializer,
|
||||
final StaffRepository staffRepository, final OfficeRepository officeRepository) {
|
||||
this.fromApiJsonDeserializer = fromApiJsonDeserializer;
|
||||
this.staffRepository = staffRepository;
|
||||
this.officeRepository = officeRepository;
|
||||
@@ -52,8 +48,6 @@ public class StaffWritePlatformServiceJpaRepositoryImpl implements StaffWritePla
|
||||
public CommandProcessingResult createStaff(final JsonCommand command) {
|
||||
|
||||
try {
|
||||
this.context.authenticatedUser();
|
||||
|
||||
this.fromApiJsonDeserializer.validateForCreate(command.json());
|
||||
|
||||
final Long officeId = command.longValueOfParameterNamed("officeId");
|
||||
@@ -80,8 +74,6 @@ public class StaffWritePlatformServiceJpaRepositoryImpl implements StaffWritePla
|
||||
public CommandProcessingResult updateStaff(final Long staffId, final JsonCommand command) {
|
||||
|
||||
try {
|
||||
this.context.authenticatedUser();
|
||||
|
||||
this.fromApiJsonDeserializer.validateForUpdate(command.json());
|
||||
|
||||
final Staff staffForUpdate = this.staffRepository.findOne(staffId);
|
||||
|
||||
+8
-1
@@ -23,11 +23,12 @@ public class AccountTransferDTO {
|
||||
private final Integer fromTransferType;
|
||||
private final Integer toTransferType;
|
||||
private final Long chargeId;
|
||||
private final Integer loanInstallmentNumber;
|
||||
|
||||
public AccountTransferDTO(final LocalDate transactionDate, final BigDecimal transactionAmount,
|
||||
final PortfolioAccountType fromAccountType, final PortfolioAccountType toAccountType, final Long fromAccountId,
|
||||
final Long toAccountId, final String description, final Locale locale, final DateTimeFormatter fmt,
|
||||
final PaymentDetail paymentDetail, final Integer fromTransferType, final Integer toTransferType, final Long chargeId) {
|
||||
final PaymentDetail paymentDetail, final Integer fromTransferType, final Integer toTransferType, final Long chargeId, Integer loanInstallmentNumber) {
|
||||
this.transactionDate = transactionDate;
|
||||
this.transactionAmount = transactionAmount;
|
||||
this.fromAccountType = fromAccountType;
|
||||
@@ -41,6 +42,7 @@ public class AccountTransferDTO {
|
||||
this.fromTransferType = fromTransferType;
|
||||
this.toTransferType = toTransferType;
|
||||
this.chargeId = chargeId;
|
||||
this.loanInstallmentNumber = loanInstallmentNumber;
|
||||
}
|
||||
|
||||
public LocalDate getTransactionDate() {
|
||||
@@ -95,4 +97,9 @@ public class AccountTransferDTO {
|
||||
return this.chargeId;
|
||||
}
|
||||
|
||||
|
||||
public Integer getLoanInstallmentNumber() {
|
||||
return this.loanInstallmentNumber;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
+1
-1
@@ -229,7 +229,7 @@ public class AccountTransfersWritePlatformServiceImpl implements AccountTransfer
|
||||
|
||||
final LoanTransaction loanRepaymentTransaction = this.loanAccountDomainService.makeChargePayment(toLoanAccount,
|
||||
accountTransferDTO.getChargeId(), accountTransferDTO.getTransactionDate(), accountTransferDTO.getTransactionAmount(),
|
||||
accountTransferDTO.getPaymentDetail(), null, null, accountTransferDTO.getToTransferType());
|
||||
accountTransferDTO.getPaymentDetail(), null, null, accountTransferDTO.getToTransferType(), accountTransferDTO.getLoanInstallmentNumber());
|
||||
|
||||
final AccountTransfer transferTransaction = this.accountTransferAssembler.assembleSavingsToLoanTransfer(accountTransferDTO,
|
||||
fromSavingsAccount, toLoanAccount, withdrawal, loanRepaymentTransaction);
|
||||
|
||||
+2
-1
@@ -10,11 +10,12 @@ import java.util.Set;
|
||||
|
||||
public class CalendarConstants {
|
||||
|
||||
public static final String CALENDAR_RESOURCE_NAME = "calendar";
|
||||
public static enum CALENDAR_SUPPORTED_PARAMETERS {
|
||||
CALENDAR_ID("id"), ENTITY_TYPE("entityType"), ENTITY_ID("entityId"), TITLE("title"), DESCRIPTION("description"), LOCATION(
|
||||
"location"), START_DATE("startDate"), END_DATE("endDate"), CREATED_DATE("createdDate"), DURATION("duration"), TYPE_ID(
|
||||
"typeId"), REPEATING("repeating"), REMIND_BY_ID("remindById"), FIRST_REMINDER("firstReminder"), SECOND_REMINDER(
|
||||
"secondReminder"), LOCALE("locale"), DATE_FORMAT("dateFormat"), REPEATS("repeats"), REPEATS_EVERY("repeatsEvery"), REPEATS_ON_DAY(
|
||||
"secondReminder"), LOCALE("locale"), DATE_FORMAT("dateFormat"), FREQUENCY("frequency"), INTERVAL("interval"), REPEATS_ON_DAY(
|
||||
"repeatsOnDay");
|
||||
|
||||
private final String value;
|
||||
|
||||
+19
-8
@@ -26,6 +26,7 @@ import javax.ws.rs.core.Context;
|
||||
import javax.ws.rs.core.MediaType;
|
||||
import javax.ws.rs.core.UriInfo;
|
||||
|
||||
import org.joda.time.LocalDate;
|
||||
import org.mifosplatform.commands.domain.CommandWrapper;
|
||||
import org.mifosplatform.commands.service.CommandWrapperBuilder;
|
||||
import org.mifosplatform.commands.service.PortfolioCommandSourceWritePlatformService;
|
||||
@@ -54,10 +55,12 @@ public class CalendarsApiResource {
|
||||
/**
|
||||
* The set of parameters that are supported in response for {@link Calendar}
|
||||
*/
|
||||
private final Set<String> RESPONSE_DATA_PARAMETERS = new HashSet<String>(Arrays.asList("id", "entityId", "entityType", "title",
|
||||
"description", "location", "startDate", "endDate", "duration", "type", "repeating", "recurrence", "remindBy", "firstReminder",
|
||||
"secondReminder", "humanReadable", "createdDate", "lastUpdatedDate", "createdByUserId", "createdByUsername",
|
||||
"lastUpdatedByUserId", "lastUpdatedByUsername", "recurringDates", "nextTenRecurringDates"));
|
||||
private final Set<String> RESPONSE_DATA_PARAMETERS = new HashSet<String>(
|
||||
Arrays.asList("id", "entityId", "entityType", "title", "description", "location", "startDate", "endDate", "duration", "type",
|
||||
"repeating", "recurrence", "frequency", "interval", "repeatsOnDay", "remindBy", "firstReminder", "secondReminder",
|
||||
"humanReadable", "createdDate", "lastUpdatedDate", "createdByUserId", "createdByUsername", "lastUpdatedByUserId",
|
||||
"lastUpdatedByUsername", "recurringDates", "nextTenRecurringDates", "entityTypeOptions", "calendarTypeOptions",
|
||||
"remindByOptions", "frequencyOptions", "repeatsOnDayOptions"));
|
||||
private final String resourceNameForPermissions = "CALENDAR";
|
||||
|
||||
private final PlatformSecurityContext context;
|
||||
@@ -92,7 +95,12 @@ public class CalendarsApiResource {
|
||||
CalendarData calendarData = this.readPlatformService.retrieveCalendar(calendarId, entityId, entityTypeId);
|
||||
|
||||
// Include recurring date details
|
||||
calendarData = this.readPlatformService.generateRecurringDate(calendarData);
|
||||
final boolean withHistory = true;
|
||||
final LocalDate tillDate = null;
|
||||
final Collection<LocalDate> recurringDates = this.readPlatformService.generateRecurringDates(calendarData, withHistory, tillDate);
|
||||
final Collection<LocalDate> nextTenRecurringDates = this.readPlatformService.generateNextTenRecurringDates(calendarData);
|
||||
final LocalDate recentEligibleMeetingDate = null;
|
||||
calendarData = CalendarData.withRecurringDates(calendarData, recurringDates, nextTenRecurringDates, recentEligibleMeetingDate);
|
||||
|
||||
final ApiRequestJsonSerializationSettings settings = this.apiRequestParameterHelper.process(uriInfo.getQueryParameters());
|
||||
if (settings.isTemplate()) {
|
||||
@@ -133,7 +141,7 @@ public class CalendarsApiResource {
|
||||
CalendarEntityType.valueOf(entityType.toUpperCase()).getValue(), calendarTypeOptions));
|
||||
|
||||
// Add recurring dates
|
||||
calendarsData = this.readPlatformService.generateRecurringDates(calendarsData);
|
||||
calendarsData = this.readPlatformService.updateWithRecurringDates(calendarsData);
|
||||
|
||||
final ApiRequestJsonSerializationSettings settings = this.apiRequestParameterHelper.process(uriInfo.getQueryParameters());
|
||||
return this.toApiJsonSerializer.serialize(settings, calendarsData, this.RESPONSE_DATA_PARAMETERS);
|
||||
@@ -188,7 +196,7 @@ public class CalendarsApiResource {
|
||||
@Path("{calendarId}")
|
||||
@Consumes({ MediaType.APPLICATION_JSON })
|
||||
@Produces({ MediaType.APPLICATION_JSON })
|
||||
public String deleteGLAccount(@PathParam("entityType") final String entityType, @PathParam("entityId") final Long entityId,
|
||||
public String deleteCalendar(@PathParam("entityType") final String entityType, @PathParam("entityId") final Long entityId,
|
||||
@PathParam("calendarId") final Long calendarId) {
|
||||
|
||||
final CommandWrapper commandRequest = new CommandWrapperBuilder().deleteCalendar(entityType, entityId, calendarId).build();
|
||||
@@ -202,7 +210,10 @@ public class CalendarsApiResource {
|
||||
final List<EnumOptionData> entityTypeOptions = this.dropdownReadPlatformService.retrieveCalendarEntityTypeOptions();
|
||||
final List<EnumOptionData> calendarTypeOptions = this.dropdownReadPlatformService.retrieveCalendarTypeOptions();
|
||||
final List<EnumOptionData> remindByOptions = this.dropdownReadPlatformService.retrieveCalendarRemindByOptions();
|
||||
return new CalendarData(calendarData, entityTypeOptions, calendarTypeOptions, remindByOptions);
|
||||
final List<EnumOptionData> frequencyOptions = this.dropdownReadPlatformService.retrieveCalendarFrequencyTypeOptions();
|
||||
final List<EnumOptionData> repeatsOnDayOptions = this.dropdownReadPlatformService.retrieveCalendarWeekDaysTypeOptions();
|
||||
return CalendarData.withTemplateOptions(calendarData, entityTypeOptions, calendarTypeOptions, remindByOptions, frequencyOptions,
|
||||
repeatsOnDayOptions);
|
||||
}
|
||||
|
||||
}
|
||||
+154
-99
@@ -10,8 +10,10 @@ import java.util.List;
|
||||
|
||||
import org.joda.time.LocalDate;
|
||||
import org.mifosplatform.infrastructure.core.data.EnumOptionData;
|
||||
import org.mifosplatform.portfolio.calendar.domain.CalendarFrequencyType;
|
||||
import org.mifosplatform.portfolio.calendar.domain.CalendarRemindBy;
|
||||
import org.mifosplatform.portfolio.calendar.domain.CalendarType;
|
||||
import org.mifosplatform.portfolio.calendar.domain.CalendarWeekDaysType;
|
||||
import org.mifosplatform.portfolio.calendar.service.CalendarEnumerations;
|
||||
|
||||
/**
|
||||
@@ -20,6 +22,7 @@ import org.mifosplatform.portfolio.calendar.service.CalendarEnumerations;
|
||||
public class CalendarData {
|
||||
|
||||
private final Long id;
|
||||
private final Long calendarInstanceId;
|
||||
private final Long entityId;
|
||||
private final EnumOptionData entityType;
|
||||
private final String title;
|
||||
@@ -31,6 +34,9 @@ public class CalendarData {
|
||||
private final EnumOptionData type;
|
||||
private final boolean repeating;
|
||||
private final String recurrence;
|
||||
private final EnumOptionData frequency;
|
||||
private final Integer interval;
|
||||
private final EnumOptionData repeatsOnDay;
|
||||
private final EnumOptionData remindBy;
|
||||
private final Integer firstReminder;
|
||||
private final Integer secondReminder;
|
||||
@@ -50,112 +56,61 @@ public class CalendarData {
|
||||
final List<EnumOptionData> entityTypeOptions;
|
||||
final List<EnumOptionData> calendarTypeOptions;
|
||||
final List<EnumOptionData> remindByOptions;
|
||||
final List<EnumOptionData> frequencyOptions;
|
||||
final List<EnumOptionData> repeatsOnDayOptions;
|
||||
|
||||
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 recentEligibleMeetingDate,
|
||||
final LocalDate createdDate, final LocalDate lastUpdatedDate, final Long createdByUserId, final String createdByUsername,
|
||||
final Long lastUpdatedByUserId, final String lastUpdatedByUsername) {
|
||||
public static CalendarData instance(final Long id, final Long calendarInstanceId, 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 frequency,
|
||||
final Integer interval, final EnumOptionData repeatsOnDay, final EnumOptionData remindBy, final Integer firstReminder,
|
||||
final Integer secondReminder, final String humanReadable, final LocalDate createdDate, final LocalDate lastUpdatedDate,
|
||||
final Long createdByUserId, final String createdByUsername, final Long lastUpdatedByUserId, final String lastUpdatedByUsername) {
|
||||
|
||||
this.id = id;
|
||||
this.entityId = entityId;
|
||||
this.entityType = entityType;
|
||||
this.title = title;
|
||||
this.description = description;
|
||||
this.location = location;
|
||||
this.startDate = startDate;
|
||||
this.endDate = endDate;
|
||||
this.duration = duration;
|
||||
this.type = type;
|
||||
this.repeating = repeating;
|
||||
this.recurrence = recurrence;
|
||||
this.remindBy = remindBy;
|
||||
this.firstReminder = firstReminder;
|
||||
this.secondReminder = secondReminder;
|
||||
this.entityTypeOptions = null;
|
||||
this.calendarTypeOptions = null;
|
||||
this.remindByOptions = null;
|
||||
this.recurringDates = null;
|
||||
this.nextTenRecurringDates = null;
|
||||
this.humanReadable = humanReadable;
|
||||
this.recentEligibleMeetingDate = recentEligibleMeetingDate;
|
||||
final Collection<LocalDate> recurringDates = null;
|
||||
final Collection<LocalDate> nextTenRecurringDates = null;
|
||||
final LocalDate recentEligibleMeetingDate = null;
|
||||
|
||||
this.createdDate = createdDate;
|
||||
this.lastUpdatedDate = lastUpdatedDate;
|
||||
this.createdByUserId = createdByUserId;
|
||||
this.createdByUsername = createdByUsername;
|
||||
this.lastUpdatedByUserId = lastUpdatedByUserId;
|
||||
this.lastUpdatedByUsername = lastUpdatedByUsername;
|
||||
final List<EnumOptionData> entityTypeOptions = null;
|
||||
final List<EnumOptionData> calendarTypeOptions = null;
|
||||
final List<EnumOptionData> remindByOptions = null;
|
||||
final List<EnumOptionData> frequencyOptions = null;
|
||||
final List<EnumOptionData> repeatsOnDayOptions = null;
|
||||
|
||||
return new CalendarData(id, calendarInstanceId, entityId, entityType, title, description, location, startDate, endDate, duration, type, repeating,
|
||||
recurrence, frequency, interval, repeatsOnDay, remindBy, firstReminder, secondReminder, recurringDates,
|
||||
nextTenRecurringDates, humanReadable, recentEligibleMeetingDate, createdDate, lastUpdatedDate, createdByUserId,
|
||||
createdByUsername, lastUpdatedByUserId, lastUpdatedByUsername, entityTypeOptions, calendarTypeOptions, remindByOptions,
|
||||
frequencyOptions, repeatsOnDayOptions);
|
||||
}
|
||||
|
||||
public CalendarData(final CalendarData calendarData, final List<EnumOptionData> entityTypeOptions,
|
||||
final List<EnumOptionData> calendarTypeOptions, final List<EnumOptionData> remindByOptions) {
|
||||
this.id = calendarData.id;
|
||||
this.entityId = calendarData.entityId;
|
||||
this.entityType = calendarData.entityType;
|
||||
this.title = calendarData.title;
|
||||
this.description = calendarData.description;
|
||||
this.location = calendarData.location;
|
||||
this.startDate = calendarData.startDate;
|
||||
this.endDate = calendarData.endDate;
|
||||
this.duration = calendarData.duration;
|
||||
this.type = calendarData.type;
|
||||
this.repeating = calendarData.repeating;
|
||||
this.recurrence = calendarData.recurrence;
|
||||
this.remindBy = calendarData.remindBy;
|
||||
this.firstReminder = calendarData.firstReminder;
|
||||
this.secondReminder = calendarData.secondReminder;
|
||||
this.entityTypeOptions = entityTypeOptions;
|
||||
this.calendarTypeOptions = calendarTypeOptions;
|
||||
this.remindByOptions = remindByOptions;
|
||||
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;
|
||||
this.createdByUsername = calendarData.createdByUsername;
|
||||
this.lastUpdatedByUserId = calendarData.lastUpdatedByUserId;
|
||||
this.lastUpdatedByUsername = calendarData.lastUpdatedByUsername;
|
||||
}
|
||||
|
||||
public CalendarData(final CalendarData calendarData, final Collection<LocalDate> recurringDates,
|
||||
public static CalendarData withRecurringDates(final CalendarData calendarData, final Collection<LocalDate> recurringDates,
|
||||
final Collection<LocalDate> nextTenRecurringDates, final LocalDate recentEligibleMeetingDate) {
|
||||
this.id = calendarData.id;
|
||||
this.entityId = calendarData.entityId;
|
||||
this.entityType = calendarData.entityType;
|
||||
this.title = calendarData.title;
|
||||
this.description = calendarData.description;
|
||||
this.location = calendarData.location;
|
||||
this.startDate = calendarData.startDate;
|
||||
this.endDate = calendarData.endDate;
|
||||
this.duration = calendarData.duration;
|
||||
this.type = calendarData.type;
|
||||
this.repeating = calendarData.repeating;
|
||||
this.recurrence = calendarData.recurrence;
|
||||
this.remindBy = calendarData.remindBy;
|
||||
this.firstReminder = calendarData.firstReminder;
|
||||
this.secondReminder = calendarData.secondReminder;
|
||||
this.entityTypeOptions = null;
|
||||
this.calendarTypeOptions = null;
|
||||
this.remindByOptions = null;
|
||||
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;
|
||||
this.createdByUsername = calendarData.createdByUsername;
|
||||
this.lastUpdatedByUserId = calendarData.lastUpdatedByUserId;
|
||||
this.lastUpdatedByUsername = calendarData.lastUpdatedByUsername;
|
||||
|
||||
return new CalendarData(calendarData.id, calendarData.calendarInstanceId, calendarData.entityId, calendarData.entityType, calendarData.title,
|
||||
calendarData.description, calendarData.location, calendarData.startDate, calendarData.endDate, calendarData.duration,
|
||||
calendarData.type, calendarData.repeating, calendarData.recurrence, calendarData.frequency, calendarData.interval,
|
||||
calendarData.repeatsOnDay, calendarData.remindBy, calendarData.firstReminder, calendarData.secondReminder, recurringDates,
|
||||
nextTenRecurringDates, calendarData.humanReadable, recentEligibleMeetingDate, calendarData.createdDate,
|
||||
calendarData.lastUpdatedDate, calendarData.createdByUserId, calendarData.createdByUsername,
|
||||
calendarData.lastUpdatedByUserId, calendarData.lastUpdatedByUsername, calendarData.entityTypeOptions,
|
||||
calendarData.calendarTypeOptions, calendarData.remindByOptions, calendarData.frequencyOptions,
|
||||
calendarData.repeatsOnDayOptions);
|
||||
}
|
||||
|
||||
public static CalendarData withRecentEligibleMeetingDate(final CalendarData calendarData, final LocalDate recentEligibleMeetingDate) {
|
||||
return new CalendarData(calendarData.id, calendarData.calendarInstanceId, calendarData.entityId, calendarData.entityType, calendarData.title,
|
||||
calendarData.description, calendarData.location, calendarData.startDate, calendarData.endDate, calendarData.duration,
|
||||
calendarData.type, calendarData.repeating, calendarData.recurrence, calendarData.frequency, calendarData.interval,
|
||||
calendarData.repeatsOnDay, calendarData.remindBy, calendarData.firstReminder, calendarData.secondReminder, calendarData.recurringDates,
|
||||
calendarData.nextTenRecurringDates, calendarData.humanReadable, recentEligibleMeetingDate, calendarData.createdDate,
|
||||
calendarData.lastUpdatedDate, calendarData.createdByUserId, calendarData.createdByUsername,
|
||||
calendarData.lastUpdatedByUserId, calendarData.lastUpdatedByUsername, calendarData.entityTypeOptions,
|
||||
calendarData.calendarTypeOptions, calendarData.remindByOptions, calendarData.frequencyOptions,
|
||||
calendarData.repeatsOnDayOptions);
|
||||
}
|
||||
|
||||
public static CalendarData sensibleDefaultsForNewCalendarCreation() {
|
||||
final Long id = null;
|
||||
final Long calendarInstanceId = null;
|
||||
final Long entityId = null;
|
||||
final EnumOptionData entityType = null;
|
||||
final String title = null;
|
||||
@@ -167,12 +122,23 @@ public class CalendarData {
|
||||
final EnumOptionData type = CalendarEnumerations.calendarType(CalendarType.COLLECTION);
|
||||
final boolean repeating = false;
|
||||
final String recurrence = null;
|
||||
final EnumOptionData frequency = CalendarEnumerations.calendarFrequencyType(CalendarFrequencyType.DAILY);
|
||||
final Integer interval = new Integer(1);
|
||||
final EnumOptionData repeatsOnDay = CalendarEnumerations.calendarWeekDaysType(CalendarWeekDaysType.MO);
|
||||
final EnumOptionData remindBy = CalendarEnumerations.calendarRemindBy(CalendarRemindBy.EMAIL);
|
||||
final Integer firstReminder = new Integer(0);
|
||||
final Integer secondReminder = new Integer(0);
|
||||
final String humanReadable = null;
|
||||
final Collection<LocalDate> recurringDates = null;
|
||||
final Collection<LocalDate> nextTenRecurringDates = null;
|
||||
final LocalDate recentEligibleMeetingDate = null;
|
||||
|
||||
final List<EnumOptionData> entityTypeOptions = null;
|
||||
final List<EnumOptionData> calendarTypeOptions = null;
|
||||
final List<EnumOptionData> remindByOptions = null;
|
||||
final List<EnumOptionData> frequencyOptions = null;
|
||||
final List<EnumOptionData> repeatsOnDayOptions = null;
|
||||
|
||||
final LocalDate createdDate = null;
|
||||
final LocalDate lastUpdatedDate = null;
|
||||
final Long createdByUserId = null;
|
||||
@@ -180,9 +146,71 @@ public class CalendarData {
|
||||
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, recentEligibleMeetingDate, createdDate,
|
||||
lastUpdatedDate, createdByUserId, createdByUsername, lastUpdatedByUserId, lastUpdatedByUsername);
|
||||
return new CalendarData(id, calendarInstanceId, entityId, entityType, title, description, location, startDate, endDate, duration, type, repeating,
|
||||
recurrence, frequency, interval, repeatsOnDay, remindBy, firstReminder, secondReminder, recurringDates,
|
||||
nextTenRecurringDates, humanReadable, recentEligibleMeetingDate, createdDate, lastUpdatedDate, createdByUserId,
|
||||
createdByUsername, lastUpdatedByUserId, lastUpdatedByUsername, entityTypeOptions, calendarTypeOptions, remindByOptions,
|
||||
frequencyOptions, repeatsOnDayOptions);
|
||||
}
|
||||
|
||||
public static CalendarData withTemplateOptions(final CalendarData calendarData, final List<EnumOptionData> entityTypeOptions,
|
||||
final List<EnumOptionData> calendarTypeOptions, final List<EnumOptionData> remindByOptions,
|
||||
final List<EnumOptionData> repeatsOptions, final List<EnumOptionData> repeatsOnDayOptions) {
|
||||
|
||||
return new CalendarData(calendarData.id, calendarData.calendarInstanceId, calendarData.entityId, calendarData.entityType, calendarData.title,
|
||||
calendarData.description, calendarData.location, calendarData.startDate, calendarData.endDate, calendarData.duration,
|
||||
calendarData.type, calendarData.repeating, calendarData.recurrence, calendarData.frequency, calendarData.interval,
|
||||
calendarData.repeatsOnDay, calendarData.remindBy, calendarData.firstReminder, calendarData.secondReminder,
|
||||
calendarData.recurringDates, calendarData.nextTenRecurringDates, calendarData.humanReadable,
|
||||
calendarData.recentEligibleMeetingDate, calendarData.createdDate, calendarData.lastUpdatedDate,
|
||||
calendarData.createdByUserId, calendarData.createdByUsername, calendarData.lastUpdatedByUserId, calendarData.lastUpdatedByUsername,
|
||||
entityTypeOptions, calendarTypeOptions, remindByOptions, repeatsOptions, repeatsOnDayOptions);
|
||||
}
|
||||
|
||||
private CalendarData(final Long id, final Long calendarInstanceId, 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 frequency, final Integer interval,
|
||||
final EnumOptionData repeatsOnDay, final EnumOptionData remindBy, final Integer firstReminder, final Integer secondReminder,
|
||||
final Collection<LocalDate> recurringDates, final Collection<LocalDate> nextTenRecurringDates, final String humanReadable,
|
||||
final LocalDate recentEligibleMeetingDate, final LocalDate createdDate, final LocalDate lastUpdatedDate,
|
||||
final Long createdByUserId, final String createdByUsername, final Long lastUpdatedByUserId, final String lastUpdatedByUsername,
|
||||
final List<EnumOptionData> entityTypeOptions, final List<EnumOptionData> calendarTypeOptions,
|
||||
final List<EnumOptionData> remindByOptions, final List<EnumOptionData> repeatsOptions,
|
||||
final List<EnumOptionData> repeatsOnDayOptions) {
|
||||
this.id = id;
|
||||
this.calendarInstanceId = calendarInstanceId;
|
||||
this.entityId = entityId;
|
||||
this.entityType = entityType;
|
||||
this.title = title;
|
||||
this.description = description;
|
||||
this.location = location;
|
||||
this.startDate = startDate;
|
||||
this.endDate = endDate;
|
||||
this.duration = duration;
|
||||
this.type = type;
|
||||
this.repeating = repeating;
|
||||
this.recurrence = recurrence;
|
||||
this.frequency = frequency;
|
||||
this.interval = interval;
|
||||
this.repeatsOnDay = repeatsOnDay;
|
||||
this.remindBy = remindBy;
|
||||
this.firstReminder = firstReminder;
|
||||
this.secondReminder = secondReminder;
|
||||
this.recurringDates = recurringDates;
|
||||
this.nextTenRecurringDates = nextTenRecurringDates;
|
||||
this.humanReadable = humanReadable;
|
||||
this.recentEligibleMeetingDate = recentEligibleMeetingDate;
|
||||
this.createdDate = createdDate;
|
||||
this.lastUpdatedDate = lastUpdatedDate;
|
||||
this.createdByUserId = createdByUserId;
|
||||
this.createdByUsername = createdByUsername;
|
||||
this.lastUpdatedByUserId = lastUpdatedByUserId;
|
||||
this.lastUpdatedByUsername = lastUpdatedByUsername;
|
||||
this.entityTypeOptions = entityTypeOptions;
|
||||
this.calendarTypeOptions = calendarTypeOptions;
|
||||
this.remindByOptions = remindByOptions;
|
||||
this.frequencyOptions = repeatsOptions;
|
||||
this.repeatsOnDayOptions = repeatsOnDayOptions;
|
||||
}
|
||||
|
||||
public Long getId() {
|
||||
@@ -265,4 +293,31 @@ public class CalendarData {
|
||||
return this.humanReadable;
|
||||
}
|
||||
|
||||
|
||||
public Long getCalendarInstanceId() {
|
||||
return this.calendarInstanceId;
|
||||
}
|
||||
|
||||
public boolean isStartDateBeforeOrEqual(final LocalDate compareDate) {
|
||||
if (this.startDate != null && compareDate != null) {
|
||||
if (this.startDate.isBefore(compareDate) || this.startDate.equals(compareDate)) { return true; }
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
public boolean isEndDateAfterOrEqual(final LocalDate compareDate) {
|
||||
if (this.endDate != null && compareDate != null) {
|
||||
if (this.endDate.isAfter(compareDate) || this.endDate.isEqual(compareDate)) { return true; }
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
public boolean isBetweenStartAndEndDate(final LocalDate compareDate){
|
||||
if (isStartDateBeforeOrEqual(compareDate)){
|
||||
if (this.endDate == null || isEndDateAfterOrEqual(compareDate)){
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
+122
-21
@@ -6,12 +6,21 @@
|
||||
|
||||
package org.mifosplatform.portfolio.calendar.domain;
|
||||
|
||||
import static org.mifosplatform.portfolio.calendar.CalendarConstants.CALENDAR_RESOURCE_NAME;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Date;
|
||||
import java.util.HashSet;
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
|
||||
import javax.persistence.Column;
|
||||
import javax.persistence.Entity;
|
||||
import javax.persistence.FetchType;
|
||||
import javax.persistence.JoinColumn;
|
||||
import javax.persistence.OneToMany;
|
||||
import javax.persistence.Table;
|
||||
import javax.persistence.Temporal;
|
||||
import javax.persistence.TemporalType;
|
||||
@@ -19,7 +28,11 @@ import javax.persistence.TemporalType;
|
||||
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.domain.AbstractAuditableCustom;
|
||||
import org.mifosplatform.infrastructure.core.exception.PlatformApiDataValidationException;
|
||||
import org.mifosplatform.infrastructure.core.service.DateUtils;
|
||||
import org.mifosplatform.portfolio.calendar.CalendarConstants.CALENDAR_SUPPORTED_PARAMETERS;
|
||||
import org.mifosplatform.portfolio.calendar.exception.CalendarDateException;
|
||||
import org.mifosplatform.portfolio.calendar.exception.CalendarParameterUpdateNotSupportedException;
|
||||
@@ -68,6 +81,10 @@ public class Calendar extends AbstractAuditableCustom<AppUser, Long> {
|
||||
@Column(name = "second_reminder", nullable = true)
|
||||
private Integer secondReminder;
|
||||
|
||||
@OneToMany(fetch = FetchType.EAGER)
|
||||
@JoinColumn(name = "calendar_id")
|
||||
private Set<CalendarHistory> calendarHistory = new HashSet<CalendarHistory>();
|
||||
|
||||
protected Calendar() {
|
||||
|
||||
}
|
||||
@@ -75,18 +92,29 @@ public class Calendar extends AbstractAuditableCustom<AppUser, Long> {
|
||||
public Calendar(final String title, final String description, final String location, final LocalDate startDate,
|
||||
final LocalDate endDate, final Integer duration, final Integer typeId, final boolean repeating, final String recurrence,
|
||||
final Integer remindById, final Integer firstReminder, final Integer secondReminder) {
|
||||
|
||||
final List<ApiParameterError> dataValidationErrors = new ArrayList<ApiParameterError>();
|
||||
final DataValidatorBuilder baseDataValidator = new DataValidatorBuilder(dataValidationErrors).resource(CALENDAR_RESOURCE_NAME);
|
||||
|
||||
final CalendarType calendarType = CalendarType.fromInt(typeId);
|
||||
if (calendarType.isCollection() && !repeating) {
|
||||
baseDataValidator.reset().parameter(CALENDAR_SUPPORTED_PARAMETERS.REPEATING.getValue())
|
||||
.failWithCodeNoParameterAddedToErrorCode("must.repeat.for.collection.calendar");
|
||||
if (!dataValidationErrors.isEmpty()) { throw new PlatformApiDataValidationException(dataValidationErrors); }
|
||||
}
|
||||
|
||||
this.title = StringUtils.defaultIfEmpty(title, null);
|
||||
this.description = StringUtils.defaultIfEmpty(description, null);
|
||||
this.location = StringUtils.defaultIfEmpty(location, null);
|
||||
|
||||
if (null != startDate) {
|
||||
this.startDate = startDate.toDateMidnight().toDate();
|
||||
this.startDate = startDate.toDateTimeAtStartOfDay().toDate();
|
||||
} else {
|
||||
this.startDate = null;
|
||||
}
|
||||
|
||||
if (null != endDate) {
|
||||
this.endDate = endDate.toDateMidnight().toDate();
|
||||
this.endDate = endDate.toDateTimeAtStartOfDay().toDate();
|
||||
} else {
|
||||
this.endDate = null;
|
||||
}
|
||||
@@ -153,17 +181,22 @@ public class Calendar extends AbstractAuditableCustom<AppUser, Long> {
|
||||
|
||||
final String valueAsInput = command.stringValueOfParameterNamed(startDateParamName);
|
||||
final LocalDate newValue = command.localDateValueOfParameterNamed(startDateParamName);
|
||||
if (isStartDateBefore(newValue)) {
|
||||
final LocalDate currentDate = DateUtils.getLocalDateOfTenant();
|
||||
|
||||
if (newValue.isBefore(currentDate)) {
|
||||
final String defaultUserMessage = "New meeting effective from date cannot be in past";
|
||||
throw new CalendarDateException("new.start.date.cannot.be.in.past", defaultUserMessage, newValue,
|
||||
getStartDateLocalDate());
|
||||
}else if (isStartDateAfter(newValue) && isStartDateBeforeOrEqual(currentDate)) {
|
||||
//new meeting date should be on or after start date or current date
|
||||
final String defaultUserMessage = "New meeting effective from date cannot be a date before existing meeting start date";
|
||||
throw new CalendarDateException("new.start.date.before.existing.date", defaultUserMessage, newValue,
|
||||
getStartDateLocalDate());
|
||||
} else {
|
||||
actualChanges.put(startDateParamName, valueAsInput);
|
||||
actualChanges.put("dateFormat", dateFormatAsInput);
|
||||
actualChanges.put("locale", localeAsInput);
|
||||
this.startDate = newValue.toDate();
|
||||
} else {
|
||||
// new meeting start date should be greater than existing
|
||||
// meeting start date
|
||||
final String defaultUserMessage = "New meeting start on or after date cannot be a date before existing meeting start date";
|
||||
throw new CalendarDateException("new.start.date.before.existing.date", defaultUserMessage, newValue,
|
||||
getStartDateLocalDate());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -211,8 +244,21 @@ public class Calendar extends AbstractAuditableCustom<AppUser, Long> {
|
||||
this.repeating = newValue;
|
||||
}
|
||||
|
||||
//if repeating is false then update recurrence to NULL
|
||||
if(!this.repeating) this.recurrence = null;
|
||||
|
||||
final List<ApiParameterError> dataValidationErrors = new ArrayList<ApiParameterError>();
|
||||
final DataValidatorBuilder baseDataValidator = new DataValidatorBuilder(dataValidationErrors).resource(CALENDAR_RESOURCE_NAME);
|
||||
|
||||
final CalendarType calendarType = CalendarType.fromInt(this.typeId);
|
||||
if (calendarType.isCollection() && !this.repeating) {
|
||||
baseDataValidator.reset().parameter(CALENDAR_SUPPORTED_PARAMETERS.REPEATING.getValue())
|
||||
.failWithCodeNoParameterAddedToErrorCode("must.repeat.for.collection.calendar");
|
||||
if (!dataValidationErrors.isEmpty()) { throw new PlatformApiDataValidationException(dataValidationErrors); }
|
||||
}
|
||||
|
||||
final String newRecurrence = Calendar.constructRecurrence(command, this);
|
||||
if (this.recurrence != null && !newRecurrence.equalsIgnoreCase(this.recurrence)) {
|
||||
if (!StringUtils.isBlank(this.recurrence) && !newRecurrence.equalsIgnoreCase(this.recurrence)) {
|
||||
|
||||
// FIXME: AA - Is this restriction required only for collection type
|
||||
// meetings or for all?.
|
||||
@@ -319,9 +365,48 @@ public class Calendar extends AbstractAuditableCustom<AppUser, Long> {
|
||||
}
|
||||
return endDateLocalDate;
|
||||
}
|
||||
|
||||
public Set<CalendarHistory> history() {
|
||||
return this.calendarHistory;
|
||||
}
|
||||
|
||||
public boolean isStartDateBefore(final LocalDate newStartDate) {
|
||||
if (this.startDate != null && newStartDate != null && getStartDateLocalDate().isBefore(newStartDate)) { return true; }
|
||||
public boolean isStartDateBefore(final LocalDate compareDate) {
|
||||
if (this.startDate != null && compareDate != null && getStartDateLocalDate().isBefore(compareDate)) { return true; }
|
||||
return false;
|
||||
}
|
||||
|
||||
public boolean isStartDateBeforeOrEqual(final LocalDate compareDate) {
|
||||
if (this.startDate != null && compareDate != null) {
|
||||
if (getStartDateLocalDate().isBefore(compareDate) || getStartDateLocalDate().equals(compareDate)) { return true; }
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
public boolean isStartDateAfter(final LocalDate compareDate) {
|
||||
if (this.startDate != null && compareDate != null && getStartDateLocalDate().isAfter(compareDate)) { return true; }
|
||||
return false;
|
||||
}
|
||||
|
||||
public boolean isStartDateAfterOrEqual(final LocalDate compareDate) {
|
||||
if (this.startDate != null && compareDate != null) {
|
||||
if (getStartDateLocalDate().isAfter(compareDate) || getStartDateLocalDate().isEqual(compareDate)) { return true; }
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
public boolean isEndDateAfterOrEqual(final LocalDate compareDate) {
|
||||
if (this.endDate != null && compareDate != null) {
|
||||
if (getEndDateLocalDate().isAfter(compareDate) || getEndDateLocalDate().isEqual(compareDate)) { return true; }
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
public boolean isBetweenStartAndEndDate(final LocalDate compareDate){
|
||||
if (isStartDateBeforeOrEqual(compareDate)){
|
||||
if (getEndDateLocalDate() == null || isEndDateAfterOrEqual(compareDate)){
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -337,23 +422,39 @@ public class Calendar extends AbstractAuditableCustom<AppUser, Long> {
|
||||
|
||||
if (repeating) {
|
||||
final StringBuilder recurrenceBuilder = new StringBuilder(200);
|
||||
final String repeats = command.stringValueOfParameterNamed(CALENDAR_SUPPORTED_PARAMETERS.REPEATS.getValue());
|
||||
final Integer frequency = command.integerValueOfParameterNamed(CALENDAR_SUPPORTED_PARAMETERS.FREQUENCY.getValue());
|
||||
final CalendarFrequencyType frequencyType = CalendarFrequencyType.fromInt(frequency);
|
||||
recurrenceBuilder.append("FREQ=");
|
||||
recurrenceBuilder.append(repeats.toUpperCase());
|
||||
final Integer repeatsEvery = command.integerValueOfParameterNamed(CALENDAR_SUPPORTED_PARAMETERS.REPEATS_EVERY.getValue());
|
||||
if (repeatsEvery > 1) {
|
||||
recurrenceBuilder.append(frequencyType.toString().toUpperCase());
|
||||
final Integer interval = command.integerValueOfParameterNamed(CALENDAR_SUPPORTED_PARAMETERS.INTERVAL.getValue());
|
||||
if (interval > 1) {
|
||||
recurrenceBuilder.append(";INTERVAL=");
|
||||
recurrenceBuilder.append(repeatsEvery);
|
||||
recurrenceBuilder.append(interval);
|
||||
}
|
||||
if (repeats.equalsIgnoreCase("Weekly")) {
|
||||
final String repeatsOnDay = command.stringValueOfParameterNamed(CALENDAR_SUPPORTED_PARAMETERS.REPEATS_ON_DAY.getValue());
|
||||
if (repeatsOnDay != null && repeatsOnDay != "") {
|
||||
if (frequencyType.isWeekly()) {
|
||||
final Integer repeatsOnDay = command.integerValueOfParameterNamed(CALENDAR_SUPPORTED_PARAMETERS.REPEATS_ON_DAY.getValue());
|
||||
final CalendarWeekDaysType weekDays = CalendarWeekDaysType.fromInt(repeatsOnDay);
|
||||
if (!weekDays.isInvalid()) {
|
||||
recurrenceBuilder.append(";BYDAY=");
|
||||
recurrenceBuilder.append(repeatsOnDay);
|
||||
recurrenceBuilder.append(weekDays.toString().toUpperCase());
|
||||
}
|
||||
}
|
||||
return recurrenceBuilder.toString();
|
||||
}
|
||||
return "";
|
||||
}
|
||||
|
||||
public boolean isValidRecurringDate(final LocalDate compareDate) {
|
||||
|
||||
if (isBetweenStartAndEndDate(compareDate)) { return CalendarUtils.isValidRedurringDate(getRecurrence(), getStartDateLocalDate(),
|
||||
compareDate); }
|
||||
|
||||
// validate with history details.
|
||||
for (CalendarHistory history : history()) {
|
||||
if (history.isBetweenStartAndEndDate(compareDate)) { return CalendarUtils.isValidRedurringDate(history.getRecurrence(),
|
||||
history.getStartDateLocalDate(), compareDate); }
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
+32
@@ -82,4 +82,36 @@ public enum CalendarEntityType {
|
||||
public static boolean isCenter(final String name) {
|
||||
return CalendarEntityType.CENTERS.name().equalsIgnoreCase(name) ? true : false;
|
||||
}
|
||||
|
||||
public static boolean isLoan(final Integer value) {
|
||||
return CalendarEntityType.LOANS.value.equals(value) ? true : false;
|
||||
}
|
||||
|
||||
public static boolean isLoan(final String name) {
|
||||
return CalendarEntityType.LOANS.name().equalsIgnoreCase(name) ? true : false;
|
||||
}
|
||||
|
||||
public static boolean isClient(final Integer value) {
|
||||
return CalendarEntityType.CLIENTS.value.equals(value) ? true : false;
|
||||
}
|
||||
|
||||
public static boolean isClient(final String name) {
|
||||
return CalendarEntityType.CLIENTS.name().equalsIgnoreCase(name) ? true : false;
|
||||
}
|
||||
|
||||
public boolean isCenter() {
|
||||
return this.value.equals(CalendarEntityType.CENTERS.getValue());
|
||||
}
|
||||
|
||||
public boolean isGroup() {
|
||||
return this.value.equals(CalendarEntityType.GROUPS.getValue());
|
||||
}
|
||||
|
||||
public boolean isLoan() {
|
||||
return this.value.equals(CalendarEntityType.LOANS.getValue());
|
||||
}
|
||||
|
||||
public boolean isClient() {
|
||||
return this.value.equals(CalendarEntityType.CLIENTS.getValue());
|
||||
}
|
||||
}
|
||||
|
||||
+87
@@ -0,0 +1,87 @@
|
||||
/**
|
||||
* 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 java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
import org.springframework.util.StringUtils;
|
||||
|
||||
public enum CalendarFrequencyType {
|
||||
|
||||
INVALID(0, "calendarFrequencyType.invalid"), DAILY(1, "calendarFrequencyType.daily"), WEEKLY(2, "calendarFrequencyType.weekly"), MONTHLY(
|
||||
3, "calendarFrequencyType.monthly"), YEARLY(4, "calendarFrequencyType.yearly");
|
||||
|
||||
private final Integer value;
|
||||
private final String code;
|
||||
|
||||
private CalendarFrequencyType(final Integer value, final String code) {
|
||||
this.value = value;
|
||||
this.code = code;
|
||||
}
|
||||
|
||||
public Integer getValue() {
|
||||
return this.value;
|
||||
}
|
||||
|
||||
public String getCode() {
|
||||
return this.code;
|
||||
}
|
||||
|
||||
private static final Map<Integer, CalendarFrequencyType> intToEnumMap = new HashMap<Integer, CalendarFrequencyType>();
|
||||
private static int minValue = CalendarFrequencyType.DAILY.value;
|
||||
private static int maxValue = CalendarFrequencyType.YEARLY.value;
|
||||
|
||||
static {
|
||||
for (final CalendarFrequencyType type : CalendarFrequencyType.values()) {
|
||||
intToEnumMap.put(type.value, type);
|
||||
}
|
||||
}
|
||||
|
||||
public static CalendarFrequencyType fromInt(final int i) {
|
||||
final CalendarFrequencyType type = intToEnumMap.get(Integer.valueOf(i));
|
||||
return type;
|
||||
}
|
||||
|
||||
public static CalendarFrequencyType fromString(final String frequencyString) {
|
||||
CalendarFrequencyType frequency = CalendarFrequencyType.INVALID;
|
||||
|
||||
if (StringUtils.isEmpty(frequencyString)) return frequency;
|
||||
|
||||
if (frequencyString.equalsIgnoreCase(CalendarFrequencyType.DAILY.toString())) {
|
||||
frequency = CalendarFrequencyType.DAILY;
|
||||
} else if (frequencyString.equalsIgnoreCase(CalendarFrequencyType.WEEKLY.toString())) {
|
||||
frequency = CalendarFrequencyType.WEEKLY;
|
||||
} else if (frequencyString.equalsIgnoreCase(CalendarFrequencyType.MONTHLY.toString())) {
|
||||
frequency = CalendarFrequencyType.MONTHLY;
|
||||
} else if (frequencyString.equalsIgnoreCase(CalendarFrequencyType.YEARLY.toString())) {
|
||||
frequency = CalendarFrequencyType.YEARLY;
|
||||
}
|
||||
|
||||
return frequency;
|
||||
}
|
||||
|
||||
public static int getMinValue() {
|
||||
return minValue;
|
||||
}
|
||||
|
||||
public static int getMaxValue() {
|
||||
return maxValue;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return name().toString();
|
||||
}
|
||||
|
||||
public boolean isWeekly(){
|
||||
return this.value.equals(CalendarFrequencyType.WEEKLY.value);
|
||||
}
|
||||
|
||||
public boolean isInvalid(){
|
||||
return this.value.equals(CalendarFrequencyType.INVALID.value);
|
||||
}
|
||||
}
|
||||
+134
@@ -0,0 +1,134 @@
|
||||
/**
|
||||
* 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 java.util.Date;
|
||||
|
||||
import javax.persistence.Column;
|
||||
import javax.persistence.Entity;
|
||||
import javax.persistence.JoinColumn;
|
||||
import javax.persistence.ManyToOne;
|
||||
import javax.persistence.Table;
|
||||
import javax.persistence.Temporal;
|
||||
import javax.persistence.TemporalType;
|
||||
|
||||
import org.joda.time.LocalDate;
|
||||
import org.springframework.data.jpa.domain.AbstractPersistable;
|
||||
|
||||
@Entity
|
||||
@Table(name = "m_calendar_history")
|
||||
public class CalendarHistory extends AbstractPersistable<Long>{
|
||||
|
||||
@ManyToOne(optional = false)
|
||||
@JoinColumn(name = "calendar_id", referencedColumnName = "id", nullable = false)
|
||||
private Calendar calendar;
|
||||
|
||||
@Column(name = "title", length = 50, nullable = false)
|
||||
private String title;
|
||||
|
||||
@Column(name = "description", length = 100, nullable = true)
|
||||
private String description;
|
||||
|
||||
@Column(name = "location", length = 100, nullable = true)
|
||||
private String location;
|
||||
|
||||
@Column(name = "start_date", nullable = false)
|
||||
@Temporal(TemporalType.DATE)
|
||||
private Date startDate;
|
||||
|
||||
@Column(name = "end_date", nullable = true)
|
||||
@Temporal(TemporalType.DATE)
|
||||
private Date endDate;
|
||||
|
||||
@Column(name = "duration", nullable = true)
|
||||
private Integer duration;
|
||||
|
||||
@Column(name = "calendar_type_enum", nullable = false)
|
||||
private Integer typeId;
|
||||
|
||||
@Column(name = "repeating", nullable = false)
|
||||
private boolean repeating = false;
|
||||
|
||||
@Column(name = "recurrence", length = 100, nullable = true)
|
||||
private String recurrence;
|
||||
|
||||
@Column(name = "remind_by_enum", nullable = true)
|
||||
private Integer remindById;
|
||||
|
||||
@Column(name = "first_reminder", nullable = true)
|
||||
private Integer firstReminder;
|
||||
|
||||
@Column(name = "second_reminder", nullable = true)
|
||||
private Integer secondReminder;
|
||||
|
||||
protected CalendarHistory() {
|
||||
|
||||
}
|
||||
|
||||
public CalendarHistory(Calendar calendar, Date startDate) {
|
||||
this.calendar = calendar;
|
||||
this.title = calendar.getTitle();
|
||||
this.description = calendar.getDescription();
|
||||
this.location = calendar.getLocation();
|
||||
this.startDate = startDate;
|
||||
this.endDate = calendar.getStartDate();//Calendar start date become end date for history data.
|
||||
this.duration = calendar.getDuration();
|
||||
this.typeId = calendar.getTypeId();
|
||||
this.repeating = calendar.isRepeating();
|
||||
this.recurrence = calendar.getRecurrence();
|
||||
this.remindById = calendar.getRemindById();
|
||||
this.firstReminder = calendar.getFirstReminder();
|
||||
this.secondReminder = calendar.getSecondReminder();
|
||||
}
|
||||
|
||||
public String getRecurrence() {
|
||||
return this.recurrence;
|
||||
}
|
||||
|
||||
public LocalDate getStartDateLocalDate() {
|
||||
LocalDate startDateLocalDate = null;
|
||||
if (this.startDate != null) {
|
||||
startDateLocalDate = LocalDate.fromDateFields(this.startDate);
|
||||
}
|
||||
return startDateLocalDate;
|
||||
}
|
||||
|
||||
public LocalDate getEndDateLocalDate() {
|
||||
LocalDate endDateLocalDate = null;
|
||||
if (this.endDate != null) {
|
||||
endDateLocalDate = LocalDate.fromDateFields(this.endDate);
|
||||
}
|
||||
return endDateLocalDate;
|
||||
}
|
||||
|
||||
public boolean isEndDateAfterOrEqual(final LocalDate compareDate) {
|
||||
if (this.endDate != null && compareDate != null) {
|
||||
if (getEndDateLocalDate().isAfter(compareDate) || getEndDateLocalDate().isEqual(compareDate)) { return true; }
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
public boolean isStartDateBeforeOrEqual(final LocalDate compareDate) {
|
||||
if (this.startDate != null && compareDate != null) {
|
||||
if (getStartDateLocalDate().isBefore(compareDate) || getStartDateLocalDate().equals(compareDate)) { return true; }
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
public boolean isBetweenStartAndEndDate(final LocalDate compareDate){
|
||||
if (isStartDateBeforeOrEqual(compareDate)){
|
||||
if (getEndDateLocalDate() == null || isEndDateAfterOrEqual(compareDate)){
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
public void updateEndDate(Date historyCalEndDate){
|
||||
this.endDate = historyCalEndDate;
|
||||
}
|
||||
}
|
||||
+13
@@ -0,0 +1,13 @@
|
||||
/**
|
||||
* 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.springframework.data.jpa.repository.JpaRepository;
|
||||
import org.springframework.data.jpa.repository.JpaSpecificationExecutor;
|
||||
|
||||
public interface CalendarHistoryRepository extends JpaRepository<CalendarHistory, Long>, JpaSpecificationExecutor<CalendarHistory> {
|
||||
|
||||
}
|
||||
+4
@@ -66,4 +66,8 @@ public enum CalendarType {
|
||||
public String toString() {
|
||||
return name().toString();
|
||||
}
|
||||
|
||||
public boolean isCollection(){
|
||||
return this.value.equals(CalendarType.COLLECTION.value);
|
||||
}
|
||||
}
|
||||
|
||||
+91
@@ -0,0 +1,91 @@
|
||||
/**
|
||||
* 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 java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
import org.springframework.util.StringUtils;
|
||||
|
||||
public enum CalendarWeekDaysType {
|
||||
|
||||
INVALID(0, "calendarWeekDaysType.invalid"), MO(1, "calendarWeekDaysType.monday"), TU(2, "calendarWeekDaysType.tuesday"), WE(3,
|
||||
"calendarWeekDaysType.wednesday"), TH(4, "calendarWeekDaysType.thursday"), FR(5, "calendarWeekDaysType.friday"), SA(6,
|
||||
"calendarWeekDaysType.saturday"), SU(7, "calendarWeekDaysType.sunday");
|
||||
|
||||
private final Integer value;
|
||||
private final String code;
|
||||
|
||||
private CalendarWeekDaysType(final Integer value, final String code) {
|
||||
this.value = value;
|
||||
this.code = code;
|
||||
}
|
||||
|
||||
public Integer getValue() {
|
||||
return this.value;
|
||||
}
|
||||
|
||||
public String getCode() {
|
||||
return this.code;
|
||||
}
|
||||
|
||||
private static final Map<Integer, CalendarWeekDaysType> intToEnumMap = new HashMap<Integer, CalendarWeekDaysType>();
|
||||
private static int minValue = CalendarWeekDaysType.MO.value;
|
||||
private static int maxValue = CalendarWeekDaysType.SU.value;
|
||||
|
||||
static {
|
||||
for (final CalendarWeekDaysType type : CalendarWeekDaysType.values()) {
|
||||
intToEnumMap.put(type.value, type);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public static CalendarWeekDaysType fromInt(final int i) {
|
||||
final CalendarWeekDaysType type = intToEnumMap.get(Integer.valueOf(i));
|
||||
return type;
|
||||
}
|
||||
|
||||
public static int getMinValue() {
|
||||
return minValue;
|
||||
}
|
||||
|
||||
public static int getMaxValue() {
|
||||
return maxValue;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return name().toString();
|
||||
}
|
||||
|
||||
public boolean isInvalid(){
|
||||
return this.value.equals(CalendarWeekDaysType.INVALID.value);
|
||||
}
|
||||
|
||||
public static CalendarWeekDaysType fromString(final String weekDayString) {
|
||||
CalendarWeekDaysType weekDay = CalendarWeekDaysType.INVALID;
|
||||
|
||||
if (StringUtils.isEmpty(weekDayString)) return weekDay;
|
||||
|
||||
if (weekDayString.equalsIgnoreCase(CalendarWeekDaysType.MO.toString())) {
|
||||
weekDay = CalendarWeekDaysType.MO;
|
||||
} else if (weekDayString.equalsIgnoreCase(CalendarWeekDaysType.TU.toString())) {
|
||||
weekDay = CalendarWeekDaysType.TU;
|
||||
} else if (weekDayString.equalsIgnoreCase(CalendarWeekDaysType.WE.toString())) {
|
||||
weekDay = CalendarWeekDaysType.WE;
|
||||
} else if (weekDayString.equalsIgnoreCase(CalendarWeekDaysType.TH.toString())) {
|
||||
weekDay = CalendarWeekDaysType.TH;
|
||||
} else if (weekDayString.equalsIgnoreCase(CalendarWeekDaysType.FR.toString())) {
|
||||
weekDay = CalendarWeekDaysType.FR;
|
||||
} else if (weekDayString.equalsIgnoreCase(CalendarWeekDaysType.SA.toString())) {
|
||||
weekDay = CalendarWeekDaysType.SA;
|
||||
} else if (weekDayString.equalsIgnoreCase(CalendarWeekDaysType.SU.toString())) {
|
||||
weekDay = CalendarWeekDaysType.SU;
|
||||
}
|
||||
|
||||
return weekDay;
|
||||
}
|
||||
}
|
||||
+23
-20
@@ -22,7 +22,9 @@ import org.mifosplatform.infrastructure.core.serialization.FromJsonHelper;
|
||||
import org.mifosplatform.portfolio.calendar.CalendarConstants.CALENDAR_SUPPORTED_PARAMETERS;
|
||||
import org.mifosplatform.portfolio.calendar.command.CalendarCommand;
|
||||
import org.mifosplatform.portfolio.calendar.domain.CalendarEntityType;
|
||||
import org.mifosplatform.portfolio.calendar.domain.CalendarFrequencyType;
|
||||
import org.mifosplatform.portfolio.calendar.domain.CalendarRemindBy;
|
||||
import org.mifosplatform.portfolio.calendar.domain.CalendarWeekDaysType;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
@@ -141,22 +143,22 @@ public class CalendarCommandFromApiJsonDeserializer extends AbstractFromApiJsonD
|
||||
baseDataValidator.reset().parameter(CALENDAR_SUPPORTED_PARAMETERS.REPEATING.getValue()).value(repeating).notNull();
|
||||
|
||||
if (repeating) {
|
||||
final String repeats = this.fromApiJsonHelper.extractStringNamed(CALENDAR_SUPPORTED_PARAMETERS.REPEATS.getValue(), element);
|
||||
baseDataValidator.reset().parameter(CALENDAR_SUPPORTED_PARAMETERS.REPEATS.getValue()).value(repeats).notBlank()
|
||||
.notExceedingLengthOf(20);
|
||||
final Integer frequency = this.fromApiJsonHelper.extractIntegerSansLocaleNamed(
|
||||
CALENDAR_SUPPORTED_PARAMETERS.FREQUENCY.getValue(), element);
|
||||
baseDataValidator.reset().parameter(CALENDAR_SUPPORTED_PARAMETERS.FREQUENCY.getValue()).value(frequency).notBlank()
|
||||
.inMinMaxRange(CalendarFrequencyType.getMinValue(), CalendarFrequencyType.getMaxValue());
|
||||
|
||||
if (this.fromApiJsonHelper.parameterExists(CALENDAR_SUPPORTED_PARAMETERS.REPEATS_EVERY.getValue(), element)) {
|
||||
final Integer repeatsEvery = this.fromApiJsonHelper.extractIntegerSansLocaleNamed(
|
||||
CALENDAR_SUPPORTED_PARAMETERS.REPEATS_EVERY.getValue(), element);
|
||||
baseDataValidator.reset().parameter(CALENDAR_SUPPORTED_PARAMETERS.REPEATS_EVERY.getValue()).value(repeatsEvery)
|
||||
if (this.fromApiJsonHelper.parameterExists(CALENDAR_SUPPORTED_PARAMETERS.INTERVAL.getValue(), element)) {
|
||||
final Integer interval = this.fromApiJsonHelper.extractIntegerSansLocaleNamed(
|
||||
CALENDAR_SUPPORTED_PARAMETERS.INTERVAL.getValue(), element);
|
||||
baseDataValidator.reset().parameter(CALENDAR_SUPPORTED_PARAMETERS.INTERVAL.getValue()).value(interval)
|
||||
.notNull().integerGreaterThanZero();
|
||||
}
|
||||
|
||||
if (this.fromApiJsonHelper.parameterExists(CALENDAR_SUPPORTED_PARAMETERS.REPEATS_ON_DAY.getValue(), element)) {
|
||||
final String repeatsOnDay = this.fromApiJsonHelper.extractStringNamed(
|
||||
if (CalendarFrequencyType.fromInt(frequency).isWeekly()) {
|
||||
final Integer repeatsOnDay = this.fromApiJsonHelper.extractIntegerSansLocaleNamed(
|
||||
CALENDAR_SUPPORTED_PARAMETERS.REPEATS_ON_DAY.getValue(), element);
|
||||
baseDataValidator.reset().parameter(CALENDAR_SUPPORTED_PARAMETERS.REPEATS_ON_DAY.getValue()).value(repeatsOnDay)
|
||||
.notBlank().notNull();
|
||||
.notBlank().inMinMaxRange(CalendarWeekDaysType.getMinValue(), CalendarWeekDaysType.getMaxValue());
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -251,22 +253,23 @@ public class CalendarCommandFromApiJsonDeserializer extends AbstractFromApiJsonD
|
||||
baseDataValidator.reset().parameter(CALENDAR_SUPPORTED_PARAMETERS.REPEATING.getValue()).value(repeating).notNull();
|
||||
|
||||
if (repeating) {
|
||||
final String repeats = this.fromApiJsonHelper.extractStringNamed(CALENDAR_SUPPORTED_PARAMETERS.REPEATS.getValue(), element);
|
||||
baseDataValidator.reset().parameter(CALENDAR_SUPPORTED_PARAMETERS.REPEATS.getValue()).value(repeats).ignoreIfNull()
|
||||
.notBlank().notExceedingLengthOf(20);
|
||||
final Integer frequency = this.fromApiJsonHelper.extractIntegerSansLocaleNamed(
|
||||
CALENDAR_SUPPORTED_PARAMETERS.FREQUENCY.getValue(), element);
|
||||
baseDataValidator.reset().parameter(CALENDAR_SUPPORTED_PARAMETERS.FREQUENCY.getValue()).value(frequency).notBlank()
|
||||
.inMinMaxRange(CalendarFrequencyType.getMinValue(), CalendarFrequencyType.getMaxValue());
|
||||
|
||||
if (this.fromApiJsonHelper.parameterExists(CALENDAR_SUPPORTED_PARAMETERS.REPEATS_EVERY.getValue(), element)) {
|
||||
final Integer repeatsEvery = this.fromApiJsonHelper.extractIntegerSansLocaleNamed(
|
||||
CALENDAR_SUPPORTED_PARAMETERS.REPEATS_EVERY.getValue(), element);
|
||||
baseDataValidator.reset().parameter(CALENDAR_SUPPORTED_PARAMETERS.REPEATS_EVERY.getValue()).value(repeatsEvery)
|
||||
if (this.fromApiJsonHelper.parameterExists(CALENDAR_SUPPORTED_PARAMETERS.INTERVAL.getValue(), element)) {
|
||||
final Integer interval = this.fromApiJsonHelper.extractIntegerSansLocaleNamed(
|
||||
CALENDAR_SUPPORTED_PARAMETERS.INTERVAL.getValue(), element);
|
||||
baseDataValidator.reset().parameter(CALENDAR_SUPPORTED_PARAMETERS.INTERVAL.getValue()).value(interval)
|
||||
.notNull().integerGreaterThanZero();
|
||||
}
|
||||
|
||||
if (this.fromApiJsonHelper.parameterExists(CALENDAR_SUPPORTED_PARAMETERS.REPEATS_ON_DAY.getValue(), element)) {
|
||||
final String repeatsOnDay = this.fromApiJsonHelper.extractStringNamed(
|
||||
final Integer repeatsOnDay = this.fromApiJsonHelper.extractIntegerSansLocaleNamed(
|
||||
CALENDAR_SUPPORTED_PARAMETERS.REPEATS_ON_DAY.getValue(), element);
|
||||
baseDataValidator.reset().parameter(CALENDAR_SUPPORTED_PARAMETERS.REPEATS_ON_DAY.getValue()).value(repeatsOnDay)
|
||||
.notBlank();
|
||||
.notBlank().inMinMaxRange(CalendarWeekDaysType.getMinValue(), CalendarWeekDaysType.getMaxValue());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+4
@@ -16,5 +16,9 @@ public interface CalendarDropdownReadPlatformService {
|
||||
List<EnumOptionData> retrieveCalendarTypeOptions();
|
||||
|
||||
List<EnumOptionData> retrieveCalendarRemindByOptions();
|
||||
|
||||
List<EnumOptionData> retrieveCalendarFrequencyTypeOptions();
|
||||
|
||||
List<EnumOptionData> retrieveCalendarWeekDaysTypeOptions();
|
||||
|
||||
}
|
||||
+11
@@ -9,8 +9,10 @@ import java.util.List;
|
||||
|
||||
import org.mifosplatform.infrastructure.core.data.EnumOptionData;
|
||||
import org.mifosplatform.portfolio.calendar.domain.CalendarEntityType;
|
||||
import org.mifosplatform.portfolio.calendar.domain.CalendarFrequencyType;
|
||||
import org.mifosplatform.portfolio.calendar.domain.CalendarRemindBy;
|
||||
import org.mifosplatform.portfolio.calendar.domain.CalendarType;
|
||||
import org.mifosplatform.portfolio.calendar.domain.CalendarWeekDaysType;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
@Service
|
||||
@@ -31,4 +33,13 @@ public class CalendarDropdownReadPlatformServiceImpl implements CalendarDropdown
|
||||
return CalendarEnumerations.calendarRemindBy(CalendarRemindBy.values());
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<EnumOptionData> retrieveCalendarFrequencyTypeOptions() {
|
||||
return CalendarEnumerations.calendarFrequencyType(CalendarFrequencyType.values());
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<EnumOptionData> retrieveCalendarWeekDaysTypeOptions() {
|
||||
return CalendarEnumerations.calendarWeekDaysType(CalendarWeekDaysType.values());
|
||||
}
|
||||
}
|
||||
|
||||
+40
@@ -10,8 +10,10 @@ import java.util.List;
|
||||
|
||||
import org.mifosplatform.infrastructure.core.data.EnumOptionData;
|
||||
import org.mifosplatform.portfolio.calendar.domain.CalendarEntityType;
|
||||
import org.mifosplatform.portfolio.calendar.domain.CalendarFrequencyType;
|
||||
import org.mifosplatform.portfolio.calendar.domain.CalendarRemindBy;
|
||||
import org.mifosplatform.portfolio.calendar.domain.CalendarType;
|
||||
import org.mifosplatform.portfolio.calendar.domain.CalendarWeekDaysType;
|
||||
|
||||
public class CalendarEnumerations {
|
||||
|
||||
@@ -65,4 +67,42 @@ public class CalendarEnumerations {
|
||||
}
|
||||
return optionDatas;
|
||||
}
|
||||
|
||||
public static EnumOptionData calendarFrequencyType(final int id) {
|
||||
return calendarFrequencyType(CalendarFrequencyType.fromInt(id));
|
||||
}
|
||||
|
||||
public static EnumOptionData calendarFrequencyType(final CalendarFrequencyType calendarFrequencyType) {
|
||||
final EnumOptionData optionData = new EnumOptionData(calendarFrequencyType.getValue().longValue(), calendarFrequencyType.getCode(), calendarFrequencyType.toString());
|
||||
return optionData;
|
||||
}
|
||||
|
||||
public static List<EnumOptionData> calendarFrequencyType(final CalendarFrequencyType[] calendarFrequencyTypes) {
|
||||
final List<EnumOptionData> optionDatas = new ArrayList<EnumOptionData>();
|
||||
for (final CalendarFrequencyType calendarFrequencyType : calendarFrequencyTypes) {
|
||||
if(!calendarFrequencyType.isInvalid()){
|
||||
optionDatas.add(calendarFrequencyType(calendarFrequencyType));
|
||||
}
|
||||
}
|
||||
return optionDatas;
|
||||
}
|
||||
|
||||
public static EnumOptionData calendarWeekDaysType(final int id) {
|
||||
return calendarWeekDaysType(CalendarWeekDaysType.fromInt(id));
|
||||
}
|
||||
|
||||
public static EnumOptionData calendarWeekDaysType(final CalendarWeekDaysType calendarWeekDaysType) {
|
||||
final EnumOptionData optionData = new EnumOptionData(calendarWeekDaysType.getValue().longValue(), calendarWeekDaysType.getCode(), calendarWeekDaysType.toString());
|
||||
return optionData;
|
||||
}
|
||||
|
||||
public static List<EnumOptionData> calendarWeekDaysType(final CalendarWeekDaysType[] calendarWeekDaysTypes) {
|
||||
final List<EnumOptionData> optionDatas = new ArrayList<EnumOptionData>();
|
||||
for (final CalendarWeekDaysType calendarWeekDaysType : calendarWeekDaysTypes) {
|
||||
if(!calendarWeekDaysType.isInvalid()){
|
||||
optionDatas.add(calendarWeekDaysType(calendarWeekDaysType));
|
||||
}
|
||||
}
|
||||
return optionDatas;
|
||||
}
|
||||
}
|
||||
|
||||
+6
-3
@@ -10,6 +10,7 @@ import java.util.List;
|
||||
|
||||
import org.joda.time.LocalDate;
|
||||
import org.mifosplatform.portfolio.calendar.data.CalendarData;
|
||||
import org.mifosplatform.portfolio.meeting.data.MeetingData;
|
||||
|
||||
public interface CalendarReadPlatformService {
|
||||
|
||||
@@ -24,14 +25,16 @@ public interface CalendarReadPlatformService {
|
||||
|
||||
CalendarData retrieveNewCalendarDetails();
|
||||
|
||||
CalendarData generateRecurringDate(final CalendarData calendarData);
|
||||
Collection<LocalDate> generateRecurringDates(final CalendarData calendarData, final boolean withHistory, final LocalDate tillDate);
|
||||
|
||||
CalendarData generateRecurringDate(final CalendarData calendarData, final LocalDate tillDate);
|
||||
Collection<LocalDate> generateNextTenRecurringDates(final CalendarData calendarData);
|
||||
|
||||
Collection<CalendarData> generateRecurringDates(final Collection<CalendarData> calendarsData);
|
||||
Collection<CalendarData> updateWithRecurringDates(final Collection<CalendarData> calendarsData);
|
||||
|
||||
CalendarData retrieveLoanCalendar(final Long loanId);
|
||||
|
||||
CalendarData retrieveCollctionCalendarByEntity(final Long entityId, final Integer entityTypeId);
|
||||
|
||||
LocalDate generateNextEligibleMeetingDateForCollection(CalendarData calendarData, MeetingData lastMeetingData);
|
||||
|
||||
}
|
||||
|
||||
+203
-30
@@ -20,6 +20,7 @@ import org.mifosplatform.portfolio.calendar.data.CalendarData;
|
||||
import org.mifosplatform.portfolio.calendar.domain.CalendarEntityType;
|
||||
import org.mifosplatform.portfolio.calendar.domain.CalendarType;
|
||||
import org.mifosplatform.portfolio.calendar.exception.CalendarNotFoundException;
|
||||
import org.mifosplatform.portfolio.meeting.data.MeetingData;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.dao.EmptyResultDataAccessException;
|
||||
import org.springframework.jdbc.core.JdbcTemplate;
|
||||
@@ -40,7 +41,7 @@ public class CalendarReadPlatformServiceImpl implements CalendarReadPlatformServ
|
||||
private static final class CalendarDataMapper implements RowMapper<CalendarData> {
|
||||
|
||||
public String schema() {
|
||||
return " select c.id as id, ci.entity_id as entityId, ci.entity_type_enum as entityTypeId, c.title as title, "
|
||||
return " select c.id as id, ci.id as calendarInstanceId, ci.entity_id as entityId, ci.entity_type_enum as entityTypeId, c.title as title, "
|
||||
+ " c.description as description, c.location as location, c.start_date as startDate, c.end_date as endDate, "
|
||||
+ " c.duration as duration, c.calendar_type_enum as typeId, c.repeating as repeating, "
|
||||
+ " c.recurrence as recurrence, c.remind_by_enum as remindById, c.first_reminder as firstReminder, c.second_reminder as secondReminder, "
|
||||
@@ -54,6 +55,7 @@ public class CalendarReadPlatformServiceImpl implements CalendarReadPlatformServ
|
||||
public CalendarData mapRow(final ResultSet rs, @SuppressWarnings("unused") final int rowNum) throws SQLException {
|
||||
|
||||
final Long id = rs.getLong("id");
|
||||
final Long calendarInstanceId = rs.getLong("calendarInstanceId");
|
||||
final Long entityId = rs.getLong("entityId");
|
||||
final Integer entityTypeId = rs.getInt("entityTypeId");
|
||||
final EnumOptionData entityType = CalendarEnumerations.calendarEntityType(entityTypeId);
|
||||
@@ -67,6 +69,9 @@ public class CalendarReadPlatformServiceImpl implements CalendarReadPlatformServ
|
||||
final EnumOptionData type = CalendarEnumerations.calendarType(typeId);
|
||||
final boolean repeating = rs.getBoolean("repeating");
|
||||
final String recurrence = rs.getString("recurrence");
|
||||
final EnumOptionData frequency = CalendarEnumerations.calendarFrequencyType(CalendarUtils.getFrequency(recurrence));
|
||||
final Integer interval = new Integer(CalendarUtils.getInterval(recurrence));
|
||||
final EnumOptionData repeatsOnDay = CalendarEnumerations.calendarWeekDaysType(CalendarUtils.getRepeatsOnDay(recurrence));
|
||||
final Integer remindById = rs.getInt("remindById");
|
||||
EnumOptionData remindBy = null;
|
||||
if (remindById != null && remindById != 0) {
|
||||
@@ -86,11 +91,10 @@ public class CalendarReadPlatformServiceImpl implements CalendarReadPlatformServ
|
||||
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, recentEligibleMeetingDate, createdDate,
|
||||
lastUpdatedDate, createdByUserId, createdByUserName, lastUpdatedByUserId, lastUpdatedByUserName);
|
||||
return CalendarData.instance(id, calendarInstanceId, entityId, entityType, title, description, location, startDate, endDate,
|
||||
duration, type, repeating, recurrence, frequency, interval, repeatsOnDay, remindBy, firstReminder, secondReminder,
|
||||
humanReadable, createdDate, lastUpdatedDate, createdByUserId, createdByUserName, lastUpdatedByUserId,
|
||||
lastUpdatedByUserName);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -183,49 +187,139 @@ public class CalendarReadPlatformServiceImpl implements CalendarReadPlatformServ
|
||||
}
|
||||
|
||||
@Override
|
||||
public CalendarData generateRecurringDate(final CalendarData calendarData) {
|
||||
return generateRecurringDate(calendarData, null);
|
||||
public Collection<LocalDate> generateRecurringDates(final CalendarData calendarData, final boolean withHistory, final LocalDate tillDate) {
|
||||
final LocalDate fromDate = null;
|
||||
Collection<LocalDate> recurringDates = generateRecurringDate(calendarData, fromDate, tillDate, -1);
|
||||
|
||||
if (withHistory) {
|
||||
final Collection<CalendarData> calendarHistorys = this.retrieveCalendarsFromHistory(calendarData.getId());
|
||||
for (CalendarData calendarHistory : calendarHistorys) {
|
||||
recurringDates.addAll(generateRecurringDate(calendarHistory, fromDate, tillDate, -1));
|
||||
}
|
||||
}
|
||||
|
||||
return recurringDates;
|
||||
}
|
||||
|
||||
@Override
|
||||
public CalendarData generateRecurringDate(final CalendarData calendarData, final LocalDate tillDate) {
|
||||
if (!calendarData.isRepeating()) { return calendarData; }
|
||||
public Collection<LocalDate> generateNextTenRecurringDates(CalendarData calendarData) {
|
||||
final LocalDate tillDate = null;
|
||||
return generateRecurringDate(calendarData, DateUtils.getLocalDateOfTenant(), tillDate, 10);
|
||||
}
|
||||
|
||||
private Collection<LocalDate> generateRecurringDate(final CalendarData calendarData, final LocalDate fromDate, final LocalDate tillDate, final int maxCount) {
|
||||
|
||||
if (!calendarData.isRepeating()) { return null; }
|
||||
final String rrule = calendarData.getRecurrence();
|
||||
final LocalDate currentDate = DateUtils.getLocalDateOfTenant();
|
||||
final LocalDate seedDate = calendarData.getStartDate();
|
||||
LocalDate endDate = calendarData.getEndDate();
|
||||
LocalDate startDate = calendarData.getStartDate();
|
||||
if (seedDate.isBefore(currentDate.minusYears(1))) {
|
||||
startDate = currentDate.minusYears(1);
|
||||
/**
|
||||
* Start date or effective from date of calendar recurrence.
|
||||
*/
|
||||
final LocalDate seedDate = this.getSeedDate(calendarData.getStartDate());
|
||||
/**
|
||||
* periodStartDate date onwards recurring dates will be generated.
|
||||
*/
|
||||
final LocalDate periodStartDate = this.getPeriodStartDate(seedDate, calendarData.getStartDate(), fromDate);
|
||||
/**
|
||||
* till periodEndDate recurring dates will be generated.
|
||||
*/
|
||||
final LocalDate periodEndDate = this.getPeriodEndDate(calendarData.getEndDate(), tillDate);
|
||||
|
||||
final Collection<LocalDate> recurringDates = CalendarUtils.getRecurringDates(rrule, seedDate, periodStartDate, periodEndDate,
|
||||
maxCount);
|
||||
return recurringDates;
|
||||
}
|
||||
|
||||
private LocalDate getSeedDate(LocalDate date) {
|
||||
return date;
|
||||
}
|
||||
|
||||
private LocalDate getPeriodStartDate(final LocalDate seedDate, final LocalDate recurrenceStartDate, final LocalDate fromDate) {
|
||||
LocalDate periodStartDate = null;
|
||||
if(fromDate != null) {
|
||||
periodStartDate = fromDate;
|
||||
}else {
|
||||
final LocalDate currentDate = DateUtils.getLocalDateOfTenant();
|
||||
if (seedDate.isBefore(currentDate.minusYears(1))) {
|
||||
periodStartDate = currentDate.minusYears(1);
|
||||
}else{
|
||||
periodStartDate = recurrenceStartDate;
|
||||
}
|
||||
}
|
||||
return periodStartDate;
|
||||
}
|
||||
|
||||
private LocalDate getPeriodEndDate(LocalDate endDate, LocalDate tillDate) {
|
||||
LocalDate periodEndDate = endDate;
|
||||
final LocalDate currentDate = DateUtils.getLocalDateOfTenant();
|
||||
|
||||
if (tillDate != null) {
|
||||
if (endDate != null) {
|
||||
if (endDate.isAfter(tillDate)) {
|
||||
endDate = tillDate;// to retrieve meeting dates till
|
||||
// specified date (tillDate)
|
||||
// to retrieve meeting dates tillspecified date (tillDate)
|
||||
periodEndDate = tillDate;
|
||||
}
|
||||
} else {
|
||||
endDate = tillDate;// end date is null then fetch meeting dates
|
||||
// tillDate
|
||||
// end date is null then fetch meeting dates tillDate
|
||||
periodEndDate = tillDate;
|
||||
}
|
||||
} else if (endDate == null || endDate.isAfter(currentDate.plusYears(1))) {
|
||||
endDate = currentDate.plusYears(1);
|
||||
periodEndDate = currentDate.plusYears(1);
|
||||
}
|
||||
|
||||
final Collection<LocalDate> recurringDates = CalendarUtils.getRecurringDates(rrule, seedDate, startDate, endDate, -1);
|
||||
final Collection<LocalDate> nextTenRecurringDates = CalendarUtils.getRecurringDates(rrule, seedDate, endDate);
|
||||
final LocalDate recentEligibleMeetingDate = CalendarUtils.getRecentEligibleMeetingDate(rrule, seedDate);
|
||||
return new CalendarData(calendarData, recurringDates, nextTenRecurringDates, recentEligibleMeetingDate);
|
||||
|
||||
return periodEndDate;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Collection<CalendarData> generateRecurringDates(final Collection<CalendarData> calendarsData) {
|
||||
final Collection<CalendarData> recuCalendarsData = new ArrayList<CalendarData>();
|
||||
public LocalDate generateNextEligibleMeetingDateForCollection(final CalendarData calendarData, final MeetingData lastMeetingData) {
|
||||
|
||||
final LocalDate lastMeetingDate = (lastMeetingData == null) ? null : lastMeetingData.getMeetingDate();
|
||||
// get applicable calendar based on meeting date
|
||||
CalendarData applicableCalendarData = calendarData;
|
||||
LocalDate nextEligibleMeetingDate = null;
|
||||
/**
|
||||
* The next available meeting date for collection should be taken from
|
||||
* application calendar for that time period. e.g. If the previous
|
||||
* calendar details has weekly meeting starting from 1st of Oct 2013 on
|
||||
* every Tuesday, then meeting dates for collection are 1,8,15,22,29..
|
||||
*
|
||||
* If meeting schedule has changed from Tuesday to Friday with effective
|
||||
* from 15th of Oct (calendar update has made on 2nd of Oct) , then
|
||||
* application should allow to generate collection sheet on 8th of Oct
|
||||
* which is still on Tuesday and next collection sheet date should be on
|
||||
* 18th of Oct as per current calendar
|
||||
*/
|
||||
if (lastMeetingDate != null && !calendarData.isBetweenStartAndEndDate(lastMeetingDate)
|
||||
&& !calendarData.isBetweenStartAndEndDate(DateUtils.getLocalDateOfTenant())) {
|
||||
applicableCalendarData = this.retrieveApplicableCalendarFromHistory(calendarData.getId(), lastMeetingDate);
|
||||
nextEligibleMeetingDate = CalendarUtils.getRecentEligibleMeetingDate(applicableCalendarData.getRecurrence(), lastMeetingDate);
|
||||
}
|
||||
|
||||
/**
|
||||
* If nextEligibleMeetingDate is on or after current calendar startdate
|
||||
* then regenerate the nextEligible meeting date based on
|
||||
*/
|
||||
if (nextEligibleMeetingDate == null) {
|
||||
final LocalDate seedDate = (lastMeetingDate != null) ? lastMeetingDate : calendarData.getStartDate();
|
||||
nextEligibleMeetingDate = CalendarUtils.getRecentEligibleMeetingDate(applicableCalendarData.getRecurrence(), seedDate);
|
||||
} else if (calendarData.isBetweenStartAndEndDate(nextEligibleMeetingDate)) {
|
||||
nextEligibleMeetingDate = CalendarUtils.getRecentEligibleMeetingDate(applicableCalendarData.getRecurrence(),
|
||||
calendarData.getStartDate());
|
||||
}
|
||||
|
||||
return nextEligibleMeetingDate;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Collection<CalendarData> updateWithRecurringDates(final Collection<CalendarData> calendarsData) {
|
||||
final Collection<CalendarData> recuCalendarsData = new ArrayList<CalendarData>();
|
||||
final boolean withHistory = true;
|
||||
final LocalDate tillDate = null;
|
||||
for (final CalendarData calendarData : calendarsData) {
|
||||
recuCalendarsData.add(generateRecurringDate(calendarData));
|
||||
final Collection<LocalDate> recurringDates = this.generateRecurringDates(calendarData, withHistory, tillDate);
|
||||
final Collection<LocalDate> nextTenRecurringDates = this.generateNextTenRecurringDates(calendarData);
|
||||
final LocalDate recentEligibleMeetingDate = null;
|
||||
final CalendarData updatedCalendarData = CalendarData.withRecurringDates(calendarData, recurringDates, nextTenRecurringDates,
|
||||
recentEligibleMeetingDate);
|
||||
recuCalendarsData.add(updatedCalendarData);
|
||||
}
|
||||
|
||||
return recuCalendarsData;
|
||||
@@ -278,4 +372,83 @@ public class CalendarReadPlatformServiceImpl implements CalendarReadPlatformServ
|
||||
return conditionSql;
|
||||
}
|
||||
|
||||
private CalendarData retrieveApplicableCalendarFromHistory(Long calendarId, LocalDate compareDate) {
|
||||
try {
|
||||
final CalendarDataFromHistoryMapper rm = new CalendarDataFromHistoryMapper();
|
||||
|
||||
final String sql = rm.schema() + " where c.calendar_id = ? and date(?) between c.start_date and c.end_date limit 1";
|
||||
|
||||
return this.jdbcTemplate.queryForObject(sql, rm, new Object[] { calendarId, compareDate.toDate() });
|
||||
} catch (final EmptyResultDataAccessException e) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
private Collection<CalendarData> retrieveCalendarsFromHistory(Long calendarId) {
|
||||
try {
|
||||
final CalendarDataFromHistoryMapper rm = new CalendarDataFromHistoryMapper();
|
||||
|
||||
final String sql = rm.schema() + " where c.calendar_id = ? ";
|
||||
|
||||
final Collection<CalendarData> calendars = this.jdbcTemplate.query(sql, rm, new Object[] { calendarId });
|
||||
return calendars;
|
||||
} catch (final EmptyResultDataAccessException e) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
private static final class CalendarDataFromHistoryMapper implements RowMapper<CalendarData> {
|
||||
|
||||
public String schema() {
|
||||
return " select c.calendar_id as id, c.title as title, c.description as description, c.location as location, c.start_date as startDate, "
|
||||
+ " c.end_date as endDate, c.duration as duration, c.calendar_type_enum as typeId, c.repeating as repeating, "
|
||||
+ " c.recurrence as recurrence, c.remind_by_enum as remindById, c.first_reminder as firstReminder, c.second_reminder as secondReminder "
|
||||
+ " from m_calendar_history c ";
|
||||
}
|
||||
|
||||
@Override
|
||||
public CalendarData mapRow(final ResultSet rs, @SuppressWarnings("unused") final int rowNum) throws SQLException {
|
||||
|
||||
final Long id = rs.getLong("id");
|
||||
final Long calendarInstanceId = null;
|
||||
final Long entityId = null;
|
||||
final EnumOptionData entityType = null;
|
||||
final String title = rs.getString("title");
|
||||
final String description = rs.getString("description");
|
||||
final String location = rs.getString("location");
|
||||
final LocalDate startDate = JdbcSupport.getLocalDate(rs, "startDate");
|
||||
final LocalDate endDate = JdbcSupport.getLocalDate(rs, "endDate");
|
||||
final Integer duration = rs.getInt("duration");
|
||||
final Integer typeId = rs.getInt("typeId");
|
||||
final EnumOptionData type = CalendarEnumerations.calendarType(typeId);
|
||||
final boolean repeating = rs.getBoolean("repeating");
|
||||
final String recurrence = rs.getString("recurrence");
|
||||
final EnumOptionData frequency = CalendarEnumerations.calendarFrequencyType(CalendarUtils.getFrequency(recurrence));
|
||||
final Integer interval = new Integer(CalendarUtils.getInterval(recurrence));
|
||||
final EnumOptionData repeatsOnDay = CalendarEnumerations.calendarWeekDaysType(CalendarUtils.getRepeatsOnDay(recurrence));
|
||||
final Integer remindById = rs.getInt("remindById");
|
||||
EnumOptionData remindBy = null;
|
||||
if (remindById != null && remindById != 0) {
|
||||
remindBy = CalendarEnumerations.calendarRemindBy(remindById);
|
||||
}
|
||||
final Integer firstReminder = rs.getInt("firstReminder");
|
||||
final Integer secondReminder = rs.getInt("secondReminder");
|
||||
String humanReadable = null;
|
||||
if (startDate != null && recurrence != null) {
|
||||
humanReadable = CalendarUtils.getRRuleReadable(startDate, recurrence);
|
||||
}
|
||||
|
||||
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 CalendarData.instance(id, calendarInstanceId, entityId, entityType, title, description, location, startDate, endDate,
|
||||
duration, type, repeating, recurrence, frequency, interval, repeatsOnDay, remindBy, firstReminder, secondReminder,
|
||||
humanReadable, createdDate, lastUpdatedDate, createdByUserId, createdByUserName, lastUpdatedByUserId,
|
||||
lastUpdatedByUserName);
|
||||
}
|
||||
}
|
||||
}
|
||||
+16
@@ -32,6 +32,8 @@ import org.mifosplatform.infrastructure.core.service.DateUtils;
|
||||
import org.mifosplatform.organisation.workingdays.domain.WorkingDays;
|
||||
import org.mifosplatform.organisation.workingdays.service.WorkingDaysUtil;
|
||||
import org.mifosplatform.portfolio.calendar.domain.Calendar;
|
||||
import org.mifosplatform.portfolio.calendar.domain.CalendarFrequencyType;
|
||||
import org.mifosplatform.portfolio.calendar.domain.CalendarWeekDaysType;
|
||||
import org.mifosplatform.portfolio.loanproduct.domain.PeriodFrequencyType;
|
||||
|
||||
public class CalendarUtils {
|
||||
@@ -284,6 +286,20 @@ public class CalendarUtils {
|
||||
final Recur recur = CalendarUtils.getICalRecur(recurringRule);
|
||||
return recur.getInterval();
|
||||
}
|
||||
|
||||
public static CalendarFrequencyType getFrequency(final String recurringRule){
|
||||
final Recur recur = CalendarUtils.getICalRecur(recurringRule);
|
||||
return CalendarFrequencyType.fromString(recur.getFrequency());
|
||||
}
|
||||
|
||||
public static CalendarWeekDaysType getRepeatsOnDay(final String recurringRule){
|
||||
final Recur recur = CalendarUtils.getICalRecur(recurringRule);
|
||||
final WeekDayList weekDays = recur.getDayList();
|
||||
if(weekDays.isEmpty()) return CalendarWeekDaysType.INVALID;
|
||||
//supports only one day
|
||||
WeekDay weekDay = (WeekDay) weekDays.get(0);
|
||||
return CalendarWeekDaysType.fromString(weekDay.getDay());
|
||||
}
|
||||
|
||||
public static LocalDate getFirstRepaymentMeetingDate(final Calendar calendar, final LocalDate disbursementDate,
|
||||
final Integer loanRepaymentInterval, final String frequency) {
|
||||
|
||||
+97
-11
@@ -5,20 +5,40 @@
|
||||
*/
|
||||
package org.mifosplatform.portfolio.calendar.service;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.Date;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import org.joda.time.LocalDate;
|
||||
import org.joda.time.format.DateTimeFormat;
|
||||
import org.joda.time.format.DateTimeFormatter;
|
||||
import org.mifosplatform.infrastructure.configuration.domain.ConfigurationDomainService;
|
||||
import org.mifosplatform.infrastructure.core.api.JsonCommand;
|
||||
import org.mifosplatform.infrastructure.core.data.ApiParameterError;
|
||||
import org.mifosplatform.infrastructure.core.data.CommandProcessingResult;
|
||||
import org.mifosplatform.infrastructure.core.data.CommandProcessingResultBuilder;
|
||||
import org.mifosplatform.infrastructure.core.data.DataValidatorBuilder;
|
||||
import org.mifosplatform.infrastructure.core.exception.PlatformApiDataValidationException;
|
||||
import org.mifosplatform.infrastructure.core.service.DateUtils;
|
||||
import org.mifosplatform.portfolio.calendar.CalendarConstants.CALENDAR_SUPPORTED_PARAMETERS;
|
||||
import org.mifosplatform.portfolio.calendar.domain.Calendar;
|
||||
import org.mifosplatform.portfolio.calendar.domain.CalendarEntityType;
|
||||
import org.mifosplatform.portfolio.calendar.domain.CalendarHistory;
|
||||
import org.mifosplatform.portfolio.calendar.domain.CalendarHistoryRepository;
|
||||
import org.mifosplatform.portfolio.calendar.domain.CalendarInstance;
|
||||
import org.mifosplatform.portfolio.calendar.domain.CalendarInstanceRepository;
|
||||
import org.mifosplatform.portfolio.calendar.domain.CalendarRepository;
|
||||
import org.mifosplatform.portfolio.calendar.domain.CalendarType;
|
||||
import org.mifosplatform.portfolio.calendar.exception.CalendarNotFoundException;
|
||||
import org.mifosplatform.portfolio.calendar.serialization.CalendarCommandFromApiJsonDeserializer;
|
||||
import org.mifosplatform.portfolio.client.domain.Client;
|
||||
import org.mifosplatform.portfolio.client.domain.ClientRepositoryWrapper;
|
||||
import org.mifosplatform.portfolio.group.domain.Group;
|
||||
import org.mifosplatform.portfolio.group.domain.GroupRepositoryWrapper;
|
||||
import org.mifosplatform.portfolio.loanaccount.domain.Loan;
|
||||
import org.mifosplatform.portfolio.loanaccount.domain.LoanRepository;
|
||||
import org.mifosplatform.portfolio.loanaccount.service.LoanWritePlatformService;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.stereotype.Service;
|
||||
@@ -28,29 +48,90 @@ import org.springframework.util.CollectionUtils;
|
||||
public class CalendarWritePlatformServiceJpaRepositoryImpl implements CalendarWritePlatformService {
|
||||
|
||||
private final CalendarRepository calendarRepository;
|
||||
private final CalendarHistoryRepository calendarHistoryRepository;
|
||||
private final CalendarCommandFromApiJsonDeserializer fromApiJsonDeserializer;
|
||||
private final CalendarInstanceRepository calendarInstanceRepository;
|
||||
private final LoanWritePlatformService loanWritePlatformService;
|
||||
private final ConfigurationDomainService configurationDomainService;
|
||||
private final GroupRepositoryWrapper groupRepository;
|
||||
private final LoanRepository loanRepository;
|
||||
private final ClientRepositoryWrapper clientRepository;
|
||||
|
||||
@Autowired
|
||||
public CalendarWritePlatformServiceJpaRepositoryImpl(final CalendarRepository calendarRepository,
|
||||
final CalendarHistoryRepository calendarHistoryRepository,
|
||||
final CalendarCommandFromApiJsonDeserializer fromApiJsonDeserializer,
|
||||
final CalendarInstanceRepository calendarInstanceRepository, final LoanWritePlatformService loanWritePlatformService,
|
||||
final ConfigurationDomainService configurationDomainService) {
|
||||
final ConfigurationDomainService configurationDomainService, final GroupRepositoryWrapper groupRepository,
|
||||
final LoanRepository loanRepository, final ClientRepositoryWrapper clientRepository) {
|
||||
this.calendarRepository = calendarRepository;
|
||||
this.calendarHistoryRepository = calendarHistoryRepository;
|
||||
this.fromApiJsonDeserializer = fromApiJsonDeserializer;
|
||||
this.calendarInstanceRepository = calendarInstanceRepository;
|
||||
this.loanWritePlatformService = loanWritePlatformService;
|
||||
this.configurationDomainService = configurationDomainService;
|
||||
this.groupRepository = groupRepository;
|
||||
this.loanRepository = loanRepository;
|
||||
this.clientRepository = clientRepository;
|
||||
}
|
||||
|
||||
@Override
|
||||
public CommandProcessingResult createCalendar(final JsonCommand command) {
|
||||
|
||||
this.fromApiJsonDeserializer.validateForCreate(command.json());
|
||||
final Long entityId = command.getSupportedEntityId();
|
||||
final CalendarEntityType entityType = CalendarEntityType.valueOf(command.getSupportedEntityType().toUpperCase());
|
||||
LocalDate entityActivationDate = null;
|
||||
Group centerOrGroup = null;
|
||||
if (entityType.isCenter() || entityType.isGroup()) {
|
||||
centerOrGroup = this.groupRepository.findOneWithNotFoundDetection(entityId);
|
||||
entityActivationDate = centerOrGroup.getActivationLocalDate();
|
||||
} else if (entityType.isLoan()) {
|
||||
final Loan loan = this.loanRepository.findOne(entityId);
|
||||
entityActivationDate = (loan.getApprovedOnDate() == null) ? loan.getSubmittedOnDate() : loan.getApprovedOnDate();
|
||||
} else if (entityType.isLoan()) {
|
||||
final Client client = this.clientRepository.findOneWithNotFoundDetection(entityId);
|
||||
entityActivationDate = client.getActivationLocalDate();
|
||||
}
|
||||
|
||||
final Calendar newCalendar = Calendar.fromJson(command);
|
||||
|
||||
final List<ApiParameterError> dataValidationErrors = new ArrayList<ApiParameterError>();
|
||||
final DataValidatorBuilder baseDataValidator = new DataValidatorBuilder(dataValidationErrors).resource("calendar");
|
||||
if (entityActivationDate == null || newCalendar.getStartDateLocalDate().isBefore(entityActivationDate)) {
|
||||
final DateTimeFormatter formatter = DateTimeFormat.forPattern(command.dateFormat()).withLocale(command.extractLocale());
|
||||
String dateAsString = "";
|
||||
if (entityActivationDate != null) dateAsString = formatter.print(entityActivationDate);
|
||||
|
||||
final String errorMessage = "cannot.be.before." + entityType.name().toLowerCase() + ".activation.date";
|
||||
baseDataValidator.reset().parameter(CALENDAR_SUPPORTED_PARAMETERS.START_DATE.getValue()).value(dateAsString)
|
||||
.failWithCodeNoParameterAddedToErrorCode(errorMessage);
|
||||
}
|
||||
|
||||
if (entityType.isCenter() || entityType.isGroup()) {
|
||||
Long centerOrGroupId = entityId;
|
||||
Integer centerOrGroupEntityTypeId = entityType.getValue();
|
||||
|
||||
if (entityType.isGroup()) {
|
||||
@SuppressWarnings("null")
|
||||
final Group parent = centerOrGroup.getParent();
|
||||
if (parent != null) {
|
||||
centerOrGroupId = parent.getId();
|
||||
centerOrGroupEntityTypeId = CalendarEntityType.CENTERS.getValue();
|
||||
}
|
||||
}
|
||||
|
||||
final CalendarInstance collectionCalendarInstance = this.calendarInstanceRepository
|
||||
.findByEntityIdAndEntityTypeIdAndCalendarTypeId(centerOrGroupId, centerOrGroupEntityTypeId,
|
||||
CalendarType.COLLECTION.getValue());
|
||||
if (collectionCalendarInstance != null) {
|
||||
final String errorMessage = "multiple.collection.calendar.not.supported";
|
||||
baseDataValidator.reset().failWithCodeNoParameterAddedToErrorCode(errorMessage);
|
||||
}
|
||||
}
|
||||
|
||||
if (!dataValidationErrors.isEmpty()) { throw new PlatformApiDataValidationException(dataValidationErrors); }
|
||||
|
||||
this.calendarRepository.save(newCalendar);
|
||||
|
||||
final CalendarInstance newCalendarInstance = CalendarInstance.fromJson(newCalendar, command);
|
||||
@@ -71,25 +152,30 @@ public class CalendarWritePlatformServiceJpaRepositoryImpl implements CalendarWr
|
||||
final Long calendarId = command.entityId();
|
||||
final Calendar calendarForUpdate = this.calendarRepository.findOne(calendarId);
|
||||
if (calendarForUpdate == null) { throw new CalendarNotFoundException(calendarId); }
|
||||
|
||||
final Date oldStartDate = calendarForUpdate.getStartDate();
|
||||
final LocalDate currentDate = DateUtils.getLocalDateOfTenant();
|
||||
//create calendar history before updating calendar
|
||||
final CalendarHistory calendarHistory = new CalendarHistory(calendarForUpdate, oldStartDate);
|
||||
final Map<String, Object> changes = calendarForUpdate.update(command);
|
||||
|
||||
|
||||
if (!changes.isEmpty()) {
|
||||
//update calendar history table only if there is a change in calendar start date.
|
||||
if(currentDate.isAfter(new LocalDate(oldStartDate))){
|
||||
final Date endDate = calendarForUpdate.getStartDateLocalDate().minusDays(1).toDate();
|
||||
calendarHistory.updateEndDate(endDate);
|
||||
this.calendarHistoryRepository.save(calendarHistory);
|
||||
}
|
||||
|
||||
this.calendarRepository.saveAndFlush(calendarForUpdate);
|
||||
|
||||
if (this.configurationDomainService.isRescheduleFutureRepaymentsEnabled()) {
|
||||
// In this approach loans following this meeting calendar will
|
||||
// be affected immediately.
|
||||
// get all calendar instances following this meeting calendar
|
||||
// and calendar entity type is loan
|
||||
if (this.configurationDomainService.isRescheduleFutureRepaymentsEnabled() && calendarForUpdate.isRepeating()) {
|
||||
//fetch all loan calendar instances associated with modifying calendar.
|
||||
final Collection<CalendarInstance> loanCalendarInstances = this.calendarInstanceRepository.findByCalendarIdAndEntityTypeId(
|
||||
calendarId, CalendarEntityType.LOANS.getValue());
|
||||
|
||||
if (!CollectionUtils.isEmpty(loanCalendarInstances)) {
|
||||
// update all loans which are following this meeting
|
||||
// calendar
|
||||
//update all loans associated with modifying calendar
|
||||
this.loanWritePlatformService.applyMeetingDateChanges(calendarForUpdate, loanCalendarInstances);
|
||||
//
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+18
-1
@@ -29,7 +29,12 @@ public enum ChargeCalculationType {
|
||||
return this.code;
|
||||
}
|
||||
|
||||
public static Object[] validValues() {
|
||||
public static Object[] validValuesForLoan() {
|
||||
return new Integer[] { ChargeCalculationType.FLAT.getValue(), ChargeCalculationType.PERCENT_OF_AMOUNT.getValue(),
|
||||
ChargeCalculationType.PERCENT_OF_AMOUNT_AND_INTEREST.getValue(),ChargeCalculationType.PERCENT_OF_INTEREST.getValue() };
|
||||
}
|
||||
|
||||
public static Object[] validValuesForSavings() {
|
||||
return new Integer[] { ChargeCalculationType.FLAT.getValue(), ChargeCalculationType.PERCENT_OF_AMOUNT.getValue() };
|
||||
}
|
||||
|
||||
@@ -56,6 +61,14 @@ public enum ChargeCalculationType {
|
||||
return this.value.equals(ChargeCalculationType.PERCENT_OF_AMOUNT.getValue());
|
||||
}
|
||||
|
||||
public boolean isPercentageOfAmountAndInterest() {
|
||||
return this.value.equals(ChargeCalculationType.PERCENT_OF_AMOUNT_AND_INTEREST.getValue());
|
||||
}
|
||||
|
||||
public boolean isPercentageOfInterest() {
|
||||
return this.value.equals(ChargeCalculationType.PERCENT_OF_INTEREST.getValue());
|
||||
}
|
||||
|
||||
public boolean isFlat() {
|
||||
return this.value.equals(ChargeCalculationType.FLAT.getValue());
|
||||
}
|
||||
@@ -63,4 +76,8 @@ public enum ChargeCalculationType {
|
||||
public boolean isAllowedSavingsChargeCalculationType() {
|
||||
return isFlat() || isPercentageOfAmount();
|
||||
}
|
||||
|
||||
public boolean isPercentageBased(){
|
||||
return isPercentageOfAmount() || isPercentageOfAmountAndInterest() || isPercentageOfInterest();
|
||||
}
|
||||
}
|
||||
Regular → Executable
+20
-3
@@ -16,7 +16,9 @@ public enum ChargeTimeType {
|
||||
SAVINGS_CLOSURE(4, "chargeTimeType.savingsClosure"), // only for savings
|
||||
WITHDRAWAL_FEE(5, "chargeTimeType.withdrawalFee"), // only for savings
|
||||
ANNUAL_FEE(6, "chargeTimeType.annualFee"), // only for savings
|
||||
MONTHLY_FEE(7, "chargeTimeType.monthlyFee"); // only for savings
|
||||
MONTHLY_FEE(7, "chargeTimeType.monthlyFee"), // only for savings
|
||||
INSTALMENT_FEE(8, "chargeTimeType.instalmentFee"),// only for loan charges
|
||||
OVERDUE_INSTALLMENT(9, "chargeTimeType.overdueInstallment"); // only for loan charges
|
||||
|
||||
private final Integer value;
|
||||
private final String code;
|
||||
@@ -35,7 +37,8 @@ public enum ChargeTimeType {
|
||||
}
|
||||
|
||||
public static Object[] validLoanValues() {
|
||||
return new Integer[] { ChargeTimeType.DISBURSEMENT.getValue(), ChargeTimeType.SPECIFIED_DUE_DATE.getValue() };
|
||||
return new Integer[] { ChargeTimeType.DISBURSEMENT.getValue(), ChargeTimeType.SPECIFIED_DUE_DATE.getValue(),
|
||||
ChargeTimeType.INSTALMENT_FEE.getValue(),ChargeTimeType.OVERDUE_INSTALLMENT.getValue() };
|
||||
}
|
||||
|
||||
public static Object[] validSavingsValues() {
|
||||
@@ -69,6 +72,12 @@ public enum ChargeTimeType {
|
||||
case 7:
|
||||
chargeTimeType = MONTHLY_FEE;
|
||||
break;
|
||||
case 8:
|
||||
chargeTimeType = INSTALMENT_FEE;
|
||||
break;
|
||||
case 9:
|
||||
chargeTimeType = OVERDUE_INSTALLMENT;
|
||||
break;
|
||||
default:
|
||||
chargeTimeType = INVALID;
|
||||
break;
|
||||
@@ -105,8 +114,16 @@ public enum ChargeTimeType {
|
||||
return this.value.equals(ChargeTimeType.MONTHLY_FEE.getValue());
|
||||
}
|
||||
|
||||
public boolean isInstalmentFee() {
|
||||
return this.value.equals(ChargeTimeType.INSTALMENT_FEE.getValue());
|
||||
}
|
||||
|
||||
public boolean isOverdueInstallment(){
|
||||
return this.value.equals(ChargeTimeType.OVERDUE_INSTALLMENT.getValue());
|
||||
}
|
||||
|
||||
public boolean isAllowedLoanChargeTime() {
|
||||
return isTimeOfDisbursement() || isOnSpecifiedDueDate();
|
||||
return isTimeOfDisbursement() || isOnSpecifiedDueDate() || isInstalmentFee() || isOverdueInstallment();
|
||||
}
|
||||
|
||||
public boolean isAllowedSavingsChargeTime() {
|
||||
|
||||
+11
-3
@@ -11,7 +11,7 @@ public class LoanChargeCannotBePayedException extends AbstractPlatformDomainRule
|
||||
|
||||
/*** enum of reasons of why Loan Charge cannot be waived **/
|
||||
public static enum LOAN_CHARGE_CANNOT_BE_PAYED_REASON {
|
||||
ALREADY_PAID, ALREADY_WAIVED, LOAN_INACTIVE, CHARGE_NOT_ACCOUNT_TRANSFER;
|
||||
ALREADY_PAID, ALREADY_WAIVED, LOAN_INACTIVE, CHARGE_NOT_ACCOUNT_TRANSFER,CHARGE_NOT_PAYABLE;
|
||||
|
||||
public String errorMessage() {
|
||||
if (name().toString().equalsIgnoreCase("ALREADY_PAID")) {
|
||||
@@ -20,7 +20,11 @@ public class LoanChargeCannotBePayedException extends AbstractPlatformDomainRule
|
||||
return "This loan charge has already been waived";
|
||||
} else if (name().toString().equalsIgnoreCase("LOAN_INACTIVE")) {
|
||||
return "This loan charge can be payed as the loan associated with it is currently inactive";
|
||||
} else if (name().toString().equalsIgnoreCase("CHARGE_NOT_ACCOUNT_TRANSFER")) { return "This loan charge can be payed as the charge payment mode is not account transfer"; }
|
||||
} else if (name().toString().equalsIgnoreCase("CHARGE_NOT_ACCOUNT_TRANSFER")) {
|
||||
return "This loan charge can be payed as the charge payment mode is not account transfer";
|
||||
}else if (name().toString().equalsIgnoreCase("CHARGE_NOT_PAYABLE")) {
|
||||
return "This loan charge is not Payable through account transfer";
|
||||
}
|
||||
|
||||
return name().toString();
|
||||
}
|
||||
@@ -32,7 +36,11 @@ public class LoanChargeCannotBePayedException extends AbstractPlatformDomainRule
|
||||
return "error.msg.loan.charge.already.waived";
|
||||
} else if (name().toString().equalsIgnoreCase("LOAN_INACTIVE")) {
|
||||
return "error.msg.loan.charge.associated.loan.inactive";
|
||||
} else if (name().toString().equalsIgnoreCase("CHARGE_NOT_ACCOUNT_TRANSFER")) { return "error.msg.loan.charge.payment.mode.not.account.transfer"; }
|
||||
} else if (name().toString().equalsIgnoreCase("CHARGE_NOT_ACCOUNT_TRANSFER")) {
|
||||
return "error.msg.loan.charge.payment.mode.not.account.transfer";
|
||||
}else if (name().toString().equalsIgnoreCase("CHARGE_NOT_PAYABLE")) {
|
||||
return "error.msg.loan.charge.payment.not.allowed.account.transfer";
|
||||
}
|
||||
return name().toString();
|
||||
}
|
||||
}
|
||||
|
||||
+6
-2
@@ -18,7 +18,9 @@ public class LoanChargeCannotBeUpdatedException extends AbstractPlatformDomainRu
|
||||
return "This loan charge has been partially/completely paid";
|
||||
} else if (name().toString().equalsIgnoreCase("ALREADY_WAIVED")) {
|
||||
return "This loan charge has already been waived";
|
||||
} else if (name().toString().equalsIgnoreCase("LOAN_NOT_IN_SUBMITTED_AND_PENDING_APPROVAL_STAGE")) { return "This charge cannot be updated as the loan it is associated with is not in submitted and pending approval stage"; }
|
||||
} else if (name().toString().equalsIgnoreCase("LOAN_NOT_IN_SUBMITTED_AND_PENDING_APPROVAL_STAGE")) {
|
||||
return "This charge cannot be updated as the loan it is associated with is not in submitted and pending approval stage";
|
||||
}
|
||||
return name().toString();
|
||||
}
|
||||
|
||||
@@ -27,7 +29,9 @@ public class LoanChargeCannotBeUpdatedException extends AbstractPlatformDomainRu
|
||||
return "error.msg.loan.charge.already.paid";
|
||||
} else if (name().toString().equalsIgnoreCase("ALREADY_WAIVED")) {
|
||||
return "error.msg.loan.charge.already.waived";
|
||||
} else if (name().toString().equalsIgnoreCase("LOAN_NOT_IN_SUBMITTED_AND_PENDING_APPROVAL_STAGE")) { return "error.msg.loan.charge.associated.loan.not.in.submitted.and.pending.approval.stage"; }
|
||||
} else if (name().toString().equalsIgnoreCase("LOAN_NOT_IN_SUBMITTED_AND_PENDING_APPROVAL_STAGE")) {
|
||||
return "error.msg.loan.charge.associated.loan.not.in.submitted.and.pending.approval.stage";
|
||||
}
|
||||
return name().toString();
|
||||
}
|
||||
}
|
||||
|
||||
+12
-3
@@ -11,14 +11,19 @@ public class LoanChargeCannotBeWaivedException extends AbstractPlatformDomainRul
|
||||
|
||||
/*** enum of reasons of why Loan Charge cannot be waived **/
|
||||
public static enum LOAN_CHARGE_CANNOT_BE_WAIVED_REASON {
|
||||
ALREADY_PAID, ALREADY_WAIVED, LOAN_INACTIVE;
|
||||
ALREADY_PAID, ALREADY_WAIVED, LOAN_INACTIVE, WAIVE_NOT_ALLOWED_FOR_CHARGE;
|
||||
|
||||
public String errorMessage() {
|
||||
if (name().toString().equalsIgnoreCase("ALREADY_PAID")) {
|
||||
return "This loan charge has been completely paid";
|
||||
} else if (name().toString().equalsIgnoreCase("ALREADY_WAIVED")) {
|
||||
return "This loan charge has already been waived";
|
||||
} else if (name().toString().equalsIgnoreCase("LOAN_INACTIVE")) { return "This loan charge can be waived as the loan associated with it is currently inactive"; }
|
||||
} else if (name().toString().equalsIgnoreCase("LOAN_INACTIVE")) {
|
||||
return "This loan charge can be waived as the loan associated with it is currently inactive";
|
||||
} else if(name().toString().equalsIgnoreCase("WAIVE_NOT_ALLOWED_FOR_CHARGE")){
|
||||
return "This loan charge can be waived";
|
||||
}
|
||||
|
||||
return name().toString();
|
||||
}
|
||||
|
||||
@@ -27,7 +32,11 @@ public class LoanChargeCannotBeWaivedException extends AbstractPlatformDomainRul
|
||||
return "error.msg.loan.charge.already.paid";
|
||||
} else if (name().toString().equalsIgnoreCase("ALREADY_WAIVED")) {
|
||||
return "error.msg.loan.charge.already.waived";
|
||||
} else if (name().toString().equalsIgnoreCase("LOAN_INACTIVE")) { return "error.msg.loan.charge.associated.loan.inactive"; }
|
||||
} else if (name().toString().equalsIgnoreCase("LOAN_INACTIVE")) {
|
||||
return "error.msg.loan.charge.associated.loan.inactive";
|
||||
} else if(name().toString().equalsIgnoreCase("WAIVE_NOT_ALLOWED_FOR_CHARGE")) {
|
||||
return "error.msg.loan.charge.waive.not.allowed";
|
||||
}
|
||||
return name().toString();
|
||||
}
|
||||
}
|
||||
|
||||
+11
-6
@@ -67,6 +67,9 @@ public final class ChargeDefinitionCommandFromApiJsonDeserializer {
|
||||
baseDataValidator.reset().parameter("chargeAppliesTo").value(chargeAppliesTo).isOneOfTheseValues(ChargeAppliesTo.validValues());
|
||||
}
|
||||
|
||||
final Integer chargeCalculationType = this.fromApiJsonHelper.extractIntegerSansLocaleNamed("chargeCalculationType", element);
|
||||
baseDataValidator.reset().parameter("chargeCalculationType").value(chargeCalculationType).notNull();
|
||||
|
||||
final ChargeAppliesTo appliesTo = ChargeAppliesTo.fromInt(chargeAppliesTo);
|
||||
if (appliesTo.isLoanCharge()) {
|
||||
// loan applicable validation
|
||||
@@ -81,6 +84,10 @@ public final class ChargeDefinitionCommandFromApiJsonDeserializer {
|
||||
if (chargePaymentMode != null) {
|
||||
baseDataValidator.reset().parameter("chargePaymentMode").value(chargePaymentMode).isOneOfTheseValues(ChargePaymentMode.validValues());
|
||||
}
|
||||
|
||||
if (chargeCalculationType != null) {
|
||||
baseDataValidator.reset().parameter("chargeCalculationType").value(chargeCalculationType).isOneOfTheseValues(ChargeCalculationType.validValuesForLoan());
|
||||
}
|
||||
|
||||
} else if (appliesTo.isSavingsCharge()) {
|
||||
// savings applicable validation
|
||||
@@ -103,6 +110,10 @@ public final class ChargeDefinitionCommandFromApiJsonDeserializer {
|
||||
final MonthDay monthDay = this.fromApiJsonHelper.extractMonthDayNamed("feeOnMonthDay", element);
|
||||
baseDataValidator.reset().parameter("feeOnMonthDay").value(monthDay).notNull();
|
||||
}
|
||||
|
||||
if (chargeCalculationType != null) {
|
||||
baseDataValidator.reset().parameter("chargeCalculationType").value(chargeCalculationType).isOneOfTheseValues(ChargeCalculationType.validValuesForSavings());
|
||||
}
|
||||
}
|
||||
|
||||
final String name = this.fromApiJsonHelper.extractStringNamed("name", element);
|
||||
@@ -124,12 +135,6 @@ public final class ChargeDefinitionCommandFromApiJsonDeserializer {
|
||||
baseDataValidator.reset().parameter("active").value(active).notNull();
|
||||
}
|
||||
|
||||
final Integer chargeCalculationType = this.fromApiJsonHelper.extractIntegerSansLocaleNamed("chargeCalculationType", element);
|
||||
baseDataValidator.reset().parameter("chargeCalculationType").value(chargeCalculationType).notNull();
|
||||
if (chargeCalculationType != null) {
|
||||
baseDataValidator.reset().parameter("chargeCalculationType").value(chargeCalculationType).isOneOfTheseValues(ChargeCalculationType.validValues());
|
||||
}
|
||||
|
||||
if (this.fromApiJsonHelper.parameterExists("minCap", element)) {
|
||||
final BigDecimal minCap = this.fromApiJsonHelper.extractBigDecimalWithLocaleNamed("minCap", element.getAsJsonObject());
|
||||
baseDataValidator.reset().parameter("minCap").value(minCap).notNull().positiveAmount();
|
||||
|
||||
Regular → Executable
+11
-13
@@ -5,14 +5,6 @@
|
||||
*/
|
||||
package org.mifosplatform.portfolio.charge.service;
|
||||
|
||||
import static org.mifosplatform.portfolio.charge.service.ChargeEnumerations.chargeCalculationType;
|
||||
import static org.mifosplatform.portfolio.charge.service.ChargeEnumerations.chargePaymentMode;
|
||||
import static org.mifosplatform.portfolio.charge.service.ChargeEnumerations.chargeTimeType;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
|
||||
import org.mifosplatform.infrastructure.core.data.EnumOptionData;
|
||||
import org.mifosplatform.portfolio.charge.domain.ChargeAppliesTo;
|
||||
import org.mifosplatform.portfolio.charge.domain.ChargeCalculationType;
|
||||
@@ -20,6 +12,12 @@ import org.mifosplatform.portfolio.charge.domain.ChargePaymentMode;
|
||||
import org.mifosplatform.portfolio.charge.domain.ChargeTimeType;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
|
||||
import static org.mifosplatform.portfolio.charge.service.ChargeEnumerations.*;
|
||||
|
||||
@Service
|
||||
public class ChargeDropdownReadPlatformServiceImpl implements ChargeDropdownReadPlatformService {
|
||||
|
||||
@@ -27,9 +25,9 @@ public class ChargeDropdownReadPlatformServiceImpl implements ChargeDropdownRead
|
||||
public List<EnumOptionData> retrieveCalculationTypes() {
|
||||
|
||||
return Arrays.asList(chargeCalculationType(ChargeCalculationType.FLAT),
|
||||
chargeCalculationType(ChargeCalculationType.PERCENT_OF_AMOUNT)
|
||||
// chargeCalculationType(ChargeCalculationType.PERCENT_OF_AMOUNT_AND_INTEREST),
|
||||
// chargeCalculationType(ChargeCalculationType.PERCENT_OF_INTEREST)
|
||||
chargeCalculationType(ChargeCalculationType.PERCENT_OF_AMOUNT),
|
||||
chargeCalculationType(ChargeCalculationType.PERCENT_OF_AMOUNT_AND_INTEREST),
|
||||
chargeCalculationType(ChargeCalculationType.PERCENT_OF_INTEREST)
|
||||
);
|
||||
}
|
||||
|
||||
@@ -64,12 +62,12 @@ public class ChargeDropdownReadPlatformServiceImpl implements ChargeDropdownRead
|
||||
|
||||
@Override
|
||||
public List<EnumOptionData> retrieveLoanCalculationTypes() {
|
||||
return Arrays.asList(chargeCalculationType(ChargeCalculationType.FLAT), chargeCalculationType(ChargeCalculationType.PERCENT_OF_AMOUNT));
|
||||
return Arrays.asList(chargeCalculationType(ChargeCalculationType.FLAT), chargeCalculationType(ChargeCalculationType.PERCENT_OF_AMOUNT), chargeCalculationType(ChargeCalculationType.PERCENT_OF_AMOUNT_AND_INTEREST), chargeCalculationType(ChargeCalculationType.PERCENT_OF_INTEREST));
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<EnumOptionData> retrieveLoanCollectionTimeTypes() {
|
||||
return Arrays.asList(chargeTimeType(ChargeTimeType.DISBURSEMENT), chargeTimeType(ChargeTimeType.SPECIFIED_DUE_DATE));
|
||||
return Arrays.asList(chargeTimeType(ChargeTimeType.DISBURSEMENT), chargeTimeType(ChargeTimeType.SPECIFIED_DUE_DATE),chargeTimeType(ChargeTimeType.INSTALMENT_FEE),chargeTimeType(ChargeTimeType.OVERDUE_INSTALLMENT));
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
Regular → Executable
+6
@@ -43,6 +43,12 @@ public class ChargeEnumerations {
|
||||
case MONTHLY_FEE:
|
||||
optionData = new EnumOptionData(ChargeTimeType.MONTHLY_FEE.getValue().longValue(), ChargeTimeType.MONTHLY_FEE.getCode(), "Monthly Fee");
|
||||
break;
|
||||
case INSTALMENT_FEE:
|
||||
optionData = new EnumOptionData(ChargeTimeType.INSTALMENT_FEE.getValue().longValue(), ChargeTimeType.INSTALMENT_FEE.getCode(), "Instalment Fee");
|
||||
break;
|
||||
case OVERDUE_INSTALLMENT:
|
||||
optionData = new EnumOptionData(ChargeTimeType.OVERDUE_INSTALLMENT.getValue().longValue(),ChargeTimeType.OVERDUE_INSTALLMENT.getCode(),"overdue fees") ;
|
||||
break;
|
||||
default:
|
||||
optionData = new EnumOptionData(ChargeTimeType.INVALID.getValue().longValue(), ChargeTimeType.INVALID.getCode(), "Invalid");
|
||||
break;
|
||||
|
||||
+8
-5
@@ -25,6 +25,7 @@ public class ClientApiConstants {
|
||||
public static final String groupIdParamName = "groupId";
|
||||
public static final String accountNoParamName = "accountNo";
|
||||
public static final String externalIdParamName = "externalId";
|
||||
public static final String mobileNoParamName = "mobileNo";
|
||||
public static final String firstnameParamName = "firstname";
|
||||
public static final String middlenameParamName = "middlename";
|
||||
public static final String lastnameParamName = "lastname";
|
||||
@@ -36,6 +37,7 @@ public class ClientApiConstants {
|
||||
public static final String staffIdParamName = "staffId";
|
||||
public static final String closureDateParamName = "closureDate";
|
||||
public static final String closureReasonIdParamName = "closureReasonId";
|
||||
public static final String submittedOnDateParamName="submittedOnDate";
|
||||
// response parameters
|
||||
public static final String statusParamName = "status";
|
||||
public static final String hierarchyParamName = "hierarchy";
|
||||
@@ -53,12 +55,13 @@ public class ClientApiConstants {
|
||||
public static final String staffOptionsParamName = "staffOptions";
|
||||
|
||||
public static final Set<String> CLIENT_CREATE_REQUEST_DATA_PARAMETERS = new HashSet<String>(Arrays.asList(localeParamName,
|
||||
dateFormatParamName, groupIdParamName, accountNoParamName, externalIdParamName, firstnameParamName, middlenameParamName,
|
||||
lastnameParamName, fullnameParamName, officeIdParamName, activeParamName, activationDateParamName, staffIdParamName));
|
||||
dateFormatParamName, groupIdParamName, accountNoParamName, externalIdParamName, mobileNoParamName, firstnameParamName,
|
||||
middlenameParamName, lastnameParamName, fullnameParamName, officeIdParamName, activeParamName, activationDateParamName,
|
||||
staffIdParamName,submittedOnDateParamName));
|
||||
|
||||
public static final Set<String> CLIENT_UPDATE_REQUEST_DATA_PARAMETERS = new HashSet<String>(Arrays.asList(localeParamName,
|
||||
dateFormatParamName, accountNoParamName, externalIdParamName, firstnameParamName, middlenameParamName, lastnameParamName,
|
||||
fullnameParamName, activeParamName, activationDateParamName, staffIdParamName));
|
||||
dateFormatParamName, accountNoParamName, externalIdParamName, mobileNoParamName, firstnameParamName, middlenameParamName,
|
||||
lastnameParamName, fullnameParamName, activeParamName, activationDateParamName, staffIdParamName));
|
||||
|
||||
/**
|
||||
* These parameters will match the class level parameters of
|
||||
@@ -66,7 +69,7 @@ public class ClientApiConstants {
|
||||
* match those of request parameters.
|
||||
*/
|
||||
public static final Set<String> CLIENT_RESPONSE_DATA_PARAMETERS = new HashSet<String>(Arrays.asList(idParamName, accountNoParamName,
|
||||
externalIdParamName, statusParamName, activeParamName, activationDateParamName, firstnameParamName, middlenameParamName,
|
||||
externalIdParamName, mobileNoParamName, statusParamName, activeParamName, activationDateParamName, firstnameParamName, middlenameParamName,
|
||||
lastnameParamName, fullnameParamName, displayNameParamName, officeIdParamName, officeNameParamName, transferOfficeIdParamName,
|
||||
trasnferOfficeNameParamName, hierarchyParamName, imageKeyParamName, imagePresentParamName, groupsParamName,
|
||||
officeOptionsParamName, staffOptionsParamName));
|
||||
|
||||
+1
@@ -135,6 +135,7 @@ public class ClientsApiResource {
|
||||
clientData = ClientData.templateOnTop(clientData, templateData);
|
||||
}
|
||||
|
||||
|
||||
return this.toApiJsonSerializer.serialize(settings, clientData, ClientApiConstants.CLIENT_RESPONSE_DATA_PARAMETERS);
|
||||
}
|
||||
|
||||
|
||||
-61
@@ -1,61 +0,0 @@
|
||||
/**
|
||||
* 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.client.command;
|
||||
|
||||
import org.joda.time.LocalDate;
|
||||
|
||||
public class ClientCommand {
|
||||
|
||||
@SuppressWarnings("unused")
|
||||
private final String accountNo;
|
||||
private final String externalId;
|
||||
private final String firstname;
|
||||
private final String middlename;
|
||||
private final String lastname;
|
||||
private final String fullname;
|
||||
private final Long officeId;
|
||||
private final LocalDate joinedDate;
|
||||
|
||||
public ClientCommand(final String accountNo, final String externalId, final String firstname, final String middlename,
|
||||
final String lastname, final String fullname, final Long officeId, final LocalDate joinedDate) {
|
||||
this.accountNo = accountNo;
|
||||
this.externalId = externalId;
|
||||
this.firstname = firstname;
|
||||
this.middlename = middlename;
|
||||
this.lastname = lastname;
|
||||
this.fullname = fullname;
|
||||
this.officeId = officeId;
|
||||
this.joinedDate = joinedDate;
|
||||
}
|
||||
|
||||
public String getExternalId() {
|
||||
return this.externalId;
|
||||
}
|
||||
|
||||
public String getFirstname() {
|
||||
return this.firstname;
|
||||
}
|
||||
|
||||
public String getMiddlename() {
|
||||
return this.middlename;
|
||||
}
|
||||
|
||||
public String getLastname() {
|
||||
return this.lastname;
|
||||
}
|
||||
|
||||
public String getFullname() {
|
||||
return this.fullname;
|
||||
}
|
||||
|
||||
public Long getOfficeId() {
|
||||
return this.officeId;
|
||||
}
|
||||
|
||||
public LocalDate getJoiningDate() {
|
||||
return this.joinedDate;
|
||||
}
|
||||
}
|
||||
+31
-14
@@ -37,6 +37,7 @@ final public class ClientData implements Comparable<ClientData> {
|
||||
private final String lastname;
|
||||
private final String fullname;
|
||||
private final String displayName;
|
||||
private final String mobileNo;
|
||||
|
||||
private final Long officeId;
|
||||
private final String officeName;
|
||||
@@ -47,6 +48,7 @@ final public class ClientData implements Comparable<ClientData> {
|
||||
private final Boolean imagePresent;
|
||||
private final Long staffId;
|
||||
private final String staffName;
|
||||
private final ClientTimelineData timeline;
|
||||
|
||||
// associations
|
||||
private final Collection<GroupGeneralData> groups;
|
||||
@@ -59,25 +61,28 @@ final public class ClientData implements Comparable<ClientData> {
|
||||
|
||||
public static ClientData template(final Long officeId, final LocalDate joinedDate, final Collection<OfficeData> officeOptions,
|
||||
final Collection<StaffData> staffOptions, final Collection<CodeValueData> closureReasons) {
|
||||
return new ClientData(null, null, officeId, null, null, null, null, null, null, null, null, null, null, joinedDate, null, null,
|
||||
null, officeOptions, null, staffOptions, closureReasons);
|
||||
return new ClientData(null, null, officeId, null, null, null, null, null, null, null, null, null, null, null, joinedDate, null,
|
||||
null, null, officeOptions, null, staffOptions, closureReasons,null);
|
||||
|
||||
}
|
||||
|
||||
public static ClientData templateOnTop(final ClientData clientData, final ClientData templateData) {
|
||||
|
||||
return new ClientData(clientData.accountNo, clientData.status, clientData.officeId, clientData.officeName,
|
||||
clientData.transferToOfficeId, clientData.transferToOfficeName, clientData.id, clientData.firstname, clientData.middlename,
|
||||
clientData.lastname, clientData.fullname, clientData.displayName, clientData.externalId, clientData.activationDate,
|
||||
clientData.imageId, clientData.staffId, clientData.staffName, templateData.officeOptions, clientData.groups,
|
||||
templateData.staffOptions, null);
|
||||
clientData.lastname, clientData.fullname, clientData.displayName, clientData.externalId, clientData.mobileNo,
|
||||
clientData.activationDate, clientData.imageId, clientData.staffId, clientData.staffName, templateData.officeOptions,
|
||||
clientData.groups, templateData.staffOptions, null,null);
|
||||
|
||||
}
|
||||
|
||||
public static ClientData setParentGroups(final ClientData clientData, final Collection<GroupGeneralData> parentGroups) {
|
||||
return new ClientData(clientData.accountNo, clientData.status, clientData.officeId, clientData.officeName,
|
||||
clientData.transferToOfficeId, clientData.transferToOfficeName, clientData.id, clientData.firstname, clientData.middlename,
|
||||
clientData.lastname, clientData.fullname, clientData.displayName, clientData.externalId, clientData.activationDate,
|
||||
clientData.imageId, clientData.staffId, clientData.staffName, clientData.officeOptions, parentGroups,
|
||||
clientData.staffOptions, null);
|
||||
clientData.lastname, clientData.fullname, clientData.displayName, clientData.externalId, clientData.mobileNo,
|
||||
clientData.activationDate, clientData.imageId, clientData.staffId, clientData.staffName, clientData.officeOptions,
|
||||
parentGroups, clientData.staffOptions, null,clientData.timeline);
|
||||
|
||||
}
|
||||
|
||||
public static ClientData clientIdentifier(final Long id, final String accountNo, final EnumOptionData status, final String firstname,
|
||||
@@ -85,28 +90,31 @@ final public class ClientData implements Comparable<ClientData> {
|
||||
final String officeName) {
|
||||
|
||||
return new ClientData(accountNo, status, officeId, officeName, null, null, id, firstname, middlename, lastname, fullname,
|
||||
displayName, null, null, null, null, null, null, null, null, null);
|
||||
displayName, null, null, null, null, null, null, null, null, null, null,null);
|
||||
|
||||
}
|
||||
|
||||
public static ClientData lookup(final Long id, final String displayName, final Long officeId, final String officeName) {
|
||||
return new ClientData(null, null, officeId, officeName, null, null, id, null, null, null, null, displayName, null, null, null,
|
||||
null, null, null, null, null, null);
|
||||
null, null, null, null, null, null, null,null);
|
||||
|
||||
}
|
||||
|
||||
public static ClientData instance(final String accountNo, final EnumOptionData status, final Long officeId, final String officeName,
|
||||
final Long transferToOfficeId, final String transferToOfficeName, final Long id, final String firstname,
|
||||
final String middlename, final String lastname, final String fullname, final String displayName, final String externalId,
|
||||
final LocalDate activationDate, final Long imageId, final Long staffId, final String staffName) {
|
||||
final String mobileNo, final LocalDate activationDate, final Long imageId, final Long staffId, final String staffName,final ClientTimelineData timeline) {
|
||||
return new ClientData(accountNo, status, officeId, officeName, transferToOfficeId, transferToOfficeName, id, firstname, middlename,
|
||||
lastname, fullname, displayName, externalId, activationDate, imageId, staffId, staffName, null, null, null, null);
|
||||
lastname, fullname, displayName, externalId, mobileNo, activationDate, imageId, staffId, staffName, null, null, null, null,timeline);
|
||||
|
||||
}
|
||||
|
||||
private ClientData(final String accountNo, final EnumOptionData status, final Long officeId, final String officeName,
|
||||
final Long transferToOfficeId, final String transferToOfficeName, final Long id, final String firstname,
|
||||
final String middlename, final String lastname, final String fullname, final String displayName, final String externalId,
|
||||
final LocalDate activationDate, final Long imageId, final Long staffId, final String staffName,
|
||||
final String mobileNo, final LocalDate activationDate, final Long imageId, final Long staffId, final String staffName,
|
||||
final Collection<OfficeData> allowedOffices, final Collection<GroupGeneralData> groups,
|
||||
final Collection<StaffData> staffOptions, final Collection<CodeValueData> closureReasons) {
|
||||
final Collection<StaffData> staffOptions, final Collection<CodeValueData> closureReasons,final ClientTimelineData timeline) {
|
||||
this.accountNo = accountNo;
|
||||
this.status = status;
|
||||
if (status != null) {
|
||||
@@ -125,6 +133,7 @@ final public class ClientData implements Comparable<ClientData> {
|
||||
this.fullname = StringUtils.defaultIfEmpty(fullname, null);
|
||||
this.displayName = StringUtils.defaultIfEmpty(displayName, null);
|
||||
this.externalId = StringUtils.defaultIfEmpty(externalId, null);
|
||||
this.mobileNo = StringUtils.defaultIfEmpty(mobileNo, null);
|
||||
this.activationDate = activationDate;
|
||||
this.imageId = imageId;
|
||||
if (imageId != null) {
|
||||
@@ -142,6 +151,8 @@ final public class ClientData implements Comparable<ClientData> {
|
||||
this.officeOptions = allowedOffices;
|
||||
this.staffOptions = staffOptions;
|
||||
this.closureReasons = closureReasons;
|
||||
|
||||
this.timeline = timeline;
|
||||
}
|
||||
|
||||
public Long id() {
|
||||
@@ -168,12 +179,17 @@ final public class ClientData implements Comparable<ClientData> {
|
||||
return this.imagePresent;
|
||||
}
|
||||
|
||||
public ClientTimelineData getTimeline() {
|
||||
return this.timeline;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int compareTo(final ClientData obj) {
|
||||
if (obj == null) { return -1; }
|
||||
return new CompareToBuilder() //
|
||||
.append(this.id, obj.id) //
|
||||
.append(this.displayName, obj.displayName) //
|
||||
.append(this.mobileNo, obj.mobileNo) //
|
||||
.toComparison();
|
||||
}
|
||||
|
||||
@@ -186,6 +202,7 @@ final public class ClientData implements Comparable<ClientData> {
|
||||
return new EqualsBuilder() //
|
||||
.append(this.id, rhs.id) //
|
||||
.append(this.displayName, rhs.displayName) //
|
||||
.append(this.mobileNo, rhs.mobileNo) //
|
||||
.isEquals();
|
||||
}
|
||||
|
||||
|
||||
+18
@@ -115,6 +115,12 @@ public final class ClientDataValidator {
|
||||
.notExceedingLengthOf(100);
|
||||
}
|
||||
|
||||
if (this.fromApiJsonHelper.parameterExists(ClientApiConstants.mobileNoParamName, element)) {
|
||||
final String mobileNo = this.fromApiJsonHelper.extractStringNamed(ClientApiConstants.mobileNoParamName, element);
|
||||
baseDataValidator.reset().parameter(ClientApiConstants.mobileNoParamName).value(mobileNo).ignoreIfNull()
|
||||
.notExceedingLengthOf(50);
|
||||
}
|
||||
|
||||
final Boolean active = this.fromApiJsonHelper.extractBooleanNamed(ClientApiConstants.activeParamName, element);
|
||||
if (active != null) {
|
||||
if (active.booleanValue()) {
|
||||
@@ -126,6 +132,12 @@ public final class ClientDataValidator {
|
||||
baseDataValidator.reset().parameter(ClientApiConstants.activeParamName).value(active).trueOrFalseRequired(false);
|
||||
}
|
||||
|
||||
if (this.fromApiJsonHelper.parameterExists(ClientApiConstants.submittedOnDateParamName, element))
|
||||
{
|
||||
final LocalDate submittedOnDate = this.fromApiJsonHelper.extractLocalDateNamed(ClientApiConstants.submittedOnDateParamName, element);
|
||||
baseDataValidator.reset().parameter(ClientApiConstants.submittedOnDateParamName).value(submittedOnDate).notNull();
|
||||
}
|
||||
|
||||
throwExceptionIfValidationWarningsExist(dataValidationErrors);
|
||||
}
|
||||
|
||||
@@ -276,6 +288,12 @@ public final class ClientDataValidator {
|
||||
baseDataValidator.reset().parameter(ClientApiConstants.externalIdParamName).value(externalId).notExceedingLengthOf(100);
|
||||
}
|
||||
|
||||
if (this.fromApiJsonHelper.parameterExists(ClientApiConstants.mobileNoParamName, element)) {
|
||||
atLeastOneParameterPassedForUpdate = true;
|
||||
final String mobileNo = this.fromApiJsonHelper.extractStringNamed(ClientApiConstants.mobileNoParamName, element);
|
||||
baseDataValidator.reset().parameter(ClientApiConstants.mobileNoParamName).value(mobileNo).notExceedingLengthOf(50);
|
||||
}
|
||||
|
||||
final Boolean active = this.fromApiJsonHelper.extractBooleanNamed(ClientApiConstants.activeParamName, element);
|
||||
if (active != null) {
|
||||
if (active.booleanValue()) {
|
||||
|
||||
+60
@@ -0,0 +1,60 @@
|
||||
/**
|
||||
* 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.client.data;
|
||||
|
||||
import org.joda.time.LocalDate;
|
||||
import org.mifosplatform.organisation.monetary.data.CurrencyData;
|
||||
import org.mifosplatform.portfolio.loanaccount.data.RepaymentScheduleRelatedLoanData;
|
||||
|
||||
import java.math.BigDecimal;
|
||||
|
||||
/**
|
||||
* Immutable data object represent the important time-line events of a loan
|
||||
* application and loan.
|
||||
*/
|
||||
@SuppressWarnings("unused")
|
||||
public class ClientTimelineData {
|
||||
|
||||
private final LocalDate submittedOnDate;
|
||||
private final String submittedByUsername;
|
||||
private final String submittedByFirstname;
|
||||
private final String submittedByLastname;
|
||||
|
||||
private final LocalDate activatedOnDate;
|
||||
private final String activatedByUsername;
|
||||
private final String activatedByFirstname;
|
||||
private final String activatedByLastname;
|
||||
|
||||
private final LocalDate closedOnDate;
|
||||
private final String closedByUsername;
|
||||
private final String closedByFirstname;
|
||||
private final String closedByLastname;
|
||||
|
||||
|
||||
public ClientTimelineData(final LocalDate submittedOnDate, final String submittedByUsername,
|
||||
final String submittedByFirstname, final String submittedByLastname, final LocalDate activatedOnDate,
|
||||
final String activatedByUsername, final String activatedByFirstname, final String activatedByLastname,
|
||||
final LocalDate closedOnDate, final String closedByUsername, final String closedByFirstname,
|
||||
final String closedByLastname) {
|
||||
this.submittedOnDate = submittedOnDate;
|
||||
this.submittedByUsername = submittedByUsername;
|
||||
this.submittedByFirstname = submittedByFirstname;
|
||||
this.submittedByLastname = submittedByLastname;
|
||||
|
||||
this.activatedOnDate = activatedOnDate;
|
||||
this.activatedByUsername = activatedByUsername;
|
||||
this.activatedByFirstname = activatedByFirstname;
|
||||
this.activatedByLastname = activatedByLastname;
|
||||
|
||||
this.closedOnDate = closedOnDate;
|
||||
this.closedByUsername = closedByUsername;
|
||||
this.closedByFirstname = closedByFirstname;
|
||||
this.closedByLastname = closedByLastname;
|
||||
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
+107
-24
@@ -27,6 +27,7 @@ import javax.persistence.TemporalType;
|
||||
import javax.persistence.Transient;
|
||||
import javax.persistence.UniqueConstraint;
|
||||
|
||||
import org.apache.commons.lang.ObjectUtils;
|
||||
import org.apache.commons.lang.StringUtils;
|
||||
import org.hibernate.annotations.LazyCollection;
|
||||
import org.hibernate.annotations.LazyCollectionOption;
|
||||
@@ -44,10 +45,12 @@ import org.mifosplatform.organisation.office.domain.Office;
|
||||
import org.mifosplatform.organisation.staff.domain.Staff;
|
||||
import org.mifosplatform.portfolio.client.api.ClientApiConstants;
|
||||
import org.mifosplatform.portfolio.group.domain.Group;
|
||||
import org.mifosplatform.useradministration.domain.AppUser;
|
||||
import org.springframework.data.jpa.domain.AbstractPersistable;
|
||||
|
||||
@Entity
|
||||
@Table(name = "m_client", uniqueConstraints = { @UniqueConstraint(columnNames = { "account_no" }, name = "account_no_UNIQUE") })
|
||||
@Table(name = "m_client", uniqueConstraints = { @UniqueConstraint(columnNames = { "account_no" }, name = "account_no_UNIQUE"), //
|
||||
@UniqueConstraint(columnNames = { "mobile_no" }, name = "mobile_no_UNIQUE") })
|
||||
public final class Client extends AbstractPersistable<Long> {
|
||||
|
||||
@Column(name = "account_no", length = 20, unique = true, nullable = false)
|
||||
@@ -94,6 +97,9 @@ public final class Client extends AbstractPersistable<Long> {
|
||||
@Column(name = "display_name", length = 100, nullable = false)
|
||||
private String displayName;
|
||||
|
||||
@Column(name = "mobile_no", length = 50, nullable = false, unique = true)
|
||||
private String mobileNo;
|
||||
|
||||
@Column(name = "external_id", length = 100, nullable = true, unique = true)
|
||||
private String externalId;
|
||||
|
||||
@@ -117,10 +123,28 @@ public final class Client extends AbstractPersistable<Long> {
|
||||
@Temporal(TemporalType.DATE)
|
||||
private Date closureDate;
|
||||
|
||||
public static Client createNew(final Office clientOffice, final Group clientParentGroup, final Staff staff, final JsonCommand command) {
|
||||
@ManyToOne(optional = true)
|
||||
@JoinColumn(name = "closedon_userid", nullable = true)
|
||||
private AppUser closeddBy;
|
||||
|
||||
@Column(name = "submittedon_date", nullable = true)
|
||||
@Temporal(TemporalType.DATE)
|
||||
private Date submittedOnDate;
|
||||
|
||||
@ManyToOne(optional = true)
|
||||
@JoinColumn(name = "submittedon_userid", nullable = true)
|
||||
private AppUser submittedBy;
|
||||
|
||||
@ManyToOne(optional = true)
|
||||
@JoinColumn(name = "activatedon_userid", nullable = true)
|
||||
private AppUser activatedBy;
|
||||
|
||||
public static Client createNew(final AppUser currentUser, final Office clientOffice, final Group clientParentGroup, final Staff staff,
|
||||
final JsonCommand command) {
|
||||
|
||||
final String accountNo = command.stringValueOfParameterNamed(ClientApiConstants.accountNoParamName);
|
||||
final String externalId = command.stringValueOfParameterNamed(ClientApiConstants.externalIdParamName);
|
||||
final String mobileNo = command.stringValueOfParameterNamed(ClientApiConstants.mobileNoParamName);
|
||||
|
||||
final String firstname = command.stringValueOfParameterNamed(ClientApiConstants.firstnameParamName);
|
||||
final String middlename = command.stringValueOfParameterNamed(ClientApiConstants.middlenameParamName);
|
||||
@@ -141,23 +165,37 @@ public final class Client extends AbstractPersistable<Long> {
|
||||
officeJoiningDate = activationDate;
|
||||
}
|
||||
|
||||
return new Client(status, clientOffice, clientParentGroup, accountNo, firstname, middlename, lastname, fullname, activationDate,
|
||||
officeJoiningDate, externalId, staff);
|
||||
LocalDate submittedOnDate = new LocalDate();
|
||||
if (active && submittedOnDate.isAfter(activationDate)) {
|
||||
submittedOnDate = activationDate;
|
||||
}
|
||||
if (command.hasParameter(ClientApiConstants.submittedOnDateParamName)) {
|
||||
submittedOnDate = command.localDateValueOfParameterNamed(ClientApiConstants.submittedOnDateParamName);
|
||||
}
|
||||
|
||||
return new Client(currentUser, status, clientOffice, clientParentGroup, accountNo, firstname, middlename, lastname, fullname,
|
||||
activationDate, officeJoiningDate, externalId, mobileNo, staff, submittedOnDate);
|
||||
}
|
||||
|
||||
protected Client() {
|
||||
//
|
||||
}
|
||||
|
||||
private Client(final ClientStatus status, final Office office, final Group clientParentGroup, final String accountNo,
|
||||
final String firstname, final String middlename, final String lastname, final String fullname, final LocalDate activationDate,
|
||||
final LocalDate officeJoiningDate, final String externalId, final Staff staff) {
|
||||
private Client(final AppUser currentUser, final ClientStatus status, final Office office, final Group clientParentGroup,
|
||||
final String accountNo, final String firstname, final String middlename, final String lastname, final String fullname,
|
||||
final LocalDate activationDate, final LocalDate officeJoiningDate, final String externalId, final String mobileNo,
|
||||
final Staff staff, final LocalDate submittedOnDate) {
|
||||
|
||||
if (StringUtils.isBlank(accountNo)) {
|
||||
this.accountNumber = new RandomPasswordGenerator(19).generate();
|
||||
this.accountNumberRequiresAutoGeneration = true;
|
||||
} else {
|
||||
this.accountNumber = accountNo;
|
||||
}
|
||||
|
||||
this.submittedOnDate = submittedOnDate.toDate();
|
||||
this.submittedBy = currentUser;
|
||||
|
||||
this.status = status.getValue();
|
||||
this.office = office;
|
||||
if (StringUtils.isNotBlank(externalId)) {
|
||||
@@ -165,11 +203,19 @@ public final class Client extends AbstractPersistable<Long> {
|
||||
} else {
|
||||
this.externalId = null;
|
||||
}
|
||||
|
||||
if (StringUtils.isNotBlank(mobileNo)) {
|
||||
this.mobileNo = mobileNo.trim();
|
||||
} else {
|
||||
this.mobileNo = null;
|
||||
}
|
||||
|
||||
if (activationDate != null) {
|
||||
this.activationDate = activationDate.toDateMidnight().toDate();
|
||||
this.activationDate = activationDate.toDateTimeAtStartOfDay().toDate();
|
||||
this.activatedBy = currentUser;
|
||||
}
|
||||
if (officeJoiningDate != null) {
|
||||
this.officeJoiningDate = officeJoiningDate.toDateMidnight().toDate();
|
||||
this.officeJoiningDate = officeJoiningDate.toDateTimeAtStartOfDay().toDate();
|
||||
}
|
||||
if (StringUtils.isNotBlank(firstname)) {
|
||||
this.firstname = firstname.trim();
|
||||
@@ -234,7 +280,8 @@ public final class Client extends AbstractPersistable<Long> {
|
||||
this.accountNumberRequiresAutoGeneration = false;
|
||||
}
|
||||
|
||||
public void activate(final DateTimeFormatter formatter, final LocalDate activationLocalDate) {
|
||||
public void activate(final AppUser currentUser, final DateTimeFormatter formatter, final LocalDate activationLocalDate) {
|
||||
|
||||
if (isActive()) {
|
||||
final String defaultUserMessage = "Cannot activate client. Client is already active.";
|
||||
final ApiParameterError error = ApiParameterError.parameterError("error.msg.clients.already.active", defaultUserMessage,
|
||||
@@ -246,19 +293,8 @@ public final class Client extends AbstractPersistable<Long> {
|
||||
throw new PlatformApiDataValidationException(dataValidationErrors);
|
||||
}
|
||||
|
||||
if (isDateInTheFuture(activationLocalDate)) {
|
||||
|
||||
final String defaultUserMessage = "Activation date cannot be in the future.";
|
||||
final ApiParameterError error = ApiParameterError.parameterError("error.msg.clients.activationDate.in.the.future",
|
||||
defaultUserMessage, ClientApiConstants.activationDateParamName, activationLocalDate);
|
||||
|
||||
final List<ApiParameterError> dataValidationErrors = new ArrayList<ApiParameterError>();
|
||||
dataValidationErrors.add(error);
|
||||
|
||||
throw new PlatformApiDataValidationException(dataValidationErrors);
|
||||
}
|
||||
|
||||
this.activationDate = activationLocalDate.toDate();
|
||||
this.activatedBy = currentUser;
|
||||
this.officeJoiningDate = this.activationDate;
|
||||
this.status = ClientStatus.ACTIVE.getValue();
|
||||
|
||||
@@ -323,6 +359,12 @@ public final class Client extends AbstractPersistable<Long> {
|
||||
this.externalId = StringUtils.defaultIfEmpty(newValue, null);
|
||||
}
|
||||
|
||||
if (command.isChangeInStringParameterNamed(ClientApiConstants.mobileNoParamName, this.mobileNo)) {
|
||||
final String newValue = command.stringValueOfParameterNamed(ClientApiConstants.mobileNoParamName);
|
||||
actualChanges.put(ClientApiConstants.mobileNoParamName, newValue);
|
||||
this.mobileNo = StringUtils.defaultIfEmpty(newValue, null);
|
||||
}
|
||||
|
||||
if (command.isChangeInStringParameterNamed(ClientApiConstants.firstnameParamName, this.firstname)) {
|
||||
final String newValue = command.stringValueOfParameterNamed(ClientApiConstants.firstnameParamName);
|
||||
actualChanges.put(ClientApiConstants.firstnameParamName, newValue);
|
||||
@@ -398,7 +440,35 @@ public final class Client extends AbstractPersistable<Long> {
|
||||
}
|
||||
|
||||
private void validateActivationDate(final List<ApiParameterError> dataValidationErrors) {
|
||||
if (this.activationDate != null) {
|
||||
|
||||
if (getSubmittedOnDate() != null && isDateInTheFuture(getSubmittedOnDate())) {
|
||||
|
||||
final String defaultUserMessage = "submitted date cannot be in the future.";
|
||||
final ApiParameterError error = ApiParameterError.parameterError("error.msg.clients.submittedOnDate.in.the.future",
|
||||
defaultUserMessage, ClientApiConstants.submittedOnDateParamName, this.submittedOnDate);
|
||||
|
||||
dataValidationErrors.add(error);
|
||||
}
|
||||
|
||||
if (getActivationLocalDate() != null && getSubmittedOnDate() != null && getSubmittedOnDate().isAfter(getActivationLocalDate())) {
|
||||
|
||||
final String defaultUserMessage = "submitted date cannot be after the activation date";
|
||||
final ApiParameterError error = ApiParameterError.parameterError("error.msg.clients.submittedOnDate.after.activation.date",
|
||||
defaultUserMessage, ClientApiConstants.submittedOnDateParamName, this.submittedOnDate);
|
||||
|
||||
dataValidationErrors.add(error);
|
||||
}
|
||||
|
||||
if (getActivationLocalDate() != null && isDateInTheFuture(getActivationLocalDate())) {
|
||||
|
||||
final String defaultUserMessage = "Activation date cannot be in the future.";
|
||||
final ApiParameterError error = ApiParameterError.parameterError("error.msg.clients.activationDate.in.the.future",
|
||||
defaultUserMessage, ClientApiConstants.activationDateParamName, getActivationLocalDate());
|
||||
|
||||
dataValidationErrors.add(error);
|
||||
}
|
||||
|
||||
if (getActivationLocalDate() != null) {
|
||||
if (this.office.isOpeningDateAfter(getActivationLocalDate())) {
|
||||
final String defaultUserMessage = "Client activation date cannot be a date before the office opening date.";
|
||||
final ApiParameterError error = ApiParameterError.parameterError(
|
||||
@@ -431,6 +501,10 @@ public final class Client extends AbstractPersistable<Long> {
|
||||
this.displayName = nameBuilder.toString();
|
||||
}
|
||||
|
||||
public LocalDate getSubmittedOnDate() {
|
||||
return (LocalDate) ObjectUtils.defaultIfNull(new LocalDate(this.submittedOnDate), null);
|
||||
}
|
||||
|
||||
public LocalDate getActivationLocalDate() {
|
||||
LocalDate activationLocalDate = null;
|
||||
if (this.activationDate != null) {
|
||||
@@ -463,6 +537,14 @@ public final class Client extends AbstractPersistable<Long> {
|
||||
return this.image;
|
||||
}
|
||||
|
||||
public String mobileNo() {
|
||||
return this.mobileNo;
|
||||
}
|
||||
|
||||
public void setMobileNo(final String mobileNo) {
|
||||
this.mobileNo = mobileNo;
|
||||
}
|
||||
|
||||
public String getDisplayName() {
|
||||
return this.displayName;
|
||||
}
|
||||
@@ -519,9 +601,10 @@ public final class Client extends AbstractPersistable<Long> {
|
||||
return this.groups;
|
||||
}
|
||||
|
||||
public void close(final CodeValue closureReason, final Date closureDate) {
|
||||
public void close(final AppUser currentUser, final CodeValue closureReason, final Date closureDate) {
|
||||
this.closureReason = closureReason;
|
||||
this.closureDate = closureDate;
|
||||
this.closeddBy = currentUser;
|
||||
this.status = ClientStatus.CLOSED.getValue();
|
||||
}
|
||||
|
||||
|
||||
+91
-6
@@ -27,6 +27,7 @@ import org.mifosplatform.organisation.office.service.OfficeReadPlatformService;
|
||||
import org.mifosplatform.organisation.staff.data.StaffData;
|
||||
import org.mifosplatform.organisation.staff.service.StaffReadPlatformService;
|
||||
import org.mifosplatform.portfolio.client.data.ClientData;
|
||||
import org.mifosplatform.portfolio.client.data.ClientTimelineData;
|
||||
import org.mifosplatform.portfolio.client.domain.ClientEnumerations;
|
||||
import org.mifosplatform.portfolio.client.domain.ClientStatus;
|
||||
import org.mifosplatform.portfolio.client.exception.ClientNotFoundException;
|
||||
@@ -93,7 +94,7 @@ public class ClientReadPlatformServiceImpl implements ClientReadPlatformService
|
||||
@Override
|
||||
public Page<ClientData> retrieveAll(final SearchParameters searchParameters) {
|
||||
|
||||
final String userOfficeHierarchy = this.context.OfficeHierarchy();
|
||||
final String userOfficeHierarchy = this.context.officeHierarchy();
|
||||
final String underHierarchySearchString = userOfficeHierarchy + "%";
|
||||
|
||||
// if (searchParameters.isScopedByOfficeHierarchy()) {
|
||||
@@ -183,8 +184,7 @@ public class ClientReadPlatformServiceImpl implements ClientReadPlatformService
|
||||
@Override
|
||||
public ClientData retrieveOne(final Long clientId) {
|
||||
try {
|
||||
final AppUser currentUser = this.context.authenticatedUser();
|
||||
final String hierarchy = currentUser.getOffice().getHierarchy();
|
||||
final String hierarchy = this.context.officeHierarchy();
|
||||
final String hierarchySearchString = hierarchy + "%";
|
||||
|
||||
final String sql = "select " + this.clientMapper.schema()
|
||||
@@ -262,14 +262,34 @@ public class ClientReadPlatformServiceImpl implements ClientReadPlatformService
|
||||
sqlBuilder.append("c.transfer_to_office_id as transferToOfficeId, transferToOffice.name as transferToOfficeName, ");
|
||||
sqlBuilder.append("c.firstname as firstname, c.middlename as middlename, c.lastname as lastname, ");
|
||||
sqlBuilder.append("c.fullname as fullname, c.display_name as displayName, ");
|
||||
sqlBuilder.append("c.mobile_no as mobileNo, ");
|
||||
sqlBuilder.append("c.activation_date as activationDate, c.image_id as imageId, ");
|
||||
sqlBuilder.append("c.staff_id as staffId, s.display_name as staffName ");
|
||||
sqlBuilder.append("c.staff_id as staffId, s.display_name as staffName,");
|
||||
|
||||
sqlBuilder.append("c.submittedon_date as submittedOnDate, ");
|
||||
sqlBuilder.append("sbu.username as submittedByUsername, ");
|
||||
sqlBuilder.append("sbu.firstname as submittedByFirstname, ");
|
||||
sqlBuilder.append("sbu.lastname as submittedByLastname, ");
|
||||
|
||||
sqlBuilder.append("c.closedon_date as closedOnDate, ");
|
||||
sqlBuilder.append("clu.username as closedByUsername, ");
|
||||
sqlBuilder.append("clu.firstname as closedByFirstname, ");
|
||||
sqlBuilder.append("clu.lastname as closedByLastname, ");
|
||||
|
||||
sqlBuilder.append("acu.username as activatedByUsername, ");
|
||||
sqlBuilder.append("acu.firstname as activatedByFirstname, ");
|
||||
sqlBuilder.append("acu.lastname as activatedByLastname ");
|
||||
|
||||
sqlBuilder.append("from m_client c ");
|
||||
sqlBuilder.append("join m_office o on o.id = c.office_id ");
|
||||
sqlBuilder.append("join m_group_client pgc on pgc.client_id = c.id ");
|
||||
sqlBuilder.append("left join m_staff s on s.id = c.staff_id ");
|
||||
sqlBuilder.append("left join m_office transferToOffice on transferToOffice.id = c.transfer_to_office_id ");
|
||||
|
||||
sqlBuilder.append("left join m_appuser sbu on sbu.id = c.submittedon_userid ");
|
||||
sqlBuilder.append("left join m_appuser acu on acu.id = c.activatedon_userid ");
|
||||
sqlBuilder.append("left join m_appuser clu on clu.id = c.closedon_userid ");
|
||||
|
||||
this.schema = sqlBuilder.toString();
|
||||
}
|
||||
|
||||
@@ -298,13 +318,35 @@ public class ClientReadPlatformServiceImpl implements ClientReadPlatformService
|
||||
final String fullname = rs.getString("fullname");
|
||||
final String displayName = rs.getString("displayName");
|
||||
final String externalId = rs.getString("externalId");
|
||||
final String mobileNo = rs.getString("mobileNo");
|
||||
|
||||
final LocalDate activationDate = JdbcSupport.getLocalDate(rs, "activationDate");
|
||||
final Long imageId = JdbcSupport.getLong(rs, "imageId");
|
||||
final Long staffId = JdbcSupport.getLong(rs, "staffId");
|
||||
final String staffName = rs.getString("staffName");
|
||||
|
||||
final LocalDate closedOnDate = JdbcSupport.getLocalDate(rs, "closedOnDate");
|
||||
final String closedByUsername = rs.getString("closedByUsername");
|
||||
final String closedByFirstname = rs.getString("closedByFirstname");
|
||||
final String closedByLastname = rs.getString("closedByLastname");
|
||||
|
||||
final LocalDate submittedOnDate = JdbcSupport.getLocalDate(rs, "submittedOnDate");
|
||||
final String submittedByUsername = rs.getString("submittedByUsername");
|
||||
final String submittedByFirstname = rs.getString("submittedByFirstname");
|
||||
final String submittedByLastname = rs.getString("submittedByLastname");
|
||||
|
||||
|
||||
final String activatedByUsername = rs.getString("activatedByUsername");
|
||||
final String activatedByFirstname = rs.getString("activatedByFirstname");
|
||||
final String activatedByLastname = rs.getString("activatedByLastname");
|
||||
|
||||
final ClientTimelineData timeline = new ClientTimelineData (submittedOnDate, submittedByUsername, submittedByFirstname, submittedByLastname,
|
||||
activationDate, activatedByUsername, activatedByFirstname, activatedByLastname, closedOnDate, closedByUsername,
|
||||
closedByFirstname, closedByLastname);
|
||||
|
||||
return ClientData.instance(accountNo, status, officeId, officeName, transferToOfficeId, transferToOfficeName, id, firstname,
|
||||
middlename, lastname, fullname, displayName, externalId, activationDate, imageId, staffId, staffName);
|
||||
middlename, lastname, fullname, displayName, externalId, mobileNo, activationDate, imageId, staffId, staffName,timeline);
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@@ -335,12 +377,35 @@ public class ClientReadPlatformServiceImpl implements ClientReadPlatformService
|
||||
builder.append("c.transfer_to_office_id as transferToOfficeId, transferToOffice.name as transferToOfficeName, ");
|
||||
builder.append("c.firstname as firstname, c.middlename as middlename, c.lastname as lastname, ");
|
||||
builder.append("c.fullname as fullname, c.display_name as displayName, ");
|
||||
builder.append("c.mobile_no as mobileNo, ");
|
||||
|
||||
|
||||
builder.append("c.submittedon_date as submittedOnDate, ");
|
||||
builder.append("sbu.username as submittedByUsername, ");
|
||||
builder.append("sbu.firstname as submittedByFirstname, ");
|
||||
builder.append("sbu.lastname as submittedByLastname, ");
|
||||
|
||||
builder.append("c.closedon_date as closedOnDate, ");
|
||||
builder.append("clu.username as closedByUsername, ");
|
||||
builder.append("clu.firstname as closedByFirstname, ");
|
||||
builder.append("clu.lastname as closedByLastname, ");
|
||||
|
||||
// builder.append("c.submittedon as submittedOnDate, ");
|
||||
builder.append("acu.username as activatedByUsername, ");
|
||||
builder.append("acu.firstname as activatedByFirstname, ");
|
||||
builder.append("acu.lastname as activatedByLastname, ");
|
||||
|
||||
|
||||
builder.append("c.activation_date as activationDate, c.image_id as imageId, ");
|
||||
builder.append("c.staff_id as staffId, s.display_name as staffName ");
|
||||
builder.append("from m_client c ");
|
||||
builder.append("join m_office o on o.id = c.office_id ");
|
||||
builder.append("left join m_staff s on s.id = c.staff_id ");
|
||||
builder.append("left join m_office transferToOffice on transferToOffice.id = c.transfer_to_office_id ");
|
||||
builder.append("left join m_appuser sbu on sbu.id = c.submittedon_userid ");
|
||||
builder.append("left join m_appuser acu on acu.id = c.activatedon_userid ");
|
||||
builder.append("left join m_appuser clu on clu.id = c.closedon_userid ");
|
||||
|
||||
this.schema = builder.toString();
|
||||
}
|
||||
|
||||
@@ -369,13 +434,33 @@ public class ClientReadPlatformServiceImpl implements ClientReadPlatformService
|
||||
final String fullname = rs.getString("fullname");
|
||||
final String displayName = rs.getString("displayName");
|
||||
final String externalId = rs.getString("externalId");
|
||||
final String mobileNo = rs.getString("mobileNo");
|
||||
final LocalDate activationDate = JdbcSupport.getLocalDate(rs, "activationDate");
|
||||
final Long imageId = JdbcSupport.getLong(rs, "imageId");
|
||||
final Long staffId = JdbcSupport.getLong(rs, "staffId");
|
||||
final String staffName = rs.getString("staffName");
|
||||
|
||||
final LocalDate closedOnDate = JdbcSupport.getLocalDate(rs, "closedOnDate");
|
||||
final String closedByUsername = rs.getString("closedByUsername");
|
||||
final String closedByFirstname = rs.getString("closedByFirstname");
|
||||
final String closedByLastname = rs.getString("closedByLastname");
|
||||
|
||||
final LocalDate submittedOnDate = JdbcSupport.getLocalDate(rs, "submittedOnDate");
|
||||
final String submittedByUsername = rs.getString("submittedByUsername");
|
||||
final String submittedByFirstname = rs.getString("submittedByFirstname");
|
||||
final String submittedByLastname = rs.getString("submittedByLastname");
|
||||
|
||||
final String activatedByUsername = rs.getString("activatedByUsername");
|
||||
final String activatedByFirstname = rs.getString("activatedByFirstname");
|
||||
final String activatedByLastname = rs.getString("activatedByLastname");
|
||||
|
||||
final ClientTimelineData timeline = new ClientTimelineData (submittedOnDate, submittedByUsername, submittedByFirstname, submittedByLastname,
|
||||
activationDate, activatedByUsername, activatedByFirstname, activatedByLastname, closedOnDate, closedByUsername,
|
||||
closedByFirstname, closedByLastname);
|
||||
|
||||
return ClientData.instance(accountNo, status, officeId, officeName, transferToOfficeId, transferToOfficeName, id, firstname,
|
||||
middlename, lastname, fullname, displayName, externalId, activationDate, imageId, staffId, staffName);
|
||||
middlename, lastname, fullname, displayName, externalId, mobileNo, activationDate, imageId, staffId, staffName,timeline);
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+8
-6
@@ -44,6 +44,7 @@ import org.mifosplatform.portfolio.note.domain.Note;
|
||||
import org.mifosplatform.portfolio.note.domain.NoteRepository;
|
||||
import org.mifosplatform.portfolio.savings.domain.SavingsAccount;
|
||||
import org.mifosplatform.portfolio.savings.domain.SavingsAccountRepository;
|
||||
import org.mifosplatform.useradministration.domain.AppUser;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
@@ -136,7 +137,7 @@ public class ClientWritePlatformServiceJpaRepositoryImpl implements ClientWriteP
|
||||
public CommandProcessingResult createClient(final JsonCommand command) {
|
||||
|
||||
try {
|
||||
this.context.authenticatedUser();
|
||||
final AppUser currentUser = this.context.authenticatedUser();
|
||||
|
||||
this.fromApiJsonDeserializer.validateForCreate(command.json());
|
||||
|
||||
@@ -159,7 +160,7 @@ public class ClientWritePlatformServiceJpaRepositoryImpl implements ClientWriteP
|
||||
staff = this.staffRepository.findByOfficeHierarchyWithNotFoundDetection(staffId, clientOffice.getHierarchy());
|
||||
}
|
||||
|
||||
final Client newClient = Client.createNew(clientOffice, clientParentGroup, staff, command);
|
||||
final Client newClient = Client.createNew(currentUser,clientOffice, clientParentGroup, staff, command);
|
||||
|
||||
this.clientRepository.save(newClient);
|
||||
|
||||
@@ -188,8 +189,6 @@ public class ClientWritePlatformServiceJpaRepositoryImpl implements ClientWriteP
|
||||
public CommandProcessingResult updateClient(final Long clientId, final JsonCommand command) {
|
||||
|
||||
try {
|
||||
this.context.authenticatedUser();
|
||||
|
||||
this.fromApiJsonDeserializer.validateForUpdate(command.json());
|
||||
|
||||
final Client clientForUpdate = this.clientRepository.findOneWithNotFoundDetection(clientId);
|
||||
@@ -239,7 +238,8 @@ public class ClientWritePlatformServiceJpaRepositoryImpl implements ClientWriteP
|
||||
final DateTimeFormatter fmt = DateTimeFormat.forPattern(command.dateFormat()).withLocale(locale);
|
||||
final LocalDate activationDate = command.localDateValueOfParameterNamed("activationDate");
|
||||
|
||||
client.activate(fmt, activationDate);
|
||||
final AppUser currentUser = this.context.authenticatedUser();
|
||||
client.activate(currentUser, fmt, activationDate);
|
||||
|
||||
this.clientRepository.saveAndFlush(client);
|
||||
|
||||
@@ -332,6 +332,8 @@ public class ClientWritePlatformServiceJpaRepositoryImpl implements ClientWriteP
|
||||
@Override
|
||||
public CommandProcessingResult closeClient(final Long clientId, final JsonCommand command) {
|
||||
try {
|
||||
|
||||
final AppUser currentUser = this.context.authenticatedUser();
|
||||
this.fromApiJsonDeserializer.validateClose(command);
|
||||
|
||||
final Client client = this.clientRepository.findOneWithNotFoundDetection(clientId);
|
||||
@@ -389,7 +391,7 @@ public class ClientWritePlatformServiceJpaRepositoryImpl implements ClientWriteP
|
||||
}
|
||||
}
|
||||
|
||||
client.close(closureReason, closureDate.toDate());
|
||||
client.close(currentUser,closureReason, closureDate.toDate());
|
||||
this.clientRepository.saveAndFlush(client);
|
||||
|
||||
return new CommandProcessingResultBuilder() //
|
||||
|
||||
+14
-8
@@ -30,7 +30,6 @@ 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;
|
||||
@@ -304,9 +303,11 @@ public class CollectionSheetReadPlatformServiceImpl implements CollectionSheetRe
|
||||
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); }
|
||||
// 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 + "%";
|
||||
@@ -316,7 +317,10 @@ public class CollectionSheetReadPlatformServiceImpl implements CollectionSheetRe
|
||||
final JLGCollectionSheetFaltDataMapper mapper = new JLGCollectionSheetFaltDataMapper();
|
||||
|
||||
final 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 ");
|
||||
sql.append(" WHERE gp.id = :groupId ")
|
||||
.append(" and (gp.status_enum = 300 or (gp.status_enum = 600 and gp.closedon_date >= :dueDate)) ")
|
||||
.append(" and (cl.status_enum = 300 or (cl.status_enum = 600 and cl.closedon_date >= :dueDate)) ")
|
||||
.append(" GROUP BY gp.id ,cl.id , ln.id ORDER BY gp.id , cl.id , ln.id ");
|
||||
|
||||
// entityType should be center if it's within a center
|
||||
final CalendarEntityType entityType = (group.isChildGroup()) ? CalendarEntityType.CENTERS : CalendarEntityType.GROUPS;
|
||||
@@ -348,17 +352,19 @@ public class CollectionSheetReadPlatformServiceImpl implements CollectionSheetRe
|
||||
|
||||
final JLGCollectionSheetFaltDataMapper mapper = new JLGCollectionSheetFaltDataMapper();
|
||||
|
||||
String sql = mapper.collectionSheetSchema();
|
||||
sql += "WHERE gp.parent_id = :centerId 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.parent_id = :centerId ")
|
||||
.append(" and (gp.status_enum = 300 or (gp.status_enum = 600 and gp.closedon_date >= :dueDate)) ")
|
||||
.append(" and (cl.status_enum = 300 or (cl.status_enum = 600 and cl.closedon_date >= :dueDate)) ")
|
||||
.append(" 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("entityTypeId", CalendarEntityType.CENTERS.getValue());
|
||||
|
||||
final Collection<JLGCollectionSheetFlatData> collectionSheetFlatDatas = this.namedParameterjdbcTemplate.query(sql, namedParameters,
|
||||
final Collection<JLGCollectionSheetFlatData> collectionSheetFlatDatas = this.namedParameterjdbcTemplate.query(sql.toString(), namedParameters,
|
||||
mapper);
|
||||
|
||||
return buildJLGCollectionSheet(transactionDate, collectionSheetFlatDatas);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
+20
-6
@@ -12,6 +12,7 @@ import java.util.Set;
|
||||
|
||||
import javax.ws.rs.Consumes;
|
||||
import javax.ws.rs.DELETE;
|
||||
import javax.ws.rs.DefaultValue;
|
||||
import javax.ws.rs.GET;
|
||||
import javax.ws.rs.POST;
|
||||
import javax.ws.rs.PUT;
|
||||
@@ -24,6 +25,7 @@ import javax.ws.rs.core.MediaType;
|
||||
import javax.ws.rs.core.UriInfo;
|
||||
|
||||
import org.apache.commons.lang.StringUtils;
|
||||
import org.joda.time.LocalDate;
|
||||
import org.mifosplatform.commands.domain.CommandWrapper;
|
||||
import org.mifosplatform.commands.service.CommandWrapperBuilder;
|
||||
import org.mifosplatform.commands.service.PortfolioCommandSourceWritePlatformService;
|
||||
@@ -48,6 +50,8 @@ import org.mifosplatform.portfolio.group.data.CenterData;
|
||||
import org.mifosplatform.portfolio.group.data.GroupGeneralData;
|
||||
import org.mifosplatform.portfolio.group.service.CenterReadPlatformService;
|
||||
import org.mifosplatform.portfolio.group.service.SearchParameters;
|
||||
import org.mifosplatform.portfolio.meeting.data.MeetingData;
|
||||
import org.mifosplatform.portfolio.meeting.service.MeetingReadPlatformService;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.context.annotation.Scope;
|
||||
import org.springframework.stereotype.Component;
|
||||
@@ -70,6 +74,7 @@ public class CentersApiResource {
|
||||
private final FromJsonHelper fromJsonHelper;
|
||||
private final AccountDetailsReadPlatformService accountDetailsReadPlatformService;
|
||||
private final CalendarReadPlatformService calendarReadPlatformService;
|
||||
private final MeetingReadPlatformService meetingReadPlatformService;
|
||||
|
||||
@Autowired
|
||||
public CentersApiResource(final PlatformSecurityContext context, final CenterReadPlatformService centerReadPlatformService,
|
||||
@@ -79,7 +84,7 @@ public class CentersApiResource {
|
||||
final PortfolioCommandSourceWritePlatformService commandsSourceWritePlatformService,
|
||||
final CollectionSheetReadPlatformService collectionSheetReadPlatformService, final FromJsonHelper fromJsonHelper,
|
||||
final AccountDetailsReadPlatformService accountDetailsReadPlatformService,
|
||||
final CalendarReadPlatformService calendarReadPlatformService) {
|
||||
final CalendarReadPlatformService calendarReadPlatformService, final MeetingReadPlatformService meetingReadPlatformService) {
|
||||
this.context = context;
|
||||
this.centerReadPlatformService = centerReadPlatformService;
|
||||
this.centerApiJsonSerializer = centerApiJsonSerializer;
|
||||
@@ -91,6 +96,7 @@ public class CentersApiResource {
|
||||
this.fromJsonHelper = fromJsonHelper;
|
||||
this.accountDetailsReadPlatformService = accountDetailsReadPlatformService;
|
||||
this.calendarReadPlatformService = calendarReadPlatformService;
|
||||
this.meetingReadPlatformService = meetingReadPlatformService;
|
||||
}
|
||||
|
||||
@GET
|
||||
@@ -98,7 +104,8 @@ public class CentersApiResource {
|
||||
@Consumes({ MediaType.APPLICATION_JSON })
|
||||
@Produces({ MediaType.APPLICATION_JSON })
|
||||
public String retrieveTemplate(@Context final UriInfo uriInfo, @QueryParam("command") final String commandParam,
|
||||
@QueryParam("officeId") final Long officeId) {
|
||||
@QueryParam("officeId") final Long officeId,
|
||||
@DefaultValue("false") @QueryParam("staffInSelectedOfficeOnly") final boolean staffInSelectedOfficeOnly) {
|
||||
|
||||
this.context.authenticatedUser().validateHasReadPermission(GroupingTypesApiConstants.CENTER_RESOURCE_NAME);
|
||||
|
||||
@@ -109,7 +116,7 @@ public class CentersApiResource {
|
||||
GroupingTypesApiConstants.CENTER_RESPONSE_DATA_PARAMETERS);
|
||||
}
|
||||
|
||||
final CenterData template = this.centerReadPlatformService.retrieveTemplate(officeId);
|
||||
final CenterData template = this.centerReadPlatformService.retrieveTemplate(officeId, staffInSelectedOfficeOnly);
|
||||
|
||||
final ApiRequestJsonSerializationSettings settings = this.apiRequestParameterHelper.process(uriInfo.getQueryParameters());
|
||||
return this.centerApiJsonSerializer.serialize(settings, template, GroupingTypesApiConstants.CENTER_RESPONSE_DATA_PARAMETERS);
|
||||
@@ -138,7 +145,8 @@ public class CentersApiResource {
|
||||
@Path("{centerId}")
|
||||
@Consumes({ MediaType.APPLICATION_JSON })
|
||||
@Produces({ MediaType.APPLICATION_JSON })
|
||||
public String retrieveOne(@Context final UriInfo uriInfo, @PathParam("centerId") final Long centerId) {
|
||||
public String retrieveOne(@Context final UriInfo uriInfo, @PathParam("centerId") final Long centerId,
|
||||
@DefaultValue("false") @QueryParam("staffInSelectedOfficeOnly") final boolean staffInSelectedOfficeOnly) {
|
||||
|
||||
this.context.authenticatedUser().validateHasReadPermission(GroupingTypesApiConstants.CENTER_RESOURCE_NAME);
|
||||
final Set<String> associationParameters = ApiParameterHelper.extractAssociationsForResponseIfProvided(uriInfo.getQueryParameters());
|
||||
@@ -148,7 +156,7 @@ public class CentersApiResource {
|
||||
|
||||
final boolean template = ApiParameterHelper.template(uriInfo.getQueryParameters());
|
||||
if (template) {
|
||||
final CenterData templateCenter = this.centerReadPlatformService.retrieveTemplate(center.officeId());
|
||||
final CenterData templateCenter = this.centerReadPlatformService.retrieveTemplate(center.officeId(), staffInSelectedOfficeOnly);
|
||||
center = CenterData.withTemplate(templateCenter, center);
|
||||
}
|
||||
|
||||
@@ -161,7 +169,13 @@ public class CentersApiResource {
|
||||
collectionMeetingCalendar = this.calendarReadPlatformService.retrieveCollctionCalendarByEntity(centerId,
|
||||
CalendarEntityType.CENTERS.getValue());
|
||||
if (collectionMeetingCalendar != null) {
|
||||
collectionMeetingCalendar = this.calendarReadPlatformService.generateRecurringDate(collectionMeetingCalendar);
|
||||
final boolean withHistory = true;
|
||||
final LocalDate tillDate = null;
|
||||
final Collection<LocalDate> recurringDates = this.calendarReadPlatformService.generateRecurringDates(collectionMeetingCalendar, withHistory, tillDate);
|
||||
final Collection<LocalDate> nextTenRecurringDates = this.calendarReadPlatformService.generateNextTenRecurringDates(collectionMeetingCalendar);
|
||||
final MeetingData lastMeeting = this.meetingReadPlatformService.retrieveLastMeeting(collectionMeetingCalendar.getCalendarInstanceId());
|
||||
final LocalDate recentEligibleMeetingDate = this.calendarReadPlatformService.generateNextEligibleMeetingDateForCollection(collectionMeetingCalendar, lastMeeting);
|
||||
collectionMeetingCalendar = CalendarData.withRecurringDates(collectionMeetingCalendar, recurringDates, nextTenRecurringDates, recentEligibleMeetingDate);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+6
-3
@@ -42,6 +42,8 @@ public class GroupingTypesApiConstants {
|
||||
public static final String activationDateParamName = "activationDate";
|
||||
public static final String groupMembersParamName = "groupMembers";
|
||||
|
||||
public static final String submittedOnDateParamName = "submittedOnDate";
|
||||
|
||||
// group parameters
|
||||
public static final String centerIdParamName = "centerId";
|
||||
public static final String clientMembersParamName = "clientMembers";
|
||||
@@ -55,6 +57,7 @@ public class GroupingTypesApiConstants {
|
||||
public static final String staffOptionsParamName = "staffOptions";
|
||||
public static final String clientOptionsParamName = "clientOptions";
|
||||
public static final String collectionMeetingCalendar = "collectionMeetingCalendar";
|
||||
public static final String timeLine ="timeline";
|
||||
|
||||
// group close parameters
|
||||
public static final String closureDateParamName = "closureDate";
|
||||
@@ -62,11 +65,11 @@ public class GroupingTypesApiConstants {
|
||||
|
||||
public static final Set<String> CENTER_REQUEST_DATA_PARAMETERS = new HashSet<String>(Arrays.asList(localeParamName,
|
||||
dateFormatParamName, idParamName, nameParamName, externalIdParamName, officeIdParamName, staffIdParamName, activeParamName,
|
||||
activationDateParamName, groupMembersParamName));
|
||||
activationDateParamName, groupMembersParamName,submittedOnDateParamName));
|
||||
|
||||
public static final Set<String> GROUP_REQUEST_DATA_PARAMETERS = new HashSet<String>(Arrays.asList(localeParamName, dateFormatParamName,
|
||||
idParamName, nameParamName, externalIdParamName, centerIdParamName, officeIdParamName, staffIdParamName, activeParamName,
|
||||
activationDateParamName, clientMembersParamName, collectionMeetingCalendar));
|
||||
activationDateParamName, clientMembersParamName, collectionMeetingCalendar,submittedOnDateParamName));
|
||||
|
||||
public static final Set<String> GROUP_ROLES_REQUEST_DATA_PARAMETERS = new HashSet<String>(Arrays.asList(roleParamName,
|
||||
clientIdParamName));
|
||||
@@ -86,7 +89,7 @@ public class GroupingTypesApiConstants {
|
||||
|
||||
public static final Set<String> GROUP_RESPONSE_DATA_PARAMETERS = new HashSet<String>(Arrays.asList(idParamName, nameParamName,
|
||||
externalIdParamName, officeIdParamName, officeNameParamName, "parentId", "parentName", staffIdParamName, staffNameParamName,
|
||||
hierarchyParamName, officeOptionsParamName, staffOptionsParamName, clientOptionsParamName));
|
||||
hierarchyParamName, officeOptionsParamName, staffOptionsParamName, clientOptionsParamName,timeLine));
|
||||
|
||||
public static final Set<String> ACTIVATION_REQUEST_DATA_PARAMETERS = new HashSet<String>(Arrays.asList(localeParamName,
|
||||
dateFormatParamName, activationDateParamName));
|
||||
|
||||
+13
-2
@@ -26,6 +26,7 @@ import javax.ws.rs.core.MediaType;
|
||||
import javax.ws.rs.core.UriInfo;
|
||||
|
||||
import org.apache.commons.lang.StringUtils;
|
||||
import org.joda.time.LocalDate;
|
||||
import org.mifosplatform.commands.domain.CommandWrapper;
|
||||
import org.mifosplatform.commands.service.CommandWrapperBuilder;
|
||||
import org.mifosplatform.commands.service.PortfolioCommandSourceWritePlatformService;
|
||||
@@ -55,6 +56,8 @@ import org.mifosplatform.portfolio.group.service.CenterReadPlatformService;
|
||||
import org.mifosplatform.portfolio.group.service.GroupReadPlatformService;
|
||||
import org.mifosplatform.portfolio.group.service.GroupRolesReadPlatformService;
|
||||
import org.mifosplatform.portfolio.group.service.SearchParameters;
|
||||
import org.mifosplatform.portfolio.meeting.data.MeetingData;
|
||||
import org.mifosplatform.portfolio.meeting.service.MeetingReadPlatformService;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.context.annotation.Scope;
|
||||
import org.springframework.stereotype.Component;
|
||||
@@ -81,6 +84,7 @@ public class GroupsApiResource {
|
||||
private final GroupRolesReadPlatformService groupRolesReadPlatformService;
|
||||
private final AccountDetailsReadPlatformService accountDetailsReadPlatformService;
|
||||
private final CalendarReadPlatformService calendarReadPlatformService;
|
||||
private final MeetingReadPlatformService meetingReadPlatformService;
|
||||
|
||||
@Autowired
|
||||
public GroupsApiResource(final PlatformSecurityContext context, final GroupReadPlatformService groupReadPlatformService,
|
||||
@@ -93,7 +97,7 @@ public class GroupsApiResource {
|
||||
final CollectionSheetReadPlatformService collectionSheetReadPlatformService, final FromJsonHelper fromJsonHelper,
|
||||
final GroupRolesReadPlatformService groupRolesReadPlatformService,
|
||||
final AccountDetailsReadPlatformService accountDetailsReadPlatformService,
|
||||
final CalendarReadPlatformService calendarReadPlatformService) {
|
||||
final CalendarReadPlatformService calendarReadPlatformService, final MeetingReadPlatformService meetingReadPlatformService) {
|
||||
|
||||
this.context = context;
|
||||
this.groupReadPlatformService = groupReadPlatformService;
|
||||
@@ -109,6 +113,7 @@ public class GroupsApiResource {
|
||||
this.groupRolesReadPlatformService = groupRolesReadPlatformService;
|
||||
this.accountDetailsReadPlatformService = accountDetailsReadPlatformService;
|
||||
this.calendarReadPlatformService = calendarReadPlatformService;
|
||||
this.meetingReadPlatformService = meetingReadPlatformService;
|
||||
}
|
||||
|
||||
@GET
|
||||
@@ -216,7 +221,13 @@ public class GroupsApiResource {
|
||||
CalendarEntityType.GROUPS.getValue());
|
||||
}
|
||||
if (collectionMeetingCalendar != null) {
|
||||
collectionMeetingCalendar = this.calendarReadPlatformService.generateRecurringDate(collectionMeetingCalendar);
|
||||
final boolean withHistory = true;
|
||||
final LocalDate tillDate = null;
|
||||
final Collection<LocalDate> recurringDates = this.calendarReadPlatformService.generateRecurringDates(collectionMeetingCalendar, withHistory, tillDate);
|
||||
final Collection<LocalDate> nextTenRecurringDates = this.calendarReadPlatformService.generateNextTenRecurringDates(collectionMeetingCalendar);
|
||||
final MeetingData lastMeeting = this.meetingReadPlatformService.retrieveLastMeeting(collectionMeetingCalendar.getCalendarInstanceId());
|
||||
final LocalDate recentEligibleMeetingDate = this.calendarReadPlatformService.generateNextEligibleMeetingDateForCollection(collectionMeetingCalendar, lastMeeting);
|
||||
collectionMeetingCalendar = CalendarData.withRecurringDates(collectionMeetingCalendar, recurringDates, nextTenRecurringDates, recentEligibleMeetingDate);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+11
-9
@@ -52,13 +52,14 @@ public class GroupGeneralData {
|
||||
private final Collection<CodeValueData> availableRoles;
|
||||
private final GroupRoleData selectedRole;
|
||||
private final Collection<CodeValueData> closureReasons;
|
||||
private final GroupTimelineData timeline;
|
||||
|
||||
public static GroupGeneralData lookup(final Long groupId, final String groupName) {
|
||||
final Collection<ClientData> clientMembers = null;
|
||||
final Collection<GroupRoleData> groupRoles = null;
|
||||
final Collection<CodeValueData> closureReasons = null;
|
||||
return new GroupGeneralData(groupId, groupName, null, null, null, null, null, null, null, null, null, null, clientMembers, null,
|
||||
null, null, null, groupRoles, null, null, null, null, closureReasons);
|
||||
null, null, null, groupRoles, null, null, null, null, closureReasons,null);
|
||||
}
|
||||
|
||||
public static GroupGeneralData template(final Long officeId, final Long centerId, final String centerName, final Long staffId,
|
||||
@@ -72,7 +73,7 @@ public class GroupGeneralData {
|
||||
|
||||
return new GroupGeneralData(null, null, null, null, null, officeId, null, centerId, centerName, staffId, staffName, null,
|
||||
clientMembers, centerOptions, officeOptions, staffOptions, clientOptions, groupRoles, availableRoles, null, null, null,
|
||||
closureReasons);
|
||||
closureReasons,null);
|
||||
}
|
||||
|
||||
public static GroupGeneralData withTemplate(final GroupGeneralData templatedGrouping, final GroupGeneralData grouping) {
|
||||
@@ -80,7 +81,7 @@ public class GroupGeneralData {
|
||||
grouping.officeId, grouping.officeName, grouping.centerId, grouping.centerName, grouping.staffId, grouping.staffName,
|
||||
grouping.hierarchy, grouping.clientMembers, templatedGrouping.centerOptions, templatedGrouping.officeOptions,
|
||||
templatedGrouping.staffOptions, templatedGrouping.clientOptions, grouping.groupRoles, templatedGrouping.availableRoles,
|
||||
grouping.selectedRole, grouping.calendarsData, grouping.collectionMeetingCalendar, grouping.closureReasons);
|
||||
grouping.selectedRole, grouping.calendarsData, grouping.collectionMeetingCalendar, grouping.closureReasons,templatedGrouping.timeline);
|
||||
}
|
||||
|
||||
public static GroupGeneralData withAssocations(final GroupGeneralData grouping, final Collection<ClientData> membersOfGroup,
|
||||
@@ -90,12 +91,12 @@ public class GroupGeneralData {
|
||||
grouping.officeId, grouping.officeName, grouping.centerId, grouping.centerName, grouping.staffId, grouping.staffName,
|
||||
grouping.hierarchy, membersOfGroup, grouping.centerOptions, grouping.officeOptions, grouping.staffOptions,
|
||||
grouping.clientOptions, groupRoles, grouping.availableRoles, grouping.selectedRole, calendarsData,
|
||||
collectionMeetingCalendar, grouping.closureReasons);
|
||||
collectionMeetingCalendar, grouping.closureReasons,grouping.timeline);
|
||||
}
|
||||
|
||||
public static GroupGeneralData instance(final Long id, final String name, final String externalId, final EnumOptionData status,
|
||||
final LocalDate activationDate, final Long officeId, final String officeName, final Long centerId, final String centerName,
|
||||
final Long staffId, final String staffName, final String hierarchy) {
|
||||
final Long staffId, final String staffName, final String hierarchy,final GroupTimelineData timeline) {
|
||||
|
||||
final Collection<ClientData> clientMembers = null;
|
||||
final Collection<CenterData> centerOptions = null;
|
||||
@@ -111,7 +112,7 @@ public class GroupGeneralData {
|
||||
|
||||
return new GroupGeneralData(id, name, externalId, status, activationDate, officeId, officeName, centerId, centerName, staffId,
|
||||
staffName, hierarchy, clientMembers, centerOptions, officeOptions, staffOptions, clientOptions, groupRoles, availableRoles,
|
||||
role, calendarsData, collectionMeetingCalendar, closureReasons);
|
||||
role, calendarsData, collectionMeetingCalendar, closureReasons,timeline);
|
||||
}
|
||||
|
||||
private GroupGeneralData(final Long id, final String name, final String externalId, final EnumOptionData status,
|
||||
@@ -121,7 +122,7 @@ public class GroupGeneralData {
|
||||
final Collection<StaffData> staffOptions, final Collection<ClientData> clientOptions,
|
||||
final Collection<GroupRoleData> groupRoles, final Collection<CodeValueData> availableRoles, final GroupRoleData role,
|
||||
final Collection<CalendarData> calendarsData, final CalendarData collectionMeetingCalendar,
|
||||
final Collection<CodeValueData> closureReasons) {
|
||||
final Collection<CodeValueData> closureReasons,final GroupTimelineData timeline) {
|
||||
this.id = id;
|
||||
this.name = name;
|
||||
this.externalId = externalId;
|
||||
@@ -159,6 +160,7 @@ public class GroupGeneralData {
|
||||
this.calendarsData = calendarsData;
|
||||
this.collectionMeetingCalendar = collectionMeetingCalendar;
|
||||
this.closureReasons = closureReasons;
|
||||
this.timeline = timeline;
|
||||
}
|
||||
|
||||
public Long getId() {
|
||||
@@ -190,7 +192,7 @@ public class GroupGeneralData {
|
||||
grouping.officeId, grouping.officeName, grouping.centerId, grouping.centerName, grouping.staffId, grouping.staffName,
|
||||
grouping.hierarchy, grouping.clientMembers, grouping.centerOptions, grouping.officeOptions, grouping.staffOptions,
|
||||
grouping.clientOptions, grouping.groupRoles, grouping.availableRoles, selectedRole, grouping.calendarsData,
|
||||
grouping.collectionMeetingCalendar, grouping.closureReasons);
|
||||
grouping.collectionMeetingCalendar, grouping.closureReasons,null);
|
||||
}
|
||||
|
||||
public static GroupGeneralData withClosureReasons(final Collection<CodeValueData> closureReasons) {
|
||||
@@ -219,6 +221,6 @@ public class GroupGeneralData {
|
||||
|
||||
return new GroupGeneralData(id, name, externalId, status, activationDate, officeId, officeName, centerId, centerName, staffId,
|
||||
staffName, hierarchy, clientMembers, centerOptions, officeOptions, staffOptions, clientOptions, groupRoles, availableRoles,
|
||||
role, calendarsData, collectionMeetingCalendar, closureReasons);
|
||||
role, calendarsData, collectionMeetingCalendar, closureReasons,null);
|
||||
}
|
||||
}
|
||||
+56
@@ -0,0 +1,56 @@
|
||||
/**
|
||||
* 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.group.data;
|
||||
|
||||
import org.joda.time.LocalDate;
|
||||
|
||||
/**
|
||||
* Immutable data object represent the important time-line events of a loan
|
||||
* application and loan.
|
||||
*/
|
||||
@SuppressWarnings("unused")
|
||||
public class GroupTimelineData {
|
||||
|
||||
private final LocalDate submittedOnDate;
|
||||
private final String submittedByUsername;
|
||||
private final String submittedByFirstname;
|
||||
private final String submittedByLastname;
|
||||
|
||||
private final LocalDate activatedOnDate;
|
||||
private final String activatedByUsername;
|
||||
private final String activatedByFirstname;
|
||||
private final String activatedByLastname;
|
||||
|
||||
private final LocalDate closedOnDate;
|
||||
private final String closedByUsername;
|
||||
private final String closedByFirstname;
|
||||
private final String closedByLastname;
|
||||
|
||||
|
||||
public GroupTimelineData(final LocalDate submittedOnDate, final String submittedByUsername,
|
||||
final String submittedByFirstname, final String submittedByLastname, final LocalDate activatedOnDate,
|
||||
final String activatedByUsername, final String activatedByFirstname, final String activatedByLastname,
|
||||
final LocalDate closedOnDate, final String closedByUsername, final String closedByFirstname,
|
||||
final String closedByLastname) {
|
||||
this.submittedOnDate = submittedOnDate;
|
||||
this.submittedByUsername = submittedByUsername;
|
||||
this.submittedByFirstname = submittedByFirstname;
|
||||
this.submittedByLastname = submittedByLastname;
|
||||
|
||||
this.activatedOnDate = activatedOnDate;
|
||||
this.activatedByUsername = activatedByUsername;
|
||||
this.activatedByFirstname = activatedByFirstname;
|
||||
this.activatedByLastname = activatedByLastname;
|
||||
|
||||
this.closedOnDate = closedOnDate;
|
||||
this.closedByUsername = closedByUsername;
|
||||
this.closedByFirstname = closedByFirstname;
|
||||
this.closedByLastname = closedByLastname;
|
||||
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user