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 <akan...@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.r...@confluxtechnologies.com> wrote:
>> Hi Ed,
>> 
>>  
>> 
>> Subramanya will be working on this task tomorrow.
>> 
>>  
>> 
>> Regards,
>> 
>> Adi
>> 
>>  
>> 
>> From: Ed Cable [mailto:edca...@mifos.org] 
>> Sent: 18 April 2016 21:49
>> To: Andris Kaneps <akan...@mtgcapital.ch>
>> Cc: Agris Varpins <agris.varp...@mtgcapital.ch>; Adi Raju 
>> <adi.r...@confluxtechnologies.com>; Sander van der Heyden 
>> <sandervanderhey...@musoni.eu>; dev@fineract.incubator.apache.org; robert 
>> wizglobal <rob...@wizglobal.co.ke>; Zack Wizglobal <z...@wizglobal.co.ke>; 
>> pra...@confluxtechnologies.com Nuthakki <pra...@confluxtechnologies.com>; 
>> Philippe Storm <pst...@watucredit.com>; Markus Geiß <mge...@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 <akan...@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.varp...@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.r...@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.varp...@mtgcapital.ch] 
>> Sent: 12 April 2016 13:38
>> To: Adi Raju <adi.r...@confluxtechnologies.com>
>> Cc: Sander van der Heyden <sandervanderhey...@musoni.eu>; Ed Cable 
>> <edca...@mifos.org>; dev@fineract.incubator.apache.org; robert wizglobal 
>> <rob...@wizglobal.co.ke>; Zack Wizglobal <z...@wizglobal.co.ke>; 
>> pra...@confluxtechnologies.com Nuthakki <pra...@confluxtechnologies.com>; 
>> Andris Kaneps <akan...@mtgcapital.ch>; Philippe Storm 
>> <pst...@watucredit.com>; Markus Geiß <mge...@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.r...@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.varp...@mtgcapital.ch] 
>> Sent: 12 April 2016 13:14
>> To: Sander van der Heyden <sandervanderhey...@musoni.eu>
>> Cc: Ed Cable <edca...@mifos.org>; dev@fineract.incubator.apache.org; robert 
>> wizglobal <rob...@wizglobal.co.ke>; Zack Wizglobal <z...@wizglobal.co.ke>; 
>> pra...@confluxtechnologies.com Nuthakki <pra...@confluxtechnologies.com>; 
>> Andris Kaneps <akan...@mtgcapital.ch>; Philippe Storm 
>> <pst...@watucredit.com>; Markus Geiß <mge...@mifos.org>; Adi Raju 
>> <adi.r...@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 
>> <sandervanderhey...@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 
>> <sandervanderhey...@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 
>> <agris.varp...@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 
>> <sandervanderhey...@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 <edca...@mifos.org> wrote:
>> 
>> Sander, have you had a chance to review this thread? 
>> 
>>  
>> 
>> Andris' team is in need of this feature and wanted to get feedback on the 
>> approach they've taken to see if they can continue with that or they need to 
>> follow the path that was proposed by Pramod.
>> 
>>  
>> 
>> Ed
>> 
>> 
>> 
>>  
>> 
>> On Wed, Apr 6, 2016 at 9:38 AM, Ed Cable <edca...@mifos.org> wrote:
>> 
>> Zack and Robert have been working on contributing a fix to add the ability 
>> to reschedule a loan multiple times.
>> 
>>  
>> 
>> They have taken a different approach than what Pramod had previously 
>> outlined so we wanted to discuss their proposed fix with Sander and his team 
>> who have provided the initial fix to reschedule a loan a single time.
>> 
>>  
>> 
>> Ed
>> 
>>  
>> 
>> On Mon, Apr 4, 2016 at 9:32 PM, Adi Raju <adi.r...@confluxtechnologies.com> 
>> wrote:
>> 
>> Hi Robert,
>> 
>>  
>> 
>> Validator classes generally only perform API parameter validations, in other 
>> words they are the first check point before proceeding to more costlier DB 
>> or calculation tasks.
>> 
>> All that is done in this change is that the validation at the first check 
>> point is removed.
>> 
>> These checkpoints were added by earlier developers because they haven’t 
>> addressed those scenarios in further calculations.
>> 
>> If the core code works for multi-reschedule, they wouldn’t have put this 
>> check in the first place.
>> 
>>  
>> 
>> I really doubt this solution is working as it is supposed to be. Have you 
>> been able to test it against expected schedule and its values post 
>> reschedule action? Does other like retrieve/approve/reject reschedule APIs 
>> work with this solution?
>> 
>>  
>> 
>> +Sander, who can help us with more clarifications on why such validations 
>> were added.
>> 
>>  
>> 
>> Regards,
>> 
>> Adi
>> 
>>  
>> 
>>  
>> 
>> From: robert wizglobal [mailto:rob...@wizglobal.co.ke] 
>> Sent: 04 April 2016 22:13
>> To: Adi Raju <adi.r...@confluxtechnologies.com>
>> Cc: Zack Wizglobal <z...@wizglobal.co.ke>; Ed Cable <edca...@mifos.org>; 
>> pra...@confluxtechnologies.com; Agris Varpins <agris.varp...@mtgcapital.ch>; 
>> Andris Kaneps <akan...@mtgcapital.ch>; Philippe Storm <pst...@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 <adi.r...@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" <z...@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
>> 
>> z...@wizglobal.co.ke
>> www.wizglobal.co.ke
>> 
>>  
>> 
>> On 24 Mar 2016, at 21:06, Andris Kaneps <akan...@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
>> 
>> edca...@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
>> 
>> edca...@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
>> 
>> edca...@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.

Reply via email to