Suitescript: Workflow Action script sent emails not appearing in transaction tab - netsuite

I have created a workflow action script to send emails so that I can process the incoming messages later on with a email plugin (this might be redundant though I am just experimenting with workflow action scripts at the moment)
This is the script:
/**
*#NApiVersion 2.x
*#NScriptType WorkflowActionScript
*/
define(["N/email", "N/render", "N/record"], function (email, render, record) {
function onAction(context) {
var transaction = context.newRecord;
var transactionId = transaction.getValue({ fieldId: "tranid" });
log.debug("transaction Id", transactionId);
var recipient = transaction.getValue({
fieldId: "custbody_first_approver",
});
var recipientId = parseInt(recipient);
var vendorId = transaction.getValue({ fieldId: "entity" });
var mergeResult = render.mergeEmail({
templateId: 11,
entity: {
type: "vendor",
id: parseInt(vendorId),
},
recipient: {
type: "employee",
id: parseInt(recipient),
},
supportCaseId: null,
transactionId: transactionId,
customRecord: null,
});
var emailSubject = mergeResult.subject;
var emailBody = mergeResult.body;
email.send({
author: -5,
recipients: parseInt(recipient),
subject: "test",
body: emailBody,
relatedRecords: {
transactionId: transactionId,
},
});
}
return {
onAction: onAction,
};
});
The email is being sent though a copy of it only seems to be getting stored against the recipient's (who is an employee) entity record.
Looking at the Netsuite guide on the 'N/email' module, it suggests the
relatedRecords: {
transactionId: transactionId,
},
part of the script should be controlling where the message is stored. However, there is nothing in the transaction record under the related records or any other tab.
What do I need to change to get a copy of the email message saved against the transaction record?
Thanks

I found the cause of the issue. It was this line:
var transactionId = transaction.getValue({ fieldId: "tranid" });
It needed to be
var transactionId = transaction.getValue({ fieldId: "id" });
in order to pick up the internal id of the record and not just the transaction number.
All references to it in the script needed to be converted to integer values since otherwise I kept getting the "Wrong parameter type: options.transactionId is expected as number" error.
I converted this by using parseInt(transactionId) every time I referred to the transaction ID

Related

NetSuite Invoice from Case

