##JScript and GraphQL
Have I mentioned how much I love GraphQL?
The reason I like this method the most is because we have a lot more control over Tasks when we use GraphQL. With native SambaPOS Actions, all we have is Add Task which can Add or Update a Task, but that is it.
Using GraphQL, we can do more, including overwriting the Content field (instead of appending to it), we can mark Tasks as Completed or not Completed, and we can even Delete Tasks. Check it out:
// Queries
getTask
getTasks
// Mutations
addTask
updateTask
updateTaskState
deleteTask
##Script: ELG Event Log
##ELG Event Log JScript GQL [ELG]
(Script)##
Script Name: | ELG Event Log JScript GQL |
Script Handler: | ELG |
Script:
function updateLog(terminalName,userName,eventDate,eventName,eventData,taskIdentifier,ticketId,ticketNo,ticketTotal) {
// updateLog('Server','Q','2017-05-31 10:43:10','eName1','eData1','asdfasdf','0','','10.00')
// updateLog('Server','Q','','eName1','eData1')
// if eventDate parameter is not available, we will use NOW
var nowDate = DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss");
// if taskIdentifier is not available, we will generate one
var generatedIdent = randomString(32,'aA#');
// the eventDate will contain the ticketDate if this Event is Ticket-related, otherwise it will be blank
// in that case, we will use nowDate, generated above
eventDate = typeof eventDate==='undefined' || eventDate=='' || (eventDate.indexOf('TICKET DATE')>-1) ? nowDate : eventDate;
// the taskIdentifier will contain the ticketUid if this Event is Ticket-related, otherwise it will be blank
taskIdentifier = typeof taskIdentifier==='undefined' || taskIdentifier=='' || (taskIdentifier.indexOf('TICKET UID')>-1) ? '' : taskIdentifier;
ticketId = typeof ticketId==='undefined' || ticketId=='' || (ticketId.indexOf('TICKET ID')>-1) ? 0 : ticketId;
ticketNo = typeof ticketNo==='undefined' || ticketNo=='' || (ticketNo.indexOf('TICKET NO')>-1) ? '' : ticketNo;
ticketTotal = typeof ticketTotal==='undefined' || ticketTotal=='' || (ticketTotal.indexOf('TICKET TOTAL')>-1) ? 0 : ticketTotal;
ticketTotal = Helper.Format(ticketTotal);
var workperiodIsOpen = getWorkPeriodData('isOpen');
var workperiodId = getWorkPeriodData('id');
var eventCount = 0;
var taskType = 'ELG Event Log';
var taskName = eventDate;
taskName+= ' - ' + ticketTotal;
taskName+= ' - ' + ticketTotal;
taskName+= ' - ' + ticketId;
taskName+= ' - ' + ticketNo;
taskName+= ' - ' + eventName;
// the taskIdentifier will contain the ticketUid if this Event is Ticket-related, otherwise it will be blank
// if the taskIdentifier is blank, we will use our generatedIdent instead
// if we did NOT get a taskIdentifier (ie. ticketUid), there is NO Ticket, so empty the Ticket Properties (ticketDate,ticketUid,ticketId,ticketNo)
// if we DID get a taskIdentifier (ie. ticketUid), there IS a Ticket, so set the Ticket Properties (ticketDate,ticketUid,ticketId,ticketNo)
var ident = taskIdentifier!='' ? taskIdentifier : generatedIdent;
var ticketDate = taskIdentifier=='' ? '' : eventDate;
var ticketUid = taskIdentifier=='' ? '' : ident;
ticketId = taskIdentifier=='' ? '' : ticketId;
ticketNo = taskIdentifier=='' ? '' : ticketNo;
var customData = [];
customData.push({name:"Id",value:ident});
customData.push({name:"workperiodId",value:workperiodId});
customData.push({name:"terminalName",value:terminalName});
customData.push({name:"userName",value:userName});
customData.push({name:"eventDate",value:eventDate});
customData.push({name:"ticketUid",value:ticketUid});
customData.push({name:"ticketId",value:ticketId});
customData.push({name:"ticketNo",value:ticketNo});
customData.push({name:"ticketDate",value:ticketDate});
customData.push({name:"ticketTotal",value:ticketTotal});
// customData.push({name:"ticketTendered",value:ticketTendered});
// customData.push({name:"ticketRemaining",value:ticketRemaining});
// customData.push({name:"ticketChange",value:ticketChange});
// check to see if we have an EXISTING Task that needs to be UPDATED
var resp = gqlEXEC(getTask(taskType, ident));
//return resp;
resp = JSON.parse(resp);
var task = resp.data!=null ? resp.data.task : null;
var oldContent = "";
var oldCustomData = [];
// if the Task exists, append new eventName to the Task Name
// and update the ticketId and ticketNo
// and count the events (Custom Data Fields "eventN") to update the Custom Data Field "eventCount"
// and find the Largest ticketTotal
if (task) {
//dlg.ShowMessage(task.name);
// find the Largest ticketTotal
// this is stored in task.contentText for every event
// content lines are separated by "\n"
// each content line has this format:
// eventNum>date time >>> ticketTotal >>> eventName >>> eventData
// event1>2017-05-31 09:51:35 >>> 3.00 >>> Order Added >>> itemName>Barena~itemPrice>3.000000~itemQuantity>1
// so we can split() the line on " >>> " and grab idx 1 to find the ticketTotal at the time of the Event
// split Content Lines
var contentLines = task.contentText.split("\n");
//dlg.ShowMessage(contentLines[0]);
// iterate Content Lines
var largestTotal = 0;
for (var c=0; c<contentLines.length; c++) {
var line = contentLines[c];
// split the Line and grab idx 1 (ticketTotal at the time of the Event)
var ttl = line.split(" >>> ");
ttl = Helper.ToNumber(ttl[1]);
largestTotal = ttl > largestTotal ? ttl : largestTotal;
}
// check latest Event ticketTotal to see if it is larger
largestTotal = Helper.ToNumber(ticketTotal) > largestTotal ? Helper.ToNumber(ticketTotal) : largestTotal;
//dlg.ShowMessage('LT:'+largestTotal);
// we rebuild the Task Name because we want to retain the Largest Ticket Total through all Events
// and we also want to update the ticketId and ticketNo with new values once they are available
// the Task Name has this format:
// date time - largestTotal - ticketTotal - ticketId - ticketNo - eventName1 - eventName2 - eventName3 - etc
// 2017-05-31 09:51 - 6 - 3 - 40111 - 14689 - Order Added - Order Added - Order Cancelled - Drawer Opened - Payment Processed - Ticket Paid Full - Ticket Closing
var nameParts = task.name.split(" - ");
taskName = "";
// iterate nameParts and rebuild Task Name
for (var e=0; e<nameParts.length; e++) {
if (e==0) {
taskName += nameParts[e]; // eventDate / ticketDate
} else if (e==1) {
taskName += " - " + Helper.Format(largestTotal);
} else if (e==2) {
taskName += " - " + Helper.Format(ticketTotal);
} else if (e==3) {
taskName += " - " + ticketId;
} else if (e==4) {
taskName += " - " + ticketNo;
} else {
taskName += " - " + nameParts[e];
}
}
// append newest Event to the Task Name
taskName += ' - ' + eventName;
//dlg.ShowMessage(taskName);
// save old Content
oldContent = task.contentText;
// for debugging
var cd = "";
// count the Events
// and save old Custom Data
for (var c=0; c<task.customData.length; c++) {
// save old Custom Data
oldCustomData.push(task.customData[c]);
if (task.customData[c].name.indexOf('event') > -1 && task.customData[c].name.indexOf('eventCount') < 0) {
// increment Event Counter
eventCount++;
}
// for debugging
cd+=task.customData[c].name + " : " + task.customData[c].value + "\r";
}
}
// if we have a Reopened Ticket, we need to update the Task to set it NOT Completed
if (eventName.indexOf("Ticket Reopened") > -1) {
isCompleted = 'false';
// updateTaskByIdentifier(taskTypes, taskIdents, isCompleted, taskName, customData, content, state)
var resp = gqlEXEC(updateTaskByIdentifier([taskType], [ident], isCompleted, taskName));
//dlg.ShowMessage(resp);
//return resp;
}
eventCount++;
// set up the NEW Event
var eventNum = "event" + eventCount;
eventData = nowDate + ' >>> ' + ticketTotal + ' >>> ' + eventName + ' >>> ' + eventData;
// set the Custom Data to update eventCount and add NEW Event
customData.push({name:"eventCount",value:eventCount});
customData.push({name:eventNum,value:eventData});
var isCompleted = eventName=='Ticket Closing' ? 'true' : 'false';
// set the Task Content to APPEND
var content = eventNum+'>'+eventData;
// we ALWAYS ADD a Task - this will update existing Tasks with new Custom Data, and APPEND to the Task Content
// addTasks(taskTypes,taskNames,isCompleted,customData,userName,content,state)
var resp = gqlEXEC(addTasks([taskType], [taskName], isCompleted, customData, userName, content));
//return resp;
//resp = JSON.parse(resp);
//var task = resp.data.m0;
//ident = task.identifier;
// if the Ticket is Paid and is Closing, it will be marked IsClosed, so we can UPDATE the Task to mark it Completed
// or if there is NO Ticket (taskIdentifier / ticketUid is empty), then this Task/Event is not related to a Ticket, so we can mark it Completed as well
if (eventName=='Ticket Closing' || ticketUid=='' || taskIdentifier=='') {
isCompleted = 'true';
// updateTaskByIdentifier(taskTypes, taskIdents, isCompleted, taskName, customData, content, state)
var resp = gqlEXEC(updateTaskByIdentifier([taskType], [ident], isCompleted, taskName));
//return resp;
}
return resp;
}
// gets Last Workperiod Data
function getWorkPeriodData(dataType,date) {
var SQL = "SELECT [Id],convert(varchar(25),[StartDate],126),convert(varchar(25),[EndDate],126),[StartDescription],[EndDescription] FROM [WorkPeriods] WHERE 1=1 AND [Id] = (SELECT MAX([Id]) FROM [WorkPeriods])";
var res = sql.Exec(SQL);
var wpdata = res[0].split(',');
var retval = '';
switch (dataType) {
case 'id':
retval = wpdata[0];
break;
case 'start':
retval = wpdata[1].replace('T',' ');
break;
case 'end':
retval = wpdata[2].replace('T',' ');
break;
case 'isOpen':
retval = wpdata[1]==wpdata[2] ? true : false;
break;
case 'descStart':
retval = wpdata[3];
break;
case 'descEnd':
retval = wpdata[4];
break;
default:
retval = wpdata[0];
break;
}
return retval;
}
function randomString(length, chars) {
var mask = '';
if (chars.indexOf('a') > -1) mask += 'abcdefghijklmnopqrstuvwxyz';
if (chars.indexOf('A') > -1) mask += 'ABCDEFGHIJKLMNOPQRSTUVWXYZ';
if (chars.indexOf('#') > -1) mask += '0123456789';
if (chars.indexOf('!') > -1) mask += '~`!@#$%^&*()_+-={}[]:";\'<>?,./|\\';
var result = '';
for (var i = length; i > 0; --i) result += mask[Math.floor(Math.random() * mask.length)];
return result;
}
// main GraphQL Execute Function
function gqlEXEC(query, callback) {
//return query;
var data = gql.Exec(query); // returns JSON as String
var dobj = JSON.parse(data); // converts JSON String to Object
return data;
};
// Mutation for addTasks
function addTasks(taskTypes,taskNames,isCompleted,customData,userName,content,state) {
var q = '';
q+= 'mutation m{';
for (var t=0; t<taskNames.length; t++) {
var taskType = taskTypes[t];
var taskName = taskNames[t];
q += 'm'+t+': ';
q+= 'addTask(';
q+= 'task:{';
q+= 'taskType:"'+taskType+'"';
q+= ',name:"'+taskName+'"';
q+= ',isCompleted:'+isCompleted;
q+= ',userName:"'+userName+'"';
q+= typeof(content)==='undefined' ? '' : ',content:' + '"'+content+'"';
q+= typeof(state)==='undefined' ? '' : ',state:' + '"'+state+'"';
q+= ',customData:[';
if (customData) {
for (var d=0; d<customData.length; d++) {
q+= (d==0 ? '' : ',');
q+= '{name:"'+customData[d].name+'",value:"'+customData[d].value+'"}';
}
}
q+= ']';
q+= '}';
q+= ')';
q+= '{id,name,identifier,content,isCompleted,userName,customData{name,value}}';
q += ((t+1) != taskNames.length ? ', ' : '');
}
q+= '}';
return q;
};
// Query for getTask
function getTask(taskType, ident) {
var q = '';
q+= '{task:getTask(';
q+= 'taskType:"'+taskType+'"';
q+= 'identifier:"'+ident+'"';
q+= ')';
q+= '{id,isCompleted,identifier,name,state,content,contentText,customData{name,value},stateLog{state,start,end},stateDuration{state,duration},startDate,endDate,userName}';
q+= '}';
return q;
};
// Mutation for updateTask (by identifier and taskType)
function updateTaskByIdentifier(taskTypes, taskIdents, isCompleted, taskName, customData, content, state){
var q = 'mutation m {';
for (var t=0; t<taskIdents.length; t++) {
var taskIdent = taskIdents[t];
var taskType = taskTypes[t];
q += 'm'+t+': updateTask(';
q += 'identifier:"'+taskIdent+'"';
q += ', taskType:"'+taskType+'"';
q += ', task:{';
q += 'taskType:"'+taskType+'"';
q += (isCompleted!='' ? ',isCompleted:'+isCompleted : '');
q += (taskName ? ', name:"'+taskName+'"' : '');
q += content ? ',content:"'+content+'"' : '';
q += state ? ',state:"'+state+'"' : '';
q += ',customData:[';
if (customData) {
for (var d=0; d<customData.length; d++) {
q+= (d==0 ? '' : ',');
q+= '{name:"'+customData[d].name+'",value:"'+customData[d].value+'"}';
}
}
q+= ']';
q += '}';
q += ')';
q+= '{id,isCompleted,identifier,name,state,content,contentText,customData{name,value},stateLog{state,start,end},stateDuration{state,duration},startDate,endDate,userName}';
//q += '}';
q += ((t+1) != taskIdents.length ? ', ' : '');
}
q += '}';
return q;
};