Suitescript: copying sublist data from one record to another - suitescript2.0

I have a before load user event function on an invoice record that create a button called 'create vendor bill'.
When this button is pressed, a new vendor bill record is opened. The UE script:
/**
*#NApiVersion 2.x
*#NScriptType UserEventScript
*/
define([
"N/url",
"N/record",
"N/runtime",
"N/ui/serverWidget",
"N/redirect",
], function (url, record, runtime, serverWidget, redirect) {
var exports = {};
/**
* #param {UserEventContext.beforeLoad} context
*/
function beforeLoad(context) {
if (
context.type == context.UserEventType.EDIT ||
context.type == context.UserEventType.VIEW
) {
var record = context.newRecord;
var recordId = record.id;
var recordType = record.type;
var customer = record.getValue({ fieldId: "entity" });
log.debug("entity", customer);
var scriptObj = runtime.getCurrentScript();
var customForm = scriptObj.getParameter({
name: "custscript_custom_form_vb",
});
var recordSublist = record.getSublist({ sublistId: "item" });
log.debug("item", recordSublist);
var form = context.form;
log.debug("form", form);
var userVarStr = record;
log.debug("uservarstr", userVarStr);
var userVarURL = url.resolveRecord({
recordType: "vendorbill",
params: {
entity: parseInt(customer),
supportcase: recordId,
cf: parseInt(customForm),
},
});
form.addButton({
id: "custpage_button_test",
label: "Create Vendor Bill",
functionName: "getDetails('" + userVarURL + "')",
});
}
}
exports.beforeLoad = beforeLoad;
return exports;
});
Once the page redirects to the vendor bill form, a client script (deployed on the form), sets the field values on the body of the vendor bill using the parameters passed in the url
This is working as expected.
Where I am getting stuck is trying to work out how to pass the 'item' sublist values to from the invoice to the vendor bill?
Would I pass this as an array?
From what I understand, there is a limit to the number of characters that can be passed via the url.
I can't find anything online or in the Netsuite documentation that deals with passing sublist values between records

For starters I would want to see the Client Script.
One option would be to only pass the Invoice Record ID and Type. Then you can create a Suitelet to be used as a proxy and get the sublist data by a saved search.
Something to keep in mind is that if the sublist is very very long you may reach a execution timeout so you may want to consider triggering a MapReduce script to populate the sublist again you would pass it the recType and ID of the invoice and vendor bill and then use a saved search to get the data.
There are other approaches but I would need to see the client script.

Related

UserID from AuthenticationStateProvider appears empty

I am using AspNetCore Identity and trying to get the UserID of the currently logged in user using AuthenticationStateProvider. I am logging to the console the output however, the username outputs fine but the ID appears empty. The ID field is not empty in the db table. When printing all the claims the subs field seems to be the correct ID. Am I incorrectly retrieving the ID? The approach to retrieve the ID was suggested from another post I found; code is shown below. How might I retrieve the sub value which is the userID, in my page using AuthenticationStateProvider? Thanks in advance.
Retrieving UserID
var user = (await ASP.GetAuthenticationStateAsync()).User;
var UserStringId = user.FindFirst(c => c.Type.Equals(user.Identity.Name))?.Value;
Browser console output
USER ID: blazor.webassembly.js:1
NAME: user4#gmail.com
Sub is correct ID when looping through Claims
var user = (await ASP.GetAuthenticationStateAsync()).User;
var item = user.Claims;
foreach(var x in item)
{
Console.WriteLine(x);
}
Browser console output
s_hash: EQ_bVJS8n32qtUam0wZ1MA
sid: 2E6B597CC9644CFEFDD627532B761F02
sub: 5685a830-cb82-4b60-b459-c0852cc74563 // trying to retrieve this ID
//...
preferred_username: user4#gmail.com
name: user4#gmail.com
Try:
user.FindFirst(c => c.Type == "sub")?.Value

How can check history information for a certain customer by using scripting in NetSuite?

