Hi all

The main reason we put in the restrictions around allowing only one
reschedule, was to also enable users to undo them easily if they were made
by mistake. I think that is something that can be solved, but would require
a bit of extra work ensuring that the correct old schedules are grabbed and
reapplied to the loan.

S


Sander van der Heyden

CTO Musoni Services




Mobile (NL): +31 (0)6 14239505
Skype: s.vdheyden
Website: musonisystem.com
Follow us on Twitter!  <https://twitter.com/musonimfi>
Postal address: Hillegomstraat 12-14, office 0.09, 1058 LS, Amsterdam,
The Netherlands

On Fri, Apr 8, 2016 at 5:46 PM, Ed Cable <edca...@mifos.org> wrote:

> Sander, have you had a chance to review this thread?
>
> Andris' team is in need of this feature and wanted to get feedback on the
> approach they've taken to see if they can continue with that or they need
> to follow the path that was proposed by Pramod.
>
> Ed
>
> On Wed, Apr 6, 2016 at 9:38 AM, Ed Cable <edca...@mifos.org> wrote:
>
>> Zack and Robert have been working on contributing a fix to add the
>> ability to reschedule a loan multiple times.
>>
>> They have taken a different approach than what Pramod had previously
>> outlined so we wanted to discuss their proposed fix with Sander and his
>> team who have provided the initial fix to reschedule a loan a single time.
>>
>> Ed
>>
>> On Mon, Apr 4, 2016 at 9:32 PM, Adi Raju <
>> adi.r...@confluxtechnologies.com
>> <https://web.chilipiper.com/link/mifos.org/57053b41e4b02bbec5bc216d?link=bWFpbHRvJTNBYWRpLnJhanUlNDBjb25mbHV4dGVjaG5vbG9naWVzLmNvbQ==>
>> > wrote:
>>
>>> Hi Robert,
>>>
>>>
>>>
>>> Validator classes generally only perform API parameter validations, in
>>> other words they are the first check point before proceeding to more
>>> costlier DB or calculation tasks.
>>>
>>> All that is done in this change is that the validation at the first
>>> check point is removed.
>>>
>>> These checkpoints were added by earlier developers because they haven’t
>>> addressed those scenarios in further calculations.
>>>
>>> If the core code works for multi-reschedule, they wouldn’t have put this
>>> check in the first place.
>>>
>>>
>>>
>>> I really doubt this solution is working as it is supposed to be. Have
>>> you been able to test it against expected schedule and its values post
>>> reschedule action? Does other like retrieve/approve/reject reschedule APIs
>>> work with this solution?
>>>
>>>
>>>
>>> +Sander, who can help us with more clarifications on why such
>>> validations were added.
>>>
>>>
>>>
>>> Regards,
>>>
>>> Adi
>>>
>>>
>>>
>>>
>>>
>>> *From:* robert wizglobal [mailto:rob...@wizglobal.co.ke
>>> <https://web.chilipiper.com/link/mifos.org/57053b41e4b02bbec5bc216d?link=bWFpbHRvJTNBcm9iZXJ0JTQwd2l6Z2xvYmFsLmNvLmtl>]
>>>
>>> *Sent:* 04 April 2016 22:13
>>> *To:* Adi Raju <adi.r...@confluxtechnologies.com
>>> <https://web.chilipiper.com/link/mifos.org/57053b41e4b02bbec5bc216d?link=bWFpbHRvJTNBYWRpLnJhanUlNDBjb25mbHV4dGVjaG5vbG9naWVzLmNvbQ==>
>>> >
>>> *Cc:* Zack Wizglobal <z...@wizglobal.co.ke
>>> <https://web.chilipiper.com/link/mifos.org/57053b41e4b02bbec5bc216d?link=bWFpbHRvJTNBemFjayU0MHdpemdsb2JhbC5jby5rZQ==>>;
>>> Ed Cable <edca...@mifos.org
>>> <https://web.chilipiper.com/link/mifos.org/57053b41e4b02bbec5bc216d?link=bWFpbHRvJTNBZWRjYWJsZSU0MG1pZm9zLm9yZw==>>;
>>> pra...@confluxtechnologies.com
>>> <https://web.chilipiper.com/link/mifos.org/57053b41e4b02bbec5bc216d?link=bWFpbHRvJTNBcHJhbW9kJTQwY29uZmx1eHRlY2hub2xvZ2llcy5jb20=>;
>>> Agris Varpins <agris.varp...@mtgcapital.ch
>>> <https://web.chilipiper.com/link/mifos.org/57053b41e4b02bbec5bc216d?link=bWFpbHRvJTNBYWdyaXMudmFycGlucyU0MG10Z2NhcGl0YWwuY2g=>>;
>>> Andris Kaneps <akan...@mtgcapital.ch
>>> <https://web.chilipiper.com/link/mifos.org/57053b41e4b02bbec5bc216d?link=bWFpbHRvJTNBYWthbmVwcyU0MG10Z2NhcGl0YWwuY2g=>>;
>>> Philippe Storm <pst...@watucredit.com
>>> <https://web.chilipiper.com/link/mifos.org/57053b41e4b02bbec5bc216d?link=bWFpbHRvJTNBcHN0b3JtJTQwd2F0dWNyZWRpdC5jb20=>
>>> >
>>> *Subject:* Re: Mifos fix
>>>
>>>
>>>
>>> Hello Adi
>>>
>>>
>>>
>>> It Was Not a Major Fix Below is the Change i did on the  
>>> *LoanRescheduleRequestDataValidator
>>>  Class*
>>>
>>>
>>>
>>> /**
>>>
>>>  * Licensed to the Apache Software Foundation (ASF) under one
>>>
>>>  * or more contributor license agreements. See the NOTICE file
>>>
>>>  * distributed with this work for additional information
>>>
>>>  * regarding copyright ownership. The ASF licenses this file
>>>
>>>  * to you under the Apache License, Version 2.0 (the
>>>
>>>  * "License"); you may not use this file except in compliance
>>>
>>>  * with the License. You may obtain a copy of the License at
>>>
>>>  *
>>>
>>>  * http://www.apache.org/licenses/LICENSE-2.0
>>> <https://web.chilipiper.com/link/mifos.org/57053b41e4b02bbec5bc216d?link=aHR0cCUzQSUyRiUyRnd3dy5hcGFjaGUub3JnJTJGbGljZW5zZXMlMkZMSUNFTlNFLTIuMA==>
>>>
>>>  *
>>>
>>>  * Unless required by applicable law or agreed to in writing,
>>>
>>>  * software distributed under the License is distributed on an
>>>
>>>  * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
>>>
>>>  * KIND, either express or implied. See the License for the
>>>
>>>  * specific language governing permissions and limitations
>>>
>>>  * under the License.
>>>
>>>  */
>>>
>>> package org.apache.fineract.portfolio.loanaccount.rescheduleloan.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.apache.fineract.infrastructure.core.api.JsonCommand;
>>>
>>> import org.apache.fineract.infrastructure.core.data.ApiParameterError;
>>>
>>> import org.apache.fineract.infrastructure.core.data.DataValidatorBuilder;
>>>
>>> import
>>> org.apache.fineract.infrastructure.core.exception.InvalidJsonException;
>>>
>>> import
>>> org.apache.fineract.infrastructure.core.exception.PlatformApiDataValidationException;
>>>
>>> import
>>> org.apache.fineract.infrastructure.core.serialization.FromJsonHelper;
>>>
>>> import org.apache.fineract.portfolio.loanaccount.domain.Loan;
>>>
>>> import
>>> org.apache.fineract.portfolio.loanaccount.domain.LoanRepaymentScheduleInstallment;
>>>
>>> import org.apache.fineract.portfolio.loanaccount.domain.LoanStatus;
>>>
>>> import
>>> org.apache.fineract.portfolio.loanaccount.rescheduleloan.RescheduleLoansApiConstants;
>>>
>>> import
>>> org.apache.fineract.portfolio.loanaccount.rescheduleloan.domain.LoanRescheduleRequest;
>>>
>>> import
>>> org.apache.fineract.portfolio.loanaccount.rescheduleloan.service.LoanRescheduleRequestReadPlatformService;
>>>
>>> import org.joda.time.LocalDate;
>>>
>>> import org.springframework.beans.factory.annotation.Autowired;
>>>
>>> import org.springframework.stereotype.Component;
>>>
>>>
>>>
>>> import com.google
>>> <https://web.chilipiper.com/link/mifos.org/57053b41e4b02bbec5bc216d?link=aHR0cCUzQSUyRiUyRmNvbS5nb29nbGU=>
>>> .gson.JsonElement;
>>>
>>> import com.google
>>> <https://web.chilipiper.com/link/mifos.org/57053b41e4b02bbec5bc216d?link=aHR0cCUzQSUyRiUyRmNvbS5nb29nbGU=>
>>> .gson.reflect.TypeToken;
>>>
>>>
>>>
>>> @Component
>>>
>>> public class LoanRescheduleRequestDataValidator {
>>>
>>>
>>>
>>>     private final FromJsonHelper fromJsonHelper;
>>>
>>>     private final LoanRescheduleRequestReadPlatformService
>>> loanRescheduleRequestReadPlatformService;
>>>
>>>
>>>
>>>     @Autowired
>>>
>>>     public LoanRescheduleRequestDataValidator(FromJsonHelper
>>> fromJsonHelper,
>>>
>>>             LoanRescheduleRequestReadPlatformService
>>> loanRescheduleRequestReadPlatformService) {
>>>
>>>         this.fromJsonHelper = fromJsonHelper;
>>>
>>>         this.loanRescheduleRequestReadPlatformService =
>>> loanRescheduleRequestReadPlatformService;
>>>
>>>     }
>>>
>>>
>>>
>>>     /**
>>>
>>>      * Validates the request to create a new loan reschedule entry
>>>
>>>      *
>>>
>>>      * @param jsonCommand
>>>
>>>      *            the JSON command object (instance of the JsonCommand
>>> class)
>>>
>>>      * @return void
>>>
>>>      **/
>>>
>>>     public void validateForCreateAction(final JsonCommand jsonCommand,
>>> final Loan loan) {
>>>
>>>
>>>
>>>         final String jsonString = jsonCommand.json();
>>>
>>>
>>>
>>>         if (StringUtils.isBlank(jsonString)) { throw new
>>> InvalidJsonException(); }
>>>
>>>
>>>
>>>         final Type typeToken = new TypeToken<Map<String, Object>>()
>>> {}.getType();
>>>
>>>         this.fromJsonHelper
>>>
>>>                 .checkForUnsupportedParameters(typeToken, jsonString,
>>> RescheduleLoansApiConstants.CREATE_REQUEST_DATA_PARAMETERS);
>>>
>>>
>>>
>>>         final List<ApiParameterError> dataValidationErrors = new
>>> ArrayList<>();
>>>
>>>         final DataValidatorBuilder dataValidatorBuilder = new
>>> DataValidatorBuilder(dataValidationErrors).resource(StringUtils
>>>
>>>                 .lowerCase(RescheduleLoansApiConstants.ENTITY_NAME));
>>>
>>>
>>>
>>>         final JsonElement jsonElement = jsonCommand.parsedJson();
>>>
>>>
>>>
>>>         if (!loan.status().isActive()) {
>>>
>>>
>>> dataValidatorBuilder.reset().failWithCodeNoParameterAddedToErrorCode("loan.is.not.active",
>>> "Loan is not active");
>>>
>>>         }
>>>
>>>
>>>
>>>         final Long loanId =
>>> this.fromJsonHelper.extractLongNamed(RescheduleLoansApiConstants.loanIdParamName,
>>> jsonElement);
>>>
>>>
>>> dataValidatorBuilder.reset().parameter(RescheduleLoansApiConstants.loanIdParamName).value(loanId).notNull()
>>>
>>>                 .integerGreaterThanZero();
>>>
>>>
>>>
>>>         final LocalDate submittedOnDate =
>>> this.fromJsonHelper.extractLocalDateNamed(RescheduleLoansApiConstants.submittedOnDateParamName,
>>>
>>>                 jsonElement);
>>>
>>>
>>> dataValidatorBuilder.reset().parameter(RescheduleLoansApiConstants.submittedOnDateParamName).value(submittedOnDate).notNull();
>>>
>>>
>>>
>>>         if (submittedOnDate != null &&
>>> loan.getDisbursementDate().isAfter(submittedOnDate)) {
>>>
>>>
>>> dataValidatorBuilder.reset().parameter(RescheduleLoansApiConstants.submittedOnDateParamName)
>>>
>>>                     .failWithCode("before.loan.disbursement.date",
>>> "Submission date cannot be before the loan disbursement date");
>>>
>>>         }
>>>
>>>
>>>
>>>         final LocalDate rescheduleFromDate =
>>> this.fromJsonHelper.extractLocalDateNamed(
>>>
>>>                 RescheduleLoansApiConstants.rescheduleFromDateParamName,
>>> jsonElement);
>>>
>>>
>>> dataValidatorBuilder.reset().parameter(RescheduleLoansApiConstants.rescheduleFromDateParamName).value(rescheduleFromDate).notNull();
>>>
>>>
>>>
>>>         final Integer graceOnPrincipal =
>>> this.fromJsonHelper.extractIntegerWithLocaleNamed(
>>>
>>>                 RescheduleLoansApiConstants.graceOnPrincipalParamName,
>>> jsonElement);
>>>
>>>
>>> dataValidatorBuilder.reset().parameter(RescheduleLoansApiConstants.graceOnPrincipalParamName).value(graceOnPrincipal)
>>>
>>>                 .ignoreIfNull().integerGreaterThanZero();
>>>
>>>
>>>
>>>         final Integer graceOnInterest =
>>> this.fromJsonHelper.extractIntegerWithLocaleNamed(
>>>
>>>                 RescheduleLoansApiConstants.graceOnInterestParamName,
>>> jsonElement);
>>>
>>>
>>> dataValidatorBuilder.reset().parameter(RescheduleLoansApiConstants.graceOnInterestParamName).value(graceOnInterest).ignoreIfNull()
>>>
>>>                 .integerGreaterThanZero();
>>>
>>>
>>>
>>>         final Integer extraTerms =
>>> this.fromJsonHelper.extractIntegerWithLocaleNamed(RescheduleLoansApiConstants.extraTermsParamName,
>>>
>>>                 jsonElement);
>>>
>>>
>>> dataValidatorBuilder.reset().parameter(RescheduleLoansApiConstants.extraTermsParamName).value(extraTerms).ignoreIfNull()
>>>
>>>                 .integerGreaterThanZero();
>>>
>>>
>>>
>>>         final Long rescheduleReasonId =
>>> this.fromJsonHelper.extractLongNamed(RescheduleLoansApiConstants.rescheduleReasonIdParamName,
>>>
>>>                 jsonElement);
>>>
>>>
>>> dataValidatorBuilder.reset().parameter(RescheduleLoansApiConstants.rescheduleReasonIdParamName).value(rescheduleReasonId).notNull()
>>>
>>>                 .integerGreaterThanZero();
>>>
>>>
>>>
>>>         final String rescheduleReasonComment =
>>> this.fromJsonHelper.extractStringNamed(
>>>
>>>
>>> RescheduleLoansApiConstants.rescheduleReasonCommentParamName, jsonElement);
>>>
>>>
>>> dataValidatorBuilder.reset().parameter(RescheduleLoansApiConstants.rescheduleReasonCommentParamName).value(rescheduleReasonComment)
>>>
>>>                 .ignoreIfNull().notExceedingLengthOf(500);
>>>
>>>
>>>
>>>         final LocalDate adjustedDueDate =
>>> this.fromJsonHelper.extractLocalDateNamed(RescheduleLoansApiConstants.adjustedDueDateParamName,
>>>
>>>                 jsonElement);
>>>
>>>
>>>
>>>         if (adjustedDueDate != null && rescheduleFromDate != null &&
>>> adjustedDueDate.isBefore(rescheduleFromDate)) {
>>>
>>>             dataValidatorBuilder
>>>
>>>                     .reset()
>>>
>>>
>>> .parameter(RescheduleLoansApiConstants.rescheduleFromDateParamName)
>>>
>>>
>>> .failWithCode("adjustedDueDate.before.rescheduleFromDate",
>>>
>>>                             "Adjusted due date cannot be before the
>>> reschedule from date");
>>>
>>>         }
>>>
>>>
>>>
>>>         // at least one of the following must be provided =>
>>> graceOnPrincipal,
>>>
>>>         // graceOnInterest, extraTerms, newInterestRate
>>>
>>>         if
>>> (!this.fromJsonHelper.parameterExists(RescheduleLoansApiConstants.graceOnPrincipalParamName,
>>> jsonElement)
>>>
>>>                 &&
>>> !this.fromJsonHelper.parameterExists(RescheduleLoansApiConstants.graceOnInterestParamName,
>>> jsonElement)
>>>
>>>                 &&
>>> !this.fromJsonHelper.parameterExists(RescheduleLoansApiConstants.extraTermsParamName,
>>> jsonElement)
>>>
>>>                 &&
>>> !this.fromJsonHelper.parameterExists(RescheduleLoansApiConstants.newInterestRateParamName,
>>> jsonElement)
>>>
>>>                 &&
>>> !this.fromJsonHelper.parameterExists(RescheduleLoansApiConstants.adjustedDueDateParamName,
>>> jsonElement)) {
>>>
>>>
>>> dataValidatorBuilder.reset().parameter(RescheduleLoansApiConstants.graceOnPrincipalParamName).notNull();
>>>
>>>         }
>>>
>>>
>>>
>>>         if (rescheduleFromDate != null) {
>>>
>>>             LoanRepaymentScheduleInstallment installment =
>>> loan.getRepaymentScheduleInstallment(rescheduleFromDate);
>>>
>>>
>>>
>>>             if (installment == null) {
>>>
>>>
>>> dataValidatorBuilder.reset().parameter(RescheduleLoansApiConstants.rescheduleFromDateParamName)
>>>
>>>
>>> .failWithCode("repayment.schedule.installment.does.not.exist", "Repayment
>>> schedule installment does not exist");
>>>
>>>             }
>>>
>>>              /*
>>>
>>>             if (installment != null && installment.isObligationsMet()) {
>>>
>>>
>>> dataValidatorBuilder.reset().parameter(RescheduleLoansApiConstants.rescheduleFromDateParamName)
>>>
>>>
>>> .failWithCode("repayment.schedule.installment.obligation.met", "Repayment
>>> schedule installment obligation met");
>>>
>>>             } */
>>>
>>>           /*
>>>
>>>             if (installment != null && installment.isPartlyPaid()) {
>>>
>>>
>>>
>>>
>>> dataValidatorBuilder.reset().parameter(RescheduleLoansApiConstants.rescheduleFromDateParamName)
>>>
>>>
>>> .failWithCode("repayment.schedule.installment.partly.paid", "Repayment
>>> schedule installment is partly paid");
>>>
>>>             } */
>>>
>>>         }
>>>
>>>
>>>
>>>         if (loanId != null) {
>>>
>>>             List<LoanRescheduleRequestData> loanRescheduleRequestData =
>>> this.loanRescheduleRequestReadPlatformService
>>>
>>>                     .readLoanRescheduleRequests(loanId,
>>> LoanStatus.APPROVED.getValue());
>>>
>>>          /*   //commented this for loan reshedule
>>>
>>>             if (loanRescheduleRequestData.size() > 0) {
>>>
>>>
>>> dataValidatorBuilder.reset().failWithCodeNoParameterAddedToErrorCode("loan.already.rescheduled",
>>>
>>>                         "The loan can only be rescheduled once.");
>>>
>>>             } */
>>>
>>>         }
>>>
>>>         if(loan.isMultiDisburmentLoan()) {
>>>
>>>
>>> dataValidatorBuilder.reset().failWithCodeNoParameterAddedToErrorCode(RescheduleLoansApiConstants.resheduleForMultiDisbursementNotSupportedErrorCode,
>>>
>>>                     "Loan rescheduling is not supported for
>>> multidisbursement loans");
>>>
>>>         }
>>>
>>>
>>>
>>>         if(loan.isInterestRecalculationEnabledForProduct()) {
>>>
>>>
>>> dataValidatorBuilder.reset().failWithCodeNoParameterAddedToErrorCode(RescheduleLoansApiConstants.resheduleWithInterestRecalculationNotSupportedErrorCode,
>>>
>>>                     "Loan rescheduling is not supported for the loan
>>> product with interest recalculation enabled");
>>>
>>>         }
>>>
>>>
>>>
>>>         if (!dataValidationErrors.isEmpty()) { throw new
>>> PlatformApiDataValidationException(dataValidationErrors); }
>>>
>>>     }
>>>
>>>
>>>
>>>     /**
>>>
>>>      * Validates a user request to approve a loan reschedule request
>>>
>>>      *
>>>
>>>      * @param jsonCommand
>>>
>>>      *            the JSON command object (instance of the JsonCommand
>>> class)
>>>
>>>      * @return void
>>>
>>>      **/
>>>
>>>     public void validateForApproveAction(final JsonCommand jsonCommand,
>>> LoanRescheduleRequest loanRescheduleRequest) {
>>>
>>>         final String jsonString = jsonCommand.json();
>>>
>>>
>>>
>>>         if (StringUtils.isBlank(jsonString)) { throw new
>>> InvalidJsonException(); }
>>>
>>>
>>>
>>>         final Type typeToken = new TypeToken<Map<String, Object>>()
>>> {}.getType();
>>>
>>>         this.fromJsonHelper.checkForUnsupportedParameters(typeToken,
>>> jsonString,
>>>
>>>
>>> RescheduleLoansApiConstants.APPROVE_REQUEST_DATA_PARAMETERS);
>>>
>>>
>>>
>>>         final List<ApiParameterError> dataValidationErrors = new
>>> ArrayList<>();
>>>
>>>         final DataValidatorBuilder dataValidatorBuilder = new
>>> DataValidatorBuilder(dataValidationErrors).resource(StringUtils
>>>
>>>                 .lowerCase(RescheduleLoansApiConstants.ENTITY_NAME));
>>>
>>>
>>>
>>>         final JsonElement jsonElement = jsonCommand.parsedJson();
>>>
>>>
>>>
>>>         final LocalDate approvedOnDate =
>>> this.fromJsonHelper.extractLocalDateNamed(RescheduleLoansApiConstants.approvedOnDateParam,
>>>
>>>                 jsonElement);
>>>
>>>
>>> dataValidatorBuilder.reset().parameter(RescheduleLoansApiConstants.approvedOnDateParam).value(approvedOnDate).notNull();
>>>
>>>
>>>
>>>         if (approvedOnDate != null &&
>>> loanRescheduleRequest.getSubmittedOnDate().isAfter(approvedOnDate)) {
>>>
>>>
>>> dataValidatorBuilder.reset().parameter(RescheduleLoansApiConstants.approvedOnDateParam)
>>>
>>>                     .failWithCode("before.submission.date", "Approval
>>> date cannot be before the request submission date.");
>>>
>>>         }
>>>
>>>
>>>
>>>         LoanRescheduleRequestStatusEnumData
>>> loanRescheduleRequestStatusEnumData = LoanRescheduleRequestEnumerations
>>>
>>>                 .status(loanRescheduleRequest.getStatusEnum());
>>>
>>>
>>>
>>>         if (!loanRescheduleRequestStatusEnumData.isPendingApproval()) {
>>>
>>>
>>> dataValidatorBuilder.reset().failWithCodeNoParameterAddedToErrorCode(
>>>
>>>                     "request.is.not.in
>>> <https://web.chilipiper.com/link/mifos.org/57053b41e4b02bbec5bc216d?link=aHR0cCUzQSUyRiUyRnJlcXVlc3QuaXMubm90Lmlu>
>>> .submitted.and.pending.state",
>>>
>>>                     "Loan reschedule request approval is not allowed. "
>>>
>>>                             + "Loan reschedule request is not in
>>> submitted and pending approval state.");
>>>
>>>         }
>>>
>>>
>>>
>>>         LocalDate rescheduleFromDate =
>>> loanRescheduleRequest.getRescheduleFromDate();
>>>
>>>         final Loan loan = loanRescheduleRequest.getLoan();
>>>
>>>
>>>
>>>         if (loan != null) {
>>>
>>>             Long loanId = loan.getId();
>>>
>>>
>>>
>>>             if (!loan.status().isActive()) {
>>>
>>>
>>> dataValidatorBuilder.reset().failWithCodeNoParameterAddedToErrorCode("loan.is.not.active",
>>> "Loan is not active");
>>>
>>>             }
>>>
>>>
>>>
>>>             if (rescheduleFromDate != null) {
>>>
>>>                 LoanRepaymentScheduleInstallment installment =
>>> loan.getRepaymentScheduleInstallment(rescheduleFromDate);
>>>
>>>
>>>
>>>                 if (installment == null) {
>>>
>>>
>>> dataValidatorBuilder.reset().failWithCodeNoParameterAddedToErrorCode(
>>>
>>>
>>> "loan.repayment.schedule.installment.does.not.exist", "Repayment schedule
>>> installment does not exist");
>>>
>>>                 }
>>>
>>>                  /*
>>>
>>>                 if (installment != null &&
>>> installment.isObligationsMet()) {
>>>
>>>
>>> dataValidatorBuilder.reset().failWithCodeNoParameterAddedToErrorCode(
>>>
>>>                             "loan.repayment.schedule.installment." +
>>> "obligation.met", "Repayment schedule installment obligation met");
>>>
>>>                 } */
>>>
>>>             }
>>>
>>>
>>>
>>>             if (loanId != null) {
>>>
>>>                 List<LoanRescheduleRequestData>
>>> loanRescheduleRequestData = this.loanRescheduleRequestReadPlatformService
>>>
>>>                         .readLoanRescheduleRequests(loanId,
>>> LoanStatus.APPROVED.getValue());
>>>
>>>              /*
>>>
>>>                 if (loanRescheduleRequestData.size() > 0) {
>>>
>>>
>>> dataValidatorBuilder.reset().failWithCodeNoParameterAddedToErrorCode("loan.already.rescheduled",
>>>
>>>                             "The loan can only be rescheduled once.");
>>>
>>>                 } */
>>>
>>>             }
>>>
>>>         }
>>>
>>>
>>>
>>>         if (!dataValidationErrors.isEmpty()) { throw new
>>> PlatformApiDataValidationException(dataValidationErrors); }
>>>
>>>     }
>>>
>>>
>>>
>>>     /**
>>>
>>>      * Validates a user request to reject a loan reschedule request
>>>
>>>      *
>>>
>>>      * @param jsonCommand
>>>
>>>      *            the JSON command object (instance of the JsonCommand
>>> class)
>>>
>>>      * @return void
>>>
>>>      **/
>>>
>>>     public void validateForRejectAction(final JsonCommand jsonCommand,
>>> LoanRescheduleRequest loanRescheduleRequest) {
>>>
>>>         final String jsonString = jsonCommand.json();
>>>
>>>
>>>
>>>         if (StringUtils.isBlank(jsonString)) { throw new
>>> InvalidJsonException(); }
>>>
>>>
>>>
>>>         final Type typeToken = new TypeToken<Map<String, Object>>()
>>> {}.getType();
>>>
>>>         this.fromJsonHelper
>>>
>>>                 .checkForUnsupportedParameters(typeToken, jsonString,
>>> RescheduleLoansApiConstants.REJECT_REQUEST_DATA_PARAMETERS);
>>>
>>>
>>>
>>>         final List<ApiParameterError> dataValidationErrors = new
>>> ArrayList<>();
>>>
>>>         final DataValidatorBuilder dataValidatorBuilder = new
>>> DataValidatorBuilder(dataValidationErrors).resource(StringUtils
>>>
>>>                 .lowerCase(RescheduleLoansApiConstants.ENTITY_NAME));
>>>
>>>
>>>
>>>         final JsonElement jsonElement = jsonCommand.parsedJson();
>>>
>>>
>>>
>>>         final LocalDate rejectedOnDate =
>>> this.fromJsonHelper.extractLocalDateNamed(RescheduleLoansApiConstants.rejectedOnDateParam,
>>>
>>>                 jsonElement);
>>>
>>>
>>> dataValidatorBuilder.reset().parameter(RescheduleLoansApiConstants.rejectedOnDateParam).value(rejectedOnDate).notNull();
>>>
>>>
>>>
>>>         if (rejectedOnDate != null &&
>>> loanRescheduleRequest.getSubmittedOnDate().isAfter(rejectedOnDate)) {
>>>
>>>
>>> dataValidatorBuilder.reset().parameter(RescheduleLoansApiConstants.rejectedOnDateParam)
>>>
>>>                     .failWithCode("before.submission.date", "Rejection
>>> date cannot be before the request submission date.");
>>>
>>>         }
>>>
>>>
>>>
>>>         LoanRescheduleRequestStatusEnumData
>>> loanRescheduleRequestStatusEnumData = LoanRescheduleRequestEnumerations
>>>
>>>                 .status(loanRescheduleRequest.getStatusEnum());
>>>
>>>
>>>
>>>         if (!loanRescheduleRequestStatusEnumData.isPendingApproval()) {
>>>
>>>
>>> dataValidatorBuilder.reset().failWithCodeNoParameterAddedToErrorCode(
>>>
>>>                     "request.is.not.in
>>> <https://web.chilipiper.com/link/mifos.org/57053b41e4b02bbec5bc216d?link=aHR0cCUzQSUyRiUyRnJlcXVlc3QuaXMubm90Lmlu>
>>> .submitted.and.pending.state",
>>>
>>>                     "Loan reschedule request rejection is not allowed. "
>>>
>>>                             + "Loan reschedule request is not in
>>> submitted and pending approval state.");
>>>
>>>         }
>>>
>>>
>>>
>>>         if (!dataValidationErrors.isEmpty()) { throw new
>>> PlatformApiDataValidationException(dataValidationErrors); }
>>>
>>>     }
>>>
>>> }
>>>
>>>
>>>
>>>
>>>
>>> On Sat, Apr 2, 2016 at 5:14 AM, Adi Raju <
>>> adi.r...@confluxtechnologies.com
>>> <https://web.chilipiper.com/link/mifos.org/57053b41e4b02bbec5bc216d?link=bWFpbHRvJTNBYWRpLnJhanUlNDBjb25mbHV4dGVjaG5vbG9naWVzLmNvbQ==>>
>>> wrote:
>>>
>>> Hi Robert,
>>>
>>> Please send either a pull request or share your fork and branch details
>>> for us to have a look at code changes. Also if possible send us a short
>>> description of your technical solution.
>>>
>>> Regards,
>>> Adi
>>>
>>> On 01-Apr-2016 7:00 pm, "Zack Wizglobal" <z...@wizglobal.co.ke
>>> <https://web.chilipiper.com/link/mifos.org/57053b41e4b02bbec5bc216d?link=bWFpbHRvJTNBemFjayU0MHdpemdsb2JhbC5jby5rZQ==>>
>>> wrote:
>>>
>>> Hi Ed,
>>>
>>>
>>>
>>> Thanks for the call. Robert copied here is our key developer for the
>>> Mifos System and he will be able to answer all your questions.
>>>
>>> Robert here we have a team from Mifos who would want to know how we
>>> implemented the loan reschedule.
>>>
>>>
>>>
>>> --
>>> Kind Regards,
>>>
>>> Zack Githinji
>>> Systems Developer
>>> Wizglobal Kenya
>>> P.O. BOX 21373-00100
>>> Nairobi.
>>> Mobile: +254 (0) 722 649199
>>> <https://web.chilipiper.com/link/mifos.org/57053b41e4b02bbec5bc216d?link=dGVsJTNBJTI1MkIyNTQlMjUyMCUyNTI4MCUyNTI5JTI1MjA3MjIlMjUyMDY0OTE5OQ==>
>>>
>>> z...@wizglobal.co.ke
>>> <https://web.chilipiper.com/link/mifos.org/57053b41e4b02bbec5bc216d?link=bWFpbHRvJTNBemFjayU0MHdpemdsb2JhbC5jby5rZQ==>
>>> www.wizglobal.co.ke
>>> <https://web.chilipiper.com/link/mifos.org/57053b41e4b02bbec5bc216d?link=aHR0cCUzQSUyRiUyRnd3dy53aXpnbG9iYWwuY28ua2U=>
>>>
>>>
>>>
>>> On 24 Mar 2016, at 21:06, Andris Kaneps <akan...@mtgcapital.ch
>>> <https://web.chilipiper.com/link/mifos.org/57053b41e4b02bbec5bc216d?link=bWFpbHRvJTNBYWthbmVwcyU0MG10Z2NhcGl0YWwuY2g=>>
>>> wrote:
>>>
>>>
>>>
>>> Dear Zack, Ed, Adi and Pramod,
>>>
>>> As you may know Mifos currently has a problem with rescheduling function
>>> - we can't reschedule a loan more than once and its impossible to
>>> reschedule a loan if any repayment has been entered.
>>>
>>> This function is crucial for Watu Credit loan product so we have
>>> commissioned a Nairobi based software developer Wizglobal (represented by
>>> Zack Githinji) to fix the problem. The fix currently is complete and we
>>> have done preliminary testing.
>>>
>>> As discussed with Ed, we would like to contribute the fix to Mifos
>>> community so that the problem is solved in next Mifos update.
>>>
>>> So Adi and Pramod, could you please get in touch directly with Zack to
>>> discuss all the technical details?
>>>
>>> Kind regards,
>>>
>>> Andris Kaneps
>>>
>>>
>>>
>>>
>>>
>>>
>>>
>>>
>>>
>>
>>
>>
>> --
>> *Ed Cable*
>> Director of Community Programs, Mifos Initiative
>> edca...@mifos.org
>> <https://web.chilipiper.com/link/mifos.org/57053b41e4b02bbec5bc216d?link=bWFpbHRvJTNBZWRjYWJsZSU0MG1pZm9zLm9yZw==>
>>  |
>> Skype: edcable | Mobile: +1.484.477.8649
>>
>> *Collectively Creating a World of 3 Billion Maries | *http://mifos.org
>> <https://web.chilipiper.com/link/mifos.org/57053b41e4b02bbec5bc216d?link=aHR0cCUzQSUyRiUyRm1pZm9zLm9yZw==>
>>
>> <https://web.chilipiper.com/link/mifos.org/57053b41e4b02bbec5bc216d?link=aHR0cCUzQSUyRiUyRmZhY2Vib29rLmNvbSUyRm1pZm9z>
>>
>> <https://web.chilipiper.com/link/mifos.org/57053b41e4b02bbec5bc216d?link=aHR0cCUzQSUyRiUyRnd3dy50d2l0dGVyLmNvbSUyRm1pZm9z>
>>
>>
>
>
> --
> *Ed Cable*
> Director of Community Programs, Mifos Initiative
> edca...@mifos.org | Skype: edcable | Mobile: +1.484.477.8649
>
> *Collectively Creating a World of 3 Billion Maries | *http://mifos.org
> <http://facebook.com/mifos>  <http://www.twitter.com/mifos>
>
>

Reply via email to