Hoping some one may be able to help me out with this error I am receiving... I am working a custom button on the case record that will create an invoice using fields from the case. I have a custom field that is a multi select of all items that can be needed as part of a case. Not all cases require an item, so I will code in logic or workflow to prevent the button from showing up if an item isn't selected and also lock editing and mark the case status as invoiced with a stage of closed once invoice has been created from the record. My problem is that when testing the suitelet I am getting an error when trying to set the subsidiary field and also department. Here is my error: ["type":"error.SuiteScriptError"."name":"INVALID_FLD_VALUE", "message":"You have entered an Invalid Field Value 2 for the following field: subsidiary"
The customer I am testing with is assigned the subsidiary with a internal Id of 2
Below is a portion of my code, I've tried removing quotes in sub value and also trying to set the subsidiary value using the current record.getValue. both throw the same error
function onRequest(context) {
var custom_id = context.request.parameters.custom_id;
var currentRecord = record.load({
type: record.Type.SUPPORT_CASE,
id: custom_id
});
var newRecord = record.create({
type: record.Type.INVOICE,
isDynamic: true
});
newRecord.setValue({
fieldId: 'customform',
value: 122
});
newRecord.setValue({
fieldId: 'entity',
value: currentRecord.getValue('entity')
});
newRecord.setValue({
fieldId: 'otherrefnum',
value: currentRecord.getValue('casenumber')
});
newRecord.setValue({
fieldId: 'subsidiary', value: '2'
});
newRecord.setValue({
fieldId: 'department',
value: '17'
});
newRecord.selectNewLine({
sublistId: 'item'
});
newRecord.setCurrentSublistValue({
sublistId: 'item',
fieldId: 'item',
//value: 46
value: currentRecord.getValue('custevent_multi_select_work_orders')
});
newRecord.setCurrentSublistValue({
sublistId: 'item',
fieldId: 'quantity',
value: '1'
});
}
Any help much appreciated!
Errors I found:
There is a typo when you are loading the Support Case Record. It should be SUPPORT_CASE
var currentRecord = record.load({
type: record.Type.SUPPORT_CASE,
id: custom_id
});
There are many typos like an inverted comma here, hope you look into it
newRecord.setValue({
fieldId: 'customform',
value: 122'
});
Regarding your main Subsidiary issue, you are passing value (2) using Inverted Commas. Try passing it without those
newRecord.setValue({
fieldId: 'subsidiary',
value: 2
});
OR
newRecord.setValue({
fieldId: 'subsidiary',
value: Number(2)
});
Use inverted commas only to pass String value. For Numerical value, don't use them.
Try these changes and let me know if the problem still persist, there are many possibilities to this error!
I know this isn't exactly what you need, but it is fully functioning and you can make customizations/pick-and-choose parts to use. It's a custom function I've used in the past to create a Sales Order from a Case Record. Best of luck!
/**
* case_createSOButton.js
* #NApiVersion 2.x
* #NScriptType ClientScript
*/
define (['N/record', 'N/currentRecord'],
function (record, currentRecord){
//NetSiuite requires the existence of 1 of their functions
function pageInit(context) {
var currentRecord = context.currentRecord;
}
//Button function to create a Sales order and indicate on the Case record the new Sales Order record
//in the UI on the Script record add this function name to the "Buttons" section
function createSO(){
log.audit('function started', 'Cases - Service Case CS createSO');
var caseRecord = currentRecord.get();
//if record is in create mode than do not allow creation of a Sales Order
//mode property is not available, so base it off of id properrty. ids dont exist until record is saved
var caseId = caseRecord.id;
if (!caseId){
alert('You cannot create a Sales Order while creating a new Case.\nPlease save the Case, then try again.');
return;
}
//if sales order already exists, do not allow creation of a new SO
var associatedSO = caseRecord.getValue({fieldId: 'custevent_case_associated_sales_orde'});
if (associatedSO){
alert('Cannot create a Sales Order since "Associated Sales Order" already exists.');
return;
}
//gather info from user
var memo = prompt("What's the reason for the charge?\nThe text below will be copied onto the Sales Order \"Memo\" field.");
//if user clicks cancel, do not continue
if (memo == null){
return;
}
var description = prompt("Enter a description for the Service Work Item.");
//if user clicks cancel, do not continue
if (description == null){
return;
}
var amount = prompt("Enter an amount for the Service Work Item.\nPlease only enter #s, no letters, decimal/cents optional.");
//if user clicks cancel or there's no # value found, do not continue
var hasNumber = /\d/; //validation for confirming the amount variable is a number
hasNumber = hasNumber.test(amount);
if (amount == null){
return;
}
if(hasNumber == false){
alert('No numbers found in entry, please try again.');
return;
}
alert('Please wait for the process to complete before closing this page.');
//declare static values
var customform = 199;
var subsidiary = 2;
var status = 3;
var specialist = 62736;
var channel = 181;
var totalKW = 0;
var lenderPoints = 0;
var today = new Date();
var itemId = 3566;
var lender = 10;
var loanProduct = 37;
//load customer to gather values
var entity = caseRecord.getValue({fieldId: 'company'});
var customerRec = record.load({type: record.Type.CUSTOMER, id: entity});
var location = customerRec.getValue({fieldId: 'custentity_customer_market'})|| null;
var job = caseRecord.getValue({fieldId: 'custevent_case_associated_project'});
//load associated project to gather values
var projectRec = record.load({type: record.Type.JOB, id: job});
var projectMgr = projectRec.getValue({fieldId: 'custentity_project_manager_customer'})|| null;
var engineer = projectRec.getValue({fieldId: 'custentity31'})|| null;
var installMgr = projectRec.getValue({fieldId: 'custentity_install_manager'})|| null;
var state = projectRec.getValue({fieldId: 'custentity_csegmarke'})|| null;
var region = projectRec.getValue({fieldId: 'custentity_cseg2'})|| null;
var market = projectRec.getValue({fieldId: 'custentity_cseg3'})|| null;
//create SO record, set values
var newSORec = record.create({type: record.Type.SALES_ORDER, isDynamic: true});
newSORec.setValue({fieldId: 'customform', value: customform, ignoreFieldChange: false});
newSORec.setValue({fieldId: 'entity', value: entity});
newSORec.setValue({fieldId: 'job', value: job});
newSORec.setValue({fieldId: 'custbody_sostatus', value: status});
newSORec.setValue({fieldId: 'custbody_total', value: totalKW});
newSORec.setValue({fieldId: 'custbody13', value: lenderPoints});
newSORec.setValue({fieldId: 'custbody_fundingissues', value: memo});
newSORec.setValue({fieldId: 'subsidiary', value: subsidiary});
newSORec.setValue({fieldId: 'custbody_finance_specialist', value: specialist});
newSORec.setValue({fieldId: 'saleseffectivedate', value: today});
newSORec.setValue({fieldId: 'custbody_cseglende', value: lender});
newSORec.setValue({fieldId: 'custbody_csegloan', value: loanProduct});
newSORec.setValue({fieldId: 'custbody_project_manager', value: projectMgr});
newSORec.setValue({fieldId: 'custbody_engineer', value: engineer});
newSORec.setValue({fieldId: 'custbody_installmgr', value: installMgr});
newSORec.setValue({fieldId: 'class', value: channel, forceSyncSourcing: true});
newSORec.setValue({fieldId: 'custbody_csegmarke', value: state, forceSyncSourcing: true});
newSORec.setValue({fieldId: 'custbody_cseg2', value: region, forceSyncSourcing: true});
newSORec.setValue({fieldId: 'custbody_cseg3', value: market, forceSyncSourcing: true});
newSORec.setValue({fieldId: 'location', value: location, forceSyncSourcing: true});
//set default line item(s)
newSORec.selectLine({sublistId: 'item', line: 0});
newSORec.setCurrentSublistValue({sublistId: 'item', fieldId: 'item', value: itemId, ignoreFieldChange: false});
newSORec.setCurrentSublistValue({sublistId: 'item', fieldId: 'description', value: description, ignoreFieldChange: false});
newSORec.setCurrentSublistValue({sublistId: 'item', fieldId: 'rate', value: parseInt(amount), ignoreFieldChange: false});
newSORec.commitLine({sublistId: 'item'});
//save new SO
var newSORecId = newSORec.save({enableSourcing: true, ignoreMandatoryFields: false});
//add SO Rec to Case
record.submitFields({
type: record.Type.SUPPORT_CASE,
id: caseRecord.id,
values: {
custevent_case_associated_sales_orde: newSORecId
},
options: {
//enableSourcing: false, //default is true
ignoreMandatoryFields : true //default is false
}
});
//alert user when SO is created and open in a new tab
alert("The new Sales Order will open in a new tab. \n*Reminder - to save this record if you've made changes.");
var url = 'https://1234567.app.netsuite.com/app/accounting/transactions/salesord.nl?id='+newSORecId
window.open(url, '_blank');
log.audit('function end', 'Cases - Service Case CS createSO');
}//end of create SO funciton
return {
pageInit: pageInit,
createSO: createSO
}
}
);