I want to create a Script in NetSuite which needs some history information from a customer. In fact the information I need is to know if the user has purchased an item.
For this, I would need in some way to access to the history of this customer.
Pablo.
Try including this function and passing customer's internalID and item internalID
function hasPurchasedBefore(customerInternalID, itemInternalID){
var results = [];
var filters = [];
var columns = [];
filters.push(new nlobjSearchFilter('internalidnumber', 'customermain', 'equalto', [customerInternalID]))
filters.push(new nlobjSearchFilter('anylineitem', null, 'anyof', [itemInternalID]));
filters.push(new nlobjSearchFilter('type', null, 'anyof', ['CustInvc']));
columns.push(new nlobjSearchColumn('internalid', null, 'GROUP'));
results = nlapiSearchRecord('transaction', null, filters, columns);
if (results && results.length){
return true;
}
return false;
}
Example:
var record = nlapiLoadRecord(nlapiGetRecordType(),nlapiGetRecordId());
var customerInternalID = record.getFieldValue('entity');
var itemInternalID = record.getLineItemValue('item', 'item', 1); //Gets line 1 item Internal ID
if( hasPurchasedBefore(customerInternalID, itemInternalID) ) {
//Has bought something before
}
You could use a saved search nlapiLoadSearch or nlapiCreateSearch for invoices, filtered by customer, and also reporting invoice items (or just a particular item). Using nlapiCreateSearch can be tricky to use, so I'd recommend building the saved search using the UI, then load it using nlapiLoadSeach(type, id)
This will give you an array of invoices/customers that bought your item.

Sitecore Lucene search - hit count differs from result count

I have the following method to return search results based on a supplied query
private List<Item> GetResults(QueryBase qBase)
{
using (IndexSearchContext sc = SearchManager.GetIndex("story").CreateSearchContext())
{
var hits = sc.Search(qBase, int.MaxValue);
var h1 = hits.FetchResults(0, 25);
var h2 = h1.Select(r => r.GetObject<Item>());
var h3 = h2.Where(item => item != null);
return h3.ToList();
}
}
The index being searched indexes web and master content. If I pass in a query that I know matches a single published item and break at the line beginning var h2 = then I see the variable hits has 2 items. This I expect because actually the items are both the same item, one from web and one from master.
However, the variable h1 only has a single result. The result from web has been omitted.
This is the case whether I'm debugging in the context of web or master. Can anyone explain?
When fetching the items using FetchResults method, Sitecore groups the items from lucene by the id of the item. First of the items becomes a SearchResult in the resulting SearchResultCollection object, and other items become Subresults for this results.
For example if you have a home item with id {110D559F-DEA5-42EA-9C1C-8A5DF7E70EF9} with one published version and 4 versions in different languages for the home item, what you'll get from lucene is a single result and 4 subresults for this result:
using (IndexSearchContext sc = SearchManager.GetIndex("story").CreateSearchContext())
{
var hits = sc.Search(qBase, int.MaxValue);
var h1 = hits.FetchResults(0, 25);
foreach (SearchResult result in h1)
{
var url = result.Url;
foreach (SearchResult subresult in result.Subresults)
{
var subUrl = subresult.Url; // other versions of this item
}
}
}
The urls for results and subresults in my case would be:
sitecore://web/{110D559F-DEA5-42EA-9C1C-8A5DF7E70EF9}?lang=en&ver=1
sitecore://master/{110D559F-DEA5-42EA-9C1C-8A5DF7E70EF9}?lang=en&ver=1 (subresult)
sitecore://master/{110D559F-DEA5-42EA-9C1C-8A5DF7E70EF9}?lang=ja-JP&ver=1 (subresult)
sitecore://master/{110D559F-DEA5-42EA-9C1C-8A5DF7E70EF9}?lang=de-DE&ver=1 (subresult)
sitecore://master/{110D559F-DEA5-42EA-9C1C-8A5DF7E70EF9}?lang=da&ver=1 (subresult)
so for retrieving the all the items with their versions you can use this code:
private List<Item> GetResults(QueryBase qBase)
{
using (IndexSearchContext sc = SearchManager.GetIndex("story").CreateSearchContext())
{
var hits = sc.Search(qBase, int.MaxValue);
var h1 = hits.FetchResults(0, 25);
var h2 = h1.Select(r => r.GetObject<Item>()).ToList();
// add other versions of item to the resulting list
foreach (IEnumerable<SearchResult> subresults in h1.Select(sr => sr.Subresults))
{
h2.AddRange(subresults.Select(r => r.GetObject<Item>()));
}
var h3 = h2.Where(item => item != null);
return h3.ToList();
}
}
You can not assume with item will be returned as the first one from the lucene and which items will be returned as subresults. If you want to get any specific item you need to pass version number, language and database to the query.

"update" query - error invalid input synatx for integer: "{39}" - postgresql

