I am executing nlapiSearchRecord function on itemfulfillment record and the search is working fine but its return result with repetition/duplicate.
Below is the my working code i just want to know that which filter should i use to avoid repetition/duplicate record.
var filters = [
new nlobjSearchFilter('internalid', null, 'is',id),
new nlobjSearchFilter('mainline', null, 'is', 'F'),
new nlobjSearchFilter('shipping', null, 'is', 'F'),
new nlobjSearchFilter('taxline', null, 'is', 'F')
], columns = [
new nlobjSearchColumn('trandate'),
new nlobjSearchColumn('tranid'),
new nlobjSearchColumn('item'),
new nlobjSearchColumn('quantity'),
new nlobjSearchColumn('location')
];
var searchresults = lapiSearchRecord('itemfulfillment',null, filters, columns);
Below is the search result for your understanding and you can see that there is one item but it's is duplicated two times with positive quantity and one time with negative quantity.
[{"id":"123","recordtype":"itemfulfillment",
"columns":{"trandate":"2/1/2222","tranid":"xx-xxxx","status":{"name":"xxxx","internalid":"xxxx"},"item":{"name":"Test-1","internalid":"1111"},"quantity":1,"location":{"name":"xxxx","internalid":"xxx"}}},
{"id":"123","recordtype":"itemfulfillment",
"columns":{"trandate":"2/1/2222","tranid":"xx-xxxx","status":{"name":"xxxx","internalid":"xxxx"},"item":{"name":"Test-1","internalid":"1111"},"quantity":1,"location":{"name":"xxxx","internalid":"xxx"}}},{"id":"123","recordtype":"itemfulfillment",
"columns":{"trandate":"2/1/2222","tranid":"xx-xxxx","status":{"name":"xxxx","internalid":"xxxx"},"item":{"name":"Test-1","internalid":"xxxx"},"quantity":-1,"location":{"name":"xxxx","internalid":"xx"}}},{"trandate":"2/1/2222","tranid":"xx-xxxx","status":{"name":"xxxx","internalid":"xxxx"},"item":{"name":"XXXXX","internalid":"1111"},"quantity":1,"location":{"name":"xxxx","internalid":"xxx"}}},
{"id":"123","recordtype":"itemfulfillment",
"columns":{"trandate":"2/1/2222","tranid":"xx-xxxx","status":{"name":"xxx","internalid":"xxxx"},"item":{"name":"Test-2","internalid":"xyz"},"quantity":2,"location":{"name":"xxx","internalid":"xxxx"}}},{"id":"123","recordtype":"itemfulfillment","columns":{"trandate":"2/1/2222","tranid":"xx-xxxx","status":{"name":"xxxx","internalid":"xxxx"},"item":{"name":"Test-2","internalid":"xyz"},"quantity":2,"location":{"name":"xxxx","internalid":"10"}}},{"id":"123","recordtype":"itemfulfillment",
"columns":{"trandate":"2/1/2222","tranid":"xx-xxxx","status":{"name":"xxxx","internalid":"xxxx"},"item":{"name":"Test-2","internalid":"xyz"},"quantity":-2,"location":{"name":"xxxx","internalid":"xxxx"}}}]
Can you please guide me that how can i get items without any repetition/duplication.
The positive and negative quantities relate to the G/L entries created by the fulfillment.
Choose the G/L account for the side of the transaction you are interested in as another filter.
Related
When the billing schedule runs it auto generates invoices from sales order. When this happens - how can I create a link on the sales order that will allow me to load the corresponding invoice in code?
I need this so I can grab couple of field values from the invoice but I can't access the invoice directly from another entity which seems only related to sales order.
EDIT 1:
var fil = [];
fil[0] = new nlobjSearchFilter('createdfrom', null, 'is', nlapiGetRecordId())
var col = [];
col[0] = new nlobjSearchColumn('internalid');
var invoices = nlapiSearchRecord('invoice', null, fil, col);
nlapiLogExecution('DEBUG', 'field val', invoices);
Throws invalid operator or not in proper syntax: createdfrom.
Though adding a link on the Sales Order is a viable solution, it's not your only option. Alternatively, you could do a search for invoices where the createdfrom field is the internal ID of your Sales Order. Something like in SuiteScript 1.0:
var invoices = nlapiSearchRecord('invoice', null,
[['createdfrom', 'is', nlapiGetRecordId()]],
[/* create search columns for the fields you need off the invoice */]
) || [];
or in 2.0:
var invoices = search.create({
"type": search.Type.INVOICE,
"filters": [['createdfrom', 'is', context.currentRecord.id]],
"columns": [/* create search columns for the fields you need off the invoice */]
}).run().each(processResult);
This will get you a list of all the Invoices created from your Sales Order (which is likely only 1).
If you believe you need a link to the Invoice on the Sales Order, you could add the custom body field, then create a User Event on the Invoice record that populates this new field with its createdfrom value on the Before Submit event. But then what happens if your Sales Order gets paid via multiple Invoices?
I have a large nlobjSearchResultSet object with over 18,000 "results".
Each result is a pricing record for a customer. There may be multiple records for a single customer.
As 18000+ records is costly in governance points to do mass changes, I'm migrating to a parent (customer) record and child records (items) so I can make changes to the item pricing as a sublist.
As part of this migration, is there a simple command to select only the nlapiSearchResult objects within the big object, which match certain criteria (ie. the customer id).
This would allow me to migrate the data with only the one search, then only subsequent create/saves of the new record format.
IN a related manner, is there a simple function call to return to number of records contained in a given netsuite record? For % progress context.
Thanks in advance.
you can actually get the number of rows by running the search with an added aggregate column. A generic way to do this for a saved search that doesn't have any aggregate columns is shown below:
var res = nlapiSearchRecord('salesorder', 'customsearch29', null,
[new nlobjSearchColumn('formulanumeric', null, 'sum').setFormula('1')]);
var rowCount = res[0].getValue('formulanumeric', null, 'sum');
console.log(rowCount);
To get the total number of records, the only way is do a saved search, an ideal way to do such search is using nlobjSearch
Below is a sample code for getting infinite search Results and number of records
var search = nlapiLoadSearch(null, SAVED_SEARCH_ID).runSearch();
var res = [],
currentRes;
var i = 0;
while(i % 1000 === 0){
currentRes = (search.getResults(i, i+1000) || []);
res = res.concat(currentRes );
i = i + currentRes.length;
}
res.length or i will give you the total number of records and res will give you all the results.
This is related to a question I asked previously:
How to get customer aging fields from a Netsuite restlet
The technique described in the answer to that question works great, but it doesn't handle credit memos. I'm having problems figuring out how to take credit memos into account.
For example, I have a customer record that displays the following values:
BALANCE
1950.00
OVERDUE BALANCE
2000.00
CURRENT 1-30 DAYS 31-60 DAYS 61-90 DAYS OVER 90 DAYS
0.00 -50.00 2,000.00 0.00 0.00
I can pull the 2000 out just fine, but I can't seem to get the -50 from the credit memo.
I tried adjusting the invoice query to do this:
new nlobjSearchFilter('amountremaining', null, 'notequalto', 0),
I also tried doing a separate query for credit memos:
var agingcmemo = nlapiSearchRecord(
'creditmemo',
null,
[
new nlobjSearchFilter('daysoverdue', null, 'greaterthan', 0),
new nlobjSearchFilter('mainline', null, 'is', 'T'),
new nlobjSearchFilter('amountremaining', null, 'notequalto', 0),
new nlobjSearchFilter('entity', null, 'is', result[0].id)
],
[
new nlobjSearchColumn('entity', null, 'group'),
new nlobjSearchColumn('formulanumeric', null, 'sum').setFormula('case when {daysoverdue} < 31 then {amountremaining} else 0 end'),
new nlobjSearchColumn('formulanumeric', null, 'sum').setFormula('case when {daysoverdue} between 31 and 60 then {amountremaining} else 0 end'),
new nlobjSearchColumn('formulanumeric', null, 'sum').setFormula('case when {daysoverdue} between 61 and 90 then {amountremaining} else 0 end'),
new nlobjSearchColumn('formulanumeric', null, 'sum').setFormula('case when {daysoverdue} > 90 then {amountremaining} else 0 end')
]
);
That query returns no rows. If I remove all conditions except for the entity it returns two rows, neither of which is the actual credit memo.
Anyone have any ideas on how to get those right numbers including the credit memos?
there's no concept of daysoverdue with a credit memo. If you run the code below does that sum to $50? You should be able to use that to get your open credit memo value and combine that with your open invoice amounts.
The other than that is it possible that you have an unapplied payment or customer deposit?
var agingcmemo = nlapiSearchRecord(
'creditmemo',
null,
[
new nlobjSearchFilter('mainline', null, 'is', 'T'),
new nlobjSearchFilter('status', null, 'anyof', ['CustCred:A']),
new nlobjSearchFilter('entity', null, 'is', 996)
],
[
new nlobjSearchColumn('entity', null, 'group'),
new nlobjSearchColumn('amountremaining', null, 'sum')
]
);
agingcmemo.forEach(function(c){
var cols = c.getAllColumns();
cols.forEach(function(col, idx){ console.log(idx +': '+c.getValue(col));});
console.log('');
});
I've used a different approach to building an aging report in a Saved Search that might work better for you as it takes credit memos into account as well. (The groups below age by months rather than 30 day increments but you can replace them with the formula you were using before):
You can define "Transaction Type" in the search criteria, this way you can create saved searches for each specific transaction types. Alternately you can add transaction type as a filter even color code it by the transaction types. In my opinion transaction search is the mother of all searches in NS because majority of objects and fields are exposed to this search type.
I cannot for the life of me get the returned value from a search in NetSuite. When I use the debugger I can see the value, but I cannot access it.
var columns = new nlobjSearchColumn('custentity_employeenumber', null, 'max');
var results = new nlapiSearchRecord('employee', null, filters, columns);
var result = results[0].getValue('custentity_employeenumber');
Every time the debugger shows the result variable as null...I don't get it. I can see the value in the debugger...
I really just need the 2014103...or am I building the search wrong?
When you put a summary on a search column, you must specify the summary when you retrieve the value as well. So, because you have:
new nlobjSearchColumn('custentity_employeenumber', null, 'max');
you must retrieve the value with:
results[0].getValue('custentity_employeenumber', null, 'max');
I have a list that looks like:
Movie Year
----- ----
Fight Club 1999
The Matrix 1999
Pulp Fiction 1994
Using CAML and the SPQuery object I need to get a distinct list of items from the Year column which will populate a drop down control.
Searching around there doesn't appear to be a way of doing this within the CAML query. I'm wondering how people have gone about achieving this?
Another way to do this is to use DataView.ToTable-Method - its first parameter is the one that makes the list distinct.
SPList movies = SPContext.Current.Web.Lists["Movies"];
SPQuery query = new SPQuery();
query.Query = "<OrderBy><FieldRef Name='Year' /></OrderBy>";
DataTable tempTbl = movies.GetItems(query).GetDataTable();
DataView v = new DataView(tempTbl);
String[] columns = {"Year"};
DataTable tbl = v.ToTable(true, columns);
You can then proceed using the DataTable tbl.
If you want to bind the distinct results to a DataSource of for example a Repeater and retain the actual item via the ItemDataBound events' e.Item.DataItem method, the DataTable way is not going to work. Instead, and besides also when not wanting to bind it to a DataSource, you could also use Linq to define the distinct values.
// Retrieve the list. NEVER use the Web.Lists["Movies"] option as in the other examples as this will enumerate every list in your SPWeb and may cause serious performance issues
var list = SPContext.Current.Web.Lists.TryGetList("Movies");
// Make sure the list was successfully retrieved
if(list == null) return;
// Retrieve all items in the list
var items = list.GetItems();
// Filter the items in the results to only retain distinct items in an 2D array
var distinctItems = (from SPListItem item in items select item["Year"]).Distinct().ToArray()
// Bind results to the repeater
Repeater.DataSource = distinctItems;
Repeater.DataBind();
Remember that since there is no CAML support for distinct queries, each sample provided on this page will retrieve ALL items from the SPList. This may be fine for smaller lists, but for lists with thousands of listitems, this will seriously be a performance killer. Unfortunately there is no more optimized way of achieving the same.
There is no DISTINCT in CAML to populate your dropdown try using something like:
foreach (SPListItem listItem in listItems)
{
if ( null == ddlYear.Items.FindByText(listItem["Year"].ToString()) )
{
ListItem ThisItem = new ListItem();
ThisItem.Text = listItem["Year"].ToString();
ThisItem.Value = listItem["Year"].ToString();
ddlYear.Items.Add(ThisItem);
}
}
Assumes your dropdown is called ddlYear.
Can you switch from SPQuery to SPSiteDataQuery? You should be able to, without any problems.
After that, you can use standard ado.net behaviour:
SPSiteDataQuery query = new SPSiteDataQuery();
/// ... populate your query here. Make sure you add Year to the ViewFields.
DataTable table = SPContext.Current.Web.GetSiteData(query);
//create a new dataview for our table
DataView view = new DataView(table);
//and finally create a new datatable with unique values on the columns specified
DataTable tableUnique = view.ToTable(true, "Year");
After coming across post after post about how this was impossible, I've finally found a way. This has been tested in SharePoint Online. Here's a function that will get you all unique values for a column. It just requires you to pass in the list Id, View Id, internal list name, and a callback function.
function getUniqueColumnValues(listid, viewid, column, _callback){
var uniqueVals = [];
$.ajax({
url: _spPageContextInfo.webAbsoluteUrl + "/_layouts/15/filter.aspx?ListId={" + listid + "}&FieldInternalName=" + column + "&ViewId={" + viewid + "}&FilterOnly=1&Filter=1",
method: "GET",
headers: { "Accept": "application/json; odata=verbose" }
}).then(function(response) {
$(response).find('OPTION').each(function(a,b){
if ($(b)[0].value) {
uniqueVals.push($(b)[0].value);
}
});
_callback(true,uniqueVals);
},function(){
_callback(false,"Error retrieving unique column values");
});
}
I was considering this problem earlier today, and the best solution I could think of uses the following algorithm (sorry, no code at the moment):
L is a list of known values (starts populated with the static Choice options when querying fill-in options, for example)
X is approximately the number of possible options
1. Create a query that excludes the items in L
1. Use the query to fetch X items from list (ordered as randomly as possible)
2. Add unique items to L
3. Repeat 1 - 3 until number of fetched items < X
This would reduce the total number of items returned significantly, at the cost of making more queries.
It doesn't much matter if X is entirely accurate, but the randomness is quite important. Essentially the first query is likely to include the most common options, so the second query will exclude these and is likely to include the next most common options and so on through the iterations.
In the best case, the first query includes all the options, then the second query will be empty. (X items retrieved in total, over 2 queries)
In the worst case (e.g. the query is ordered by the options we're looking for, and there are more than X items with each option) we'll make as many queries as there are options. Returning approximately X * X items in total.