You are viewing a plain text version of this content. The canonical link for it is here.
Posted to dev@fineract.apache.org by Andris Kaneps <ak...@mtgcapital.ch> on 2016/07/12 11:10:16 UTC

Re: Clarification on Validator Classes for Multiple Rescheduling of a Loan

Dear Adi and the team,

As you may know Vishwas from Conflux Technologies has finished the
development of Mifos fix that solves the rescheduling issue. We will do
in-house testing for the coming days.

Can you please let us know when this could be implemented into Mifos update?

Regards,

Andris

On Tue, Apr 19, 2016 at 10:59 AM, Adi Raju <adi.raju@confluxtechnologies.com
> wrote:

> Hi Ed,
>
>
>
> Subramanya will be working on this task tomorrow.
>
>
>
> Regards,
>
> Adi
>
>
>
> *From:* Ed Cable [mailto:edcable@mifos.org]
> *Sent:* 18 April 2016 21:49
> *To:* Andris Kaneps <ak...@mtgcapital.ch>
> *Cc:* Agris Varpins <ag...@mtgcapital.ch>; Adi Raju <
> adi.raju@confluxtechnologies.com>; Sander van der Heyden <
> sandervanderheyden@musoni.eu>; dev@fineract.incubator.apache.org; robert
> wizglobal <ro...@wizglobal.co.ke>; Zack Wizglobal <za...@wizglobal.co.ke>;
> pramod@confluxtechnologies.com Nuthakki <pr...@confluxtechnologies.com>;
> Philippe Storm <ps...@watucredit.com>; Markus Geiß <mg...@mifos.org>
> *Subject:* Re: Clarification on Validator Classes for Multiple
> Rescheduling of a Loan
>
>
>
> Adi,
>
>
>
> Now that the team has gotten through the QA for the most recent release,
> could you have the QA team spend some time on testing the scenarios and
> APIs you referenced above. Could you also provide a bit more clarity
> regarding what Zack needs to done for allowing for the undoing of the
> reschedulings.
>
>
>
> Thanks,
>
>
>
> Ed
>
>
>
> On Tue, Apr 12, 2016 at 2:46 AM, Andris Kaneps <ak...@mtgcapital.ch>
> wrote:
>
> Gentlemen,
>
>
>
> If we would comission to Zack the "undo" function- would it be the
> solution?
>
>
>
> R,
>
> Andris
>
> Sent from my iPhone
>
>
> On 2016. gada 12. apr., at 11:44, Agris Varpins <
> agris.varpins@mtgcapital.ch> wrote:
>
> Who can test it and tell if they are working? I am not an IT person
> myself, As I said I tested the fix in test environment and ext worked fine,
> however, if there is something else to be tested purely from technical
> point of view, then, gentlemen, I trust you are the right people to deliver
> that verdict!!
>
> Cheers,
> Agris
>
>
>
> On Tue, Apr 12, 2016 at 11:49 AM, Adi Raju <
> adi.raju@confluxtechnologies.com> wrote:
>
> If you look at api doc
> https://demo.openmf.org/api-docs/apiLive.htm#loan_rescheduling
>
> I see APIs to read/reject/approve any reschedule loan request instance.
>
> As long as these APIs are tested to be working fine, it should be good
> enough.
>
>
>
> Regards,
>
> Adi
>
>
>
> *From:* Agris Varpins [mailto:agris.varpins@mtgcapital.ch]
> *Sent:* 12 April 2016 13:38
> *To:* Adi Raju <ad...@confluxtechnologies.com>
> *Cc:* Sander van der Heyden <sa...@musoni.eu>; Ed Cable <
> edcable@mifos.org>; dev@fineract.incubator.apache.org; robert wizglobal <
> robert@wizglobal.co.ke>; Zack Wizglobal <za...@wizglobal.co.ke>;
> pramod@confluxtechnologies.com Nuthakki <pr...@confluxtechnologies.com>;
> Andris Kaneps <ak...@mtgcapital.ch>; Philippe Storm <
> pstorm@watucredit.com>; Markus Geiß <mg...@mifos.org>
> *Subject:* Re: Clarification on Validator Classes for Multiple
> Rescheduling of a Loan
>
>
>
> Could you clarify what you mean by "undo reschedule if the user makes a
> mistake"? In current version extenion cannot be undone if I am not mistaken
> or are we talking about some othetr functionality?
>
>
>
> On Tue, Apr 12, 2016 at 11:02 AM, Adi Raju <
> adi.raju@confluxtechnologies.com> wrote:
>
> As mentioned by Sander:
>
> “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.”
>
>
>
> Until this additional work is done, I wouldn’t recommend current solution
> to be merged.
>
>
>
> Regards,
>
> Adi
>
>
>
> *From:* Agris Varpins [mailto:agris.varpins@mtgcapital.ch]
> *Sent:* 12 April 2016 13:14
> *To:* Sander van der Heyden <sa...@musoni.eu>
> *Cc:* Ed Cable <ed...@mifos.org>; dev@fineract.incubator.apache.org;
> robert wizglobal <ro...@wizglobal.co.ke>; Zack Wizglobal <
> zack@wizglobal.co.ke>; pramod@confluxtechnologies.com Nuthakki <
> pramod@confluxtechnologies.com>; Andris Kaneps <ak...@mtgcapital.ch>;
> Philippe Storm <ps...@watucredit.com>; Markus Geiß <mg...@mifos.org>;
> Adi Raju <ad...@confluxtechnologies.com>
> *Subject:* Re: Clarification on Validator Classes for Multiple
> Rescheduling of a Loan
>
>
>
> Good morning, gentlemen!
>
> So where do we stand with this update?  Ed, has your team done some
> testing of the update to see if it works properly with the test clients?
> When we tested for our purposes, it seemed to work as we expected - loans
> could be rescheduled multiple times and reschedule could be done without
> undoing previously entered payments. Granted, we did not test how this fix
> affects, for example, accounting function, Overall, even if some additional
> fix is necessary to the Zack's product, that still would be doable.I
> believe it is in all interests to achieve that Mifos offers this fuction to
> its user community including ourselves.
>
> Please let us now where do we stand at the moment and what are the
> prospects for this fix so that we can plan accordingly.
>
> Best regards,
>
> Agris
>
>
>
> On Mon, Apr 11, 2016 at 12:29 PM, Sander van der Heyden <
> sandervanderheyden@musoni.eu> wrote:
>
> Hi all,
>
>
>
> Ignore my response, I was responding to the wrong thread, and not paying
> attention, still early here I guess...
>
>
>
> In terms of rescheduling, I think the current solution would need to be
> tested very carefully before it can be considered stable (or not), and
> therefore I'd recommend doing that before we merge the commit. Might also
> be good to add one or 2 test cases for the multiple reschedules to ensure
> that we have it covered there as well.
>
>
>
> 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 Mon, Apr 11, 2016 at 11:17 AM, Sander van der Heyden <
> sandervanderheyden@musoni.eu> wrote:
>
> Hi Agris,
>
>
>
> You can already do all of this by using the current datatables, where you
> can add all fields necessary to the clients data that you want to capture.
> So the update is not really a requirement to get this done, a large number
> of MFI's are already using the system with all of these fields added in.
>
>
>
> Thanks,
>
> Sander
>
>
>
> 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 Mon, Apr 11, 2016 at 10:58 AM, Agris Varpins <
> agris.varpins@mtgcapital.ch> wrote:
>
> Good morning, all!
>
> Thank you all for you inputs! So what is the verdict regarding this
> update? Will it work? Or if not, can it be easily adjusted and perfected so
> that it does? I cannot overstate hot important this fix is for us and we
> are really looking to solve this issue as soon as possible,
>
> Looking forward to you feedback.
>
> Best regards,
>
> Agris
>
>
>
> On Mon, Apr 11, 2016 at 9:09 AM, Sander van der Heyden <
> sandervanderheyden@musoni.eu> wrote:
>
> 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 <ed...@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 <ed...@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.raju@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:robert@wizglobal.co.ke
> <https://web.chilipiper.com/link/mifos.org/57053b41e4b02bbec5bc216d?link=bWFpbHRvJTNBcm9iZXJ0JTQwd2l6Z2xvYmFsLmNvLmtl>]
>
> *Sent:* 04 April 2016 22:13
> *To:* Adi Raju <adi.raju@confluxtechnologies.com
> <https://web.chilipiper.com/link/mifos.org/57053b41e4b02bbec5bc216d?link=bWFpbHRvJTNBYWRpLnJhanUlNDBjb25mbHV4dGVjaG5vbG9naWVzLmNvbQ==>
> >
> *Cc:* Zack Wizglobal <zack@wizglobal.co.ke
> <https://web.chilipiper.com/link/mifos.org/57053b41e4b02bbec5bc216d?link=bWFpbHRvJTNBemFjayU0MHdpemdsb2JhbC5jby5rZQ==>>;
> Ed Cable <edcable@mifos.org
> <https://web.chilipiper.com/link/mifos.org/57053b41e4b02bbec5bc216d?link=bWFpbHRvJTNBZWRjYWJsZSU0MG1pZm9zLm9yZw==>>;
> pramod@confluxtechnologies.com
> <https://web.chilipiper.com/link/mifos.org/57053b41e4b02bbec5bc216d?link=bWFpbHRvJTNBcHJhbW9kJTQwY29uZmx1eHRlY2hub2xvZ2llcy5jb20=>;
> Agris Varpins <agris.varpins@mtgcapital.ch
> <https://web.chilipiper.com/link/mifos.org/57053b41e4b02bbec5bc216d?link=bWFpbHRvJTNBYWdyaXMudmFycGlucyU0MG10Z2NhcGl0YWwuY2g=>>;
> Andris Kaneps <akaneps@mtgcapital.ch
> <https://web.chilipiper.com/link/mifos.org/57053b41e4b02bbec5bc216d?link=bWFpbHRvJTNBYWthbmVwcyU0MG10Z2NhcGl0YWwuY2g=>>;
> Philippe Storm <pstorm@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.raju@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" <zack@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==>
>
> zack@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 <akaneps@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
>
> edcable@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
>
> edcable@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>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
> --
>
> *Ed Cable*
>
> Director of Community Programs, Mifos Initiative
>
> edcable@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>
>
>
>