I'm using node js 0.10.12 to perform querys to postgreSQL 9.1.
I get the error error invalid input synatx for integer: "{39}" (39 is an example number) when I try to perform an update query
I cannot see what is going wrong. Any advise?
Here is my code (snippets) in the front-end
//this is global
var gid=0;
//set websockets to search - works fine
var sd = new WebSocket("ws://localhost:0000");
sd.onmessage = function (evt)
{
//get data, parse it, because there is more than one vars, pass id to gid
var received_msg = evt.data;
var packet = JSON.parse(received_msg);
var tid = packet['tid'];
gid=tid;
}
//when user clicks button, set websockets to send id and other data, to perform update query
var sa = new WebSocket("ws://localhost:0000");
sa.onopen = function(){
sa.send(JSON.stringify({
command:'typesave',
indi:gid,
name:document.getElementById("typename").value,
}));
sa.onmessage = function (evt) {
alert("Saved");
sa.close;
gid=0;//make gid 0 again, for re-use
}
And the back -end (query)
var query=client.query("UPDATE type SET t_name=$1,t_color=$2 WHERE t_id = $3 ",[name, color, indi])
query.on("row", function (row, result) {
result.addRow(row);
});
query.on("end", function (result) {
connection.send("o");
client.end();
});
Why this not work and the number does not get recognized?
Thanks in advance
As one would expect from the initial problem, your database driver is sending in an integer array of one member into a field for an integer. PostgreSQL rightly rejects the data and return an error. '{39}' in PostgreSQL terms is exactly equivalent to ARRAY[39] using an array constructor and [39] in JSON.
Now, obviously you can just change your query call to pull the first item out of the JSON array. and send that instead of the whole array, but I would be worried about what happens if things change and you get multiple values. You may want to look at separating that logic out for this data structure.

Conditionally adjust visible columns in Rally Cardboard UI

So I want to allow the user to conditionally turn columns on/off in a Cardboard app I built. I have two problems.
I tried using the 'columns' attribute in the config but I can't seem to find a default value for it that would allow ALL columns to display(All check boxes checked) based on the attribute, ie. the default behavior if I don't include 'columns' in the config object at all (tried null, [] but that displays NO columns).
So that gets to my second problem, if there is no default value is there a simple way to only change that value in the config object or do I have to encapsulate the entire variable in 'if-else' statements?
Finally if I have to manually build the string I need to parse the values of an existing custom attribute (a drop list) we have on the portfolio object. I can't seem to get the rally.forEach loop syntax right. Does someone have a simple example?
Thanks
Dax - Autodesk
I found a example in the online SDK from Rally that I could modify to answer the second part (This assumes a custom attribute on Portfolio item called "ADSK Kanban State" and will output values to console) :
var showAttributeValues = function(results) {
for (var property in results) {
for (var i=0 ; i < results[property].length ; i++) {
console.log("Attribute Value : " + results[property][i]);
}
}
};
var queryConfig = [];
queryConfig[0] = {
type: 'Portfolio Item',
key : 'eKanbanState',
attribute: 'ADSK Kanban State'
};
rallyDataSource.findAll(queryConfig, showAttributeValues);
rally.forEach loops over each key in the first argument and will execute the function passed as the second argument each time.
It will work with either objects or arrays.
For an array:
var array = [1];
rally.forEach(array, function(value, i) {
//value = 1
//i = 0
});
For an object:
var obj = {
foo: 'bar'
};
rally.forEach(obj, function(value, key) {
//value = 'bar'
//key = 'foo'
});
I think that the code to dynamically build a config using the "results" collection created by your query above and passed to your sample showAttributeValues callback, is going to look a lot like the example of dynamically building a set of Table columns as shown in:
Rally App SDK: Is there a way to have variable columns for table?
I'm envisioning something like the following:
// Dynamically build column config array for cardboard config
var columnsArray = new Array();
for (var property in results) {
for (var i=0 ; i < results[property].length ; i++) {
columnsArray.push("'" + results[property][i] + "'");
}
}
var cardboardConfig = {
{
attribute: 'eKanbanState',
columns: columnsArray,
// .. rest of config here
}
// .. (re)-construct cardboard...
Sounds like you're building a neat board. You'll have to provide the board with the list of columns to show each time (destroying the old board and creating a new one).
Example config:
{
attribute: 'ScheduleState'
columns: [
'In-Progress',
'Completed'
]
}