diff --git a/api-docs/apiLive.htm b/api-docs/apiLive.htm
index 428629fa5..ca7b712d0 100644
--- a/api-docs/apiLive.htm
+++ b/api-docs/apiLive.htm
@@ -14262,8 +14262,29 @@ Request Body:
{
"resourceId": 7
}
-
-
+
+
+POST charges
+Content-Type: application/json
+Request Body:
+{
+ "chargeAppliesTo": 2,
+ "name": "Weekly Fee",
+ "currencyCode": "USD",
+ "chargeTimeType": 11,
+ "chargeCalculationType": 1,
+ "feeInterval": "1",
+ "amount": "10",
+ "active": true,
+ "locale": "en"
+}
+
+
+{
+ "resourceId": 8
+}
+
+
@@ -24295,6 +24316,36 @@ Request Body:
"resourceIdentifier": "extra_client_details"
}
+
+POST https://DomainName/api/v1/datatables
+
+Content-Type: application/json
+Request Body:
+{
+ "datatableName": "client_address",
+ "apptableName": "m_client",
+ "multiRow":"true",
+ "columns": [
+ {
+ "name": "Address1",
+ "type": "String",
+ "length": 100,
+ "mandatory": true
+ },
+ {
+ "name": "Address2",
+ "length": 100,
+ "type": "String"
+ }
+ ]
+}
+
+
+{
+ "resourceIdentifier": "client_address"
+}
+
+
diff --git a/mifosng-provider/src/integrationTest/java/org/mifosplatform/integrationtests/ClientSavingsIntegrationTest.java b/mifosng-provider/src/integrationTest/java/org/mifosplatform/integrationtests/ClientSavingsIntegrationTest.java
index 8878e607e..02827481c 100755
--- a/mifosng-provider/src/integrationTest/java/org/mifosplatform/integrationtests/ClientSavingsIntegrationTest.java
+++ b/mifosng-provider/src/integrationTest/java/org/mifosplatform/integrationtests/ClientSavingsIntegrationTest.java
@@ -9,6 +9,7 @@ import java.util.Calendar;
import java.util.HashMap;
import java.util.List;
+import org.joda.time.LocalDate;
import org.junit.Assert;
import org.junit.Before;
import org.junit.Test;
@@ -399,6 +400,35 @@ public class ClientSavingsIntegrationTest {
BigDecimal totalWaiveAmount = BigDecimal.valueOf(Double.valueOf((Float) savingsChargeForWaive.get("amount")));
totalWaiveAmount = totalWaiveAmount.add(totalWaiveAmount);
assertEquals(totalWaiveAmount.floatValue(), waiveCharge.get("amountWaived"));
+
+ final Integer weeklyFeeId = ChargesHelper.createCharges(this.requestSpec, this.responseSpec, ChargesHelper.getSavingsWeeklyFeeJSON());
+ Assert.assertNotNull(weeklyFeeId);
+
+ this.savingsAccountHelper.addChargesForSavings(savingsId, weeklyFeeId);
+ charges = this.savingsAccountHelper.getSavingsCharges(savingsId);
+ Assert.assertEquals(3, charges.size());
+
+ savingsChargeForPay = charges.get(2);
+ cal = Calendar.getInstance();
+ dates = (List) savingsChargeForPay.get("dueDate");
+ cal.set(Calendar.YEAR, (Integer) dates.get(0));
+ cal.set(Calendar.MONTH, (Integer) dates.get(1) - 1);
+ cal.set(Calendar.DAY_OF_MONTH, (Integer) dates.get(2));
+
+ // Depositing huge amount as scheduler job deducts the fee amount
+ Integer depositTransactionId = (Integer) this.savingsAccountHelper.depositToSavingsAccount(savingsId, "100000",
+ SavingsAccountHelper.TRANSACTION_DATE, CommonConstants.RESPONSE_RESOURCE_ID);
+ Assert.assertNotNull(depositTransactionId);
+
+ this.savingsAccountHelper.payCharge((Integer) savingsChargeForPay.get("id"), savingsId,
+ ((Float) savingsChargeForPay.get("amount")).toString(), sdf.format(cal.getTime()));
+ paidCharge = this.savingsAccountHelper.getSavingsCharge(savingsId, (Integer) savingsChargeForPay.get("id"));
+ assertEquals(savingsChargeForPay.get("amount"), paidCharge.get("amountPaid"));
+ List nextDueDates = (List) paidCharge.get("dueDate");
+ LocalDate nextDueDate = new LocalDate((Integer) nextDueDates.get(0), (Integer) nextDueDates.get(1), (Integer) nextDueDates.get(2));
+ LocalDate expectedNextDueDate = new LocalDate((Integer) dates.get(0), (Integer) dates.get(1), (Integer) dates.get(2))
+ .plusWeeks((Integer) paidCharge.get("feeInterval"));
+ assertEquals(expectedNextDueDate, nextDueDate);
}
private Integer createSavingsProduct(final RequestSpecification requestSpec, final ResponseSpecification responseSpec,
diff --git a/mifosng-provider/src/integrationTest/java/org/mifosplatform/integrationtests/GroupSavingsIntegrationTest.java b/mifosng-provider/src/integrationTest/java/org/mifosplatform/integrationtests/GroupSavingsIntegrationTest.java
index 2f7fe66f2..af1db0bb5 100644
--- a/mifosng-provider/src/integrationTest/java/org/mifosplatform/integrationtests/GroupSavingsIntegrationTest.java
+++ b/mifosng-provider/src/integrationTest/java/org/mifosplatform/integrationtests/GroupSavingsIntegrationTest.java
@@ -9,6 +9,7 @@ import java.util.Calendar;
import java.util.HashMap;
import java.util.List;
+import org.joda.time.LocalDate;
import org.junit.Assert;
import org.junit.Before;
import org.junit.Test;
@@ -438,6 +439,35 @@ public class GroupSavingsIntegrationTest {
BigDecimal totalWaiveAmount = BigDecimal.valueOf(Double.valueOf((Float) savingsChargeForWaive.get("amount")));
totalWaiveAmount = totalWaiveAmount.add(totalWaiveAmount);
assertEquals(totalWaiveAmount.floatValue(), waiveCharge.get("amountWaived"));
+
+ final Integer weeklyFeeId = ChargesHelper.createCharges(this.requestSpec, this.responseSpec, ChargesHelper.getSavingsWeeklyFeeJSON());
+ Assert.assertNotNull(weeklyFeeId);
+
+ this.savingsAccountHelper.addChargesForSavings(savingsId, weeklyFeeId);
+ charges = this.savingsAccountHelper.getSavingsCharges(savingsId);
+ Assert.assertEquals(3, charges.size());
+
+ savingsChargeForPay = charges.get(2);
+ cal = Calendar.getInstance();
+ dates = (List) savingsChargeForPay.get("dueDate");
+ cal.set(Calendar.YEAR, (Integer) dates.get(0));
+ cal.set(Calendar.MONTH, (Integer) dates.get(1) - 1);
+ cal.set(Calendar.DAY_OF_MONTH, (Integer) dates.get(2));
+
+ // Depositing huge amount as scheduler job deducts the fee amount
+ Integer depositTransactionId = (Integer) this.savingsAccountHelper.depositToSavingsAccount(savingsId, "100000",
+ SavingsAccountHelper.TRANSACTION_DATE, CommonConstants.RESPONSE_RESOURCE_ID);
+ Assert.assertNotNull(depositTransactionId);
+
+ this.savingsAccountHelper.payCharge((Integer) savingsChargeForPay.get("id"), savingsId,
+ ((Float) savingsChargeForPay.get("amount")).toString(), sdf.format(cal.getTime()));
+ paidCharge = this.savingsAccountHelper.getSavingsCharge(savingsId, (Integer) savingsChargeForPay.get("id"));
+ assertEquals(savingsChargeForPay.get("amount"), paidCharge.get("amountPaid"));
+ List nextDueDates = (List) paidCharge.get("dueDate");
+ LocalDate nextDueDate = new LocalDate((Integer) nextDueDates.get(0), (Integer) nextDueDates.get(1), (Integer) nextDueDates.get(2));
+ LocalDate expectedNextDueDate = new LocalDate((Integer) dates.get(0), (Integer) dates.get(1), (Integer) dates.get(2))
+ .plusWeeks((Integer) paidCharge.get("feeInterval"));
+ assertEquals(expectedNextDueDate, nextDueDate);
}
public static Integer createSavingsProduct(final RequestSpecification requestSpec, final ResponseSpecification responseSpec,
diff --git a/mifosng-provider/src/integrationTest/java/org/mifosplatform/integrationtests/common/charges/ChargesHelper.java b/mifosng-provider/src/integrationTest/java/org/mifosplatform/integrationtests/common/charges/ChargesHelper.java
index 36be16947..912e4f47d 100755
--- a/mifosng-provider/src/integrationTest/java/org/mifosplatform/integrationtests/common/charges/ChargesHelper.java
+++ b/mifosng-provider/src/integrationTest/java/org/mifosplatform/integrationtests/common/charges/ChargesHelper.java
@@ -28,6 +28,7 @@ public class ChargesHelper {
private static final Integer CHARGE_INSTALLMENT_FEE = 8;
private static final Integer CHARGE_OVERDUE_INSTALLMENT_FEE = 9;
private static final Integer CHARGE_OVERDRAFT_FEE = 10;
+ private static final Integer WEEKLY_FEE = 11;
public static final Integer CHARGE_CALCULATION_TYPE_FLAT = 1;
public static final Integer CHARGE_CALCULATION_TYPE_PERCENTAGE_AMOUNT = 2;
@@ -92,6 +93,15 @@ public class ChargesHelper {
System.out.println(chargesCreateJson);
return chargesCreateJson;
}
+
+ public static String getSavingsWeeklyFeeJSON() {
+ final HashMap map = populateDefaultsForSavings();
+ map.put("chargeTimeType", WEEKLY_FEE);
+ map.put("feeInterval", 1);
+ String chargesCreateJson = new Gson().toJson(map);
+ System.out.println(chargesCreateJson);
+ return chargesCreateJson;
+ }
public static String getSavingsOverdraftFeeJSON() {
final HashMap map = populateDefaultsForSavings();
diff --git a/mifosng-provider/src/main/java/org/mifosplatform/accounting/glaccount/domain/GLAccountType.java b/mifosng-provider/src/main/java/org/mifosplatform/accounting/glaccount/domain/GLAccountType.java
index 62e13fc6c..840dc41a5 100755
--- a/mifosng-provider/src/main/java/org/mifosplatform/accounting/glaccount/domain/GLAccountType.java
+++ b/mifosng-provider/src/main/java/org/mifosplatform/accounting/glaccount/domain/GLAccountType.java
@@ -10,7 +10,7 @@ import java.util.Map;
public enum GLAccountType {
ASSET(1, "accountType.asset"), LIABILITY(2, "accountType.liability"), EQUITY(3, "accountType.equity"), INCOME(4, "accountType.income"), EXPENSE(
- 5, "accountType.expense"), ;
+ 5, "accountType.expense");
private final Integer value;
private final String code;
diff --git a/mifosng-provider/src/main/java/org/mifosplatform/portfolio/loanaccount/service/LoanWritePlatformServiceJpaRepositoryImpl.java b/mifosng-provider/src/main/java/org/mifosplatform/portfolio/loanaccount/service/LoanWritePlatformServiceJpaRepositoryImpl.java
index 535bca1b1..f0201fffb 100755
--- a/mifosng-provider/src/main/java/org/mifosplatform/portfolio/loanaccount/service/LoanWritePlatformServiceJpaRepositoryImpl.java
+++ b/mifosng-provider/src/main/java/org/mifosplatform/portfolio/loanaccount/service/LoanWritePlatformServiceJpaRepositoryImpl.java
@@ -1662,7 +1662,7 @@ public class LoanWritePlatformServiceJpaRepositoryImpl implements LoanWritePlatf
// Update client loan counter if loan product includeInBorrowerCycle
// is true
if (loanToUpdate.loanProduct().isIncludeInBorrowerCycle()) {
- Integer currentLoanCounter = loanToUpdate.getCurrentLoanCounter();
+ Integer currentLoanCounter = loanToUpdate.getCurrentLoanCounter() == null ? 1 : loanToUpdate.getCurrentLoanCounter();
if (newLoanCounter > currentLoanCounter) {
newLoanCounter = currentLoanCounter;
}
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 00d4eb7d3..493c30ec3 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
@@ -1872,7 +1872,7 @@ public class SavingsAccount extends AbstractPersistable {
}
- if (savingsAccountCharge.isAnnualFee() || savingsAccountCharge.isMonthlyFee()) {
+ if (savingsAccountCharge.isAnnualFee() || savingsAccountCharge.isMonthlyFee() || savingsAccountCharge.isWeeklyFee()) {
// update due date
if (isActive()) {
savingsAccountCharge.updateToNextDueDateFrom(getActivationLocalDate());
diff --git a/mifosng-provider/src/main/java/org/mifosplatform/portfolio/savings/domain/SavingsAccountCharge.java b/mifosng-provider/src/main/java/org/mifosplatform/portfolio/savings/domain/SavingsAccountCharge.java
index a279956ae..021a7e476 100644
--- a/mifosng-provider/src/main/java/org/mifosplatform/portfolio/savings/domain/SavingsAccountCharge.java
+++ b/mifosng-provider/src/main/java/org/mifosplatform/portfolio/savings/domain/SavingsAccountCharge.java
@@ -155,14 +155,6 @@ public class SavingsAccountCharge extends AbstractPersistable {
}
- if (isWeeklyFee()) {
- if (dueDate == null) {
- final String defaultUserMessage = "Savings Account charge is missing due date.";
- throw new SavingsAccountChargeWithoutMandatoryFieldException("savingsaccount.charge", dueAsOfDateParamName,
- defaultUserMessage, chargeDefinition.getId(), chargeDefinition.getName());
- }
- }
-
if (isAnnualFee() || isMonthlyFee()) {
feeOnMonthDay = (feeOnMonthDay == null) ? chargeDefinition.getFeeOnMonthDay() : feeOnMonthDay;
if (feeOnMonthDay == null) {
@@ -174,6 +166,17 @@ public class SavingsAccountCharge extends AbstractPersistable {
this.feeOnMonth = feeOnMonthDay.getMonthOfYear();
this.feeOnDay = feeOnMonthDay.getDayOfMonth();
+ } else if (isWeeklyFee()) {
+ if (dueDate == null) {
+ final String defaultUserMessage = "Savings Account charge is missing due date.";
+ throw new SavingsAccountChargeWithoutMandatoryFieldException("savingsaccount.charge", dueAsOfDateParamName,
+ defaultUserMessage, chargeDefinition.getId(), chargeDefinition.getName());
+ }
+ /**
+ * For Weekly fee feeOnDay is ISO standard day of the week.
+ * Monday=1, Tuesday=2
+ */
+ this.feeOnDay = dueDate.getDayOfWeek();
} else {
this.feeOnDay = null;
this.feeOnMonth = null;
@@ -355,6 +358,9 @@ public class SavingsAccountCharge extends AbstractPersistable {
final BigDecimal transactionAmount = BigDecimal.ZERO;
if (dueDate != null) {
this.dueDate = dueDate.toDate();
+ if (isWeeklyFee()) {
+ this.feeOnDay = dueDate.getDayOfWeek();
+ }
}
if (feeOnMonthDay != null) {
@@ -410,6 +416,9 @@ public class SavingsAccountCharge extends AbstractPersistable {
final LocalDate newValue = command.localDateValueOfParameterNamed(dueAsOfDateParamName);
this.dueDate = newValue.toDate();
+ if (this.isWeeklyFee()) {
+ this.feeOnDay = newValue.getDayOfWeek();
+ }
}
if (command.hasParameter(feeOnMonthDayParamName)) {
@@ -696,6 +705,11 @@ public class SavingsAccountCharge extends AbstractPersistable {
while (startingDate.isAfter(nextDueLocalDate)) {
nextDueLocalDate = calculateNextDueDate(nextDueLocalDate);
}
+ } else if (isWeeklyFee()) {
+ nextDueLocalDate = getDueLocalDate();
+ while (startingDate.isAfter(nextDueLocalDate)) {
+ nextDueLocalDate = calculateNextDueDate(nextDueLocalDate);
+ }
} else {
nextDueLocalDate = calculateNextDueDate(startingDate);
}
@@ -714,7 +728,8 @@ public class SavingsAccountCharge extends AbstractPersistable {
nextDueLocalDate = date.plusMonths(this.feeInterval);
nextDueLocalDate = setDayOfMonth(nextDueLocalDate);
} else if (isWeeklyFee()) {
- nextDueLocalDate = date.plusDays(7 * this.feeInterval);
+ nextDueLocalDate = date.plusWeeks(this.feeInterval);
+ nextDueLocalDate = setDayOfWeek(nextDueLocalDate);
}
return nextDueLocalDate;
}
@@ -726,6 +741,13 @@ public class SavingsAccountCharge extends AbstractPersistable {
return nextDueLocalDate;
}
+ private LocalDate setDayOfWeek(LocalDate nextDueLocalDate) {
+ if (this.feeOnDay != nextDueLocalDate.getDayOfWeek()) {
+ nextDueLocalDate = nextDueLocalDate.withDayOfWeek(this.feeOnDay);
+ }
+ return nextDueLocalDate;
+ }
+
public void updateNextDueDateForRecurringFees() {
if (isAnnualFee() || isMonthlyFee() || isWeeklyFee()) {
LocalDate nextDueLocalDate = new LocalDate(dueDate);