Update Existing Line Item Values in Netsuite SuiteScript 2.0 - netsuite

No matter what I do, I can't update the line item values in an inbound shipment record. I have a ton of debug statements, and I know that I technically am at the correct line, but when I try to get or set values, they are empty.
I am working in dynamic mode, and so in order to loop, I found something online that said I needed to stringify the record. I see all the correct data, but any time I try to manipulate the values, it doesn't do anything, or the values are empty. I also keep getting asked to provide the required fields, but for this particular line, they are already there.
Here is my code:
function doPost(restletBody){
log.debug('Called from POST', restletBody);
var success = [],
errors = [];
restletBody.data.forEach(function(e)
{
try
{
//Inbound Shipment Stuff
var ibsID = e.ibShipments.inboundShipmentRecordID;
var containerNumber = e.ibShipments.containerNumber;
var memo = e.ibShipments.memo;
var cargoReturnDate = e.ibShipments.cargoReturnDate;
var billoflading = e.ibShipments.billoflading;
var quantityexpected = e.ibShipments.quantityexpected;
var destCountry = e.ibShipments.destCountry;
var actualdeliverydate = e.ibShipments.actualdeliverydate;
var expecteddeliverydate = e.ibShipments.expecteddeliverydate;
var poDueDate = e.ibShipments.poDueDate;
var shipmentstatus = e.ibShipments.shipmentstatus;
var factory = e.ibShipments.factory;
var vesselNumber = e.ibShipments.vesselNumber;
var actualshippingdate = e.ibShipments.actualshippingdate;
var expectedshippingdate = e.ibShipments.expectedshippingdate;
var vesselBookingNumber = e.ibShipments.vesselBookingNumber;
var bookingDate = e.ibShipments.bookingDate;
var recID = null;
if((ibsID == "" || ibsID == null) && (containerNumber != "" || memo != "" || cargoReturnDate != "" ||
billoflading != "" || quantityexpected != "" || destCountry != "" || actualdeliverydate != "" ||
expecteddeliverydate != "" || poDueDate != "" || shipmentstatus != "" || factory != "" || vesselNumber != "" ||
actualshippingdate != "" || expectedshippingdate != "" || vesselBookingNumber != "" || bookingDate != ""))
{
//Create a new record
log.debug('Create Record', "");
var rec =
r.create({
type: "inboundshipment",
isDynamic: true,
defaultValues: null
});
//Might need to save the record, then add the fields
recID = rec.save();
var i = 1;
}
else
{
log.debug('Update Record Instead', ibsID);
recID = ibsID;
}
var inboundShipmentUpdate = r.load({
type: 'inboundshipment',
id: recID,
isDynamic: true
});
//Get Values from purchase order
var poID = e.poID;
var poName = e.poName;
var poShipDate = e.poShipDate;
var poShipWindowStart = e.poShipWindowStart;
if(poShipWindowStart != "")
poShipWindowStart = new Date(poShipWindowStart);
else
poShipWindowStart = "";
var poShipWindowEnd = e.poShipWindowEnd;
if(poShipWindowEnd != "")
poShipWindowEnd = new Date(poShipWindowEnd);
else
poShipWindowEnd = "";
//Item Fields
var itemID = e.items.itemID;
var itemDisplayName = e.items.displayName;
var itemName = e.items.name;
//Get Values from inbound shipment entry
var shipmentnumber = e.ibShipments.shipmentnumber;
var bookingDate = e.ibShipments.bookingDate;
if(bookingDate != "")
bookingDate = new Date(bookingDate);
else
bookingDate = "";
var vesselBookingNumber = e.ibShipments.vesselBookingNumber;
var expectedshippingdate = e.ibShipments.expectedshippingdate;
if(expectedshippingdate != "")
expectedshippingdate = new Date(expectedshippingdate);
else
expectedshippingdate = "";
var actualshippingdate = e.ibShipments.actualshippingdate;
if(actualshippingdate != "")
actualshippingdate = new Date(actualshippingdate);
else
actualshippingdate = "";
var vesselNumber = e.ibShipments.vesselNumber;
var containerNumber = e.ibShipments.containerNumber;
var factory = e.ibShipments.factory;
var shipmentStatus = e.ibShipments.shipmentstatus;
var poDueDate = e.ibShipments.poDueDate;
var expecteddeliverydate = e.ibShipments.expecteddeliverydate;
if(expecteddeliverydate != "")
expecteddeliverydate = new Date(expecteddeliverydate);
else
expecteddeliverydate = "";
var actualdeliverydate = e.ibShipments.actualdeliverydate;
if(actualdeliverydate != "")
actualdeliverydate = new Date(actualdeliverydate);
else
actualdeliverydate = "";
var destCountry = e.ibShipments.destCountry;
var quantityexpected = e.ibShipments.quantityexpected;
var quantityreceived = e.ibShipments.quantityreceived;
var billoflading = e.ibShipments.billoflading;
var cargoReturnDate = e.ibShipments.cargoReturnDate;
if(cargoReturnDate != "")
cargoReturnDate = new Date(cargoReturnDate);
else
cargoReturnDate = "";
var memo = e.ibShipments.memo;
//Set Field Values
inboundShipmentUpdate.setValue('actualshippingdate', actualshippingdate);
inboundShipmentUpdate.setValue('actualdeliverydate',actualdeliverydate);
inboundShipmentUpdate.setValue('custrecord_kk_booking_date', bookingDate);
inboundShipmentUpdate.setValue('custrecord_kk_cargo_return_dt',cargoReturnDate);
inboundShipmentUpdate.setValue('expectedshippingdate',expectedshippingdate);
inboundShipmentUpdate.setValue('expecteddeliverydate',expecteddeliverydate);
inboundShipmentUpdate.setValue('shipmentmemo', memo);
inboundShipmentUpdate.setValue('externaldocumentnumber',containerNumber);
//inboundShipmentUpdate.setValue('shipmentstatus',shipmentStatus);
inboundShipmentUpdate.setValue('billoflading',billoflading);
inboundShipmentUpdate.setValue('custrecord_kk_vesselbooking_number',vesselBookingNumber);
inboundShipmentUpdate.setValue('vesselnumber',vesselNumber);
inboundShipmentUpdate.setValue('custrecord_kk_destination',destCountry);
log.debug("Inside Line Items", e.items.itemID + " " + poID);
//The item must be unique, so it cannot already be on the inbound shipment. Do not set the current sublist value to the item
//if it already exists
var objCurRecIBS = JSON.parse(JSON.stringify(inboundShipmentUpdate));
log.debug("objCurRecIBS", objCurRecIBS );
var objSublistsIBS = objCurRecIBS.sublists ? objCurRecIBS.sublists : '';
log.debug("objSublistsIBS", objSublistsIBS );
var objIBSItems = objSublistsIBS.items ? objSublistsIBS.items : '';
log.debug("objIBSItems", objIBSItems );
var itemLineCountIBS = Object.keys(objSublistsIBS.items).length; //First Item is an empty item
var itemPresent = false;
//First Item is an empty item, so start at 1
for (var k = 1; k < itemLineCountIBS; k++)
{
//This keeps coming back empty
var currentQuantity = inboundShipmentUpdate.getCurrentSublistValue({
sublistId: "items",
fieldId: "quantityexpected"
});
log.debug("Current Quantity", currentQuantity + "Line " + k );
//So does this
var currentItem = inboundShipmentUpdate.getCurrentSublistValue({
sublistId: "items",
fieldId: "shipmentitem"
});
log.debug("Current Item", currentItem + "Line " + k );
var currItemIDIBS = objIBSItems[Object.keys(objSublistsIBS.items)[k]].itemid;
log.debug("Current Line Item Id", currItemIDIBS);
var currentLineIBS = objIBSItems[Object.keys(objSublistsIBS.items)[k]];
log.debug("cURRENT iTEM IBS Line", currentLineIBS);
if(currItemIDIBS == itemID)
{
//Update the existing line, since it is already present
itemPresent = true;
log.debug("Current Item Exists in the IBS", itemPresent);
//This is empty, too
var linePO = inboundShipmentUpdate.getCurrentSublistValue({
sublistId: "items",
fieldId: "purchaseorder"
});
log.debug("Line PO: ", linePO);
var currentQuantity = inboundShipmentUpdate.getCurrentSublistValue({
sublistId: "items",
fieldId: "quantityexpected"
});
log.debug("Current Quantity", currentQuantity + "Line " + k );
var newQuantity = currentQuantity + 2;
log.debug("New Quantity", newQuantity );
inboundShipmentUpdate.selectLine({
sublistId: 'items',
line: k
});
inboundShipmentUpdate.setCurrentSublistValue({
sublistId: "items",
fieldId: "quantityexpected",
value: newQuantity
//quantityexpected
});
inboundShipmentUpdate.commitLine({sublistId:"items"});
log.debug("Inside SELECT Line Items", "Line Committed" );
}
}
if(!itemPresent)
{
log.debug("Inside Item Present Check", itemPresent);
inboundShipmentUpdate.setCurrentSublistValue({
sublistId: "items",
fieldId: "shipmentitem",
value: shipmentitem
});
inboundShipmentUpdate.setCurrentSublistValue({
sublistId: "items",
fieldId: "quantityexpected",
value: quantityexpected
});
log.debug("Inside Line Items", "Shipment ITEM Added " + shipmentitem );
inboundShipmentUpdate.commitLine({sublistId:"items"});
log.debug("Inside Line Items", "Line Committed" );
}
++i;
inboundShipmentUpdate.save();
}
catch(err)
{
var msg = '';
log.debug("There was an error", err);
}
})
return "";
}
Does anyone have any idea why everything is coming back empty for me when I try to use NetSuite's methods, but showing correctly when I read the actual record's JSON?

