From bc0a120f617de694818a5b25c8a321f491285330 Mon Sep 17 00:00:00 2001 From: ashok-conflux Date: Fri, 13 Sep 2013 12:41:45 +0530 Subject: [PATCH 1/8] Added Holidays and working days details to api doc --- api-docs/apiLive.htm | 208 +++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 208 insertions(+) diff --git a/api-docs/apiLive.htm b/api-docs/apiLive.htm index e900d2935..452d91557 100644 --- a/api-docs/apiLive.htm +++ b/api-docs/apiLive.htm @@ -900,6 +900,22 @@ Update Loan Product Mix Delete Loan Products Mix + + Holidays + holidays + Create a Holiday + List Holidays + + + + + Working days + + + + + + @@ -8916,6 +8932,194 @@ DELETE loanproducts/5/productmix + +   +
+
+

Holidays

+

Some MFI's span large regions where different branch offices might observe different holidays. They need the ability to define holidays for specific branch offices and be able to set the repayment rule to follow during those holidays. +

+

+ The reschedule of repayments to repaymentsRescheduledTo date durign defined holidays is turned on/off by enabling/disabling reschedule-repayments-on-holidays in Global configurations. +

+

Allow Repayment transactions on a defined holidays is turned on/off by enabling/disabling allow-transactions-on-holiday in Global configurations. +

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Field Descriptions
name
Name of the holiday. +
fromDate
The date on holiday begins. +
toDate
The date on holiday ends. +
repaymentsRescheduledTo
Date to which repayments will be rescheduled when repayments date falls on a defined holiday. e.g. A holiday is defined on 25th of October 2013 with repaymentsRescheduledTo date to 26th of October 2013 and any loans with repayments date on 25th of October 2013 will be rescheduled to 26th of October 2013. +
officeId
The officeId represents the office to which holiday is applied. +
+
+
+ +   +
+
+

List Holidays

+

Example Requests:

+
holidays?officeId=1
+
+
+
+
+ +GET https://DomainName/api/v1/holidays?officeId=1 + + +[ + { + "id": 1, + "name": "Good Friday", + "fromDate": [ + 2013, + 10, + 25 + ], + "toDate": [ + 2013, + 10, + 25 + ], + "repaymentsScheduleTo": [ + 2013, + 10, + 26 + ] + } +] + +
+
+ +   +
+
+

Create a Holiday

+ + + + + + + +
Mandatory Fields
name, fromDate, toDate, repaymentsRescheduledTo, offices
+
+
+ +POST https://DomainName/api/v1/holidays + + +POST holidays +Content-Type: application/json +Request Body: +{ + "name": "Good Friday", + "dateFormat": "dd MMMM yyyy", + "locale": "en", + "fromDate": "25 October 2013", + "toDate": "25 October 2013", + "repaymentsRescheduledTo": "26 October 2013", + "offices": [ + "officeId":"1", + "officeId":"2" + ] +} + + +{ + "resourceId": 1 +} + +
+
+ + + +   +
+
+

Working days

+

The days of the week that are workdays. +

+

+ Rescheduling of repayments when it falls on a non-working is turned on /off by enable/disable reschedule-future-repayments parameter in Global configurations. +

+

+ Allow transactions on non-working days is configurable by enabling/disbaling the allow-transactions-on-non_workingday parameter in Global configurations. +

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Schedule for repayments on non-working day
Same day
The repayments schedule for same day regardless of it's a non-working day. +
Next workday
The repayments reschedule to next working day. e.g. if a repayment falls on a non-working day will be rescheduled to next available working day. +
Previous workday
The repayments reschedule to previous working day. e.g. if a repayment falls on a non-working day will be rescheduled to previous available working day. +
Next scheduled meeting
The repayments reschduled to next scheduled meeting. +
+
+
+ + +  
@@ -9035,6 +9239,10 @@ Request Body:

Global configuration related to set of supported enable/disable configurations:

  1. maker-checker - defaults to false - if true turns on maker-checker functionality
  2. +
  3. reschedule-future-repayments - defaults to false - if true reschedules repayemnts which falls on a non-working day to configured repayment rescheduling rule
  4. +
  5. allow-transactions-on-non_workingday - defaults to false - if true allows transactions on non-working days
  6. +
  7. reschedule-repayments-on-holidays - defaults to false - if true reschedules repayemnts which falls on a non-working day to defined reschedule date
  8. +
  9. allow-transactions-on-holiday - defaults to false - if true allows transactions on holidays
From b6324630ff2691e51bd638a42850c2fc617ce3c2 Mon Sep 17 00:00:00 2001 From: Keith Woodlock Date: Wed, 18 Sep 2013 09:46:19 +0100 Subject: [PATCH 2/8] bump up version numbers for release. --- api-docs/apiLive.htm | 2 +- mifosng-provider/gradle.properties | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/api-docs/apiLive.htm b/api-docs/apiLive.htm index e900d2935..5c333931c 100644 --- a/api-docs/apiLive.htm +++ b/api-docs/apiLive.htm @@ -90,7 +90,7 @@
- +