Suitescript that should auto populate the custom field(Primary Contact & Primary Email) when a customer field in sales record is entered by a value

Primary contact and email information should be retrieved from the particular customer, mentioned in the sales order.
I tried the below code, but I'm unable to retrieve the role (Primary Contact) from Customer Record. I'm getting null value(empty) while entering the customer field in sales order and also not auto-populating the custom fields.
function fieldChanged(context)
{
var sales=context.currentRecord;
if(context.fieldId=='entity')
{
var cusid=sales.getValue('entity');
var cust=record.load({
type: record.Type.CUSTOMER,
id:cusid
});
var custid=cust.getText('entityid');
log.debug(custid);
var roleCount= cust.getLineCount({
sublistId :'contactroles',
});
log.debug('count',roleCount);
for(var i=0;i<roleCount;i++)
{
var roleName=cust.getSublistText({ sublistId : 'contactroles',fieldId : 'contactrole', line:i});
log.debug('role',roleName);
if(roleName=='Primary Contact')
{
var emailinfo=cust.getSublistText({ sublistId : 'contactroles',fieldId : 'email', line:i});
sales.setValue('custbody_primary_email',emailinfo);
}
}
}
}
function fieldChanged(context) {
try {
var sales = context.currentRecord;
if (context.fieldId == 'entity') //checking whether the cursor is in customer field or not
{
var cusid = sales.getValue('entity'); //retrieving the id of customer in salesOrder
var cust = record.load({ //loading the customer record using above id
type: record.Type.CUSTOMER,
id: cusid
});
log.debug('customer id', cusid);
var custid = cust.getText('entityid');
log.debug(custid);
var roleCount = cust.getLineCount({ //counting the lines in sublist (customer record)
sublistId: 'contactroles'
});
log.debug('count', roleCount);
for (var i = 0; i < roleCount; i++) //traversing the list in sublist(contact list)
{
var roleId = cust.getSublistValue({
sublistId: 'contactroles',
fieldId: 'contact',
line: i
});
log.debug('role id', roleId);
var contactRecord = record.load({ //loading the contact record
type: record.Type.CONTACT,
id: roleId
});
var roleName = contactRecord.getValue({ //fetching the role in contact record
fieldId: 'contactrole'
});
var phone1 = contactRecord.getText('phone');
var emailinfo = contactRecord.getText('email');
if (roleName == '-10') //checking whether it is primary contact or not(primary contact id is -10)
{
sales.setValue('custbody_primary_email', emailinfo);//setting the custom fields )
sales.setValue('custbody_primary_contact', phone1);
}
}
}
} catch (e) {
log.error('Error Occurred in Updating Values' + e.message);
}
}
You need to reference a customer field 'contact'. This field will give you the internal id of primary contact. From there you can build a logic to get the information out of the primary contact.
There's no contactrole field in the contactroles sublist. See the Records Browser for correct field IDs.