-- 
This e-mail was sent to you by MTG Capital Management,any attached
documents may contain privileged and confidential information and should
only be read by those persons to whom this e-mail is addressed. Use by
other than intended recipients is prohibited. If you are not the addressee,
you must not copy, distribute, disclose or use any of the information in
it. If you have received it in error, please delete it and immediately
notify the sender. MTG Capital Management reserves the right to monitor all
e-mail messages passing through its network. As we cannot guarantee the
genuineness,accuracy or completeness of the information contained in this
message, the statements set forth are not legally binding.

RE: Clarification on Validator Classes for Multiple Rescheduling of a Loan

Posted by Adi Raju <ad...@confluxtechnologies.com>.
Hi Andris,

 

I have checked with conflux team about the approach and we are fine with it.

Please let us know when you can complete the testing and send final PR for the same.

 

We do not have any releases planned for this month of July.

We think the next release would be sometime in first half of Aug (tested formal).

 

Regards,

Adi

 

From: Andris Kaneps [mailto:akaneps@mtgcapital.ch] 
Sent: 14 July 2016 11:49
To: Adi Raju <ad...@confluxtechnologies.com>
Cc: Ed Cable <ed...@mifos.org>; Agris Varpins <ag...@mtgcapital.ch>; Sander van der Heyden <sa...@musoni.eu>; dev@fineract.incubator.apache.org; subramanya@confluxtechnologies.com; Pramod Nuthakki <pr...@confluxtechnologies.com>; Philippe Storm <ps...@watucredit.com>; Markus Geiß <mg...@mifos.org>
Subject: Re: Clarification on Validator Classes for Multiple Rescheduling of a Loan

 

