Jira Code: PROT-202
Update: To add the item scanning after the SO is scanned. Item is scanned using its UPC code.
Suitelet Script: PROT-176 SL SearchSO
/**
* @NApiVersion 2.x
* @NScriptType Suitelet
* @NModuleScope SameAccount
*/
/**
* Script Description
* This suitelet to search SO and return item lines.
*/
/*******************************************************************************
*
*
* NetSuite Name :PROT-176 SL SearchSO
* Script ID: customscriptprot_176_sl_searchso
*
* *****************************************************************************
*
*
* $Author: Jobin & Jismi IT Services LLP $
*
* DESCRIPTION
* This suitelet to search SO and return item lines.
*
* Date Created :07-03-2019
*
* REVISION HISTORY Update:
*
*
*
******************************************************************************/
define(['N/search', 'N/file'],
function(search, file) {
var main = {
onRequest: function(context) {
if (context.request.method === 'GET') {
var index = file.load({ id: '690626' });
var html = index.getContents();
context.response.write({
output: html
});
} else {
var SOid = context.request.parameters.so;
log.debug('SOid', SOid);
var results = main.SearchSO(SOid);
if (results)
context.response.write(JSON.stringify(results));
else
context.response.write('FAILED');
}
},
SearchSO: function(SOID) {
var Result = {};
var salesorderSearchObj = search.create({
type: "salesorder",
filters: [
["type", "anyof", "SalesOrd"],
"AND",
["numbertext", "is", SOID],
"AND",
["shipping", "is", "F"],
"AND",
["taxline", "is", "F"],
"AND",
["mainline", "is", "F"],
"AND",
["quantity", "isnotempty", ""]
],
columns: [
search.createColumn({ name: "internalid", join: "item", label: "Internal ID" }),
search.createColumn({ name: "internalid", label: "Internal ID" }),
search.createColumn({ name: "itemid", join: "item", label: "Name" }),
search.createColumn({ name: "quantity", label: "Quantity" }),
search.createColumn({ name: "type", join: "item", label: "Type" }),
search.createColumn({ name: "statusref", label: "Status" }),
search.createColumn({ name: "quantitypicked", label: "Quantity Picked" }),
search.createColumn({
name: "upccode",
join: "item",
label: "UPC Code"
})
]
});
var searchResultCount = salesorderSearchObj.runPaged().count;
if (searchResultCount == 0) {
return false;
} else {
salesorderSearchObj.run().each(function(result) {
var itemType = result.getText({
name: "type",
join: "item",
label: "Type"
});
log.debug('itemType', itemType)
if (itemType == 'Kit/Package') {
var id = result.getValue({ name: "internalid", join: "item", label: "Internal ID" });
var qty = Number(result.getValue({ name: "quantity", label: "Quantity" }));
var picked = Number(result.getValue({ name: "quantitypicked", label: "Quantity Picked" }));
var status = result.getText({ name: "statusref", label: "Status" });
var internalid = result.getValue({ name: "internalid", label: "Internal ID" });
var set = main.SearchItem(id, qty, picked, status, Result, internalid);
} else {
var picked = Number(result.getValue({ name: "quantitypicked", label: "Quantity Picked" }));
var id = result.getValue({ name: "internalid", join: "item", label: "Internal ID" });
var obj = {
id: result.getValue({ name: "internalid", join: "item", label: "Internal ID" }),
name: result.getValue({ name: "itemid", join: "item", label: "Name" }),
qty: Number(result.getValue({ name: "quantity", label: "Quantity" })) - picked,
summary: '---',
status: result.getText({ name: "statusref", label: "Status" }),
internalid: result.getValue({ name: "internalid", label: "Internal ID" }),
type: result.getValue({ name: "type", join: "item", label: "Type" }),
upc: result.getValue({ name: "upccode", join: "item", label: "UPC Code" })
};
if (Result[id]) {
Result[id].qty = Result[id].qty + obj.qty;
} else {
Result[id] = obj;
}
log.debug('obj inv', obj)
}
return true;
});
return Result;
}
},
SearchItem: function(id, quantity, picked, status, Result, internalid) {
var kititemSearchObj = search.create({
type: "kititem",
filters: [
["type", "anyof", "Kit"],
"AND",
["internalidnumber", "equalto", id]
],
columns: [
search.createColumn({ name: "internalid", join: "memberItem", label: "Internal ID" }),
search.createColumn({ name: "itemid", join: "memberItem", label: "Name" }),
search.createColumn({ name: "memberquantity", label: "Member Quantity" }),
search.createColumn({ name: "type", join: "memberItem", label: "Type" }),
search.createColumn({
name: "upccode",
join: "memberItem",
label: "UPC Code"
})
]
});
var searchResultCount = kititemSearchObj.runPaged().count;
kititemSearchObj.run().each(function(result) {
var obj = {
id: result.getValue({ name: "internalid", join: "memberItem", label: "Internal ID" }),
name: result.getValue({ name: "itemid", join: "memberItem", label: "Name" }),
qty: Number(result.getValue({ name: "memberquantity", label: "Member Quantity" })) * quantity - picked,
summary: '---',
status: status,
internalid: internalid,
type: result.getValue({ name: "type", join: "memberItem", label: "Type" }),
upc:result.getValue({name: "upccode", join: "memberItem", label: "UPC Code"})
};
if (Result[obj.id]) {
Result[obj.id].qty = Result[obj.id].qty + obj.qty;
} else {
Result[obj.id] = obj;
}
log.debug('obj kit member', obj);
return true;
});
}
}
for (var key in main) {
if (typeof main[key] === 'function') {
main[key] = trycatch(main[key], key);
}
}
function trycatch(myfunction, key) {
return function() {
try {
return myfunction.apply(this, arguments);
} catch (e) {
log.debug("e in " + key, e);
}
}
};
return main;
});
JQuery:SingleSOPickup
var SOSerachURL = "/app/site/hosting/scriptlet.nl?script=569&deploy=1";
var LotSearchURL = "/app/site/hosting/scriptlet.nl?script=570&deploy=1";
var IFCreateURL = "/app/site/hosting/scriptlet.nl?script=571&deploy=1";
var SOsearchLink = "/app/site/hosting/scriptlet.nl?script=572&deploy=1";
var ITEMS = {};
var LOTS = {};
$(function() {
$('#LOT').hide();
$('#Itembutton').hide();
$('#ItemPage').hide();
$('#submititem').hide();
$('#searchbtn').click(function() {
Swal.showLoading();
ITEMS = {};
$('#itemTable').hide();
$('#ItemPage').hide();
$('#Itembutton').hide();
var SOID = $('#SOID').val().trim();
console.log('SOID',SOID)
if (SOID != '') {
$.post(SOSerachURL, { so: SOID },
function(data, status) {
if (data == "FAILED")
Swal.fire({
type: 'info',
title: 'No Result Found',
text: 'Enter a valid SO#'
})
else {
ITEMS = JSON.parse(data);
var status = ITEMS[Object.keys(ITEMS)[0]].status;
if (status == "Billed") {
Swal.fire({
type: 'info',
title: 'SO Billed'
})
} else if (status == "Closed") {
Swal.fire({
type: 'info',
title: 'SO Closed'
})
} else if (status == "Partially Fulfilled") {
Swal.fire({
type: 'info',
title: 'SO Partially Fulfilled'
})
$('#submitso').hide();
$('#submititem').show();
createTable(ITEMS);
} else{
$('#submitso').hide();
$('#submititem').show();
createTable(ITEMS);
}
//console.log(ITEMS)
}
});
} else {
Swal.fire({
type: 'error',
title: 'Oops...',
text: 'Enter SO#'
})
}
});
$('#searchbtn2').click(function(){
Swal.showLoading();
console.log('ITEMS',ITEMS)
var item_id = $('#item_id').val().trim();
console.log('item_id',item_id)
if (item_id != ''){
var flag=true;
var t = keyOfObject(ITEMS, 'upc', item_id);
console.log('t',t);
if(t== false || !t) flag=false;
if(Array.isArray(t))
if(t.length==0)flag=false;
if(flag==false){
Swal.fire({
type: 'error',
title: 'Oops...',
text: 'Wrong UPC Code#'
});
return;
}
for (var key in ITEMS) {
// console.log('ITEMS[key].name',ITEMS[key].name)
if((ITEMS[key].upc) == item_id){
console.log('correct item_id ' +ITEMS[key].upc,item_id)
pickItem(key, ITEMS[key].qty, ITEMS[key].name)
break;
}
}
// if(flag == false){
// Swal.fire({
// type: 'error',
// title: 'Oops...',
// text: 'Wrong UPC Code#'
// })
// }
}else{
console.log('empty item_id',item_id)
Swal.fire({
type: 'error',
title: 'Oops...',
text: 'Enter UPC code#'
})
}
})
$('#Lotcancel').click(function() {
var summary = [];
var LotUsed = {};
ITEM_ID = $('#itemID').text();
ITEMS[ITEM_ID].summary = summary;
ITEMS[ITEM_ID]['Lots'] = LotUsed;
createTable(ITEMS);
$('#LOT').hide();
$('#SOITEMS').show();
});
$('#Lotproceed').click(function() {
var summary = [];
var LotUsed = {};
var pick_qty=0;
ITEM_ID = $('#itemID').text();
console.log('LOTS',ITEMS[ITEM_ID]);
for (var key in LOTS) {
if (Number(LOTS[key].available) != 0) {
var qty = Number($('#' + key).val());
pick_qty +=qty
}
}
if(ITEMS[ITEM_ID].qty>pick_qty){
Swal.fire({
type: 'error',
title: 'Oops...',
text: 'Picked Quantity is less than Quantity to Pick'
})
return false;
}
console.log('pick_qty',pick_qty);
for (var key in LOTS) {
if (Number(LOTS[key].available) != 0) {
var qty = Number($('#' + key).val());
if (qty != 0) {
summary.push(LOTS[key].lot + ': ' + LOTS[key].bin.text + ': ' + '<b>' + qty + '</b>');
LotUsed[key] = { LotId: key, BinID: LOTS[key].bin.value, Quantity: qty };
}
}
}
ITEMS[ITEM_ID].summary = summary;
ITEMS[ITEM_ID]['Lots'] = LotUsed;
//console.log('ITEMS', ITEMS);
createTable(ITEMS);
$('#LOT').hide();
$('#SOITEMS').show();
});
$('#proceed').click(function() {
Swal.showLoading();
fetch(IFCreateURL, {
method: 'POST', // or 'PUT'
body: JSON.stringify(ITEMS), // data can be `string` or {object}!
headers: { 'Content-Type': 'application/json' }
}).then(function(res) {
console.log('res', res);
return res.json();
})
.then(function(response) {
console.log('Success:', JSON.stringify(response));
var data = response;
// console.log('data', data);
if (data.text == 'SUCCESS') {
Swal.close();
Swal.fire({
type: 'success',
title: 'Item Fulfillment Created: ' + data.value,
allowOutsideClick: false
}).then(function() {
window.location.reload();
})
} else if (data.text == 'FAIL') {
Swal.close();
Swal.fire({
type: 'error',
title: 'Pick items & Proceed'
});
} else {
Swal.close();
Swal.fire({
type: 'error',
title: 'Error in Creating Item fulfillment'
});
}
})
.catch(function(error) {
console.log('Error:', error)
Swal.close();
Swal.fire({
type: 'error',
title: 'Error in Creating Item fulfillment'
});
})
});
$('#cancel').click(function() {
window.location.reload();
})
});
function createTable(items) {
var create = false;
for (var key in items) {
if (Number(items[key].qty) > 0) {
create = true;
break;
}
}
if (create) {
$('#ItemPage').html('');
var table_body = '<table id="ItemTable" class="table table-bordered table-striped table-condensed table-hover table-sm" data-show-toggle="true" data-expand-first="false" data-paging="true" data-paging-size="3">';
table_body += "<thead>";
table_body += "<tr>";
table_body += " <th>Item</th>";
table_body += "<th>Qty to Pick</th>";
table_body += " <th data-breakpoints=\"xs sm\">Summary</th>";
table_body += " <th>Action</th>";
table_body += "</tr>";
table_body += "</thead>";
table_body += "</tbody>";
for (var key in items) {
if (items[key].type == 'InvtPart' && Number(items[key].qty) != 0) {
table_body += '<tr>';
table_body += '<td>';
table_body += items[key].name;
table_body += '</td>';
table_body += '<td>';
table_body += items[key].qty;
table_body += '</td>';
table_body += '<td>';
table_body += createList(items[key].summary);
table_body += '</td>';
table_body += '<td>';
if (createList(items[key].summary) == '---')
table_body += '<div><button class="btn btn-primary btn-sm" onclick="pickItem(' + items[key].id + ',' + items[key].qty + ',' + '\'' + items[key].name + '\'' + ')">Pick</button></div>';
else
table_body += '<div><button class="btn btn-danger btn-sm" onclick="pickItem(' + items[key].id + ',' + items[key].qty + ',' + '\'' + items[key].name + '\'' + ')">Picked</button></div>';
table_body += '</td>';
table_body += '</tr>';
}
}
table_body += '</tbody>';
table_body += '</table>';
$('#itemTable').html(table_body);
$('#ItemTable').footable({
"columns": [{
"type": "text"
},
{
"type": "text"
},
{
"type": "html"
}, {
"type": "html"
}
]
});
Swal.close();
$('#itemTable').show();
$('#Itembutton').show();
var SOID = $('#SOID').val().trim();
var url=SOsearchLink+'&so='+SOID;
$('#downloadBtn').attr('href',url);
} else {
Swal.close();
Swal.fire({
type: 'info',
title: 'All items picked'
});
$('#submitso').show();
$('#submititem').hide();
}
}
function pickItem(ITEM_ID, ITEM_QTY, ITEM_NAME) {
Swal.showLoading();
$.post(LotSearchURL, { itemId: ITEM_ID },
function(data, status) {
if (data == "")
Swal.fire({
type: 'error',
title: 'Oops...',
text: 'Something went wrong!!'
})
else if (data == 'FAILED')
Swal.fire({
type: 'info',
title: 'Item Not Available'
})
else {
LOTS = JSON.parse(data);
createLotTable(LOTS, ITEM_ID, ITEM_QTY, ITEM_NAME);
}
});
}
function createLotTable(lots, ITEM_ID, ITEM_QTY, ITEM_NAME) {
var create = false;
for (var key in lots) {
if (Number(lots[key].available) > 0) {
create = true;
break;
}
}
if (create) {
$('#ItemPage').hide();
var itemQty = 'Item Name: ' + ITEM_NAME + '(ID: <span id=\"itemID\">' + ITEM_ID + '</span>)' + ', Quantity to Pick: ' + ITEM_QTY;
var itemPickedMsg = "Quantity Picked: 0";
$('#itemName').html(itemQty);
$('#picked').text(itemPickedMsg);
var table_body = '<table id="lotTable" class="table table-bordered table-striped table-condensed table-hover table-sm">';
table_body += "<thead>";
table_body += "<tr>";
table_body += " <th>Bin</th>";
table_body += "<th>Lot</th>";
table_body += " <th>Available Qty</th>";
table_body += " <th>Pick Qty</th>";
table_body += "</tr>";
table_body += "</thead>";
table_body += "</tbody>";
for (var key in lots) {
if (Number(lots[key].available) != 0) {
var Onchange = "quantityPick(" + key + ",'" + escape(JSON.stringify(lots)) + "'," + ITEM_ID + "," + ITEM_QTY + ")";
table_body += '<tr>';
table_body += '<td>';
table_body += lots[key].bin.text;
table_body += '</td>';
table_body += '<td>';
table_body += lots[key].lot;
table_body += '</td>';
table_body += '<td>';
table_body += lots[key].available;
table_body += '</td>';
table_body += '<td>';
table_body += '<input type="number" id="' + key + '" min="0" max="' + ITEM_QTY + '" value="0" onchange="' + Onchange + '"></input>';
table_body += '</td>';
table_body += '</tr>';
}
}
table_body += '</tbody>';
table_body += '</table>';
Swal.close();
$('#SOITEMS').hide();
$('#LOT').show();
$('#LotTable').html(table_body);
} else {
Swal.close();
Swal.fire({
type: 'info',
title: 'Item Not Available'
})
}
}
function quantityPick(ID, lots, ITEM_ID, ITEM_QTY) {
var PickeQty = 0;
lots = JSON.parse(unescape(lots));
var SelectedQty = $('#' + ID).val();
if (Number(SelectedQty) > Number(lots[ID].available)) {
Swal.fire({
type: 'info',
title: 'Oops...',
text: 'Selected quantity not available at inventory'
});
$('#' + ID).val(0);
}
if ((Number(SelectedQty) > Number(ITEM_QTY)) && (Number(SelectedQty) < Number(ITEM_QTY))) {
$('#' + ID).val(ITEM_QTY);
}
for (var key in lots) {
if (Number(lots[key].available) != 0) {
var qty = Number($('#' + key).val());
PickeQty += qty;
}
}
if (Number(PickeQty) > Number(ITEM_QTY)) {
Swal.fire({
type: 'error',
title: 'Oops...',
text: 'Picked Quantity is greater than Quantity to Pick'
})
$('#' + ID).val(0);
return false;
}
var itemPickedMsg = "Quantity Picked: " + PickeQty;
ITEMS[ITEM_ID]['PICKED'] = PickeQty;
ITEMS[ITEM_ID]['SetQty'] = PickeQty;
$('#picked').text(itemPickedMsg);
}
function createList(Summary) {
if (Summary == '---')
return Summary;
else if (Summary.length == 0)
return '---';
else {
var list = '<ul>';
for (var i = 0; i < Summary.length; i++) {
list += '<li>' + Summary[i] + '</li>';
}
list += '</ul>';
return list;
}
}
function keyOfObject(obj, property, value) {
if (typeof obj === 'object' && obj !== null)
return Object.keys(obj).reduce(function(a, c) {
if (obj[c][property] == value)
a.push(c)
return a;
}, []);
return false;
}