suitescript 2.0 : How to modify and save subrecord in clientscript

I'm trying to modify and save subrecord in clientscript, but when it is saved, I get the following error:
"Cannot read property 'invalidateCurrentSublistLineForSubrecordCache' of undefined"
Current code:
/**
* #NApiVersion 2.x
* #NModuleScope public
*/
define(['N/record','N/currentRecord','N/search'],
function(record,currentRecord,search) {
return({
stock: function(context) {
var curRec = currentRecord.get();
var ab_search = search.create({
type: search.Type.TRANSACTION,
title: 'YXZC_Assembly_Build_Search',
id: 'customsearch_yxzc_assembly_build_search',
columns: ['internalid'],
filters: [
['createdfrom', 'is', curRec.id],'and',['type','is','Build']
]
});
ab_search.save();
var searchResult = ab_search.run().getRange({
start: 0,
end: 1
})[0];
var internalid = searchResult.getValue(searchResult.columns[0]);
search.delete({
id: 'customsearch_yxzc_assembly_build_search'
});
var rec = record.load({
type: record.Type.ASSEMBLY_BUILD,
id: internalid,
// isDynamic: true,
});
var inventorydetailRec = rec.getSubrecord({
fieldId: 'inventorydetail',
});
var line = inventorydetailRec.getLineCount({
sublistId: 'inventoryassignment'
});
for (var i=0; i<line; i++){
inventorydetailRec.setSublistValue({
sublistId:'inventoryassignment',
fieldId: 'inventorystatus',
line: i,
value: '2'
});
};
var recId = rec.save({
enableSourcing: true,
ignoreMandatoryFields: true
});
}
});
});
I am not sure what invalidateCurrentSublistLineForSubrecordCache property means.
What does anyone know about why this error is occurring?
Try the record.submitFields()
See https://system.netsuite.com/app/help/helpcenter.nl?fid=section_4267283788.html
I have just stumbled upon your question since I had the same issue but found a solution by the help of #erictgrubaugh
Subrecords are read-only for client scripts. Clients scripts are able to delete a subrecord from a parent record, but they can not modify them. See Supported Deployments for Subrecord Scripting in the NetSuite help

Transformation from Sales Order to Item Fulfillment Error