Dear Adi, Sander, Pramod,

 

Did you have a chance to look into the matter below?

 

Regards,

Andris Kaneps



 


On 2016. gada 12. jūl., at 14:10, Andris Kaneps <akaneps@mtgcapital.ch <ma...@mtgcapital.ch> > wrote:

Dear Adi and the team,

As you may know Vishwas from Conflux Technologies has finished the development of Mifos fix that solves the rescheduling issue. We will do in-house testing for the coming days. 

Can you please let us know when this could be implemented into Mifos update?

Regards,

Andris

 

On Tue, Apr 19, 2016 at 10:59 AM, Adi Raju <adi.raju@confluxtechnologies.com <ma...@confluxtechnologies.com> > wrote:

Hi Ed,

 

Subramanya will be working on this task tomorrow.

 

Regards,

Adi

 

From: Ed Cable [mailto:edcable@mifos.org <ma...@mifos.org> ] 
Sent: 18 April 2016 21:49
To: Andris Kaneps <akaneps@mtgcapital.ch <ma...@mtgcapital.ch> >
Cc: Agris Varpins <agris.varpins@mtgcapital.ch <ma...@mtgcapital.ch> >; Adi Raju <adi.raju@confluxtechnologies.com <ma...@confluxtechnologies.com> >; Sander van der Heyden <sandervanderheyden@musoni.eu <ma...@musoni.eu> >; dev@fineract.incubator.apache.org <ma...@fineract.incubator.apache.org> ; robert wizglobal <robert@wizglobal.co.ke <ma...@wizglobal.co.ke> >; Zack Wizglobal <zack@wizglobal.co.ke <ma...@wizglobal.co.ke> >; pramod@confluxtechnologies.com <ma...@confluxtechnologies.com>  Nuthakki <pramod@confluxtechnologies.com <ma...@confluxtechnologies.com> >; Philippe Storm <pstorm@watucredit.com <ma...@watucredit.com> >; Markus Geiß <mgeiss@mifos.org <ma...@mifos.org> >
Subject: Re: Clarification on Validator Classes for Multiple Rescheduling of a Loan

 

