Issue with List Apply in NetSuite - netsuite

Unable to find a matching line for sublist apply with key: [doc,line] and value: [5489377,1].
I'm seeing this error when I try to update an apply list on a NetSuite transaction object. The "doc" is the internal ID of the object, and the line number seems to correspond to a line number on the object.
Why is this happening? Can't seem to find a solution.

This works for applying a credit memo to a particular invoice. invId is the internalid of the invoice record:
function applyPayment(creditMemo, payAmount, invId){
var didApply = false;
creditMemo.setFieldValue('autoapply', 'F');
if(payAmount === null) payAmount = creditMemo.getFieldValue('amountremaining');
for(var i = 1; i<=creditMemo.getLineItemCount('apply'); i++){
if(invId == creditMemo.getLineItemValue('apply', 'doc', i)){
didApply = true;
creditMemo.setLineItemValue('apply', 'apply', i, 'T');
creditMemo.setLineItemValue('apply', 'amount',i, payAmount);
}else if('T' == creditMemo.getLineItemValue('apply', 'apply', i)) creditMemo.setLineItemValue('apply', 'apply', i, 'F');
}
if(didApply) nlapiSubmitRecord(creditMemo);
}

We were getting this error with the Chargebee-Netsuite integration and the solution was to open the corresponding Accounting Period in Netsuite and rerun the sync.
Like you mentioned, the first number[5489377,1] is the Netsuite internal ID of the affected document. If you navigate to the document in Netsuite and it has a padlock this could be the reason Locked document
Open the Accounting Period for the affected document and rerun the sync. setup/accounting/manage accounting periods Manage accounting periods

Related

NetSuite Suitescript 2.0 How can I access custom item options records?