I'm having some trouble transforming a sales order to item fulfillment. Here is my code:
/**
* #NApiVersion 2.x
* #NScriptType UserEventScript
* #NModuleScope SameAccount
*/
define(['N/record', 'N/log'],
function(record, log) {
function afterSubmit(context) {
var orderId = context.newRecord.id;
var fulfillmentRecord = record.transform({
fromType: record.Type.SALES_ORDER,
fromId: orderId,
toType: record.Type.ITEM_FULFILLMENT,
isDynamic: true
});
fulfillmentRecord.setValue({
fieldId: 'location',
value: 'San Francisco'
});
log.error({
title: 'Debug Entry',
details: fulfillmentRecord
});
var rid = fulfillmentRecord.save();
}
return {
afterSubmit: afterSubmit
};
});
I keep getting this error, which is a little confusing because I don't know what they mean by "stack":
{"type":"error.SuiteScriptError",
"name":"USER_ERROR",
"message":"Please provide values for the following fields in the Items list: Location",
"stack":["anonymous(N/serverRecordService)",
"afterSubmit(/SuiteScripts/fulfillmentCreator.js:23)"],
"cause":{
"type":"internal error",
"code":"USER_ERROR",
"details":"Please provide values for the following fields in the Items list: Location",
"userEvent":"aftersubmit",
"stackTrace":["anonymous(N/serverRecordService)","afterSubmit(/SuiteScripts/fulfillmentCreator.js:23)"],"notifyOff":false},"id":"","notifyOff":false}
I see that you have set the location field at the header but based on the error, you will also need to set the location field on the item sublist.
Looking at the record browser, I cannot see any location field on Fulfillment header https://system.netsuite.com/help/helpcenter/en_US/srbrowser/Browser2020_1/script/record/itemfulfillment.html
This should work:-
function afterSubmit(context) {
var orderId = context.newRecord.id;
var fulfillmentRecord = record.transform({
fromType: record.Type.SALES_ORDER,
fromId: orderId,
toType: record.Type.ITEM_FULFILLMENT,
isDynamic: true
});
var lineCount = fulfillmentRecord.getLineCount({sublistId:'item});
for(var i=0;i<lineCount; i++){
fulfillmentRecord.selectLine({sublistId:'item',line:i});
fulfillmentRecord.setCurrentSublistValue({
sublistId:'item',
fieldId: 'location',
value: '123' //Enter the location internal id, instead of name i.e San Francisco
});
}
log.error({
title: 'Debug Entry',
details: fulfillmentRecord
});
var rid = fulfillmentRecord.save();
}
This error comes when Netsuite can't fetch value that you are assigning in the script. Location is List/Record type. And you are setting location based on value. Try to use setText instead of setValue.

How to send Email with Letter Template Using suite script

I am trying to send an email using suitescript2 i am trying to attach the the Letter template programaticaly. Is there any way attach my custom letter template?
function templatemerge() {
var myMergeResult = render.mergeEmail({
templateId: 12,
entity: {
type: 'customer',
id: 31921
},
recipient: {
type: 'customer',
id: 31921
},
supportCaseId: 'NULL',
transactionId: 'NULL',
customRecord: 'custrecordid'
});
}
templatemerge();
function sendEmailWithAttachement() {
var newId = context.newRecord;
var emailbody = 'attachment';
var senderId = -5;
var recipientEmail = 'red#imi.com';
email.send({
author: senderId,
recipients: recipientEmail,
subject: 'Item Fulfillments',
body: emailbody
});
}
sendEmailWithAttachement();
If, by letter template, you mean email template. Here is a basic idea (I pulled that part from a larger script file that I am using) of how to do it.
var emailTemp4=nlapiLoadRecord('emailtemplate',emailTempID4);
var emailSubj4=emailTemp4.getFieldValue('subject');
var emailBody4=emailTemp4.getFieldValue('content');
var renderer4=nlapiCreateTemplateRenderer();
renderer4.setTemplate(emailSubj4);
renderSubj4=renderer4.renderToString();
renderer4.setTemplate(emailBody4);
renderBody4=renderer4.renderToString();
nlapiSendEmail(-4,'RecipientEmail#domain.com',renderSubj4,renderBody4,null,null);

Resources