Adi,

 

Now that the team has gotten through the QA for the most recent release, could you have the QA team spend some time on testing the scenarios and APIs you referenced above. Could you also provide a bit more clarity regarding what Zack needs to done for allowing for the undoing of the reschedulings.

 

Thanks,

 

Ed

  <https://web.chilipiper.com/track/mifos.org/5715089de4b02bbec5bc37f1.png> 

 

On Tue, Apr 12, 2016 at 2:46 AM, Andris Kaneps <akaneps@mtgcapital.ch <ma...@mtgcapital.ch> > wrote:

Gentlemen,

 

If we would comission to Zack the "undo" function- would it be the solution?

 

R,

Andris

Sent from my iPhone


On 2016. gada 12. apr., at 11:44, Agris Varpins <agris.varpins@mtgcapital.ch <ma...@mtgcapital.ch> > wrote:

Who can test it and tell if they are working? I am not an IT person myself, As I said I tested the fix in test environment and ext worked fine, however, if there is something else to be tested purely from technical point of view, then, gentlemen, I trust you are the right people to deliver that verdict!!

Cheers,
Agris

 

On Tue, Apr 12, 2016 at 11:49 AM, Adi Raju <adi.raju@confluxtechnologies.com <ma...@confluxtechnologies.com> > wrote:

If you look at api doc https://demo.openmf.org/api-docs/apiLive.htm#loan_rescheduling 

I see APIs to read/reject/approve any reschedule loan request instance.

As long as these APIs are tested to be working fine, it should be good enough.

 

Regards,

Adi

 

From: Agris Varpins [mailto:agris.varpins@mtgcapital.ch <ma...@mtgcapital.ch> ] 
Sent: 12 April 2016 13:38
To: Adi Raju <adi.raju@confluxtechnologies.com <ma...@confluxtechnologies.com> >
Cc: Sander van der Heyden <sandervanderheyden@musoni.eu <ma...@musoni.eu> >; Ed Cable <edcable@mifos.org <ma...@mifos.org> >; dev@fineract.incubator.apache.org <ma...@fineract.incubator.apache.org> ; robert wizglobal <robert@wizglobal.co.ke <ma...@wizglobal.co.ke> >; Zack Wizglobal <zack@wizglobal.co.ke <ma...@wizglobal.co.ke> >; pramod@confluxtechnologies.com <ma...@confluxtechnologies.com>  Nuthakki <pramod@confluxtechnologies.com <ma...@confluxtechnologies.com> >; Andris Kaneps <akaneps@mtgcapital.ch <ma...@mtgcapital.ch> >; Philippe Storm <pstorm@watucredit.com <ma...@watucredit.com> >; Markus Geiß <mgeiss@mifos.org <ma...@mifos.org> >
Subject: Re: Clarification on Validator Classes for Multiple Rescheduling of a Loan

 

Could you clarify what you mean by "undo reschedule if the user makes a mistake"? In current version extenion cannot be undone if I am not mistaken or are we talking about some othetr functionality?

 

On Tue, Apr 12, 2016 at 11:02 AM, Adi Raju <adi.raju@confluxtechnologies.com <ma...@confluxtechnologies.com> > wrote:

As mentioned by Sander:

“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.”

 

Until this additional work is done, I wouldn’t recommend current solution to be merged.

 

Regards,

Adi

 

From: Agris Varpins [mailto:agris.varpins@mtgcapital.ch <ma...@mtgcapital.ch> ] 
Sent: 12 April 2016 13:14
To: Sander van der Heyden <sandervanderheyden@musoni.eu <ma...@musoni.eu> >
Cc: Ed Cable <edcable@mifos.org <ma...@mifos.org> >; dev@fineract.incubator.apache.org <ma...@fineract.incubator.apache.org> ; robert wizglobal <robert@wizglobal.co.ke <ma...@wizglobal.co.ke> >; Zack Wizglobal <zack@wizglobal.co.ke <ma...@wizglobal.co.ke> >; pramod@confluxtechnologies.com <ma...@confluxtechnologies.com>  Nuthakki <pramod@confluxtechnologies.com <ma...@confluxtechnologies.com> >; Andris Kaneps <akaneps@mtgcapital.ch <ma...@mtgcapital.ch> >; Philippe Storm <pstorm@watucredit.com <ma...@watucredit.com> >; Markus Geiß <mgeiss@mifos.org <ma...@mifos.org> >; Adi Raju <adi.raju@confluxtechnologies.com <ma...@confluxtechnologies.com> >
Subject: Re: Clarification on Validator Classes for Multiple Rescheduling of a Loan

 

Good morning, gentlemen!