Overview

diff --git a/mifosng-provider/gradle.properties b/mifosng-provider/gradle.properties index 43e264960..b6d1bc2ae 100644 --- a/mifosng-provider/gradle.properties +++ b/mifosng-provider/gradle.properties @@ -1 +1 @@ -releaseVersion=1.9.1.RELEASE +releaseVersion=1.9.2.RELEASE From b2168bff2ce0728e859377589739b20650147fa2 Mon Sep 17 00:00:00 2001 From: Keith Woodlock Date: Wed, 18 Sep 2013 12:15:30 +0100 Subject: [PATCH 3/8] MIFOSX-672: fix issue with FLAT interest calculation not correctly calculation prinicpal balance for final installments. --- .../domain/LoanApplicationTerms.java | 61 ++++++++----------- 1 file changed, 26 insertions(+), 35 deletions(-) diff --git a/mifosng-provider/src/main/java/org/mifosplatform/portfolio/loanaccount/loanschedule/domain/LoanApplicationTerms.java b/mifosng-provider/src/main/java/org/mifosplatform/portfolio/loanaccount/loanschedule/domain/LoanApplicationTerms.java index 0286f054b..f32d691f2 100644 --- a/mifosng-provider/src/main/java/org/mifosplatform/portfolio/loanaccount/loanschedule/domain/LoanApplicationTerms.java +++ b/mifosng-provider/src/main/java/org/mifosplatform/portfolio/loanaccount/loanschedule/domain/LoanApplicationTerms.java @@ -50,7 +50,7 @@ public final class LoanApplicationTerms { * Integer representing the number of 'repayment frequencies' or * installments where 'grace' should apply to the payment of interest in a * loans repayment period (installment). - * + * * Note: Interest is still calculated taking into account the full * loan term, the interest is simply offset to a later period. */ @@ -60,7 +60,7 @@ public final class LoanApplicationTerms { * Integer representing the number of 'repayment frequencies' or * installments where 'grace' should apply to the charging of interest in a * loans repayment period (installment). - * + * * Note: The loan is interest-free for the period of time * indicated. */ @@ -68,7 +68,7 @@ public final class LoanApplicationTerms { /** * Legacy method of support 'grace' on the charging of interest on a loan. - * + * *

* For the typical structured loan, its reasonable to use an integer to * indicate the number of 'repayment frequency' periods the 'grace' should @@ -171,15 +171,10 @@ public final class LoanApplicationTerms { Money adjusted = principalForPeriod; - // adjust cumulative fields for principal & interest if needed - if (this.principal.getAmount().subtract(totalCumulativePrincipalToDate.getAmount()).add(principalForPeriod.getAmount()).compareTo(principalForPeriod.getAmount()) == -1) { - adjusted = adjusted.minus(adjusted); - MonetaryCurrency monetaryCurrency = new MonetaryCurrency(adjusted.getCurrencyCode(), 0, adjusted.getCurrencyInMultiplesOf()); - BigDecimal diff = this.principal.getAmount().subtract(totalCumulativePrincipalToDate.getAmount()).add(principalForPeriod.getAmount()); - if(diff.doubleValue()<0){ - diff = BigDecimal.ZERO; - } - adjusted = adjusted.plus(Money.of(monetaryCurrency,diff)); + final Money totalPrincipalRemaining = this.principal.minus(totalCumulativePrincipalToDate); + if (totalPrincipalRemaining.isLessThanZero()) { + // paid too much principal, subtract amount that overpays from principal paid for period. + adjusted = principalForPeriod.minus(totalPrincipalRemaining.abs()); } else if (isLastRepaymentPeriod(this.numberOfRepayments, periodNumber)) { final Money difference = totalCumulativePrincipalToDate.minus(this.principal); @@ -197,15 +192,11 @@ public final class LoanApplicationTerms { final Money totalInterestDueForLoan, final int periodNumber) { Money adjusted = interestForThisPeriod; - if (totalInterestDueForLoan.getAmount().subtract(totalCumulativeInterestToDate.getAmount()).add(interestForThisPeriod.getAmount()) - .compareTo(interestForThisPeriod.getAmount()) == -1) { - adjusted = adjusted.minus(adjusted); - MonetaryCurrency monetaryCurrency = new MonetaryCurrency(adjusted.getCurrencyCode(), 0, adjusted.getCurrencyInMultiplesOf()); - BigDecimal diff = totalInterestDueForLoan.getAmount().subtract(totalCumulativeInterestToDate.getAmount()).add(interestForThisPeriod.getAmount()); - if(diff.doubleValue()<0){ - diff = BigDecimal.ZERO; - } - adjusted = adjusted.plus(Money.of(monetaryCurrency,diff)); + + final Money totalInterestRemaining = totalInterestDueForLoan.minus(totalCumulativeInterestToDate); + if (totalInterestRemaining.isLessThanZero()) { + // paid too much interest, subtract amount that overpays from interest paid for period. + adjusted = interestForThisPeriod.minus(totalInterestRemaining.abs()); } else if (isLastRepaymentPeriod(this.numberOfRepayments, periodNumber)) { final Money interestDifference = totalCumulativeInterestToDate.minus(totalInterestDueForLoan); if (interestDifference.isLessThanZero()) { @@ -223,7 +214,7 @@ public final class LoanApplicationTerms { /** * Calculates the total interest to be charged on loan taking into account * grace settings. - * + * */ public Money calculateTotalInterestCharged(final PaymentPeriodsInOneYearCalculator calculator, final MathContext mc) { @@ -270,7 +261,7 @@ public final class LoanApplicationTerms { switch (this.amortizationMethod) { case EQUAL_INSTALLMENTS: // equal installments - int periodsElapsed = periodNumber - 1; + final int periodsElapsed = periodNumber - 1; final BigDecimal periodicInterestRateForRepaymentPeriod = periodicInterestRate(calculator, mc); final Money totalPmtForThisInstallment = calculateTotalDueForEqualInstallmentRepaymentPeriod( @@ -313,7 +304,7 @@ public final class LoanApplicationTerms { case EQUAL_PRINCIPAL: // interest follows time-value of money and is brought // forward to next applicable interest payment period - PrincipalInterest result = calculateTotalFlatInterestForPeriod(calculator, periodNumber, mc, + final PrincipalInterest result = calculateTotalFlatInterestForPeriod(calculator, periodNumber, mc, interestBroughtForwardDueToGrace); interestForInstallment = result.interest(); interestBroughtForwardDueToGrace = result.interestPaymentDueToGrace(); @@ -324,10 +315,10 @@ public final class LoanApplicationTerms { break; case DECLINING_BALANCE: - Money interestForThisInstallmentBeforeGrace = calculateDecliningInterestDueForInstallmentBeforeApplyingGrace(calculator, + final Money interestForThisInstallmentBeforeGrace = calculateDecliningInterestDueForInstallmentBeforeApplyingGrace(calculator, mc, daysInPeriod, outstandingBalance); - Money interestForThisInstallmentAfterGrace = calculateDecliningInterestDueForInstallmentAfterApplyingGrace(calculator, + final Money interestForThisInstallmentAfterGrace = calculateDecliningInterestDueForInstallmentAfterApplyingGrace(calculator, interestCalculationGraceOnRepaymentPeriodFraction, mc, daysInPeriod, outstandingBalance, periodNumber); interestForInstallment = interestForThisInstallmentAfterGrace; @@ -359,7 +350,7 @@ public final class LoanApplicationTerms { final double paymentPerRepaymentPeriod = paymentPerPeriod(periodicInterestRate, this.principal, periodsElapsed); final double totalRepayment = paymentPerRepaymentPeriod * this.numberOfRepayments; - return Money.of(principal.getCurrency(), BigDecimal.valueOf(totalRepayment)); + return Money.of(this.principal.getCurrency(), BigDecimal.valueOf(totalRepayment)); } /** @@ -448,12 +439,12 @@ public final class LoanApplicationTerms { final Money totalInterestForLoanTerm = calculateTotalInterestDueWithoutGrace(calculator, mc); - Money interestPerGracePeriod = calculateTotalInterestPerInstallmentWithoutGrace(calculator, mc); + final Money interestPerGracePeriod = calculateTotalInterestPerInstallmentWithoutGrace(calculator, mc); - Money totalInterestFree = interestPerGracePeriod.multipliedBy(getInterestChargingGrace()); - Money realTotalInterestForLoan = totalInterestForLoanTerm.minus(totalInterestFree); + final Money totalInterestFree = interestPerGracePeriod.multipliedBy(getInterestChargingGrace()); + final Money realTotalInterestForLoan = totalInterestForLoanTerm.minus(totalInterestFree); - Integer interestPaymentDuePeriods = calculateNumberOfRepaymentPeriodsWhereInterestPaymentIsDue(this.numberOfRepayments); + final Integer interestPaymentDuePeriods = calculateNumberOfRepaymentPeriodsWhereInterestPaymentIsDue(this.numberOfRepayments); interestForInstallment = realTotalInterestForLoan .dividedBy(BigDecimal.valueOf(interestPaymentDuePeriods), mc.getRoundingMode()); @@ -548,10 +539,10 @@ public final class LoanApplicationTerms { switch (this.interestCalculationPeriodMethod) { case DAILY: - BigDecimal dailyInterestRate = this.annualNominalInterestRate.divide(BigDecimal.valueOf(Long.valueOf(365)), mc) + final BigDecimal dailyInterestRate = this.annualNominalInterestRate.divide(BigDecimal.valueOf(Long.valueOf(365)), mc) .divide(BigDecimal.valueOf(Double.valueOf("100.0")), mc).multiply(BigDecimal.valueOf(this.repaymentEvery)); - BigDecimal equivalentInterestRateForPeriod = dailyInterestRate.multiply(BigDecimal.valueOf(Long.valueOf(daysInPeriod))); + final BigDecimal equivalentInterestRateForPeriod = dailyInterestRate.multiply(BigDecimal.valueOf(Long.valueOf(daysInPeriod))); interestDue = outstandingBalance.multiplyRetainScale(equivalentInterestRateForPeriod, mc.getRoundingMode()); break; @@ -589,7 +580,7 @@ public final class LoanApplicationTerms { } else if (interestCalculationGraceOnRepaymentPeriodFraction > Double.valueOf("0.25") && interestCalculationGraceOnRepaymentPeriodFraction < Integer.valueOf(1).doubleValue()) { - Money graceOnInterestForRepaymentPeriod = interest.multipliedBy(interestCalculationGraceOnRepaymentPeriodFraction); + final Money graceOnInterestForRepaymentPeriod = interest.multipliedBy(interestCalculationGraceOnRepaymentPeriodFraction); interest = interest.minus(graceOnInterestForRepaymentPeriod); fraction = Double.valueOf("0"); } @@ -616,7 +607,7 @@ public final class LoanApplicationTerms { private Money calculatePrincipalDueForInstallment(final PaymentPeriodsInOneYearCalculator calculator, final MathContext mc, final int periodNumber, final Money totalDuePerInstallment, final int daysInPeriod, final Money outstandingBalance) { - Money interestForThisInstallmentBeforeGrace = calculateDecliningInterestDueForInstallmentBeforeApplyingGrace(calculator, mc, + final Money interestForThisInstallmentBeforeGrace = calculateDecliningInterestDueForInstallmentBeforeApplyingGrace(calculator, mc, daysInPeriod, outstandingBalance); Money principal = totalDuePerInstallment.minus(interestForThisInstallmentBeforeGrace); From 7aa8332b301fc327e985edd5622bcc1128338657 Mon Sep 17 00:00:00 2001 From: Keith Woodlock Date: Wed, 18 Sep 2013 12:30:32 +0100 Subject: [PATCH 4/8] MIFOSX-671: ensure summary fields like balance on transactions are updated in the case where account is activated and deposit automatically made. --- .../savings/domain/SavingsAccount.java | 30 ++++++++++++------- 1 file changed, 19 insertions(+), 11 deletions(-) diff --git a/mifosng-provider/src/main/java/org/mifosplatform/portfolio/savings/domain/SavingsAccount.java b/mifosng-provider/src/main/java/org/mifosplatform/portfolio/savings/domain/SavingsAccount.java index 6aa7ceb04..c14e04d59 100644 --- a/mifosng-provider/src/main/java/org/mifosplatform/portfolio/savings/domain/SavingsAccount.java +++ b/mifosng-provider/src/main/java/org/mifosplatform/portfolio/savings/domain/SavingsAccount.java @@ -12,8 +12,8 @@ import static org.mifosplatform.portfolio.savings.SavingsApiConstants.localePara import static org.mifosplatform.portfolio.savings.SavingsApiConstants.lockinPeriodFrequencyParamName; import static org.mifosplatform.portfolio.savings.SavingsApiConstants.lockinPeriodFrequencyTypeParamName; import static org.mifosplatform.portfolio.savings.SavingsApiConstants.withdrawalFeeAmountParamName; -import static org.mifosplatform.portfolio.savings.SavingsApiConstants.withdrawalFeeTypeParamName; import static org.mifosplatform.portfolio.savings.SavingsApiConstants.withdrawalFeeForTransfersParamName; +import static org.mifosplatform.portfolio.savings.SavingsApiConstants.withdrawalFeeTypeParamName; import java.math.BigDecimal; import java.math.MathContext; @@ -168,7 +168,7 @@ public class SavingsAccount extends AbstractPersistable { /** * The interest period is the span of time at the end of which savings in a * client's account earn interest. - * + * * A value from the {@link SavingsCompoundingInterestPeriodType} * enumeration. */ @@ -261,7 +261,7 @@ public class SavingsAccount extends AbstractPersistable { final SavingsInterestCalculationDaysInYearType interestCalculationDaysInYearType, final BigDecimal minRequiredOpeningBalance, final Integer lockinPeriodFrequency, final SavingsPeriodFrequencyType lockinPeriodFrequencyType, final BigDecimal withdrawalFeeAmount, final SavingsWithdrawalFeesType withdrawalFeeType, - boolean withdrawalFeeApplicableForTransfer, final BigDecimal annualFeeAmount, final MonthDay annualFeeOnMonthDay) { + final boolean withdrawalFeeApplicableForTransfer, final BigDecimal annualFeeAmount, final MonthDay annualFeeOnMonthDay) { final SavingsAccountStatusType status = SavingsAccountStatusType.SUBMITTED_AND_PENDING_APPROVAL; return new SavingsAccount(client, group, product, fieldOfficer, accountNo, externalId, status, accountType, submittedOnDate, @@ -423,11 +423,11 @@ public class SavingsAccount extends AbstractPersistable { /** * All interest calculation based on END-OF-DAY-BALANCE. - * + * * Interest calculation is performed on-the-fly over all account * transactions. - * - * + * + * * 1. Calculate Interest From Beginning Of Account 1a. determine the * 'crediting' periods that exist for this savings acccount 1b. determine * the 'compounding' periods that exist within each 'crediting' period @@ -607,7 +607,7 @@ public class SavingsAccount extends AbstractPersistable { return activationLocalDate; } - public SavingsAccountTransaction withdraw(SavingsAccountTransactionDTO transactionDTO, final boolean applyWithdrawFee) { + public SavingsAccountTransaction withdraw(final SavingsAccountTransactionDTO transactionDTO, final boolean applyWithdrawFee) { if (isNotActive()) { @@ -728,7 +728,7 @@ public class SavingsAccount extends AbstractPersistable { } } - public void validateAccountBalanceDoesNotBecomeNegative(String transactionAction) { + public void validateAccountBalanceDoesNotBecomeNegative(final String transactionAction) { final List transactionsSortedByDate = retreiveListOfTransactions(); Money runningBalance = Money.zero(this.currency); @@ -1669,9 +1669,17 @@ public class SavingsAccount extends AbstractPersistable { // activating account. final Money minRequiredOpeningBalance = Money.of(this.currency, this.minRequiredOpeningBalance); if (minRequiredOpeningBalance.isGreaterThanZero()) { - SavingsAccountTransactionDTO transactionDTO = new SavingsAccountTransactionDTO(fmt, activationDate, minRequiredOpeningBalance.getAmount(), + final SavingsAccountTransactionDTO transactionDTO = new SavingsAccountTransactionDTO(fmt, activationDate, minRequiredOpeningBalance.getAmount(), existingTransactionIds, existingReversedTransactionIds, null); deposit(transactionDTO); + + // no openingBalance concept supported yet but probably will to allow + // for migrations. + final Money openingAccountBalance = Money.zero(this.currency); + + // update existing transactions so derived balance fields are + // correct. + recalculateDailyBalances(openingAccountBalance); } return actualChanges; @@ -1705,9 +1713,9 @@ public class SavingsAccount extends AbstractPersistable { .failWithCode("cannot.be.a.future.date"); if (!dataValidationErrors.isEmpty()) { throw new PlatformApiDataValidationException(dataValidationErrors); } } - List savingsAccountTransactions = retreiveListOfTransactions(); + final List savingsAccountTransactions = retreiveListOfTransactions(); if (savingsAccountTransactions.size() > 0) { - SavingsAccountTransaction accountTransaction = savingsAccountTransactions.get(savingsAccountTransactions.size() - 1); + final SavingsAccountTransaction accountTransaction = savingsAccountTransactions.get(savingsAccountTransactions.size() - 1); if (accountTransaction.isAfter(closedDate)) { baseDataValidator.reset().parameter(SavingsApiConstants.closedOnDateParamName).value(closedDate) .failWithCode("must.be.after.last.transaction.date"); From 08450c4a8786e22df88c36fcf1b9b664686517a8 Mon Sep 17 00:00:00 2001 From: Keith Woodlock Date: Wed, 18 Sep 2013 12:37:20 +0100 Subject: [PATCH 5/8] MIFOSX-633: fix typos --- api-docs/apiLive.htm | 332 +++++++++++++++++++++---------------------- 1 file changed, 166 insertions(+), 166 deletions(-) diff --git a/api-docs/apiLive.htm b/api-docs/apiLive.htm index c8a5b6a7c..941503d6f 100644 --- a/api-docs/apiLive.htm +++ b/api-docs/apiLive.htm @@ -2263,7 +2263,7 @@ Request Body:  

-

Reject a Client Transfer

+

Accept a Client Transfer

Allows the Destination Branch to accept the proposed Client Transfer.

The destination branch may also choose to link this client to a group (in which case, any existing active JLG loan of the client is rescheduled to match the meeting frequency of the group) and loan Officer at the time of accepting the transfer

@@ -8933,190 +8933,190 @@ DELETE loanproducts/5/productmix -   -
-
-

Holidays

-

Some MFI's span large regions where different branch offices might observe different holidays. They need the ability to define holidays for specific branch offices and be able to set the repayment rule to follow during those holidays. -

-

- The reschedule of repayments to repaymentsRescheduledTo date durign defined holidays is turned on/off by enabling/disabling reschedule-repayments-on-holidays in Global configurations. -

-

Allow Repayment transactions on a defined holidays is turned on/off by enabling/disabling allow-transactions-on-holiday in Global configurations. -

- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
Field Descriptions
name
Name of the holiday. -
fromDate
The date on holiday begins. -
toDate
The date on holiday ends. -
repaymentsRescheduledTo
Date to which repayments will be rescheduled when repayments date falls on a defined holiday. e.g. A holiday is defined on 25th of October 2013 with repaymentsRescheduledTo date to 26th of October 2013 and any loans with repayments date on 25th of October 2013 will be rescheduled to 26th of October 2013. -
officeId
The officeId represents the office to which holiday is applied. -
-
+   +
+
+

Holidays

+

Some MFI's span large regions where different branch offices might observe different holidays. They need the ability to define holidays for specific branch offices and be able to set the repayment rule to follow during those holidays. +

+

+ The reschedule of repayments to repaymentsRescheduledTo date during defined holidays is turned on/off by enabling/disabling reschedule-repayments-on-holidays in Global configurations. +

+

Allow Repayment transactions on a defined holidays is turned on/off by enabling/disabling allow-transactions-on-holiday in Global configurations. +

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Field Descriptions
name
Name of the holiday. +
fromDate
The date on holiday begins. +
toDate
The date on holiday ends. +
repaymentsRescheduledTo
Date to which repayments will be rescheduled when repayments date falls on a defined holiday. e.g. A holiday is defined on 25th of October 2013 with repaymentsRescheduledTo date to 26th of October 2013 and any loans with repayments date on 25th of October 2013 will be rescheduled to 26th of October 2013. +
officeId
The officeId represents the office to which holiday is applied. +
+
-   -
-
-

List Holidays

-

Example Requests:

-
holidays?officeId=1
-
-
-
-
- +   +
+
+

List Holidays

+

Example Requests:

+
holidays?officeId=1
+
+
+
+
+ GET https://DomainName/api/v1/holidays?officeId=1 - - + + [ - { - "id": 1, - "name": "Good Friday", - "fromDate": [ - 2013, - 10, - 25 - ], - "toDate": [ - 2013, - 10, - 25 - ], - "repaymentsScheduleTo": [ - 2013, - 10, - 26 - ] - } +{ + "id": 1, + "name": "Good Friday", + "fromDate": [ + 2013, + 10, + 25 + ], + "toDate": [ + 2013, + 10, + 25 + ], + "repaymentsScheduleTo": [ + 2013, + 10, + 26 + ] +} ] - -
+
+
-   -
-
-

Create a Holiday

- - - - - - - -
Mandatory Fields
name, fromDate, toDate, repaymentsRescheduledTo, offices
-
-
- +   +
+
+

Create a Holiday

+ + + + + + + +
Mandatory Fields
name, fromDate, toDate, repaymentsRescheduledTo, offices
+
+
+ POST https://DomainName/api/v1/holidays - - + + POST holidays Content-Type: application/json Request Body: { - "name": "Good Friday", - "dateFormat": "dd MMMM yyyy", - "locale": "en", - "fromDate": "25 October 2013", - "toDate": "25 October 2013", - "repaymentsRescheduledTo": "26 October 2013", - "offices": [ - "officeId":"1", - "officeId":"2" - ] +"name": "Good Friday", +"dateFormat": "dd MMMM yyyy", +"locale": "en", +"fromDate": "25 October 2013", +"toDate": "25 October 2013", +"repaymentsRescheduledTo": "26 October 2013", +"offices": [ + "officeId":"1", + "officeId":"2" +] } - - + + { - "resourceId": 1 +"resourceId": 1 } - -
+
- +
+ -   -
-
-

Working days

-

The days of the week that are workdays. -

-

- Rescheduling of repayments when it falls on a non-working is turned on /off by enable/disable reschedule-future-repayments parameter in Global configurations. -

-

- Allow transactions on non-working days is configurable by enabling/disbaling the allow-transactions-on-non_workingday parameter in Global configurations. -

- - - - - - - - - - - - - - - - - - - - - - - - - - - - -
Schedule for repayments on non-working day
Same day
The repayments schedule for same day regardless of it's a non-working day. -
Next workday
The repayments reschedule to next working day. e.g. if a repayment falls on a non-working day will be rescheduled to next available working day. -
Previous workday
The repayments reschedule to previous working day. e.g. if a repayment falls on a non-working day will be rescheduled to previous available working day. -
Next scheduled meeting
The repayments reschduled to next scheduled meeting. -
-
+   +
+
+

Working days

+

The days of the week that are workdays. +

+

+ Rescheduling of repayments when it falls on a non-working is turned on /off by enable/disable reschedule-future-repayments parameter in Global configurations. +

+

+ Allow transactions on non-working days is configurable by enabling/disbaling the allow-transactions-on-non_workingday parameter in Global configurations. +

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Schedule for repayments on non-working day
Same day
The repayments schedule for same day regardless of it's a non-working day. +
Next workday
The repayments reschedule to next working day. e.g. if a repayment falls on a non-working day will be rescheduled to next available working day. +
Previous workday
The repayments reschedule to previous working day. e.g. if a repayment falls on a non-working day will be rescheduled to previous available working day. +
Next scheduled meeting
The repayments reschduled to next scheduled meeting. +
+
From 244895e07d5570862956ad7ad28ef0f2e671a31e Mon Sep 17 00:00:00 2001 From: Vishwas Babu A J Date: Thu, 19 Sep 2013 09:00:54 +0530 Subject: [PATCH 6/8] minor fixes while prepping for 1.9.2 release --- .../organisation/office/api/OfficesApiResource.java | 9 ++++++--- .../office/service/OfficeReadPlatformService.java | 2 +- .../service/OfficeReadPlatformServiceImpl.java | 13 +++++++++---- ...ClientWritePlatformServiceJpaRepositoryImpl.java | 3 +++ 4 files changed, 19 insertions(+), 8 deletions(-) diff --git a/mifosng-provider/src/main/java/org/mifosplatform/organisation/office/api/OfficesApiResource.java b/mifosng-provider/src/main/java/org/mifosplatform/organisation/office/api/OfficesApiResource.java index 6e9c6c249..5d58616c3 100644 --- a/mifosng-provider/src/main/java/org/mifosplatform/organisation/office/api/OfficesApiResource.java +++ b/mifosng-provider/src/main/java/org/mifosplatform/organisation/office/api/OfficesApiResource.java @@ -11,12 +11,14 @@ import java.util.HashSet; import java.util.Set; import javax.ws.rs.Consumes; +import javax.ws.rs.DefaultValue; import javax.ws.rs.GET; import javax.ws.rs.POST; import javax.ws.rs.PUT; import javax.ws.rs.Path; import javax.ws.rs.PathParam; import javax.ws.rs.Produces; +import javax.ws.rs.QueryParam; import javax.ws.rs.core.Context; import javax.ws.rs.core.MediaType; import javax.ws.rs.core.UriInfo; @@ -53,7 +55,7 @@ public class OfficesApiResource { private final OfficeReadPlatformService readPlatformService; private final DefaultToApiJsonSerializer toApiJsonSerializer; private final ApiRequestParameterHelper apiRequestParameterHelper; - private final PortfolioCommandSourceWritePlatformService commandsSourceWritePlatformService; + private final PortfolioCommandSourceWritePlatformService commandsSourceWritePlatformService; @Autowired public OfficesApiResource(final PlatformSecurityContext context, final OfficeReadPlatformService readPlatformService, @@ -69,11 +71,12 @@ public class OfficesApiResource { @GET @Consumes({ MediaType.APPLICATION_JSON }) @Produces({ MediaType.APPLICATION_JSON }) - public String retrieveOffices(@Context final UriInfo uriInfo) { + public String retrieveOffices(@Context final UriInfo uriInfo, + @DefaultValue("false") @QueryParam("includeAllOffices") final boolean onlyManualEntries) { context.authenticatedUser().validateHasReadPermission(resourceNameForPermissions); - final Collection offices = this.readPlatformService.retrieveAllOffices(); + final Collection offices = this.readPlatformService.retrieveAllOffices(onlyManualEntries); final ApiRequestJsonSerializationSettings settings = apiRequestParameterHelper.process(uriInfo.getQueryParameters()); return this.toApiJsonSerializer.serialize(settings, offices, RESPONSE_DATA_PARAMETERS); diff --git a/mifosng-provider/src/main/java/org/mifosplatform/organisation/office/service/OfficeReadPlatformService.java b/mifosng-provider/src/main/java/org/mifosplatform/organisation/office/service/OfficeReadPlatformService.java index faa891020..c59b34f95 100644 --- a/mifosng-provider/src/main/java/org/mifosplatform/organisation/office/service/OfficeReadPlatformService.java +++ b/mifosng-provider/src/main/java/org/mifosplatform/organisation/office/service/OfficeReadPlatformService.java @@ -12,7 +12,7 @@ import org.mifosplatform.organisation.office.data.OfficeTransactionData; public interface OfficeReadPlatformService { - Collection retrieveAllOffices(); + Collection retrieveAllOffices(boolean includeAllOffices); Collection retrieveAllOfficesForDropdown(); diff --git a/mifosng-provider/src/main/java/org/mifosplatform/organisation/office/service/OfficeReadPlatformServiceImpl.java b/mifosng-provider/src/main/java/org/mifosplatform/organisation/office/service/OfficeReadPlatformServiceImpl.java index c0675c4e4..12820eec7 100644 --- a/mifosng-provider/src/main/java/org/mifosplatform/organisation/office/service/OfficeReadPlatformServiceImpl.java +++ b/mifosng-provider/src/main/java/org/mifosplatform/organisation/office/service/OfficeReadPlatformServiceImpl.java @@ -114,8 +114,8 @@ public class OfficeReadPlatformServiceImpl implements OfficeReadPlatformService Integer currencyDigits = JdbcSupport.getInteger(rs, "currencyDigits"); Integer inMultiplesOf = JdbcSupport.getInteger(rs, "inMultiplesOf"); - CurrencyData currencyData = new CurrencyData(currencyCode, currencyName, currencyDigits, inMultiplesOf, - currencyDisplaySymbol, currencyNameCode); + CurrencyData currencyData = new CurrencyData(currencyCode, currencyName, currencyDigits, inMultiplesOf, currencyDisplaySymbol, + currencyNameCode); BigDecimal transactionAmount = rs.getBigDecimal("transactionAmount"); String description = rs.getString("description"); @@ -126,12 +126,17 @@ public class OfficeReadPlatformServiceImpl implements OfficeReadPlatformService } @Override - public Collection retrieveAllOffices() { + public Collection retrieveAllOffices(boolean includeAllOffices) { AppUser currentUser = context.authenticatedUser(); String hierarchy = currentUser.getOffice().getHierarchy(); - String hierarchySearchString = hierarchy + "%"; + String hierarchySearchString = null; + if (includeAllOffices) { + hierarchySearchString = "." + "%"; + } else { + hierarchySearchString = hierarchy + "%"; + } OfficeMapper rm = new OfficeMapper(); String sql = "select " + rm.officeSchema() + "where o.hierarchy like ? order by o.hierarchy"; diff --git a/mifosng-provider/src/main/java/org/mifosplatform/portfolio/client/service/ClientWritePlatformServiceJpaRepositoryImpl.java b/mifosng-provider/src/main/java/org/mifosplatform/portfolio/client/service/ClientWritePlatformServiceJpaRepositoryImpl.java index 64adc6dc5..7da023864 100644 --- a/mifosng-provider/src/main/java/org/mifosplatform/portfolio/client/service/ClientWritePlatformServiceJpaRepositoryImpl.java +++ b/mifosng-provider/src/main/java/org/mifosplatform/portfolio/client/service/ClientWritePlatformServiceJpaRepositoryImpl.java @@ -344,6 +344,9 @@ public class ClientWritePlatformServiceJpaRepositoryImpl implements ClientWriteP if (ClientStatus.fromInt(client.getStatus()).isClosed()) { final String errorMessage = "Client is alread closed."; throw new InvalidClientStateTransitionException("close", "is.already.closed", errorMessage); + } else if (ClientStatus.fromInt(client.getStatus()).isUnderTransfer()) { + final String errorMessage = "Cannot Close a Client under Transfer"; + throw new InvalidClientStateTransitionException("close", "is.under.transfer", errorMessage); } if (client.isNotPending() && client.getActivationLocalDate().isAfter(closureDate)) { From 948da215f599662623c90a5aad145bee8e9cf79a Mon Sep 17 00:00:00 2001 From: Vishwas Babu A J Date: Thu, 19 Sep 2013 09:11:24 +0530 Subject: [PATCH 7/8] Update CHANGELOG.md for 1.9.2 release --- CHANGELOG.md | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 250a4d5ad..b38026433 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,6 +5,7 @@ See VERSIONING (https://github.com/openMF/mifosx/blob/master/VERSIONING.md) for Releases =============== +1. 18 Sep 2013 - 1.9.2.RELEASE 1. 10 Sep 2013 - 1.9.1.RELEASE 1. 8 Sep 2013 - 1.9.0.RELEASE 1. 21 Aug 2013 - 1.8.1.RELEASE @@ -35,6 +36,22 @@ Releases 1. 05 April 2013 - 0.11.1.beta 1. 05 April 2013 - 0.11.0.beta +1.9.2.RELEASE +============= +Bug Release + +Platform & API + +Bug + - [MIFOSX-659] - Not able to transfer Client between Branch offices which were created under same parent office. + - [MIFOSX-663] - No API documentation on Holidays or Working Days features + - [MIFOSX-671] - "Minimum opening balance" assigned is not displaying as balance in Transaction page after activation of savings account + - [MIFOSX-672] - Final installment of FLAT interest loans incorrectly has closing loan balance thats greater than zero. + +Improvement + - [MIFOSX-669] - Ability of Not allow to "close" client while trasfer of client is in progress + + 1.9.1.RELEASE ============= Bug Release From aaaba187b3da56f67e52d9f81f70818bc804ca44 Mon Sep 17 00:00:00 2001 From: Vishwas Babu A J Date: Thu, 19 Sep 2013 09:15:39 +0530 Subject: [PATCH 8/8] Update CHANGELOG.md fix typos --- CHANGELOG.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index b38026433..ac9b7c482 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -49,7 +49,7 @@ Bug - [MIFOSX-672] - Final installment of FLAT interest loans incorrectly has closing loan balance thats greater than zero. Improvement - - [MIFOSX-669] - Ability of Not allow to "close" client while trasfer of client is in progress + - [MIFOSX-669] - Ability to not allow to "close" a client while transfer of client is in progress 1.9.1.RELEASE