I made this much more difficult than I needed to. I used the findSublistLineWithValue function, and was able to get the correct line value (it WAS 0, for whatever reason the json of the object was coming back with two entries, the first being empty values, so I incorrectly assumed that was line 0). I also had to compare against an actual string instead of a value, or I would get -1.
var lineNumber = inboundShipmentUpdate.findSublistLineWithValue({
sublistId: 'items',
fieldId: 'itemid',
value: itemID.toString()
});
Once I did this, I was able to get the correct values using my other methods. I just really dumbed down my api calls, and that helped me figure out what was going on.

Related

Suitescript 2.0 record.load either Lead or Prospect

I created a user event script that updates a lead custom field from a new phone call record on afterSubmit. It loads the customer from the id of the entity id on the phone call event. It works fine, but it loads a lead record only. How do I fine tune this script to get the entity type and then use that to determine which record type to load?
function afterSubmit(context) {
var phoneRec = context.newRecord;
var checkbox1 = phoneRec.getValue({
fieldId: 'custevent_field1'
});
var checkbox2 = phoneRec.getValue({
fieldId: 'custevent_field2'
});
var custId = phoneRec.getValue({
fieldId: 'company'
});
if(custId && checkbox1 == true) {
var loadedcust = record.load({
type : record.Type.LEAD,
id : custId});
loadedcust.setValue({
fieldId:'custentity_filed1',
value: true });
loadedcust.save();
}
if(custId && checkbox2 == true) {
var loadedcust = record.load({
type : record.Type.LEAD,
id : custId});
loadedcust.setValue({
fieldId:'custentity_field2',
value: true });
loadedcust.save();
}
}
return {afterSubmit}
Not sure how to pull more entity information from just the id value. Any insight will help.
Yes you should be able to use just customer.
Also unless your values are exclusive you can also do the following to make the return quicker:
define(['N/record',...], function(record,...){ // include record module in your define
function afterSubmit(context) {
var phoneRec = context.newRecord;
var checkbox1 = phoneRec.getValue({
fieldId: 'custevent_field1'
});
var checkbox2 = phoneRec.getValue({
fieldId: 'custevent_field2'
});
var custId = phoneRec.getValue({
fieldId: 'company'
});
var updates = {};
var anyUpdate = false;
if(custId && checkbox1 == true) {
updates.custentity_filed1 = true; //not field1?
anyUpdate = true;
}
if(custId && checkbox2 == true) {
updates.custentity_field2 = true;
anyUpdate = true;
}
if(anyUpdate){ //single update. No need to load record twice nor submit it twice.
record.submitFields({
type:'customer',
id:custId,
values:updates
})
}
}
return {afterSubmit}
}

RCRD_DSNT_EXIST while creating user event script with aftersubmit function

I'm trying to write a user event script which loads the current record and populates a line item value through search after submit record. But, it is giving an error RCRD_DSNT_EXIST, even though the record exists.
function afterSubmit_SO(type){
try
{
//var record_type = nlapiGetRecordType();
var recordID = nlapiGetRecordId();
var context = nlapiGetContext();
var recordOBJ = nlapiLoadRecord('salesorder',recordID);
var source = context.getExecutionContext();
if(source == 'userinterface')
{
var line_count = recordOBJ.getLineItemCount('item');
nlapiLogExecution('DEBUG', 'line count ', line_count);
for(var i = 1; i <= line_count; i++)
{
var itemID = recordOBJ.getLineItemValue('item','item',i);
nlapiLogExecution('DEBUG', 'item ID', itemID);
var filter = new Array();
filter[0] = new nlobjSearchFilter('internalid', null, 'is', itemID);
var columns = new Array();
columns[0] = new nlobjSearchColumn('custitem_web_market_availability');
var a_search_results = nlapiSearchRecord('item',null,filter,columns);
if(a_search_results)
{
for(var x = 0; x < a_search_results.length; x++)
{
var item_web_availability = a_search_results[x].getText('custitem_web_market_availability');
nlapiLogExecution('DEBUG', 'value', item_web_availability);
}
} recordOBJ.setLineItemValue('item','custcol_web_item_availability',i,item_web_availability);
}
var submitID = nlapiSubmitRecord(recordOBJ, true, true);
}
}
catch(exception)
{
nlapiLogExecution('DEBUG','Exception Caught ','' + exception);
}
return true;
}```
It could be that your script is executing on the delete operation. I did not see any checking for this in the code you provided. If it is a delete operation then the after submit user event script wont be able to load the deleted record, this is why you get the error.
The type parameter of your afterSubmit function should contain the operation type. You can something like if (type == 'delete') { return true;} at the top of your script.

How to iterate a loop in nodejs

I have a json variable
var a = { Account: [ 'Name', 'Site', 'BillingState', 'Phone', 'Type', 'Owner.Alias' ],
Contact: [ 'Name1', 'Site1' ] }
and i am iterating loop like this
app.post('/', function (req, res) {
a = req.body.table_structure
b = createSelectQuery(a) res.send(b) // this return only "FROM CONTACT" })
Where i have created another function hoping i could in return get the desired string but the loop went async
function createSelectQuery(a){
var selectQuery = "Select "
var obj = JSON.parse(a);
for (var c in obj){
for (var d in obj[c]){
selectQuery += obj[c][d] + ', '
}
selectQuery = "FROM "+c
}
return selectQuery
}
I am expecting result "SELECT Name, .. etc from Account but getting
only FROM Account as output
Try this
function createSelectQuery(a){
var selectQuery = "Select ";
var obj = JSON.parse(a);
for (var c in obj) {
selectQuery += obj[c].join(", ") + " FROM " + c;
}
return selectQuery;
}
you need to use callback which will make your looping synchronous
I belive because in JSON file 'Account' is array and you try to loop in to it as if it was an object. Try :
function createSelectQuery(a){
var selectQuery = "Select "
var obj = JSON.parse(a);
for (var c in obj){
for (var d=0; d < obj[c].length; d++){
selectQuery += obj[c][d] + ', '
}
selectQuery = "FROM "+c
}
return selectQuery
}
Instead of loop, you can try join the string using arr.join() and then append the string with Object.keys. That will do the trick
var selectQuery = "Select ";
var a = { Account: [ 'Name', 'Site', 'BillingState', 'Phone', 'Type', 'Owner.Alias' ]};
var obj = a;
var arr = obj['Account'];
var joinStr = arr.join(',').toString();
selectQuery = selectQuery +" "+joinStr +" FROM "+Object.keys(a);
console.log(selectQuery);

Create Purchase receipt from Purchase order through web service

We are trying to create a PO receipt document that is linked to a PO document. Below is the code, but after submitting the selection of PO lines, the webservice not returning any results. Later it gives an execution time out exception.
apitest.Screen context = BuisnessLogicACU.context;
PO302000Content PORcptSchema;
try
{
PORcptSchema = context.PO302000GetSchema();
}
catch
{
BuisnessLogicACU.contextLogin();
PORcptSchema = context.PO302000GetSchema();
}
PORcptSchema.Actions.AddPOOrderLine2.Commit = true;
//header
AcumaticaInterface.apitest.Command[] Document = new AcumaticaInterface.apitest.Command[]
{
PORcptSchema.Actions.Insert,
new Value
{
Value = BPCode,
LinkedCommand = PORcptSchema.DocumentSummary.Vendor,
Commit = true
},
new Value
{
Value = BPRefNbr ,
LinkedCommand = PORcptSchema.DocumentSummary.VendorRef
},
new Value
{
Value = PostDate.HasValue ? ((DateTime)PostDate.Value).ToLongDateString() : "",
LinkedCommand = PORcptSchema.DocumentSummary.Date
},
new Value
{
Value = DocDate.HasValue ? ((DateTime)DocDate.Value).ToLongDateString() : "",
LinkedCommand = PORcptSchema.DocumentSummary.Date
},
new Value
{
Value = Description,
LinkedCommand = PORcptSchema.DocumentSummary.NoteText
},
new Value
{
Value = "POS Doc " + DocNum,
LinkedCommand = PORcptSchema.DocumentSummary.VendorRef
},
};
//set the dialog answer
var dgAnswer = new Command[]
{ new Value
{
Value = "OK",
LinkedCommand = PORcptSchema.AddPurchaseOrderLine.ServiceCommands.DialogAnswer,
Commit = true
}
};
Document = Document.Concat(dgAnswer).ToArray();
//select lines
foreach (POReceiptLine line in POReceiptlines.OrderBy(x => x.LineNum))
{
AcumaticaInterface.apitest.Command[] Docline = new AcumaticaInterface.apitest.Command[]
{
new Key
{
ObjectName = PORcptSchema.AddPurchaseOrderLine.OrderNbr.ObjectName,
FieldName = PORcptSchema.AddPurchaseOrderLine.OrderNbr.FieldName,
Value = "='" + line.BaseDocNum + "'"
},
new Key
{
ObjectName = PORcptSchema.AddPurchaseOrderLine.LineNbr.ObjectName,
FieldName = PORcptSchema.AddPurchaseOrderLine.LineNbr.FieldName,
Value = "='" + line.BaseLineNum + "'"
},
new Value
{
Value = "True",
LinkedCommand = PORcptSchema.AddPurchaseOrderLine.Selected,
Commit = true
}
};
Document = Document.Concat(Docline).ToArray();
}
//Add PO line.
var addPOLine = new Command[]
{
PORcptSchema.Actions.AddPOOrderLine2,
////get back the added lines in the grid
PORcptSchema.DocumentDetails.POOrderNbr,
PORcptSchema.DocumentDetails.POLineNbr
};
Document = Document.Concat(addPOLine).ToArray();
var receiptLines = context.PO302000Submit(Document);
//update quantity..
//check CreateShipment() in webservice demo
List<Command> commandList = new List<Command>();
for (int index = 0; index < receiptLines.Length; index++)
{
commandList.Add(new Value
{
Value = index.ToString(),
LinkedCommand = PORcptSchema.DocumentDetails.ServiceCommands.RowNumber
});
POReceiptLine line = POReceiptlines.Where(x => x.BaseDocNum == receiptLines[index].DocumentDetails.POOrderNbr.Value && x.BaseLineNum.ToString() == receiptLines[index].DocumentDetails.POLineNbr.Value).FirstOrDefault();
if (line != null)
{
commandList.Add(new Value
{
Value = line.Qty.ToString(),
LinkedCommand = PORcptSchema.DocumentDetails.ReceiptQty,
Commit = index < receiptLines.Length - 1
});
}
else
throw new Exception("Matching POS Rcpt line not found.");
}
//save
AcumaticaInterface.apitest.Command[] save = new AcumaticaInterface.apitest.Command[] {
PORcptSchema.Actions.Save
};
Document = Document.Concat(save).ToArray();
//SAVING And get the document nbr
AcumaticaInterface.apitest.Command[] Output = new AcumaticaInterface.apitest.Command[] {
PORcptSchema.DocumentSummary.Type,
PORcptSchema.DocumentSummary.ReceiptNbr
};
Document = Document.Concat(Output).ToArray();
var POReceipt = context.PO302000Submit(Document)[0];
After this particular line, web service is not returning any results. Anyone can assist on this?
var receiptLines = context.PO302000Submit(Document);
This solution was tested using Acumatica version 6.00.1596.
I found that to return the value of the Purchase Order Lines, you do not need to do a foreach.
After setting the value for the summary and removing the deuplicate here is what I use to get back the POLines.
var selectPOLine = new Command[]
{
new Value
{
Value = "OK",
LinkedCommand = PORcptSchema.AddPurchaseOrderLine.ServiceCommands.DialogAnswer,
Commit = true
},
addPOLineWithCommit,
new Value
{
LinkedCommand = PORcptSchema.AddPurchaseOrderLinePOSelection.OrderNbr,
Value = "PO000451"
},
new Value
{
Value = "True",
LinkedCommand = PORcptSchema.AddPurchaseOrderLine.Selected,
},
PORcptSchema.AddPurchaseOrderLine.InventoryID,
PORcptSchema.AddPurchaseOrderLine.LineDescription,
PORcptSchema.AddPurchaseOrderLine.LineType,
};
With "addPOLineWithCommit" define as
var addPOLineWithCommit = PORcptSchema.Actions.AddPOOrderLine;
addPOLineWithCommit.Commit = true;
Using these the line :
var receiptLines = context.PO302000Submit(Document);
was returning me some information on available lines.
#samol518's sample assisted me to resolve. I am posting the full code, if anyone later needs it
the below code will add lines from PO, change quantity and save the PO receipt.
public void createAcuPR()
{
apitest.Screen context = BuisnessLogicACU.context;
PO302000Content PORcptSchema;
try
{
PORcptSchema = context.PO302000GetSchema();
}
catch
{
BuisnessLogicACU.contextLogin();
PORcptSchema = context.PO302000GetSchema();
}
var addPOLineWithCommit = PORcptSchema.Actions.AddPOOrderLine;
addPOLineWithCommit.Commit = true;
//somehow if there is a second document then it goes to update mode
context.PO302000Submit(new Command[] { PORcptSchema.Actions.Insert });
//header
AcumaticaInterface.apitest.Command[] Document = new AcumaticaInterface.apitest.Command[]
{
PORcptSchema.Actions.Insert,
new Value
{
Value = BPCode,
LinkedCommand = PORcptSchema.DocumentSummary.Vendor,
Commit = true
},
new Value
{
Value = BPRefNbr ,
LinkedCommand = PORcptSchema.DocumentSummary.VendorRef
},
new Value
{
Value = PostDate.HasValue ? ((DateTime)PostDate.Value).ToLongDateString() : "",
LinkedCommand = PORcptSchema.DocumentSummary.Date
},
new Value
{
Value = "POS Doc " + DocNum + "-" + Description,
LinkedCommand = PORcptSchema.DocumentSummary.NoteText
}
};
//set the dialog answer
var dgAnswer = new Command[]
{ new Value
{
Value = "OK",
LinkedCommand = PORcptSchema.AddPurchaseOrderLine.ServiceCommands.DialogAnswer,
Commit = true
}
};
Document = Document.Concat(dgAnswer).ToArray();
//select lines from smart panel
foreach (POReceiptLine line in POReceiptlines.OrderBy(x => x.LineNum))
{
AcumaticaInterface.apitest.Command[] Docline = new AcumaticaInterface.apitest.Command[]
{
new Key
{
ObjectName = PORcptSchema.AddPurchaseOrderLine.OrderNbr.ObjectName,
FieldName = PORcptSchema.AddPurchaseOrderLine.OrderNbr.FieldName,
Value = "='" + line.BaseDocNum + "'"
},
new Key
{
ObjectName = PORcptSchema.AddPurchaseOrderLine.LineNbr.ObjectName,
FieldName = PORcptSchema.AddPurchaseOrderLine.LineNbr.FieldName,
Value = "='" + line.BaseLineNum + "'"
},
new Value
{
Value = "True",
LinkedCommand = PORcptSchema.AddPurchaseOrderLine.Selected,
Commit = true
}
};
Document = Document.Concat(Docline).ToArray();
}
//Add PO line and retrive back the added lines.
var addPOLine = new Command[]
{
addPOLineWithCommit,
////get back the added lines in the grid
PORcptSchema.DocumentDetails.POOrderNbr,
PORcptSchema.DocumentDetails.POLineNbr
};
Document = Document.Concat(addPOLine).ToArray();
var receiptLines = context.PO302000Submit(Document);
//update quantity..
List<Command> commandList = new List<Command>();
for (int index = 0; index < receiptLines.Length; index++)
{
commandList.Add(new Value
{
Value = index.ToString(),
LinkedCommand = PORcptSchema.DocumentDetails.ServiceCommands.RowNumber
});
POReceiptLine line = POReceiptlines.Where(x => x.BaseDocNum == receiptLines[index].DocumentDetails.POOrderNbr.Value && x.BaseLineNum.ToString() == receiptLines[index].DocumentDetails.POLineNbr.Value).FirstOrDefault();
if (line != null)
{
commandList.Add(new Value
{
Value = line.Qty.ToString(),
LinkedCommand = PORcptSchema.DocumentDetails.ReceiptQty,
Commit = index < receiptLines.Length - 1
});
}
else
throw new Exception("Matching POS Rcpt line not found.");
}
//save
commandList.AddRange(
//SAVING And get the document nbr
new AcumaticaInterface.apitest.Command[] {
PORcptSchema.Actions.Save,
PORcptSchema.DocumentSummary.Type,
PORcptSchema.DocumentSummary.ReceiptNbr
});
var POReceipt = context.PO302000Submit(commandList.ToArray())[0];
}
This code is working, Receipt is creating but new created receipt is not generated for newley generated Purchase order, this receipt is generated for old any PO

Synchronous Call : Call 2nd function after 1st function is executed completely

I recently stating coding in node.js and might be a very simple question.
Trying to write a XML parser/validator to validate xml schema and values against values/ xpath stored in an excel sheet.
Now once the validation function is complete I want to call a printResult function to print final result. However if I try to call the function immediately after the first function .. its printing variables initial values and if called within the first which is iterating though the number of xpaths present in excel sheet and printing result with increments.
var mocha = require('mocha');
var assert = require('chai').assert;
var fs = require('fs');
var parseString = require('xml2js').parseString;
var xpath = require('xpath');
var dom = require('xmldom').DOMParser;
var XLSX = require('xlsx');
var Excel = require("exceljs");
var should = require('chai').should();
var HashMap = require('hashmap');
var colors = require('colors');
require('/xmlValidator/dbConnect.js');
var map = new HashMap();
var elementMap = new HashMap();
var resultValue;
//console.log('hello'.green);
map.set("PASS", 0);
map.set("FAIL", 0);
map.set("INVALID_PATH", 0);
function computeResult(elementPath, result) {
var pass = map.get("PASS");
var fail = map.get("FAIL");
var invalidPath = map.get("INVALID_PATH");
elementMap.set(elementPath, result);
if (result == "PASS") {
pass++;
map.set("PASS", pass);
} else if (result == "FAIL") {
fail++;
map.set("FAIL", fail);
} else {
invalidPath++;
map.set("INVALID_PATH", invalidPath)
}
printResult();
}
function printResult() {
var pass = map.get("PASS");
var fail = map.get("FAIL");
var invalidPath = map.get("INVALID_PATH");
console.log(("PASS Count :" + pass).green);
console.log(("FAIL Count :" + fail).red);
console.log(("Inavlid Path :" + invalidPath).yellow);
elementMap.forEach(function(value, key) {
if (value == "INVALID_PATH")
console.log((key + ":" + value).yellow);
else if (value == "FAIL")
console.log((key + ":" + value).red);
else
console.log(key + ":" + value);
});
}
var workbook = new Excel.Workbook();
workbook.xlsx.readFile('utils/' + process.argv[2])
.then(function() {
var worksheet = workbook.getWorksheet(1);
worksheet.eachRow(function(row, rowNumber) {
//console.log(rowNumber);
var row = worksheet.getRow(rowNumber);
var dataPath1 = row.getCell("A").value;
var dataPath2 = row.getCell("B").value;
var dataPath = dataPath1 + dataPath2;
//console.log(dataPath);
var dataValue = row.getCell("D").value;
var flag = row.getCell("E").value;
//console.log(flag)
//console.log(dataValue);
if (!flag)
validate(dataPath, dataValue, rowNumber);
//else console.log("NOT EXECUTED" + rowNumber)
});
})
function validate(dataPath, dataValue, rowNumber) {
var fail = 0;
fs.readFile('utils/' + process.argv[3], 'utf8', function(err, data) {
if (err) {
console.log("ERROR ERROR ERROR ERROR ");
return console.log(err);
}
var doc = new dom().parseFromString(data);
var subId = String(xpath.select1(dataPath, doc));
if (subId == "undefined") {
/*console.log('undefined caught');
console.log("row number :" + rowNumber);*/
var resultValue = "INVALID_PATH";
computeResult(dataPath, resultValue);
} else {
var subId = xpath.select1(dataPath, doc);
var value = subId.lastChild.data;
/*console.log("row number :" + rowNumber);
console.log("actual value: " + value);
console.log("expected value:" + dataValue );*/
if (dataValue == null) {
assert.notEqual(value, dataValue, "value not found");
resultValue = "PASS";
computeResult(dataPath, resultValue);
} else {
if (value == dataValue)
resultValue = "PASS";
else resultValue = "FAIL";
computeResult(dataPath, resultValue);
}
}
});
}
In the code above i want to call printResult() function after validate function is completely executed (workbook.xlsx.readFile)
Can some one please help me out how to use done () function or make sync call ?
If fs.readFileAsync('utils/' + process.argv[3], 'utf8') can be executed once, then validate() will be completely synchronous and calling printResult() after the verification loop will be trivial.
In the main routine, you can simply aggregate two promises ...
var promise1 = workbook.xlsx.readFile();
var promise2 = fs.readFileAsync(); // requires `fs` to be promisified.
... before embarking on the verification loop.
Promise.all([promise1, promise2]).spread(/* verify here */);
Also a whole bunch of tidying can be considered, in particular :
establishing "PASS", "FAIL" and "INVALID_PATH" as constants to avoid lots of repetitive string creation,
using js plain objects in lieu of hashmap,
building map from elementMap inside the print function.
having validate() return its result and building elementMap in the main routine
Here's the whole thing, about as tight as I can get it. I may have made a few assumptions but hopefully not too many bad ones ...
var mocha = require('mocha');
var assert = require('chai').assert;
var Promise = require("bluebird");
var fs = Promise.promisifyAll(require("fs")); // allow Bluebird to take the pain out of promisification.
var parseString = require('xml2js').parseString;
var xpath = require('xpath');
var dom = require('xmldom').DOMParser;
var XLSX = require('xlsx');
var Excel = require("exceljs");
var should = require('chai').should();
// var HashMap = require('hashmap');
var colors = require('colors');
require('/xmlValidator/dbConnect.js');
const PASS = "PASS";
const FAIL = "FAIL";
const INVALID_PATH = "INVALID_PATH";
function printResult(elementMap) {
var key, result,
map = { PASS: 0, FAIL: 0, INVALID_PATH: 0 },
colorNames = { PASS: 'black', FAIL: 'red', INVALID_PATH: 'yellow' };
for(key in elementMap) {
result = elementMap[key];
map[(result === PASS || result === FAIL) ? result : INVALID_PATH] += 1;
console.log((key + ": " + result)[colorNames[result] || 'black']); // presumably colors can be applied with associative syntax? If so, then the code can be very concise.
}
console.log(("PASS Count: " + map.PASS)[colorNames.PASS]);
console.log(("FAIL Count: " + map.FAIL)[colorNames.FAIL]);
console.log(("Inavlid Path: " + map.INVALID_PATH)[colorNames.INVALID_PATH]);
}
function validate(doc, dataPath, dataValue) {
var subId = xpath.select1(dataPath, doc),
value = subId.lastChild.data,
result;
if (String(subId) == "undefined") {
result = INVALID_PATH;
} else {
if (dataValue === null) {
assert.notEqual(value, dataValue, "value not found"); // not too sure what this does
result = PASS;
} else {
result = (value === dataValue) ? PASS : FAIL;
}
}
return result;
}
//Main routine
var workbook = new Excel.Workbook();
var promise1 = workbook.xlsx.readFile('utils/' + process.argv[2]); // from the question, workbook.xlsx.readFile() appears to return a promise.
var promise2 = fs.readFileAsync('utils/' + process.argv[3], 'utf8');
Promise.all([promise1, promise2]).spread(function(data2, data3) {
var worksheet = workbook.getWorksheet(1),
doc = new dom().parseFromString(data3),
elementMap = {};
worksheet.eachRow(function(row, rowNumber) {
// var row = worksheet.getRow(rowNumber); // row is already a formal variable ???
var dataPath, dataValue;
if (!row.getCell('E').value)
dataPath = row.getCell('A').value + row.getCell('B').value;
dataValue = row.getCell('D').value;
elementMap[dataPath] = validate(doc, dataPath, dataValue);
});
printResult(elementMap);
});
Untested so may not run but at least you can raid the code for ideas.

Resources