I have created a suitelet that does the following:...
# suitescript
m
I have created a suitelet that does the following: Takes in a 'Transaction Serial/Lot Number' Performs a search to find the Sales Order that has that 'Transaction Serial/Lot Number' in the Inventory Detail on a line (created from the Work Order attached to the line) The search returns the Sales Order Line, Inventory Number, etc. I am trying to then Transform the Sales Order to an Item Fulfillment and fulfill only the line and quantity for that particular 'Transaction Serial/Lot Number' I am logging getCurrentSublistSubrecord for each line to try to tell what I need to set, but am having a hard time understanding. In Dynamic mode, the Item Fulfillment tries to fulfill each line that has quantity committed from the sales order. I have tried removeCurrentSublistSubrecord and trying to set a new subRecord, but get an unexpexted error. Does anyone have an example of how they've accomplished this?
b
your explanation doesn't fully make sense, it looks like you are trying to segregate your fulfillments by work order
either way, you are going to need to share your code for this one
m
Here is the whole script so far. the lines from the sales order dont match the lines on the IF for some reason.
/**
*@NApiVersion 2.1
*@NScriptType Suitelet
*/
define([
"N/record",
"N/ui/serverWidget",
"N/search",
"N/url",
"N/ui/message",
"N/http",
"N/xml",
"N/format",
"N/https",
"N/runtime",
"N/redirect",
"N/task"
], function (record, serverWidget, search, url, message, http, xml, format, https, runtime, redirect, task){
function onRequest(context) {
if (context.request.method === "GET"){
context.response.writePage(createGetForm(context));
}else{
//    let tranArray = getSerialData(context);
let itemFulfillmentId = fulfillSOLines(getSerialData(context));
//context.response.writePage(createPostForm(context));
// schedulePickups(context);
// createTask();
// redirectToScheduledShipping();
//IS THIS UPDATING?
//redirectToSelf();
}
}
function createGetForm(context){
log.debug('context', context)
let form = serverWidget.createForm({title: "Unit Shipping", hideNavBar: false, });
const sbtButton = form.addSubmitButton({ label: "Fulfill" });
form.addField({id: 'custpage_serial1', label: 'First Serial', type: serverWidget.FieldType.TEXT}).updateDisplayType({displayType: serverWidget.FieldDisplayType.NORMAL});
form.addField({id: 'custpage_serial2', label: 'Second Serial', type: serverWidget.FieldType.TEXT}).updateDisplayType({displayType: serverWidget.FieldDisplayType.NORMAL});
// form.clientScriptModulePath = 'SuiteScripts/rjmScripts/LTL Project/ShipEngine - Pickups/shipEngine_scheduleLTL_pickups_cs.js';
return form;
}
function getSerialData(context){
try{
let firstSerial = context.request.parameters.custpage_serial1;
let secondSerial = context.request.parameters.custpage_serial2;
let tranArray = [];
let mySearch = search.create({
type: "salesorder",
filters:
[
["subsidiary","anyof","2"],
"AND",
["type","anyof","SalesOrd"],
"AND",
["status","anyof","SalesOrd:B","SalesOrd:D","SalesOrd:E"],
"AND",
["location","anyof","16"],
"AND",
["mainline","is","F"],
"AND",
["shipping","is","F"],
"AND",
["taxline","is","F"],
"AND",
["custbody_sotype","anyof","7"],
"AND",
[["serialnumber","is",firstSerial],"OR",["serialnumber","is",secondSerial]]
],
columns:
[
search.createColumn({name: "internalid", label: "Internal ID"}),
search.createColumn({name: "type", label: "Type"}),
search.createColumn({name: "trandate", sort: search.Sort.ASC, label: "Date"}),
search.createColumn({name: "tranid", label: "Document Number"}),
search.createColumn({name: "entity", label: "Name"}),
search.createColumn({name: "item", label: "Item"}),
search.createColumn({name: "serialnumber", label: "Transaction Serial/Lot Number"}),
search.createColumn({name: "transactionlinetype", label: "Transaction Line Type"}),
search.createColumn({name: "internalid", join: "inventoryDetail", label: "Internal ID"}),
search.createColumn({name: "line", label: "Line ID"}),
search.createColumn({name: "lineuniquekey", label: "Line Unique Key"}),
search.createColumn({name: "formulatext", formula: "CASE WHEN {customermain.parent.id} IN ('148543') THEN 'PalletId' ELSE 'NoPalletId' END", label: "Formula (Text)" }),
search.createColumn({name: "inventorynumber", join: "inventoryDetail", label: " Number"}),
]
});
let myResultSet = mySearch.run().getRange({start: 0, end: 2});
myResultSet.forEach(function(result){
let rowObj = {
soInternalId    : result.getValue({name: 'internalid'}),
serialNumber    : result.getValue({name: 'serialnumber'}),
serialId        : result.getValue({name: "internalid", join: "inventoryDetail"}),
lineId          : result.getValue({name: 'line'}),
lineUniqueKey   : result.getValue({name: 'lineuniquekey'}),
palletIdReq     : result.getValue({name: 'formulatext', formula: "CASE WHEN {customermain.parent.id} IN ('148543') THEN 'PalletId' ELSE 'NoPalletId' END"}),
inventoryNumber : result.getValue({name: "inventorynumber", join: "inventoryDetail"}),
}
log.debug('rowObj', rowObj);
tranArray.push(rowObj);
return true;
});
log.debug('tranArray', tranArray);
let soIdArray = [];
tranArray.forEach(element => {
soIdArray.push(element.soInternalId)
return true;
})
let sameSO = soIdArray.every(element => element == soIdArray[0]);
if(!sameSO){
//TODO display page showing error with serial and Sales Order detail
log.error('SO Mismatch!', 'Serial Numbers are not for the same Sales Order....Exiting function');
return;
};
// log.debug('soIdArray', soIdArray);
// log.debug('same SO?', sameSO);
return tranArray;
}catch(e){
log.debug('Caught Error in Get Serial Data', e);
}
};
function fulfillSOLines(tranArray){
try{
let itemFulfillment = record.transform({
fromType: record.Type.SALES_ORDER,
fromId: tranArray[0].soInternalId,
toType: record.Type.ITEM_FULFILLMENT,
isDynamic: true,
});
let lineCount = itemFulfillment.getLineCount({sublistId: 'item'});
log.debug('line Count', lineCount);
for(let i = 0; i < lineCount; i++){
itemFulfillment.selectLine({sublistId: 'item', line: i});
let fulfill = itemFulfillment.getCurrentSublistValue({sublistId: 'item', fieldId: 'itemreceive'})
let subRec = itemFulfillment.getCurrentSublistSubrecord({
sublistId: 'item',
fieldId: 'inventorydetail'
});
log.debug('line', i);
log.debug('subRec', subRec);
log.debug('fulfill?', fulfill);
}
tranArray.forEach(rowObj => {
itemFulfillment.selectLine({sublistId: 'item',line: rowObj.lineId });
itemFulfillment.removeCurrentSublistSubrecord({sublistId: 'item', fieldId: 'inventorydetail'})
itemFulfillment.setSublistValue({sublistId: 'item', fieldId: 'itemreceive', line: rowObj.lineId, value: true})
itemFulfillment.setSublistValue({sublistId: 'item', fieldId: 'quantity', line: rowObj.lineId, value: 1})
itemFulfillment.setSublistValue({sublistId: 'item', fieldId: 'location', line: rowObj.lineId, value: 16})
itemFulfillment.setSublistValue({sublistId: 'item', fieldId: 'class', line: rowObj.lineId, value: 25})
itemFulfillment.removeSublistSubrecord({sublistId: 'item', fieldId: 'inventorydetail', line: 2 })
let serialSubRec = itemFulfillment.getSublistSubrecord({sublistId: 'item', fieldId: 'inventorydetail', line: rowObj.lineId})
log.debug('serialSub', serialSubRec);
serialSubRec.selectNewLine({sublistId: 'inventoryassignment'})
serialSubRec.setCurrentSublistValue({sublistId: 'inventoryassignment', fieldId: 'quantity', line: 0, value: 1 })
serialSubRec.setCurrentSublistValue({sublistId: 'inventoryassignment', fieldId: 'issueinventorynumber', line: 0, value: rowObj.inventoryNumber})
serialSubRec.commitLine({sublistId: 'inventoryassignment'})
itemFulfillment.commitLine({sublistId: 'item', ignoreRecalc: true});
})
let itemFulfillmentId = itemFulfillment.save({ignoreMandatoryFields: true});
return itemFulfillmentId;
}catch(e){
log.debug('Caught Error in Fulfillment', e);
}
}
return {
onRequest: onRequest,
};
});
b
line ids arent the same as line numbers
the line id with id 1 is not required to be the first line
its more complicated while transforming to a fulfillment as well
the first line of the sales order is not required to be the first line of the fulfillment
so basically you have a mistake on top of a mistake going here
m
Yea, I've been trying lots of different things. This is how I left it currently
b
you should start by inspecting the fulfillment's item lines
one of the columns links the fulfillment line to sales order line by line id
you will want to match using that column
m
is that column 'orderline'?
b
yes
m
ok so once i get into the right line, how would i access the inventory detail subrecord and only pass the serial number i am wanting to fulfill?
b
you are using dynamic mode, so you would set the fields in the same order you would using the ui
so basically same answer as doing it in the ui
importantly in the same order
m
ok. It is prepopulated tho with the inventory detail from the Sales Order
b
same as the ui
m
ok but more than one Serial Number could be committed at this time. so would i loop through and remove the others?
since i only want to fulfill 1
b
there are things you need to do beforehand, but yes
m
and this would be better than removeSublistSubrecord?
b
i dont think you really have a choice if you are getting unexpected errors
m
ok
thanks for your help
ok real quick. I am hard coding values to see if i can get it to go through. Getting an SuiteScriptError","name":"INVALID_FLD_VALUE","message":"You have entered an Invalid Field Value 99322 for the following field: issueinventorynumber"
itemFulfillment.selectLine({sublistId: 'item',line: 0 });
itemFulfillment.removeCurrentSublistSubrecord({sublistId: 'item', fieldId: 'inventorydetail'})
itemFulfillment.setCurrentSublistValue({sublistId: 'item', fieldId: 'itemreceive', line: 0, value: true})
itemFulfillment.setCurrentSublistValue({sublistId: 'item', fieldId: 'quantity', line: 0, value: 1})
itemFulfillment.setCurrentSublistValue({sublistId: 'item', fieldId: 'location', line: 0, value: 16})
itemFulfillment.setCurrentSublistValue({sublistId: 'item', fieldId: 'class', line: 0, value: 25})
itemFulfillment.removeCurrentSublistSubrecord({sublistId: 'item', fieldId: 'inventorydetail', line: 0 })
let serialSubRec = itemFulfillment.getCurrentSublistSubrecord({sublistId: 'item', fieldId: 'inventorydetail', line: 0})
log.debug('serialSub', serialSubRec);
serialSubRec.selectNewLine({sublistId: 'inventoryassignment'})
serialSubRec.setCurrentSublistValue({sublistId: 'inventoryassignment', fieldId: 'quantity', line: 0, value: 1 })
serialSubRec.setCurrentSublistValue({sublistId: 'inventoryassignment', fieldId: 'issueinventorynumber', line: 0, value: '99322'})
serialSubRec.commitLine({sublistId: 'inventoryassignment'})
itemFulfillment.commitLine({sublistId: 'item', ignoreRecalc: true});
is that not the right field?
b
it is, but you are still failing at removing lines
m
hmm so i am removing the subrecord before i set them and it logs as blank
{"type":"inventorydetail","isDynamic":true,"fields":{"itemdescription":"Amigo ValueShopper 34","nlloc":"0","nlsub":"2","ignoreqtyvalidation":"F","trandate":"12/31/2021","_eml_nkey_":"4086366_SB1~5~3~N","type":"inventorydetail","subrecord_parent_tran_type":"ItemShip","nsapiCT":"1640958510188","sys_id":"-1885723381998080","nluser":"5","nldept":"1","subrecord_transform_from_parent_id":"11453110","subrecord_transform_from_parent_tran_type":"SalesOrd","tolocationusesbins":"F","item":"24532","quantity":"1.0","templatestored":"F","sys_parentid":"1885722703209829","entryformquerystring":"orderline=1&item=24532&quantity=1.0&subrecord_transform_from_parent_id=11453110&trandate=12/31/2021&location=16&uitype=LOH_STRICT_VALIDATION&wavefulfillment=&subrecord_transform_from_parent_tran_type=salesord&subrecord_parent_tran_type=itemship","nlrole":"3","_csrf":"t2ZHtQNVPkcmA9beHI-VEzWzol2rzU455RYdtV1t0edXp2Ed6FrssIHIQnFVo3wO-ZMcvy5iPmb-G7lvx_avAuBm1ncWWm-8dB5IHtFul3w4IqnxR1D9tuLsLjBmeqLzLlPBC5QBZw0PrWLUPF1Cq_dKWzU7WjcLOx13RvHwfDQ=","uitype":"LOH_STRICT_VALIDATION","baseunitquantity":"1.0","baserecordtype":"inventorydetail","totalquantity":"0","orderline":"1","haslines":"F","tolocation":"-1","customform":"-10820","location":"16"},"sublists":{"inventoryassignment":{"currentline":{"basequantityavailable":"","binnumber":"","binnumber_display":"","existingexpdate":"","existinginventorynumber":"","expirationdate":"","internalid":"-1","inventorydetail":"-1","inventorystatus":"","inventorystatus_display":"","issueinventorynumber":"","lotquantityavailable":"","numberedrecordid":"","packcarton":"","pickcarton":"","quantity":"1","quantityavailable":"","quantitystaged":"","receiptinventorynumber":"","sequencenumber":"","sys_id":"-1885723381798710","sys_parentid":"-1885723381793046","tobinnumber":"","tobinnumber_display":"","toinventorystatus":"","toinventorystatus_display":"","totalquantityavailable":"","#":"1"}}}}
b
general rule for dynamic mode is that you do things like you would in the ui
you wouldnt remove the subrecord in the ui, you shouldnt in dynamic mode
m
ahh ok. I will try looping through the subrecord lines then
thanks again