NetSuite does not support access to the native UI through the DOM. You could do this on client side, but it will absolutely break the record. Therefore, I would recommend either:
Making an HTML field on the Sales Order record and writing HTML/CSS to mimic the Transaction Summary box. It would probably be best to place it in its own subtab; something like "Transaction Details", and write to it with a client script on pageInit()
.
Add a button to the Sales Order record on User Event beforeLoad()
. Have that button open a Suitelet that essentially mimics a popup with HTML/CSS to mimic the Transaction Summary as stated in example 1.
Thinking about it, I think the second option is better.
If you need additional help, please comment back and I'll be happy to assist. I have no problem stepping through code, even if baby steps.
EDIT:
Based on the conversation below, the second option seems better for your business needs.
Before we dive into that, I did some research and believe you were trying to do something similar to this post. That approach may very well work, but is not something I would do, citing this excerpt from the NetSuite Help Documentation:
"SuiteScript does not support direct access to the NetSuite UI through the Document Object Model (DOM). You should only access the NetSuite UI by using SuiteScript APIs."
NetSuite Help Documentation: SuiteScript 2.0 Custom Pages
In addition, I'm adding a few notes to this post regarding the whole thing overall. I'll say this once here, and once at the end as a reminder. But remember, it carries for everywhere.
First, if you don't understand something, don't hesitate to ask questions. The only stupid question is the one you don't ask at any time, even if it's the i-th time you're asking as asking questions is a fundamental part of learning anything. Second, make sound coding decisions. There's no way for me to know if this code is still exactly what you need, especially since I don't know your business or the setup of your account. But, I'm sure going to try my best to help in the spirit of help.
With that said, for this example, do the following in order. Once you get the hang of it, you can work with the nuances as you see fit. I won't discuss any of the nuances here. I wish I could, but that's somewhat like explaining how to ride a bike. Here we go!
Make a sub-folder in your SuiteScripts folder called "Transaction_Details" (make sure to use the underscore). We're going to upload everything to here so it's all in one folder under the folder where we need it to be for scripts to run (that is the SuiteScripts folder). From the Administrator role that's:
- Documents > Files > SuiteScripts > Add Folder
Create an HTML file that displays what you're looking for when opened on localhost. Name that file "Transaction_Details.html". NetSuite will default to this file name later, and we're going to use it a few times in our example. So, don't name the file something else. You may want to test the file in a few browsers, especially if you're supporting Internet Explorer. Since we're trying to mimic the Transaction Summary, let's make that our target. To me, it looks like a table with some CSS to make it stand out. Transaction summary is also a native NetSuite term, so we'll call this our "Transaction Details". This way, when someone says, "I don't see it in the Transaction Summary", you can say "Click the Transaction Details button which shows more details than the summary". We want to pass some numbers into this HTML which are the numbers that pertain to our "details". We don't really need syntax to do this, but it can help our readability if we, sort of, alert ourselves that whatever is supposed go in this place is marked in some way. So, we'll arbitrarily mark this as [VARIABLE_TO_REPLACE]
. A sample file is below to get you started. When you have the file the way you like it, upload that to your "Transaction_Details" subfolder. From the Administrator role that's:
- Documents > Files > SuiteScripts > Transaction_Details > Add File
- Select Transaction_Details.html from your computer and set the folder to SuiteScripts : Transaction_Details
<!DOCTYPE html>
<html>
<head>
<title>Transaction Details</title>
<style>
<!--Any CSS you might need; background color, bold, etc.-->
</style>
</head>
<body>
<table>
<tr>
<td>Gross</td>
<td>[GROSS]</td>
</tr>
<tr>
<td>Discount</td>
<td>[DISCOUNT]</td>
</tr>
<tr>
<td>Variable To Replace</td>
<td>[VARIABLE_TO_REPLACE]</td>
</tr>
<!--Rinse and repeat-->
</table>
</body>
</html>
Create a Saved Search with whatever information you need. Let's title the Saved Search "Transaction Details" and give it an ID of "_transaction_details". You may need more than one Saved Search to get everything out. But, in many, many, situations, you can get the data out in one Saved Search. Most times, this is done using SQL. Unfortunately, I don't know everything you'll need here, so I have to leave much of this step up to you; there's a lot of nuances here. However, one thing you should consider is using a filter to filter results which only pertain to a record's Internal ID. This will ensure you're only searching for information on a record. In the Saved Search, you can pick any Internal ID of a relevant record(a Sales Order, most likely) and test on that. Once your results are how you like them, remove the Internal ID filter, as we will dynamically push this as an object in our Suitelet (coming up in step 4). Eventually, you'll need to provide access to the Saved Search. Access is controlled on the Saved Search itself using things like the Audience subtab, and the "Public" checkbox. You will know which access is best for your business. But, note that for anyone to see the Transaction Details we are building they will at least need access to the search. Access permissions is a whole other thing with NetSuite; nuances. To create a saved search from the Administrator role that's:
- List > Search > Saved Searches > New > Transaction
Warning: this is a big step, but it really is all one step. Create a Suitelet that loads our HTML file and replaces our placeholder text with the proper text for that placeholder. Call this file "Transaction_Details_Suitelet.js". We're going to replace the text by running the Saved Search we created with an Internal ID filter that points to our transaction and filters the data, making it easier to extract. Now, I'm making an assumption here that the data we need came out in only one row of results. If there is more than one row, that is fine, but you'll have to do your own formatting, or give me a screenshot of your results so I can edit my answer again. An example is below to get you started. This is going to take some configuration, so it's best to get something into NetSuite that at least passes it's code inspection (which is done as you try to upload the file). Once it's uploaded, you can open the URL to the Script from its Script Deployment, which if error-free will render the HTML we've written in step 2. If it doesn't and you're getting frustrated, just upload the script as seen in example 1 below. All example 1 is saying is, "render my HTML", on the condition that your HTML is properly formatted. If that works, you know "Transaction_Details.html" is good, so you can move onto example 2. If example 2 breaks, it is likely "Transaction_Details_Suitelet.js" that is the problem. To upload the Suitelet from the Administrator role that's:
- Customization > Scripting > Scripts > New > Select Transaction_Details_Suitelet.js from your computer
- Set the folder to SuiteScripts : Transaction_Details
- Some error checking will now occur.
- If it passes, title it "Transaction Details Suitelet", and give it an ID of "_transaction_details_sl" (sl is short for Suitelet)
- Click the Deployments subtab, and title the Deployment "Transaction Details Suitelet". Give it an id of "_transaction_details_sl".
So, the Script and its Deployment should mimic each other in their names. This will be important in our next step
Example 1:
/**
* @NScriptType Suitelet
* @NApiVersion 2.x
*/
define(["N/file"], function(file) {
function onRequest(context) {
if (context.request.method === "GET") {
var fileTransactionDetails = file.load({
id: "/SuiteScripts/Transaction_Details/Transaction_Details.html"
}).getContents();
//Tell NetSuite to take the HTML in our "Transaction_Details.html" file and render that. We'll navigate to the Suitelet which renders our HTML file in step 5.
context.response.write(fileTransactionDetails);
}
}
return {onRequest: onRequest}
})
Example 2
/**
* @NScriptType Suitelet
* @NApiVersion 2.x
*/
define(["N/file"], function(file) {
function onRequest(context) {
if (context.request.method === "GET") {
var fileTransactionDetails = file.load({
id: "/SuiteScripts/Transaction_Details/Transaction_Details.html"
}).getContents();
var searchTransactionDetails = search.load({
id: "customsearch_transaction_details"
});
searchTransactionDetails.filters.push(search.createFilter({
name: "internalid",
operator: search.Operator.EQUALTO,
value: context.request.params.id
}));
var resultsTransactionDetails = searchTransactionDetails.run();
resultsTransactionDetails.each(function(result) {
// getText, if you need the text representation
fileTransactionDetails = fileTransactionDetails.replace("[GROSS]", result.getText(resultsTransactionDetails.columns[0]);
// getValue, if you need something that is a date, a SQL formula result, or something "behind the scenes" like the Internal ID of an element in a list/record.
fileTransactionDetails = fileTransactionDetails.replace("[GROSS]", result.getValue(resultsTransactionDetails.columns[0]);
// I'm intentionally commenting this line out, but if you had more than one row to consider, you would return true, which tells the search, "go to the next row". For now, don't do that.
//return true;
});
//Tell NetSuite to take the HTML in our "Transaction_Details.html" file and render that. We'll navigate to the Suitelet which renders our HTML file in step 5.
context.response.write(fileTransactionDetails);
}
}
return {onRequest: onRequest}
})
- Create a User Event Script that places a button, on a Transaction, on beforeLoad, in view mode only, that opens our Suitelet in step 4, where step 4 runs our search in step 3, replaces text in our HTML file from step 2, and renders the whole thing (sorry for the long sentence. but that's really the one sentence summary of the whole thing anyways). A very important note here: it is best to turn buttons on in view mode only so you can ensure all the data which you need is written to the database.
We'll need to upload the User Event script and tell the script to make the button appear on only the records selected in the User Event's Deployment tab. Let's assume its a Sales Order for now. From the Administrator role that's:
- Customization > Scripting > Scripts > New > Select Transaction_Details_User_Event.js from your computer and set the folder to SuiteScripts : Transaction_Details
- Some error checking will now occur.
- If it passes, title it "Transaction Details User Event", and give it an ID of "_transaction_details_ue" (ue is short for User Event).
- Select the Deployments tab > Applies To > Sales Order and set the ID to "_so_transaction_details_ue" which is like saying "This is the Sales Order Deployment for Transaction Details on the User Event side".
/**
* @NScriptType UserEventScript
* @NApiVersion 2.x
*/
define(["N/url"], function(url) {
function beforeLoad(context) {
if (context.type === context.UserEventType.VIEW) {
// This gives us the link to our Suitelet.
// We can pass any URL parameters to our Suitelet with params.
// One param you will definitely need is id,
// which is the id of the current record you are opening
// the transaction details from, and is used in our
// Saved Search in step 3.
// Recall that we need the id's of our Suitelet and it's Script
// Deployment to be exactly what we said above. NetSuite will prepend
// "customscript" and "customdeploy" to the id of the Suitelet and
// Deployment, respectively, so we need to do the same.
// Missing this step is a common reason why links won't open as
// expected.
// Lastly, although returnExternalUrl defaults to false, let's
// set it to false for peace of mind. We don't want to expose
// anything to the outside.
var urlTransactionDetails = url.resolveScript({
scriptId: "customscript_transaction_details_sl",
deploymentID: "customdeploy_transaction_details_sl",
params: {
id: context.newRecord.id
},
returnExternalUrl: false
});
// Because we're using at least 2.1, we can use `backticks` to
// interpolate urlTransactionDetails into window.open, which makes
// things much easier.
context.form.addButton({
id: "custpage_view_transaction_details,
label: "Transaction Details,
functionName: `window.open("${urlTransactionDetails}");`
});
}
}
return {beforeLoad: beforeLoad}
}
And that's it! Hopefully that gets you farther along. As I stated before, don't hesitate to ask questions. Also, practice good coding practices. Practice good anything for that matter. My intentions are to help you and others here. Unfortunately, this post will not solve everything, but I hope it will help you and others who stop by.
Let me know how it goes!