So where do we stand with this update?  Ed, has your team done some testing of the update to see if it works properly with the test clients? When we tested for our purposes, it seemed to work as we expected - loans could be rescheduled multiple times and reschedule could be done without undoing previously entered payments. Granted, we did not test how this fix affects, for example, accounting function, Overall, even if some additional fix is necessary to the Zack's product, that still would be doable.I believe it is in all interests to achieve that Mifos offers this fuction to its user community including ourselves.

Please let us now where do we stand at the moment and what are the prospects for this fix so that we can plan accordingly. 

Best regards,

Agris

 

On Mon, Apr 11, 2016 at 12:29 PM, Sander van der Heyden <sandervanderheyden@musoni.eu <ma...@musoni.eu> > wrote:

Hi all,

 

Ignore my response, I was responding to the wrong thread, and not paying attention, still early here I guess... 

 

In terms of rescheduling, I think the current solution would need to be tested very carefully before it can be considered stable (or not), and therefore I'd recommend doing that before we merge the commit. Might also be good to add one or 2 test cases for the multiple reschedules to ensure that we have it covered there as well.

 

S





Sander van der Heyden

CTO Musoni Services

  <http://musonisystem.com/logo.png> 

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

 

On Mon, Apr 11, 2016 at 11:17 AM, Sander van der Heyden <sandervanderheyden@musoni.eu <ma...@musoni.eu> > wrote:

Hi Agris,

 

You can already do all of this by using the current datatables, where you can add all fields necessary to the clients data that you want to capture. So the update is not really a requirement to get this done, a large number of MFI's are already using the system with all of these fields added in.

 

Thanks,

Sander





Sander van der Heyden

CTO Musoni Services

  <http://musonisystem.com/logo.png> 

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

 

On Mon, Apr 11, 2016 at 10:58 AM, Agris Varpins <agris.varpins@mtgcapital.ch <ma...@mtgcapital.ch> > wrote:

Good morning, all!

Thank you all for you inputs! So what is the verdict regarding this update? Will it work? Or if not, can it be easily adjusted and perfected so that it does? I cannot overstate hot important this fix is for us and we are really looking to solve this issue as soon as possible, 

Looking forward to you feedback.

Best regards,

Agris

 

On Mon, Apr 11, 2016 at 9:09 AM, Sander van der Heyden <sandervanderheyden@musoni.eu <ma...@musoni.eu> > wrote:

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

  <http://musonisystem.com/logo.png> 

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

 

On Fri, Apr 8, 2016 at 5:46 PM, Ed Cable <edcable@mifos.org <ma...@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

  <https://web.chilipiper.com/track/mifos.org/5707d12ee4b02bbec5bc26d9.png> 

 

On Wed, Apr 6, 2016 at 9:38 AM, Ed Cable <edcable@mifos.org <ma...@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.raju@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:robert@wizglobal.co.ke <https://web.chilipiper.com/link/mifos.org/57053b41e4b02bbec5bc216d?link=bWFpbHRvJTNBcm9iZXJ0JTQwd2l6Z2xvYmFsLmNvLmtl> ] 
Sent: 04 April 2016 22:13
To: Adi Raju <adi.raju@confluxtechnologies.com <https://web.chilipiper.com/link/mifos.org/57053b41e4b02bbec5bc216d?link=bWFpbHRvJTNBYWRpLnJhanUlNDBjb25mbHV4dGVjaG5vbG9naWVzLmNvbQ==> >
Cc: Zack Wizglobal <zack@wizglobal.co.ke <https://web.chilipiper.com/link/mifos.org/57053b41e4b02bbec5bc216d?link=bWFpbHRvJTNBemFjayU0MHdpemdsb2JhbC5jby5rZQ==> >; Ed Cable <edcable@mifos.org <https://web.chilipiper.com/link/mifos.org/57053b41e4b02bbec5bc216d?link=bWFpbHRvJTNBZWRjYWJsZSU0MG1pZm9zLm9yZw==> >; pramod@confluxtechnologies.com <https://web.chilipiper.com/link/mifos.org/57053b41e4b02bbec5bc216d?link=bWFpbHRvJTNBcHJhbW9kJTQwY29uZmx1eHRlY2hub2xvZ2llcy5jb20=> ; Agris Varpins <agris.varpins@mtgcapital.ch <https://web.chilipiper.com/link/mifos.org/57053b41e4b02bbec5bc216d?link=bWFpbHRvJTNBYWdyaXMudmFycGlucyU0MG10Z2NhcGl0YWwuY2g=> >; Andris Kaneps <akaneps@mtgcapital.ch <https://web.chilipiper.com/link/mifos.org/57053b41e4b02bbec5bc216d?link=bWFpbHRvJTNBYWthbmVwcyU0MG10Z2NhcGl0YWwuY2g=> >; Philippe Storm <pstorm@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.raju@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" <zack@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==> 

