MIFOS-2144 TemplateMergeService expandMapArrays + @Test arrayUsingIndex
TemplateMergeService clean up, incl. proper logging TemplateMergeServiceTest fixed up, incl. fix compileLoanSummary() now() TemplateMergeServiceTest arrayUsingLoop TemplateMergeServiceTest simplified Gradle License check exclude **/*.html for src/test/resources/template-expected.html
This commit is contained in:
@@ -125,7 +125,7 @@ war {
|
||||
|
||||
license {
|
||||
header rootProject.file('../LICENSE.md')
|
||||
excludes(["**/*.mustache", "**/*.sql", "**/package-info.java", "**/keystore.jks"])
|
||||
excludes(["**/*.html", "**/*.mustache", "**/*.sql", "**/package-info.java", "**/keystore.jks"])
|
||||
strictCheck true
|
||||
}
|
||||
|
||||
|
||||
@@ -60,7 +60,6 @@ public class Template extends AbstractPersistable<Long> {
|
||||
}
|
||||
|
||||
protected Template() {
|
||||
//
|
||||
}
|
||||
|
||||
public static Template fromJson(final JsonCommand command) {
|
||||
|
||||
+35
-22
@@ -21,10 +21,13 @@ import java.security.KeyStoreException;
|
||||
import java.security.NoSuchAlgorithmException;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import java.util.Map.Entry;
|
||||
|
||||
import org.codehaus.jackson.map.ObjectMapper;
|
||||
import org.mifosplatform.template.domain.Template;
|
||||
import org.mifosplatform.template.domain.TemplateFunctions;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.springframework.security.core.context.SecurityContextHolder;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
@@ -34,6 +37,7 @@ import com.github.mustachejava.MustacheFactory;
|
||||
|
||||
@Service
|
||||
public class TemplateMergeService {
|
||||
private final static Logger logger = LoggerFactory.getLogger(TemplateMergeService.class);
|
||||
|
||||
// private final FromJsonHelper fromApiJsonHelper;
|
||||
private Map<String, Object> scopes;
|
||||
@@ -49,7 +53,6 @@ public class TemplateMergeService {
|
||||
}
|
||||
|
||||
public String compile(final Template template, final Map<String, Object> scopes) throws MalformedURLException, IOException {
|
||||
|
||||
this.scopes = scopes;
|
||||
this.scopes.put("static", new TemplateFunctions());
|
||||
|
||||
@@ -59,19 +62,19 @@ public class TemplateMergeService {
|
||||
final Map<String, Object> mappers = getCompiledMapFromMappers(template.getMappersAsMap());
|
||||
this.scopes.putAll(mappers);
|
||||
|
||||
expandMapArrays(scopes);
|
||||
|
||||
final StringWriter stringWriter = new StringWriter();
|
||||
mustache.execute(stringWriter, this.scopes);
|
||||
|
||||
return stringWriter.toString();
|
||||
}
|
||||
|
||||
private Map<String, Object> getCompiledMapFromMappers(final Map<String, String> data) {
|
||||
|
||||
private Map<String, Object> getCompiledMapFromMappers(final Map<String, String> data) {
|
||||
final MustacheFactory mf = new DefaultMustacheFactory();
|
||||
|
||||
if (data != null) {
|
||||
for (final Map.Entry<String, String> entry : data.entrySet()) {
|
||||
|
||||
final Mustache mappersMustache = mf.compile(new StringReader(entry.getValue()), "");
|
||||
final StringWriter stringWriter = new StringWriter();
|
||||
|
||||
@@ -82,10 +85,8 @@ public class TemplateMergeService {
|
||||
}
|
||||
try {
|
||||
this.scopes.put(entry.getKey(), getMapFromUrl(url));
|
||||
} catch (final MalformedURLException e) {
|
||||
e.printStackTrace();
|
||||
} catch (final IOException e) {
|
||||
e.printStackTrace();
|
||||
logger.error("getCompiledMapFromMappers() failed", e);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -94,7 +95,6 @@ public class TemplateMergeService {
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
private Map<String, Object> getMapFromUrl(final String url) throws MalformedURLException, IOException {
|
||||
|
||||
final HttpURLConnection connection = getConnection(url);
|
||||
|
||||
final String response = getStringFromInputStream(connection.getInputStream());
|
||||
@@ -108,13 +108,11 @@ public class TemplateMergeService {
|
||||
}
|
||||
|
||||
private HttpURLConnection getConnection(final String url) {
|
||||
|
||||
if (this.authToken == null) {
|
||||
final String name = SecurityContextHolder.getContext().getAuthentication().getName();
|
||||
final String password = SecurityContextHolder.getContext().getAuthentication().getCredentials().toString();
|
||||
|
||||
Authenticator.setDefault(new Authenticator() {
|
||||
|
||||
@Override
|
||||
protected PasswordAuthentication getPasswordAuthentication() {
|
||||
return new PasswordAuthentication(name, password.toCharArray());
|
||||
@@ -132,23 +130,15 @@ public class TemplateMergeService {
|
||||
|
||||
connection.setDoInput(true);
|
||||
|
||||
} catch (final MalformedURLException e) {
|
||||
e.printStackTrace();
|
||||
} catch (final IOException e) {
|
||||
e.printStackTrace();
|
||||
} catch (final KeyManagementException e) {
|
||||
e.printStackTrace();
|
||||
} catch (final NoSuchAlgorithmException e) {
|
||||
e.printStackTrace();
|
||||
} catch (final KeyStoreException e) {
|
||||
e.printStackTrace();
|
||||
} catch (IOException | KeyManagementException | NoSuchAlgorithmException | KeyStoreException e) {
|
||||
logger.error("getConnection() failed, return null", e);
|
||||
}
|
||||
|
||||
return connection;
|
||||
}
|
||||
|
||||
// TODO Replace this with appropriate alternative available in Guava
|
||||
private static String getStringFromInputStream(final InputStream is) {
|
||||
|
||||
BufferedReader br = null;
|
||||
final StringBuilder sb = new StringBuilder();
|
||||
|
||||
@@ -161,7 +151,7 @@ public class TemplateMergeService {
|
||||
}
|
||||
|
||||
} catch (final IOException e) {
|
||||
// FIXME - HANDLE THIS CASE
|
||||
logger.error("getStringFromInputStream() failed", e);
|
||||
} finally {
|
||||
if (br != null) {
|
||||
try {
|
||||
@@ -174,4 +164,27 @@ public class TemplateMergeService {
|
||||
|
||||
return sb.toString();
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
private void expandMapArrays(Object value) {
|
||||
if (value instanceof Map) {
|
||||
Map<String, Object> valueAsMap = (Map<String, Object>) value;
|
||||
for (Entry<String, Object> valueAsMapEntry : valueAsMap.entrySet()) {
|
||||
Object valueAsMapEntryValue = valueAsMapEntry.getValue();
|
||||
if (valueAsMapEntryValue instanceof Map) { // JSON Object
|
||||
expandMapArrays(valueAsMapEntryValue);
|
||||
} else if (valueAsMapEntryValue instanceof Iterable) { // JSON Array
|
||||
Iterable<Object> valueAsMapEntryValueIterable = (Iterable<Object>) valueAsMapEntryValue;
|
||||
String valueAsMapEntryKey = valueAsMapEntry.getKey();
|
||||
int i = 0;
|
||||
for (Object object : valueAsMapEntryValueIterable) {
|
||||
valueAsMap.put(valueAsMapEntryKey + "#" + i, object);
|
||||
++i;
|
||||
expandMapArrays(object);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
+66
-43
@@ -7,78 +7,101 @@ package org.mifosplatform.template;
|
||||
|
||||
import static org.junit.Assert.assertEquals;
|
||||
|
||||
import java.io.DataInputStream;
|
||||
import java.io.File;
|
||||
import java.io.FileInputStream;
|
||||
import java.io.IOException;
|
||||
import java.lang.reflect.Type;
|
||||
import java.net.MalformedURLException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import org.joda.time.LocalDate;
|
||||
import org.junit.BeforeClass;
|
||||
import org.junit.Ignore;
|
||||
import org.junit.Test;
|
||||
import org.mifosplatform.organisation.monetary.domain.MonetaryCurrency;
|
||||
import org.mifosplatform.portfolio.loanaccount.LoanScheduleTestDataHelper;
|
||||
import org.mifosplatform.portfolio.loanaccount.MonetaryCurrencyBuilder;
|
||||
import org.mifosplatform.portfolio.loanaccount.domain.LoanRepaymentScheduleInstallment;
|
||||
import org.mifosplatform.template.domain.Template;
|
||||
import org.mifosplatform.template.domain.TemplateMapper;
|
||||
import org.mifosplatform.template.service.TemplateMergeService;
|
||||
|
||||
import com.google.common.base.Charsets;
|
||||
import com.google.common.io.Resources;
|
||||
import com.google.common.reflect.TypeToken;
|
||||
import com.google.gson.Gson;
|
||||
import com.google.gson.JsonElement;
|
||||
import com.google.gson.JsonParser;
|
||||
|
||||
public class TemplateMergeServiceTest {
|
||||
|
||||
private Template template;
|
||||
private final static String TEST_FILE = "src/test/resources/template.mustache";
|
||||
private static TemplateMergeService tms;
|
||||
private TemplateMergeService tms = new TemplateMergeService();
|
||||
|
||||
@BeforeClass
|
||||
public static void init() {
|
||||
tms = new TemplateMergeService(
|
||||
// new FromJsonHelper()
|
||||
);
|
||||
}
|
||||
|
||||
@Ignore
|
||||
@Test
|
||||
public void compileHelloTemplate() throws Exception {
|
||||
final String name = "TemplateName";
|
||||
final String text = "Hello Test for Template {{template.name}}!";
|
||||
String templateText = "Hello Test for Template {{file.name}}!";
|
||||
|
||||
this.template = new Template(name, text, null, null, null);
|
||||
File file = new File("hello");
|
||||
Map<String, Object> scopes = new HashMap<>();
|
||||
scopes.put("file", file);
|
||||
|
||||
final HashMap<String, Object> scopes = new HashMap<>();
|
||||
scopes.put("template", this.template);
|
||||
|
||||
String output = "";
|
||||
output = tms.compile(this.template, scopes);
|
||||
assertEquals("Hello Test for Template TemplateName!", output);
|
||||
String output = compileTemplateText(templateText, scopes);
|
||||
assertEquals("Hello Test for Template hello!", output);
|
||||
}
|
||||
|
||||
@Ignore
|
||||
@Test
|
||||
public void compileLoanSummary() throws IOException {
|
||||
LocalDate july2nd = new LocalDate(2012, 7, 2);
|
||||
MonetaryCurrency usDollars = new MonetaryCurrencyBuilder().withCode("USD").withDigitsAfterDecimal(2).build();
|
||||
List<LoanRepaymentScheduleInstallment> installments = LoanScheduleTestDataHelper.createSimpleLoanSchedule(july2nd, usDollars);
|
||||
|
||||
final LocalDate july2nd = new LocalDate(2012, 7, 2);
|
||||
final MonetaryCurrency usDollars = new MonetaryCurrencyBuilder().withCode("USD").withDigitsAfterDecimal(2).build();
|
||||
final List<LoanRepaymentScheduleInstallment> installments = LoanScheduleTestDataHelper.createSimpleLoanSchedule(july2nd, usDollars);
|
||||
|
||||
final File file = new File(TEST_FILE);
|
||||
final DataInputStream dis = new DataInputStream(new FileInputStream(file));
|
||||
final byte[] bytes = new byte[(int) file.length()];
|
||||
dis.readFully(bytes);
|
||||
final String content = new String(bytes, "UTF-8");
|
||||
|
||||
this.template = new Template("TemplateName", content, null, null, null);
|
||||
|
||||
final HashMap<String, Object> scopes = new HashMap<>();
|
||||
Map<String, Object> scopes = new HashMap<>();
|
||||
scopes.put("installments", installments);
|
||||
|
||||
final String output = tms.compile(this.template, scopes);
|
||||
String templateText = Resources.toString(Resources.getResource("template.mustache"), Charsets.UTF_8);
|
||||
String expectedOutput = Resources.toString(Resources.getResource("template-expected.html"), Charsets.UTF_8);
|
||||
|
||||
dis.close();
|
||||
|
||||
System.out.println(output);
|
||||
dis.close();
|
||||
String output = compileTemplateText(templateText, scopes);
|
||||
// System.out.println(output);
|
||||
assertEquals(expectedOutput, output);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void arrayUsingLoop() throws Exception {
|
||||
String templateText = "Hello Test for Template{{#data.name}} {{.}}{{/data.name}}!";
|
||||
String jsonData = "{\"name\": [ \"Michael\", \"Terence\" ] }";
|
||||
String expectedOutput = "Hello Test for Template Michael Terence!";
|
||||
|
||||
Map<String, Object> scopes = new HashMap<>();
|
||||
scopes.put("data", createMapFromJSON(jsonData));
|
||||
|
||||
String output = compileTemplateText(templateText, scopes);
|
||||
assertEquals(expectedOutput, output);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void arrayUsingIndex() throws Exception {
|
||||
String templateText = "Hello Test for Template {{data.name#1}} & {{data.name#0}}!";
|
||||
String jsonData = "{\"name\": [ \"Michael\", \"Terence\" ] }";
|
||||
String expectedOutput = "Hello Test for Template Terence & Michael!";
|
||||
|
||||
Map<String, Object> scopes = new HashMap<>();
|
||||
scopes.put("data", createMapFromJSON(jsonData));
|
||||
|
||||
String output = compileTemplateText(templateText, scopes);
|
||||
assertEquals(expectedOutput, output);
|
||||
}
|
||||
|
||||
protected String compileTemplateText(String templateText, Map<String, Object> scope) throws MalformedURLException, IOException {
|
||||
List<TemplateMapper> mappers = new ArrayList<>();
|
||||
Template template = new Template("TemplateName", templateText, null, null, mappers);
|
||||
return tms.compile(template, scope);
|
||||
}
|
||||
|
||||
protected Map<String, Object> createMapFromJSON(String jsonText) {
|
||||
Gson gson = new Gson();
|
||||
Type ssMap = new TypeToken<Map<String, Object>>(){}.getType();
|
||||
JsonElement json = new JsonParser().parse(jsonText);
|
||||
return gson.fromJson(json, ssMap);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,152 @@
|
||||
<h1><span style="font-size:20px"><strong><span style="color:#0000CD">Sample Loan Summary & Repayment Schedule </span></strong></span></h1>
|
||||
|
||||
<h2><span style="font-size:16px"><span style="color:#0000CD">TABLE 1. LOAN SUMMARY</span> </span></h2>
|
||||
|
||||
<table align="left" border="1" cellpadding="3" cellspacing="0" style="width:650px">
|
||||
<tbody>
|
||||
<tr>
|
||||
<td>Loan size and currency</td>
|
||||
<td> </td>
|
||||
<td>Total no. of installments </td>
|
||||
<td> </td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Interest rate </td>
|
||||
<td> </td>
|
||||
<td>Installment frequency</td>
|
||||
<td> </td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Commission fee</td>
|
||||
<td> </td>
|
||||
<td>Disbursement date </td>
|
||||
<td> </td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Other fees</td>
|
||||
<td> </td>
|
||||
<td>Mandatory savings</td>
|
||||
<td> </td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Purpose of loan</td>
|
||||
<td> </td>
|
||||
<td>Maturity date </td>
|
||||
<td> </td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Grace period (if applies)</td>
|
||||
<td> </td>
|
||||
<td>Type of guarantee</td>
|
||||
<td> </td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Penalty for late payment</td>
|
||||
<td> </td>
|
||||
<td>Maturity of the loan (in months) </td>
|
||||
<td> </td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Penalty for pre-payment</td>
|
||||
<td> </td>
|
||||
<td>Total cost of loan (principle + int.+ fees) </td>
|
||||
<td> </td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
|
||||
<p> </p>
|
||||
|
||||
<p> </p>
|
||||
|
||||
<p> </p>
|
||||
|
||||
<p> </p>
|
||||
|
||||
<p> </p>
|
||||
|
||||
<p> </p>
|
||||
|
||||
<p> </p>
|
||||
|
||||
<p> </p>
|
||||
|
||||
<h2><span style="font-size:16px"><span style="color:#0000CD">TABLE 2. REPAYMENT SCHEDULE </span></span></h2>
|
||||
|
||||
<table border="1" cellpadding="3" cellspacing="0" style="width:600px">
|
||||
<tbody>
|
||||
<tr>
|
||||
<td>Date</td>
|
||||
<td>Disbursement Amount</td>
|
||||
<td>
|
||||
<p>Principle Repayment</p>
|
||||
</td>
|
||||
<td> Interest Repayment</td>
|
||||
<td>Commission Payment</td>
|
||||
<td>Fees</td>
|
||||
<td>Tax Payment</td>
|
||||
<td>Total Repayment</td>
|
||||
<td>Total Balance Outstanding</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>2012-07-02</td>
|
||||
<td>1</td>
|
||||
<td>NO fromDate AS IT CHANGES</td>
|
||||
<td></td>
|
||||
<td> </td>
|
||||
<td></td>
|
||||
<td> </td>
|
||||
<td> </td>
|
||||
<td> </td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>2012-08-02</td>
|
||||
<td>2</td>
|
||||
<td>NO fromDate AS IT CHANGES</td>
|
||||
<td></td>
|
||||
<td> </td>
|
||||
<td></td>
|
||||
<td> </td>
|
||||
<td> </td>
|
||||
<td> </td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>2012-09-02</td>
|
||||
<td>3</td>
|
||||
<td>NO fromDate AS IT CHANGES</td>
|
||||
<td></td>
|
||||
<td> </td>
|
||||
<td></td>
|
||||
<td> </td>
|
||||
<td> </td>
|
||||
<td> </td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Total</td>
|
||||
<td> </td>
|
||||
<td> </td>
|
||||
<td> </td>
|
||||
<td> </td>
|
||||
<td> </td>
|
||||
<td> </td>
|
||||
<td> </td>
|
||||
<td> </td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
|
||||
<p> </p>
|
||||
|
||||
<p>Client Signature ___________________________________________________________________ </p>
|
||||
|
||||
<p>Credit Officer Signature _____________________________________________________________ </p>
|
||||
|
||||
<p>Branch Director Signature ___________________________________________________________ </p>
|
||||
|
||||
<p> </p>
|
||||
|
||||
<p> </p>
|
||||
|
||||
<p><span style="font-size:12px"><strong>Please contact the<span style="color:#FF0000"> Macro</span><span style="color:#0000CD">Dreams</span> Customer Service Line if you have questions or complaints about our products, </strong></span></p>
|
||||
|
||||
<p><span style="font-size:12px"><strong>services, or staff: 555-555-5555. Open Monday to Saturday 7:00-20:00. All calls are free. </strong></span></p>
|
||||
@@ -3,56 +3,56 @@
|
||||
<h2><span style="font-size:16px"><span style="color:#0000CD">TABLE 1. LOAN SUMMARY</span> </span></h2>
|
||||
|
||||
<table align="left" border="1" cellpadding="3" cellspacing="0" style="width:650px">
|
||||
<tbody>
|
||||
<tr>
|
||||
<td>Loan size and currency</td>
|
||||
<td> </td>
|
||||
<td>Total no. of installments </td>
|
||||
<td> </td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Interest rate </td>
|
||||
<td> </td>
|
||||
<td>Installment frequency</td>
|
||||
<td> </td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Commission fee</td>
|
||||
<td> </td>
|
||||
<td>Disbursement date </td>
|
||||
<td> </td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Other fees</td>
|
||||
<td> </td>
|
||||
<td>Mandatory savings</td>
|
||||
<td> </td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Purpose of loan</td>
|
||||
<td> </td>
|
||||
<td>Maturity date </td>
|
||||
<td> </td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Grace period (if applies)</td>
|
||||
<td> </td>
|
||||
<td>Type of guarantee</td>
|
||||
<td> </td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Penalty for late payment</td>
|
||||
<td> </td>
|
||||
<td>Maturity of the loan (in months) </td>
|
||||
<td> </td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Penalty for pre-payment</td>
|
||||
<td> </td>
|
||||
<td>Total cost of loan (principle + int.+ fees) </td>
|
||||
<td> </td>
|
||||
</tr>
|
||||
</tbody>
|
||||
<tbody>
|
||||
<tr>
|
||||
<td>Loan size and currency</td>
|
||||
<td> </td>
|
||||
<td>Total no. of installments </td>
|
||||
<td> </td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Interest rate </td>
|
||||
<td> </td>
|
||||
<td>Installment frequency</td>
|
||||
<td> </td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Commission fee</td>
|
||||
<td> </td>
|
||||
<td>Disbursement date </td>
|
||||
<td> </td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Other fees</td>
|
||||
<td> </td>
|
||||
<td>Mandatory savings</td>
|
||||
<td> </td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Purpose of loan</td>
|
||||
<td> </td>
|
||||
<td>Maturity date </td>
|
||||
<td> </td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Grace period (if applies)</td>
|
||||
<td> </td>
|
||||
<td>Type of guarantee</td>
|
||||
<td> </td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Penalty for late payment</td>
|
||||
<td> </td>
|
||||
<td>Maturity of the loan (in months) </td>
|
||||
<td> </td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Penalty for pre-payment</td>
|
||||
<td> </td>
|
||||
<td>Total cost of loan (principle + int.+ fees) </td>
|
||||
<td> </td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
|
||||
<p> </p>
|
||||
@@ -74,45 +74,45 @@
|
||||
<h2><span style="font-size:16px"><span style="color:#0000CD">TABLE 2. REPAYMENT SCHEDULE </span></span></h2>
|
||||
|
||||
<table border="1" cellpadding="3" cellspacing="0" style="width:600px">
|
||||
<tbody>
|
||||
<tr>
|
||||
<td>Date</td>
|
||||
<td>Disbursement Amount</td>
|
||||
<td>
|
||||
<p>Principle Repayment</p>
|
||||
</td>
|
||||
<td> Interest Repayment</td>
|
||||
<td>Commission Payment</td>
|
||||
<td>Fees</td>
|
||||
<td>Tax Payment</td>
|
||||
<td>Total Repayment</td>
|
||||
<td>Total Balance Outstanding</td>
|
||||
</tr>
|
||||
{{#installments}}
|
||||
<tr>
|
||||
<td>{{dueDate}}</td>
|
||||
<td>{{installmentNumber}}</td>
|
||||
<td>{{fromDate}}</td>
|
||||
<td>{{principal}}</td>
|
||||
<td> </td>
|
||||
<td>{{feeChargesCharged}}</td>
|
||||
<td> </td>
|
||||
<td> </td>
|
||||
<td> </td>
|
||||
</tr>
|
||||
{{/installments}}
|
||||
<tr>
|
||||
<td>Total</td>
|
||||
<td> </td>
|
||||
<td> </td>
|
||||
<td> </td>
|
||||
<td> </td>
|
||||
<td> </td>
|
||||
<td> </td>
|
||||
<td> </td>
|
||||
<td> </td>
|
||||
</tr>
|
||||
</tbody>
|
||||
<tbody>
|
||||
<tr>
|
||||
<td>Date</td>
|
||||
<td>Disbursement Amount</td>
|
||||
<td>
|
||||
<p>Principle Repayment</p>
|
||||
</td>
|
||||
<td> Interest Repayment</td>
|
||||
<td>Commission Payment</td>
|
||||
<td>Fees</td>
|
||||
<td>Tax Payment</td>
|
||||
<td>Total Repayment</td>
|
||||
<td>Total Balance Outstanding</td>
|
||||
</tr>
|
||||
{{#installments}}
|
||||
<tr>
|
||||
<td>{{dueDate}}</td>
|
||||
<td>{{installmentNumber}}</td>
|
||||
<td>NO fromDate AS IT CHANGES</td>
|
||||
<td>{{principal}}</td>
|
||||
<td> </td>
|
||||
<td>{{feeChargesCharged}}</td>
|
||||
<td> </td>
|
||||
<td> </td>
|
||||
<td> </td>
|
||||
</tr>
|
||||
{{/installments}}
|
||||
<tr>
|
||||
<td>Total</td>
|
||||
<td> </td>
|
||||
<td> </td>
|
||||
<td> </td>
|
||||
<td> </td>
|
||||
<td> </td>
|
||||
<td> </td>
|
||||
<td> </td>
|
||||
<td> </td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
|
||||
<p> </p>
|
||||
|
||||
Reference in New Issue
Block a user