How to resolve an ArrayIndexOutOfBoundsException in Netsuite Advanced PDF Template - java

I'm working on a template that will group results from a saved search building on these very helpful stackoverflow posts:
How to remove duplicate elements in a array using freemarker?
How can I group a list in an advanced pdf/html sheet in netsuite/freemarker?
The template I've created works fine for me, but when a different user tries to print with it they get an "unexpected error" from Netsuite, and when I logged into that user's account and tried to open the template and save it, I got this error:
The template cannot be saved due to the following errors:
Exception during template merging.com.netledger.templates.TemplateServiceException: Exception during template merging.java.lang.ArrayIndexOutOfBoundsException: Index -1 out of bounds for length 10
This other user has the same Netsuite admin role I do, and is using the same browser (Firefox). I even logged into her Netsuite account on my computer in Firefox and replicated the error, so it seems tied to her NS account(?).
My template is meant to simply group and add page breaks to the results of a saved search that returns salesperson commissions per transaction. Here is the code:
<body padding="0.5in 0.5in 0.5in 0.5in" size="Letter-landscape">
<#assign entitygroup = []>
<#list results as group><!--if the saved search results weren't sorted, they should have been be sorted here-->
<#assign groupID = group.formulatext> <!--"formulatext" is the sales rep or partner or dept, from the saved search-->
<#if entitygroup?seq_contains(groupID)><!-- do nothing / don't add it to the sequence-->
<#else><#assign entitygroup = entitygroup + [groupID]><!--add this entity to the sequence so it will be skipped next time -->
<table>
<tr><td colspan="9" style="font-weight:bold; font-size:12px;">${group.formulatext}</td></tr>
<tr>
<th style="width:10%;">${group.tranid#label}</th>
<th style="width:10%;">${group.trandate#label}</th>
<th style="width:10%;">${group.closedate#label}</th>
<th style="width:20%;">${group.companyname#label}</th>
<th align="right" style="width:10%;">${group.netamountnotax#label}</th>
<th align="right" style="width:10%;">${group.totalcostestimate#label}</th>
<th align="right" style="width:10%;">${group.tranestgrossprofit#label}</th>
<th align="right" style="width:10%;">${group.formulapercent#label}</th>
<th align="right" style="width:10%;">${group.formulacurrency#label}</th>
</tr>
<#assign total_tot = 0>
<#assign total_cost = 0>
<#assign total_profit = 0>
<#assign total_comm = 0>
<#list results as result>
<#if result.formulatext == groupID><!-- if the "entity" (rep, partner, dep) matches the current group-->
<tr>
<td style="width:10%;">${result.tranid}</td>
<td style="width:10%;">${result.trandate}</td>
<td style="width:10%;">${result.closedate}</td>
<td style="width:20%;">${result.companyname}</td>
<td align="right" style="width:10%;">${result.netamountnotax}</td>
<td align="right" style="width:10%;">${result.totalcostestimate}</td>
<td align="right" style="width:10%;">${result.tranestgrossprofit}</td>
<td align="right" style="width:10%;">${result.formulapercent}</td>
<td align="right" style="width:10%;">${result.formulacurrency}</td>
</tr>
<#assign total_tot = total_tot + result.netamountnotax>
<#assign total_cost = total_cost + result.totalcostestimate>
<#assign total_profit = total_profit + result.tranestgrossprofit>
<#assign total_comm = total_comm + result.formulacurrency>
</#if><!-- if the "entity" (rep, partner, dep) matches the current group-->
</#list><!--loop for the lines data-->
<tr style="font-weight:bold;">
<td> </td>
<td> </td>
<td> </td>
<td align="right"><strong>Totals:</strong></td>
<td align="right">${total_tot}</td>
<td align="right">${total_cost}</td>
<td align="right">${total_profit}</td>
<td> </td>
<td align="right">${total_comm}</td>
</tr>
</table>
<pbr />
</#if>
</#list><!-- loop for the "entity" grouping / goes back up to assign the next group-->
</body>
Any help is greatly appreciated, including taking a different approach to this problem!
[Additional info after more testing:]
As I've tried to run this down it seems that the way I'm doing my comments might have something to do with the out of bounds error, perhaps causing the template editor to think I've left out something so the query on the array had no results?
Logged in as the other admin user I deleted the entire body of my template, saved, then re-added it, and the error did not reoccur. Maybe the template engine reinterpreted my comments correctly (or as I intended)?
I've run into this error on another template now and re-did all of my comments in the freemarker way ("<#--") and again it stopped throwing the error, so that's a little more conclusive.
I hope this is helpful to somebody. I'm still working on these templates, so I'll update here if I get a more definitive answer.

Your error is likely because you are trying to save your template as an email template of some sort but are using N/render.TemplateRenderer and not N/render.mergeEmail.
I just store my custom templates as files to avoid validation errors on save.
Prior to saving I use https://try.freemarker.apache.org/ where running the template takes some time.
Unexpected errors generally mean a syntax error or some data that you are expecting isn't there. You might try logging your non-record data sources or have the user who is seeing the error try running your saved search directly to see if the UI reports issues accessing the data.

After working with this and another complex template I feel pretty confident that the inconsistent behavior I noted in my question was caused by using the wrong commenting tags: <!-- instead of <#--. Netsuite's template editor encourages the html-style comment by putting the text in a consistent brownish color (when using freemarker comments the text colors seem to ignore the comment tag completely) so it's a bit misleading. At least for my templates changing all the comments to the <#-- tag saved the day.

Related

Thymeleaf - skip table creation if the iterated list is null

I have an html thymeleaf template where I build a table iterating over a list:
<table>
<tr>
<th>Setup Name</th>
<th>Setup Path</th>
</tr>
<tr th:each="setup : ${upgradeState.targetUpgradeSetups.setups}">
<td th:text="${setup.name}"/>
<td th:text="${setup.path}"/>
</tr>
</table>
The problem is that the element upgradeState.targetUpgradeSetups may be null, so I would like to build this table only when the element is not null.
Note: if the element upgradeState.targetUpgradeSetups is not null, then it's guaranteed for the list setups to be not null either. Hence I only need to check for the parent element.
I have tried to use the th:if statement as follows:
<tr th:if=${upgradeState.targetUpgradeSetups != null} th:each="setup : ${upgradeState.targetUpgradeSetups.setups}">
But even like that, I still get the same exception:
Caused by: org.springframework.expression.spel.SpelEvaluationException: EL1007E: Property or field 'setups' cannot be found on null
at org.springframework.expression.spel.ast.PropertyOrFieldReference.readProperty(PropertyOrFieldReference.java:213)
at org.springframework.expression.spel.ast.PropertyOrFieldReference.getValueInternal(PropertyOrFieldReference.java:104)
at org.springframework.expression.spel.ast.PropertyOrFieldReference.access$000(PropertyOrFieldReference.java:51)
at org.springframework.expression.spel.ast.PropertyOrFieldReference$AccessorLValue.getValue(PropertyOrFieldReference.java:406)
at org.springframework.expression.spel.ast.CompoundExpression.getValueInternal(CompoundExpression.java:90)
at org.springframework.expression.spel.ast.SpelNodeImpl.getValue(SpelNodeImpl.java:109)
at org.springframework.expression.spel.standard.SpelExpression.getValue(SpelExpression.java:328)
at org.thymeleaf.spring5.expression.SPELVariableExpressionEvaluator.evaluate(SPELVariableExpressionEvaluator.java:263)
... 74 more
I didn't manage to find a specific example/reference about Thymeleaf for such issue, could anyone please suggest the right way?
You need to count on Thymeleaf Attribute Precedence. According to the order, Thymeleaf will parse iteration first and only after the condition, when placed into the same tag. The code which would work for you may look like ...
<table>
<tr>
<th>Setup Name</th>
<th>Setup Path</th>
</tr>
<tbody th:if=${upgradeState.targetUpgradeSetups != null}>
<tr th:each="setup : ${upgradeState.targetUpgradeSetups.setups}">
<td th:text="${setup.name}"/>
<td th:text="${setup.path}"/>
</tr>
</tbody>
</table>

Selenium Webdriver Xpath: Find and compare the text of an element then click the link that's 4 rows after

I want to find and compare the heading in the table. Then click on the delete button that in the next 3 rows of the heading.
Example: Lets say a given input is Heading 2. I want to search Heading 2 and see if it exists then click on the delete button that is associated with 'Heading 2' (like 3-4 rows after).
So far this is the code that i came close to. The only problem is that it always click the first selection instead of where i want it to go.
String HeadingName = "Heading 2"
driver.findElement(By.xpath("//tr[contains(.,'" + HeadingName + "')]/tr[position()=4]/td[2]/div/a[2]")).click();
This is what the table and it's code looks like.
Heading 1
Name: Joe
Gender: Male
Options: Update | Delete
Heading 2
Name: Jenny
Gender: Female
Options: Update | Delete
<table>
<tbody>
<tr>
<th class="st-head-row" colspan="2">Heading 1</th>
</tr>
<tr class="even">
<td class="st-key">Name:</td>
<td class="st-val">Joe</td>
</tr>
<tr class="even">
<td class="st-key">Gender:</td>
<td class="st-val">Male</td>
</tr>
<tr class="even last-row">
<td class="st-key">Options:</td>
<td class="st-val">
<div style="white-space:nowrap;">
<a id="save" href="linkaddress">save</a>
|
<a id="delete" href="linkaddress">delete</a>
</div>
</td>
</tr>
<tr>
<th class="st-head-row" colspan="2">Heading 2</th>
</tr>
<tr class="even">
<td class="st-key">Name:</td>
<td class="st-val">Jenny</td>
</tr>
<tr class="even">
<td class="st-key">Gender:</td>
<td class="st-val">female</td>
</tr>
<tr class="even last-row">
<td class="st-key">Options:</td>
<td class="st-val">
<div style="white-space:nowrap;">
<a id="save" href="linkaddress">save</a>
|
<a id="delete" href="linkaddress">delete</a>
</div>
</td>
</tr>
</tbody>
</table>
Try this code , hope it will help you.
driver.findElement(By.xpath("//tr/th[contains(text(),'" + HeadingName + "')]//following::tr[3]/td[2]/div/a[2]")).click();
Thanks
Try next code with xpath
String headingName = "Heading 2";
driver.findElement(By.xpath("//th[text()='"+ headingName +"']/parent::tr/following-sibling::tr[#class='even last-row']/td[#class='st-val']/div/a[#id='delete']")).click();
If it works, for detailedinfo how this xpath is created look here - http://www.w3schools.com/xpath/xpath_axes.asp
I'd try and keep the XPath a bit more "semantic", e.g.
//tr[th = 'Heading 2']/following-sibling::tr[starts-with(td[1], 'Options')][1]//a[. = 'delete']
Here I'm looking specifically for the "delete" link in the next "Options" row, rather than something more fragile like "the second link in the next-but-two row".
I actually made an answer that surprisingly worked for me.
dUtil.findElement(By.xpath("//tr/th[contains(text(),'" + headingName + "')]/../following::tr[3]/td[2]/div/a[2]")).click();
I got every condition I wanted.
Searches for the heading that is similar to the given input heading
Clicks the link 'Delete' that is 3 rows bellow the searched element
Should work even if there are more than one batch of rows (batch meaning from heading to delete)
The batch doesn't have to be in order.

How to iterate an object in JSP to get the percentage?

I am working on servlet and jsp project. I am passing an object from servlet to JSP. And currently I am iterating that object and showing them in a table -
Below is my code in jsp -
<TABLE id="tableSMS" BORDER="1" CELLPADDING="3" CELLSPACING="1" style="text-align: center;">
<TR style="color:#ffffff;background-color:#787878;">
<TH>Hash Name</TH>
<TH>Database Name</TH>
<TH>Version</TH>
</TR>
<c:forEach var="i" begin="0" end="${reportCount.getHash().size() - 1}">
<TR>
<TD>
${reportCount.getHash().get(i)}
</TD>
<TD>
${reportCount.getDatabaseName().get(i)}
</TD>
<TD>
${reportCount.getVersion().get(i)}
</TD>
</TR>
</c:forEach>
And above code is working fine and I am able to show the data properly. Now what I need to do is -
${reportCount.getDatabaseName().get(i)} will return database name as oracle or mysql only. Now I need to calculate what is the percentage of oracle database. I will get the total number of records from ${reportCount.getHash().size(). So if total number of records is 10 and oracle database is present 5 times, then the percentage should be 50%.
Now I am not sure how would I calculate the above percentage using that object? And after calculating that percentage, I need to show the result in a new table which is shown below -
<table>
<tr>
<th style="background-color: #E8E8E6;"><b>Oracle Database</b></th>
</tr>
<tr>
<!-- I would like to show the percentage in this row -->
<td>%</td>
</tr>
</table>
I am thinking I should iterate the reportCount object again in the above new table and extract the percentage here but not sure how would I do that? Can anyone provide an example?
UPDATE:-
Here is my bean code -
public class Response {
private List<String> hash = new LinkedList<String>();
private List<String> databaseName = new LinkedList<String>();
private List<String> version = new LinkedList<String>();
// getters and setters here
}
There are three things as following:
Add the functions taglib:
<%# taglib prefix="fn" uri="http://java.sun.com/jsp/jstl/functions" %>
Add reportsCounts variable to requestScope instead of session if not required on any other page & use as following:
<c:set var="oracleDBCount" value="0" scope="page" />
<c:forEach var="reportCount"
items="${requestScope.reportCounts.databaseName}" varStatus="loop">
<TR>
<TD>${requestScope.reportCounts.hash[loop.index]}</TD>
<TD>${reportCount}
<c:if test="${reportCount == 'ORACLE'}">
<c:set var="oracleDBCount" value="${oracleDBCount + 1}" scope="page"/>
</c:if>
</TD>
<TD>${requestScope.reportCounts.version[loop.index]}</TD>
</TR>
</c:forEach>
Now display percentage as:
${(oracleDBCount / fn:length(requestScope.reportCounts))*100}%
Based on my experience, doing number-crunching on a JSP page can make it unreadable very quickly. Also you may encounter additional requirements in the future such as:
Text matching (Are you guaranteed that the value is always "oracle"? Or can it become "ORACLE" or "Oracle"?
What if there are zero reports? Then you will need an if-condition to prevent division by zero.
If your client says "We have more report servers like MS, Postgres...can you show the percentage of those?"
Is it possible to do the computation inside the servlet while you are making the reportCount object?
Then you can pass the value inside a session attribute
request.getSession(true).setAttribute("oracleReports", "50%")
and then in the JSP output something like
<c:out value="${sessionScope.oracleReports}"/>
Use JavaScript for doing the operation, Here is the code
Read the comments to understand the code.
Add an id to the so that i can read the inner content using
javascript. Appended id with the index so that each raw gets different
id's
<c:forEach var="i" begin="0" end="${reportCount.getHash().size() - 1}">
<TD id="databaseName<c:out value='${i}' />">
${reportCount.getDatabaseName().get(i)}
</TD>
Add Id to the so that i can set values to the raw using
JavaScript
<tr>
<td id="oraclePercentage">%</td>
<td id="mySQLPercentage">%</td>
</tr>
call the javascript function to set the values to the raw, as we don't
have any button to trigger we open a raw and add the JavaScript call
from the JSP so that the script is triggered every time the page loads
the raw.
<TR><TD><Script>setPercentage('${reportCount.getHash().size() - 1}');</script><TD><TR>
what to do is defined here
<Script>
function setPercentage(var index){
for(var i=0; i<index;i++){
var documentType=document.getElementById("databaseName"+i).innerHTML;
var oracleCount=0;
var mySQLCount=0;
if(vardocumentType=='Oracle')
oracleCount+=(Number)1;
else if(vardocumentType=='MySQL')
mySQLCount+=(Number)1;
document.getElementById("oraclePercentage").innerHTML=(oracleCount/index)*100;
document.getElementById("mySQLPercentage").innerHTML=(mySQLCount/index)*100;
}
</script>

Regex to iterate over an table and extract the td information inside an div using java

Hello i know parsing HTML with regex is not efficient .But i need to do with regex i have no other option.
HTML
<div class="test">
<h2>what</h2>
<table cellpadding="0" cellspacing="0">
<tbody>
<tr>
<th>Example </th>
<td> ui </td>
</tr>
<tr>
<th>Sample </th>
<td>123 </td>
</tr>
</tbody>
</table>
</div>
I tried to do it using (?s)<div class="test">.*<td>(.*?)</td>.*</div> it extracts only the last value can any one tell me what is the issue?
Why only using Regular expression, how about some jquery??
$("div.test > td").each(function() {
var $this = $(this);
alert( $this.text() )
});
The * operator reads as much as is possible, so the first .* also swallows most of the text.
Try with .*?. The question mark reduces this behaviour and lets * only take as much as necessary, not as much as possible.
Otherwise please be more specific what parts you really want and which not.

How to verify the Literal text on the UI

Here is part of the UI where i have got some literal texts like
Opportunity Name Momentum Test (ID=AANA-19KVBE)
Account Account Internal
Owner Christopher Braden
Sales Order Region North America
Locale English United States
Currency US Dollar
The piece of code for the above is as follows
<table class="datatable" width="100%">
<tbody>
<tr class="oddrow">
<td>Opportunity Name</td>
<td class="wrap_content">
Momentum Test (ID=AANA-19KVBE)
<br>
<a target="_blank" href="http://www.example.com">View in Salesforce</a>
</td>
</tr>
<tr class="evenrow">
<td>Account</td>
<td class="wrap_content">
Akamai Internal
<br>
<a target="_blank" href="http://www.example.com">View in Salesforce</a>
</td>
</tr>
<tr class="oddrow">
<td>Owner</td>
<td>Christopher Braden</td>
</tr>
<tr class="evenrow">
<td>Sales Order Region</td>
<td>North America</td>
</tr>
<tr class="oddrow">
<td>Locale</td>
<td>English - United States</td>
</tr>
<tr class="evenrow">
<td>Currency</td>
<td>US Dollar</td>
</tr>
</tbody>
I need to retrieve these values individually, store it to compare it in a different page.
for example : i need to know "United States" is stored under "Location"
Please help me
Thanks & Regards
Kiran
You can read and store all this information in a Map -
Map<String,String> map = new Map<String,String>;
List<WebElement> list = driver.findElements(By.xpath("//*[#class='datatable']/tbody/tr"));
for(int i=1;i<=list.size();i++){
String key = driver.findElement(By.xpath("//*[#class='datatable']/tbody/tr["+i+"]/td[1]")).getText();
String value = driver.findElement(By.xpath("//*[#class='datatable']/tbody/tr["+i+"]/td[2]")).getText();
map.put(key,value);
}
In this way you can read all the information in the table and store it in Map to be used later. Let me know if this works for you.

Categories