zack@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 <akaneps@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

edcable@mifos.org <https://web.chilipiper.com/link/mifos.org/57053b41e4b02bbec5bc216d?link=bWFpbHRvJTNBZWRjYWJsZSU0MG1pZm9zLm9yZw==>  | Skype: edcable | Mobile: +1.484.477.8649 <tel:%2B1.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> 

 

  <https://web.chilipiper.com/track/mifos.org/57053b41e4b02bbec5bc216d.png> 





 

-- 

Ed Cable

Director of Community Programs, Mifos Initiative

edcable@mifos.org <ma...@mifos.org>  | Skype: edcable | Mobile: +1.484.477.8649 <tel:%2B1.484.477.8649> 

 

Collectively Creating a World of 3 Billion Maries | http://mifos.org  <http://facebook.com/mifos>   <http://www.twitter.com/mifos> 

 

 

 

 

 

 

 

 





 

-- 

Ed Cable

Director of Community Programs, Mifos Initiative

edcable@mifos.org <ma...@mifos.org>  | Skype: edcable | Mobile: +1.484.477.8649 <tel:%2B1.484.477.8649> 

 

Collectively Creating a World of 3 Billion Maries | http://mifos.org  <http://facebook.com/mifos>   <http://www.twitter.com/mifos> 

 




-- 

This e-mail was sent to you by MTG Capital Management,any attached documents may contain privileged and confidential information and should only be read by those persons to whom this e-mail is addressed. Use by other than intended recipients is prohibited. If you are not the addressee, you must not copy, distribute, disclose or use any of the information in it. If you have received it in error, please delete it and immediately notify the sender. MTG Capital Management reserves the right to monitor all e-mail messages passing through its network. As we cannot guarantee the genuineness,accuracy or completeness of the information contained in this message, the statements set forth are not legally binding.


Re: Clarification on Validator Classes for Multiple Rescheduling of a Loan

Posted by Andris Kaneps <ak...@mtgcapital.ch>.
Dear Adi, Sander, Pramod,

Did you have a chance to look into the matter below?

Regards,
Andris Kaneps




