I posted the script I use for my system. I do not use an entity screeen at all with it. I just use the POS likee normal but when online orders come in the tickets pop up. Its the same as someone submitting an order from a terminal.
Let me find thee thread wheree I shared my script.
Here is my script I currently use. It is modified for my needs. It actually uses Order Tags in SambaPOS so you neeed to mirror the Gloriafood modifiers with order tags in SambaPOS or it will not work. I also modified it so it will reflect any promotion discounts from Gloriafood.
var express = require('express');
var request = require('request');
var querystring = require('querystring');
var messageServer = 'localhost';
var messageServerPort = 9000;
var gloriaFoodKey = 'xxxxxxxxxxxxxx';
var serverKey = 'xxxxxxxxxx';
var timeout = 30000;
var customerEntityType = 'Customers';
var itemTagName = 'Gloria Name';
var ticketType = 'Online Ticket';
var departmentName = 'Restaurant';
var userName = 'Administrator';
var terminalName = 'Server';
var printJobName = 'Print Orders to Kitchen Printer';
var miscProductName = 'Misc';
var deliveryFeeCalculation = 'Delivery Service';
var promotionDiscount = 'Discount';
var tipCalculation = 'Tip';
var accessToken = undefined;
var accessTokenExpires = '';
Authorize(loop());
function Authorize(callback) {
accessToken = undefined;
var form = { grant_type: 'client_credentials', client_secret: serverKey, client_id: 'gloria' };
var formData = querystring.stringify(form);
var contentLength = formData.length;
request({
headers: {
'Content-Length': contentLength,
'Content-Type': 'application/x-www-form-urlencoded'
},
uri: 'http://' + messageServer + ':' + messageServerPort + '/Token',
body: formData,
method: 'POST'
}, function (err, res, body) {
if (err) {
console.log('Error while trying to authorize >', err.message);
}
else if (res.statusCode === 400) {
console.log(body);
if (callback) callback();
}
else {
var result = JSON.parse(body);
accessToken = result.access_token;
accessTokenExpires = new Date(result['.expires']);
if (callback) callback();
}
});
}
function gql(query, callback) {
if (!accessToken) {
console.log('Valid access Token is needed to execute GQL calls.')
return;
}
var data = JSON.stringify({ query: query });
request({
headers: {
'Content-Type': 'application/json',
'Accept': 'application/json',
'Authorization': 'Bearer ' + accessToken
},
uri: 'http://' + messageServer + ':' + messageServerPort + '/api/graphql',
body: data,
method: 'POST'
}, function (err, res, body) {
if (res.statusCode === 401) {
console.log('Should Authorize...');
Authorize(() => gql(query, callback));
}
else {
var data = JSON.parse(body).data;
if (callback) callback(data);
}
});
}
function readTickets(callback) {
request({
method: 'POST',
uri: 'https://pos.gloriafood.com/pos/order/pop',
headers: {
'Authorization': gloriaFoodKey,
'Accept': 'application/json',
'Glf-Api-Version': '2'
}
}, function (err, res, body) {
if (err) {
console.log(`problem with request: ${err.message}`);
} else {
callback(JSON.parse(body));
}
});
}
function loop() {
if (!accessToken) {
console.log('There is no valid access token. Skipping...')
Authorize();
}
else if (accessTokenExpires < new Date()) {
console.log('Access Token Expired. Reauthenticating...');
Authorize(() => loop());
return;
}
else {
console.log('Reading Tickets...');
readTickets((tickets) => processTickets(tickets));
}
setTimeout(loop, timeout);
}
function processTickets(tickets) {
if (tickets.count == 0) return;
tickets.orders.forEach((order) => processOrder(order));
}
function processOrder(order) {
var customer = {
firstName: order.client_first_name,
lastName: order.client_last_name,
email: order.client_email,
phone: order.client_phone,
address: order.client_address,
newCustomer: false
}
loadCustomer(customer, customer => {
var services = order.items
.filter(x => x.type === 'tip' || x.type === 'delivery_fee' || x.type === 'promo_cart')
.map(x => { return { name: getCalculationName(x.type), amount: Math.abs((x.cart_discount_rate) * 100) || x.price}; })
.filter(x => x.name);
loadItems(order.items.map(x => processItem(x)), items => {
createTicket(customer, items, order.instructions, order.fulfill_at, services, order.payment, ticketId => {
gql('mutation m {postTicketRefreshMessage(id:0){id}}', () => {
console.log(`Ticket ${ticketId} created...`);
});
});
});
});
}
function getCalculationName(name) {
if (name === 'promo_cart') return promotionDiscount;
if (name === 'tip') return tipCalculation;
if (name === 'delivery_fee') return deliveryFeeCalculation;
return undefined;
}
function loadItems(items, callback) {
var script = getLoadItemsScript(items);
gql(script, data => {
callback(items.filter(x => x.type === 'item').map(item => {
return {
id: item.id,
name: item.name,
type: item.type,
sambaName: data[`i${item.id}`][0] ? data[`i${item.id}`][0].name : miscProductName,
price: item.price,
quantity: item.quantity,
instructions: item.instructions,
options: item.options,
portions: item.portions
}
}));
});
}
function isNewCustomer(customer) {
if (customer.states && customer.states.find(x => x.stateName === 'CStatus')) {
return customer.states.find(x => x.stateName === 'CStatus').state === 'Unconfirmed';
}
return false;
}
function createTicket(customer, items, instructions, fulfill_at, services, payment, callback) {
var newCustomer = isNewCustomer(customer);
gql(getAddTicketScript(items, customer.name, newCustomer, instructions, fulfill_at, services, payment), data => {
if (newCustomer)
callback(data.addTicket.id);
else printTicketToKitchen(data.addTicket.id, () => callback(data.addTicket.id));
});
}
function printTicketToKitchen(ticketId, callback) {
gql(getKitchenPrintScript(ticketId), callback);
}
function loadCustomer(customer, callback) {
gql(getIsEntityExistsScript(customer), (data) => {
if (!data.isEntityExists) {
createCustomer(customer, callback);
} else getCustomer(customer.phone, callback);
});
}
function createCustomer(customer, callback) {
gql(getAddCustomerScript(customer), (data) => {
gql(getNewCustomerStateScript(customer), () => {
getCustomer(data.addEntity.name, callback);
})
});
}
function getCustomer(customerName, callback) {
gql(getCustomerScript(customerName), (data) => {
callback(data.getEntity);
});
}
function getLoadItemsScript(items) {
var part = items.map(item => `i${item.id}: getProducts(itemTag:{name:"${itemTagName}",value:"${item.name}"}){name} `);
return `{${part}}`;
}
function getCustomerScript(name) {
return `{getEntity(type:"${customerEntityType}",name:"${name}"){name,customData{name,value},states{stateName,state}}}`;
}
function getIsEntityExistsScript(customer) {
return `{isEntityExists(type:"${customerEntityType}",name:"${customer.phone}")}`;
}
function getAddCustomerScript(customer) {
return `
mutation m{addEntity(entity:{
entityType:"${customerEntityType}",name:"${customer.phone}",customData:[
{name:"First Name",value:"${customer.firstName}"},
{name:"Last Name",value:"${customer.lastName}"},
{name:"Address",value:"${customer.address}"},
{name:"EMail",value:"${customer.email}"}
]})
{name}
}`;
}
function getNewCustomerStateScript(customer) {
return `mutation m{updateEntityState(entityTypeName:"${customerEntityType}",entityName:"${customer.phone}",state:"Unconfirmed",stateName:"CStatus"){name}}`;
}
function getKitchenPrintScript(ticketId) {
return `mutation m {
executePrintJob(name: "${printJobName}", ticketId: ${ticketId},
orderStateFilters: [{stateName: "Status", state: "New"}],
nextOrderStates:[{stateName:"Status",currentState:"New",state:"Submitted"}])
{name}
}`;
}
function GetOrderTags(order) {
if (order.options) {
var options = order.options.map(x => `{tagName:"${x.group_name}",tag:"${x.name}",price:${x.price},quantity:${x.quantity}}`);
if (order.instructions) {
options.push(`{tagName:"Default",tag:"Instructions",note:"${order.instructions}"}`);
}
var result = options.join();
return `tags:[${result}],`
}
return "";
}
function GetPortions(order) {
if (order.portions) {
var portions = order.portions.map(x => `portion:"${x.name}",` );
var result = portions.join();
return `${result}`
}
return "";
}
function GetOrderPrice(order) {
if(order.portions){
var price = order.portions.map(x => `price:${Math.abs((x.price) + (order.price))},`);
var result = price.join();
return `${result}`
}
if (order.price > 0)
return `price:${order.price},`;
return "";
}
function getAddTicketScript(orders, customerName, newCustomer, instructions, fulfill_at, services, payment) {
var orderLines = orders.map(order => {
return `{
name:"${order.sambaName ? order.sambaName : order.name}",
menuItemName:"${order.sambaName === miscProductName ? order.name : ''}",
quantity:${order.quantity > 0 ? order.quantity : 1},
${GetPortions(order)}
${GetOrderPrice(order)}
${GetOrderTags(order)}
states:[
{stateName:"Status",state:"Submitted"}
]
}`;
});
var entityPart = customerName
? `entities:[{entityType:"${customerEntityType}",name:"${customerName}"}],`
: '';
var calculationsPart = services
? `calculations:[${services.map(x => `{name:"${x.name}",amount:${x.amount}}`).join()}],`
: '';
var result = `
mutation m{addTicket(
ticket:{type:"${ticketType}",
department:"${departmentName}",
user:"${userName}",
terminal:"${terminalName}",
note:"${instructions !== null ? instructions : ''}",
${entityPart}
states:[
{stateName:"Status",state:"Unpaid"},
{stateName:"Source",state:"Gloria"},
{stateName:"Payment",state:"${payment}"}
],
tags:[{tagName:"Cook Time Minutes",tag:"${Math.ceil(Math.abs(new Date(fulfill_at) - Date.now()) / 60000)}"}],
${calculationsPart}
orders:[${orderLines.join()}]
}){id}}`;
return result;
}
function processItem(item) {
var result = {
id: item.id,
name: item.name,
type: item.type,
price: item.price,
quantity: item.quantity,
instructions: item.instructions,
options: item.options.filter(x => x.type === 'option').map(x => { return { group_name: x.group_name, name: x.name, quantity: x.quantity, price: x.price } }),
portions: item.options.filter(x => x.type === 'size').map(x => { return { name: x.name, price: x.price}})
};
return result;
}