fineract-dev mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From Ed Cable <edca...@mifos.org>
Subject Clarification on Validator Classes for Multiple Rescheduling of a Loan
Date Wed, 06 Apr 2016 16:38:06 GMT
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>

Mime
  • Unnamed multipart/alternative (inline, None, 0 bytes)
View raw message