> On 2016. gada 12. jūl., at 14:10, Andris Kaneps <ak...@mtgcapital.ch> wrote:
> 
> Dear Adi and the team,
> 
> As you may know Vishwas from Conflux Technologies has finished the development of Mifos fix that solves the rescheduling issue. We will do in-house testing for the coming days.
> 
> Can you please let us know when this could be implemented into Mifos update?
> 
> Regards,
> Andris
> 
> 
>> On Tue, Apr 19, 2016 at 10:59 AM, Adi Raju <ad...@confluxtechnologies.com> wrote:
>> Hi Ed,
>> 
>>  
>> 
>> Subramanya will be working on this task tomorrow.
>> 
>>  
>> 
>> Regards,
>> 
>> Adi
>> 
>>  
>> 
>> From: Ed Cable [mailto:edcable@mifos.org] 
>> Sent: 18 April 2016 21:49
>> To: Andris Kaneps <ak...@mtgcapital.ch>
>> Cc: Agris Varpins <ag...@mtgcapital.ch>; Adi Raju <ad...@confluxtechnologies.com>; Sander van der Heyden <sa...@musoni.eu>; dev@fineract.incubator.apache.org; robert wizglobal <ro...@wizglobal.co.ke>; Zack Wizglobal <za...@wizglobal.co.ke>; pramod@confluxtechnologies.com Nuthakki <pr...@confluxtechnologies.com>; Philippe Storm <ps...@watucredit.com>; Markus Geiß <mg...@mifos.org>
>> Subject: Re: Clarification on Validator Classes for Multiple Rescheduling of a Loan
>> 
>>  
>> 
>> Adi,
>> 
>>  
>> 
>> Now that the team has gotten through the QA for the most recent release, could you have the QA team spend some time on testing the scenarios and APIs you referenced above. Could you also provide a bit more clarity regarding what Zack needs to done for allowing for the undoing of the reschedulings.
>> 
>>  
>> 
>> Thanks,
>> 
>>  
>> 
>> Ed
>> 
>> 
>> 
>>  
>> 
>> On Tue, Apr 12, 2016 at 2:46 AM, Andris Kaneps <ak...@mtgcapital.ch> wrote:
>> 
>> Gentlemen,
>> 
>>  
>> 
>> If we would comission to Zack the "undo" function- would it be the solution?
>> 
>>  
>> 
>> R,
>> 
>> Andris
>> 
>> Sent from my iPhone
>> 
>> 
>> On 2016. gada 12. apr., at 11:44, Agris Varpins <ag...@mtgcapital.ch> wrote:
>> 
>> Who can test it and tell if they are working? I am not an IT person myself, As I said I tested the fix in test environment and ext worked fine, however, if there is something else to be tested purely from technical point of view, then, gentlemen, I trust you are the right people to deliver that verdict!!
>> 
>> Cheers,
>> Agris
>> 
>>  
>> 
>> On Tue, Apr 12, 2016 at 11:49 AM, Adi Raju <ad...@confluxtechnologies.com> wrote:
>> 
>> If you look at api doc https://demo.openmf.org/api-docs/apiLive.htm#loan_rescheduling
>> 
>> I see APIs to read/reject/approve any reschedule loan request instance.
>> 
>> As long as these APIs are tested to be working fine, it should be good enough.
>> 
>>  
>> 
>> Regards,
>> 
>> Adi
>> 
>>  
>> 
>> From: Agris Varpins [mailto:agris.varpins@mtgcapital.ch] 
>> Sent: 12 April 2016 13:38
>> To: Adi Raju <ad...@confluxtechnologies.com>
>> Cc: Sander van der Heyden <sa...@musoni.eu>; Ed Cable <ed...@mifos.org>; dev@fineract.incubator.apache.org; robert wizglobal <ro...@wizglobal.co.ke>; Zack Wizglobal <za...@wizglobal.co.ke>; pramod@confluxtechnologies.com Nuthakki <pr...@confluxtechnologies.com>; Andris Kaneps <ak...@mtgcapital.ch>; Philippe Storm <ps...@watucredit.com>; Markus Geiß <mg...@mifos.org>
>> Subject: Re: Clarification on Validator Classes for Multiple Rescheduling of a Loan
>> 
>>  
>> 
>> Could you clarify what you mean by "undo reschedule if the user makes a mistake"? In current version extenion cannot be undone if I am not mistaken or are we talking about some othetr functionality?
>> 
>>  
>> 
>> On Tue, Apr 12, 2016 at 11:02 AM, Adi Raju <ad...@confluxtechnologies.com> wrote:
>> 
>> As mentioned by Sander:
>> 
>> “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.”
>> 
>>  
>> 
>> Until this additional work is done, I wouldn’t recommend current solution to be merged.
>> 
>>  
>> 
>> Regards,
>> 
>> Adi
>> 
>>  
>> 
>> From: Agris Varpins [mailto:agris.varpins@mtgcapital.ch] 
>> Sent: 12 April 2016 13:14
>> To: Sander van der Heyden <sa...@musoni.eu>
>> Cc: Ed Cable <ed...@mifos.org>; dev@fineract.incubator.apache.org; robert wizglobal <ro...@wizglobal.co.ke>; Zack Wizglobal <za...@wizglobal.co.ke>; pramod@confluxtechnologies.com Nuthakki <pr...@confluxtechnologies.com>; Andris Kaneps <ak...@mtgcapital.ch>; Philippe Storm <ps...@watucredit.com>; Markus Geiß <mg...@mifos.org>; Adi Raju <ad...@confluxtechnologies.com>
>> Subject: Re: Clarification on Validator Classes for Multiple Rescheduling of a Loan
>> 
>>  
>> 
>> Good morning, gentlemen!
>> 
>> So where do we stand with this update?  Ed, has your team done some testing of the update to see if it works properly with the test clients? When we tested for our purposes, it seemed to work as we expected - loans could be rescheduled multiple times and reschedule could be done without undoing previously entered payments. Granted, we did not test how this fix affects, for example, accounting function, Overall, even if some additional fix is necessary to the Zack's product, that still would be doable.I believe it is in all interests to achieve that Mifos offers this fuction to its user community including ourselves.
>> 
>> Please let us now where do we stand at the moment and what are the prospects for this fix so that we can plan accordingly. 
>> 
>> Best regards,
>> 
>> Agris
>> 
>>  
>> 
>> On Mon, Apr 11, 2016 at 12:29 PM, Sander van der Heyden <sa...@musoni.eu> wrote:
>> 
>> Hi all,
>> 
>>  
>> 
>> Ignore my response, I was responding to the wrong thread, and not paying attention, still early here I guess... 
>> 
>>  
>> 
>> In terms of rescheduling, I think the current solution would need to be tested very carefully before it can be considered stable (or not), and therefore I'd recommend doing that before we merge the commit. Might also be good to add one or 2 test cases for the multiple reschedules to ensure that we have it covered there as well.
>> 
>>  
>> 
>> S
>> 
>> 
>> 
>> 
>> Sander van der Heyden
>> 
>> CTO Musoni Services
>> 
>> 
>> 
>> Mobile (NL): +31 (0)6 14239505
>> Skype: s.vdheyden
>> Website: musonisystem.com
>> Follow us on Twitter! 
>> Postal address: Hillegomstraat 12-14, office 0.09, 1058 LS, Amsterdam, The Netherlands
>> 
>>  
>> 
>> On Mon, Apr 11, 2016 at 11:17 AM, Sander van der Heyden <sa...@musoni.eu> wrote:
>> 
>> Hi Agris,
>> 
>>  
>> 
>> You can already do all of this by using the current datatables, where you can add all fields necessary to the clients data that you want to capture. So the update is not really a requirement to get this done, a large number of MFI's are already using the system with all of these fields added in.
>> 
>>  
>> 
>> Thanks,
>> 
>> Sander
>> 
>> 
>> 
>> 
>> Sander van der Heyden
>> 
>> CTO Musoni Services
>> 
>> 
>> 
>> Mobile (NL): +31 (0)6 14239505
>> Skype: s.vdheyden
>> Website: musonisystem.com
>> Follow us on Twitter! 
>> Postal address: Hillegomstraat 12-14, office 0.09, 1058 LS, Amsterdam, The Netherlands
>> 
>>  
>> 
>> On Mon, Apr 11, 2016 at 10:58 AM, Agris Varpins <ag...@mtgcapital.ch> wrote:
>> 
>> Good morning, all!
>> 
>> Thank you all for you inputs! So what is the verdict regarding this update? Will it work? Or if not, can it be easily adjusted and perfected so that it does? I cannot overstate hot important this fix is for us and we are really looking to solve this issue as soon as possible, 
>> 
>> Looking forward to you feedback.
>> 
>> Best regards,
>> 
>> Agris
>> 
>>  
>> 
>> On Mon, Apr 11, 2016 at 9:09 AM, Sander van der Heyden <sa...@musoni.eu> wrote:
>> 
>> 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! 
>> Postal address: Hillegomstraat 12-14, office 0.09, 1058 LS, Amsterdam, The Netherlands
>> 
>>  
>> 
>> On Fri, Apr 8, 2016 at 5:46 PM, Ed Cable <ed...@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 <ed...@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 <ad...@confluxtechnologies.com> 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:robert@wizglobal.co.ke] 
>> Sent: 04 April 2016 22:13
>> To: Adi Raju <ad...@confluxtechnologies.com>
>> Cc: Zack Wizglobal <za...@wizglobal.co.ke>; Ed Cable <ed...@mifos.org>; pramod@confluxtechnologies.com; Agris Varpins <ag...@mtgcapital.ch>; Andris Kaneps <ak...@mtgcapital.ch>; Philippe Storm <ps...@watucredit.com>
>> 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
>> 
>>  *
>> 
>>  * 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.gson.JsonElement;
>> 
>> import com.google.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.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.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 <ad...@confluxtechnologies.com> 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" <za...@wizglobal.co.ke> 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
>> 
>> zack@wizglobal.co.ke
>> www.wizglobal.co.ke
>> 
>>  
>> 
>> On 24 Mar 2016, at 21:06, Andris Kaneps <ak...@mtgcapital.ch> 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
>> 
>> edcable@mifos.org | Skype: edcable | Mobile: +1.484.477.8649
>> 
>>  
>> 
>> Collectively Creating a World of 3 Billion Maries | http://mifos.org  
>> 
>>  
>> 
>> 
>> 
>> 
>> 
>> 
>>  
>> 
>> --
>> 
>> Ed Cable
>> 
>> Director of Community Programs, Mifos Initiative
>> 
>> edcable@mifos.org | Skype: edcable | Mobile: +1.484.477.8649
>> 
>>  
>> 
>> Collectively Creating a World of 3 Billion Maries | http://mifos.org  
>> 
>>  
>> 
>>  
>> 
>>  
>> 
>>  
>> 
>>  
>> 
>>  
>> 
>>  
>> 
>>  
>> 
>> 
>> 
>> 
>>  
>> 
>> --
>> 
>> Ed Cable
>> 
>> Director of Community Programs, Mifos Initiative
>> 
>> edcable@mifos.org | Skype: edcable | Mobile: +1.484.477.8649
>> 
>>  
>> 
>> Collectively Creating a World of 3 Billion Maries | http://mifos.org  
>> 
> 
> 
> 
> -- 
> This e-mail was sent to you by MTG Capital Management,any attached documents may contain privileged and confidential information and should only be read by those persons to whom this e-mail is addressed. Use by other than intended recipients is prohibited. If you are not the addressee, you must not copy, distribute, disclose or use any of the information in it. If you have received it in error, please delete it and immediately notify the sender. MTG Capital Management reserves the right to monitor all e-mail messages passing through its network. As we cannot guarantee the genuineness,accuracy or completeness of the information contained in this message, the statements set forth are not legally binding.