I have a problem that I'm trying to solve in a roundabout way since the straightforward way didn't work.
The task: Retrieve the customizable item options off of a purchase order item (using SuiteScript 2.0).
The partial solution: Currently, I extract the itemId off the PO using
po.getCurrentSublistValue({ sublistId: 'item', fieldId: 'item' });
Then I load the item and extract the item options IDs and labels using
var optionIds = item.getValue({ fieldId: 'itemoptions' });
var optionLabels = item.getText({ fieldId: 'itemoptions' });
For item options that aren't List/Record type, (like freeform text personalization), I can then loop through the item options and extract their text off of the PO item using the following code.
for (var j = 0; j < optionIds.length; j++) {
var option = po.getCurrentSublistText({
sublistId: 'item',
fieldId: optionIds[j].toLowerCase()
});
if (option !== null) {
log.debug({title: 'option found', details: optionLabels[j] + ': ' + option});
}
}
The issue: When the item option is a List/Record type, both getCurrentSublistText and getCurrentSublistValuereturn the internal ID of the list selection. For instance, if I have a custom item option for Shirt Color, and it uses the custom list Color, with Red being internal ID 2, then if my PO has an item with red shirt color on it, the option label will be "Shirt Color", but instead of "Red," the option will be 2, the internal ID from the Color list. I have no idea why getCurrentSublistText doesn't work for this use case, but I've accepted it, and I'm looking for a workaround.
My thought was, since the item option is a record in the UI (my field explorer extension says it has recordType:"itemoptioncustomfield"), I could just load it up using the option ID that I have, and if it has fieldtype:"SELECT", I would get the internal ID of the List/Record selection (fieldId: selectrecordtype) then use search.lookupFields to get the actual value of my item option, instead of the internal ID. The only issue is, I can find no way to load (or search on) an item option. The record type does not seem to exist in SuiteScript (I believe in Suite Talk it does though). Is this a possible task? Even if my workaround can't work, is there another better workaround that I'm not seeing?
Thanks in advance, I'm at a loss here.
Edit: Just to add further attempts, I found the Field.getSelectOptions() function today which looked really promising, since it would list all the select options of the item option and their values I would think. I tested it out on some other more basic fields on the order and it worked, however when I tried using getCurrentSublistField on the item option field (just as I used getCurrentSublistValue and getCurrentSublistText, the field returned was null, so looks like that is another dead end.

Creating Item Receipts from POs via SuiteScript

I'm in the process of creating a module to handle multi-PO consolidated shipments (fx imports) and writing a script to receive multiple POs with landed costs per line.
I'm using SuiteScript API 1.0
However, when I create the Item Receipt record (and include the PO# in the createdfrom field to create the link from IR to PO, during the process of copying the PO lines to the IR lines, I'm getting constant SSS_INVALID_SUBLIST_OPERATION errors.
The code in question is below:
// ** set body fields
receiptRec.setFieldValue('location',purchRec.getFieldValue('location'));
receiptRec.setFieldValue('entity',purchRec.getFieldValue('entity'));
receiptRec.setFieldValue('createdfrom',purchRec.getFieldValue('internalid'));
receiptRec.setFieldValue('currency',purchRec.getFieldValue('currency'));
receiptRec.setFieldValue('exchangerate',purchRec.getFieldValue('exchangerate'));
receiptRec.setFieldValue('isbasecurrency',purchRec.getFieldValue('isbasecurrency'));
receiptRec.setFieldValue('exchangerate',purchRec.getFieldValue('exchangerate'));
receiptRec.setFieldValue('landedcostperline','T');
log ('Receipt Record:'); log( receiptRec );
// ** copy item lines
var POlines = purchRec.getLineItemCount('item');
for ( line=1 ; line<=POlines; line++) {
var fulfill = purchRec.getLineItemValue('item','fulfillable',line); log('Fulfill?? '+fulfill)
if (fulfill == 'T') {
log('Fill From PO Line #'+line);
receiptRec.selectNewLineItem('item'); log('Debug 1');
receiptRec.setCurrentLineItemValue('item','item',purchRec.getLineItemValue('item','item',line)); log('Debug 2');
receiptRec.setCurrentLineItemValue('item','itemreceive','T',line); log('Debug 3');
receiptRec.setCurrentLineItemValue('item','quantity',purchRec.getLineItemValue('item','quantity',line)); log('Debug 4');
receiptRec.setCurrentLineItemValue('item','rate',purchRec.getLineItemValue('item','rate',line)); log('Debug 5');
receiptRec.setCurrentLineItemValue('item','taxcode',purchRec.getLineItemValue('item','taxcode',line)); log('Debug 6');
receiptRec.setCurrentLineItemValue('item','units',purchRec.getLineItemValue('item','units',line)); log('Debug 7');
receiptRec.commitLineItem('item'); log('Debug 8');
}
}
The error is triggering at the selectNewLineItem('item') point.
receiptRec is the newly created itemreceipt record.
purchRec is the existing purchase order record.
What am I missing here?
You cannot "create" a new Item Receipt record in Netsuite. You need to "transform" a Purchase Order into an Item Receipt using nlapiTransformRecord('purchaseorder', purchaseorderid, 'itemreceipt'). This will automatically copy all the line items, and then you can iterate through them to change quantities or remove lines completely, however you cannot add new lines.
See this link in the documentation for more information.

NetSuite - using nlapiCopyRecord function

I am generating an invoice when the original invoice is overdue by a certain time period. I want to know if we can use the nlapiCopyRecord to make a copy of the original invoice but allow us to insert a new line that will replace the old line item? I haven't found any sample to show how this is done.
Thanks.
Edit 1:
var new_inv = nlapiCopyRecord('invoice', internal_id,
{
item : 66,
amount: amount,
description: 'TEST'
});
var copiedId = nlapiSubmitRecord(new_inv);
return copiedId;
Above code fails in my scheduled script. You have entered an invalid default value for this record initialize operation.
I would like to override the line item on the newly copied invoice
Yes that is possible, just like if you copy a record in the UI you can modify the copy. You also need to remember that you need to save the record object after you have copied it.
Why are you doing this? If you are trying to charge a late fee you'd probably be better off by adding an expense line to the original invoice record. If you don't have expenses turned on then you could add an other "Other Charge for Sale"
If your code is running server side then:
var invRec = nlapiLoadRecord('invoice', internal_id);
var chargeIndex = invRec.getLineItemCount('item') + 1;
// don't think you need this for the end position invRec.insertLineItem('item', chargeIndex);
invRec.setLineItemValue('item', 'item', chargeIndex, charge_item_id);
invRec.setLineItemValue('item', 'rate', chargeIndex, amount);
invRec.setLineItemValue('item', 'amount', chargeIndex, amount);
nlapiSubmitRecord(invRec);
OR if you use an expense
var invRec = nlapiLoadRecord('invoice', internal_id);
invRec.insertLineItem('expense', 1);
invRec.setLineItemValue('expense', 'account', 1, penalty_account);
invRec.setLineItemValue('expense', 'amount', 1, amount);
invRec.setLineItemValue('expense', 'memo', 1, 'TEST');
nlapiSubmitRecord(invRec);

Select parts of a nlobjSearchResult

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.

Calculated Field on CRM Entity

I have a 1:N relationship between Account and Portfolios in Dynamics CRM
I.e each account has multiple Portfolios and Each Portfolio has Specific Assets.
I am trying to create a field on Account Form which calculates the sum of "ALL Assets of All related portfolios" of the account and display it on the Account form
As a workaround,I tried to create a Portfolio view grouping by Account but it doesnt SUM and rollup the Portfolio assets to Account level.
So on account Form i am trying to create a textfield which calculates the Total Account Assets to be $25,000 in this example
function setupGridRefresh() {
var targetgrid = document.getElementById("NAME OF SUBGRID");
// If already loaded
if (targetgrid.readyState == 'complete') {
targetgrid.attachEvent("onrefresh", subGridOnload);
}
else {
targetgrid.onreadystatechange = function applyRefreshEvent() {
var targetgrid = document.getElementById("NAME OF SUBGRID");
if (targetgrid.readyState == 'complete') {
targetgrid.attachEvent("onrefresh", subGridOnload);
}
}
}
subGridOnload();
}
function subGridOnload() {
//debugger;
var grid = Xrm.Page.ui.controls.get('NAME OF SUBGRID')._control;
var sum = 0.00;
if (grid.get_innerControl() == null) {
setTimeout(subGridOnload, 1000);
return;
}
else if (grid.get_innerControl()._element.innerText.search("Loading") != -1) {
setTimeout(subGridOnload, 1000);
return;
}
var ids = grid.get_innerControl().get_allRecordIds();
var cellValue;
for (i = 0; i < ids.length; i++) {
if (grid.get_innerControl().getCellValue('FIELD NAME LOWER CASE', ids[i]) != "") {
cellValue = grid.get_innerControl().getCellValue('FIELD NAME LOWER CASE', ids[i]);
cellValue = cellValue.substring(2);
cellValue = parseFloat(cellValue);
sum = sum + cellValue;
}
}
var currentSum = Xrm.Page.getAttribute('DESTINATION FIELD').getValue();
if (sum > 0 || (currentSum != sum && currentSum != null)) {
Xrm.Page.getAttribute('DESTINATION FIELD').setValue(sum);
}
}
I pieced this together from a couple of sources and currently use it one of my solutions. Let me know if you need some more help or if I've misread the question. (Btw, this solution is based on the assumption that you need the total to change when the subgrid has entries added or removed. If this is not the requirement, I would suggest the RetrieveMultiple OData call.)
Take a look at AutoSummary from Gap Consulting, well worth the cost. Or spend time to build your own. You need a field on the Account record which is updated every time you:
create a Portfolio record
update the value in a Portfolio record
delete a Portfolio record
re-parent a Partfolio record from one Account to another
The first two are easy enough to do with workflow or javascript on the onSave event on the portfolio. Third can only be done by workflow, not javascript (I think). Last one would need onLoad javascript to store current value of Account lookup so that onSave can compare and then decrement one and increment the other. All four could be done with a plugin.
Although this has been answered already, I'll put a second option on the plate for you. Take a look at FormulaManager from North 52 as well. You get a certain amount of Formulas for free so it might be an even more cost effective solution.
Update
To add to this, if the field is solely for reporting a value (and doesn't need to be saved to the database) then rather than using a physical field and plugins you could build a Web Resource that executes an Aggregated FetchXml query and simply displays the resulting value.
Again, this is something that I know Formula Manager does out of the box. Have never used Auto Summary.

Resources