Created
February 27, 2017 23:15
-
-
Save emreeren/0d26aca9b83415fa01fcc3b5d2f172ad to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
var express = require('express'); | |
var request = require('request'); | |
var querystring = require('querystring'); | |
var messageServer = 'localhost'; | |
var messageServerPort = 9000; | |
var gloriaFoodKey = 'xxxxxxxxxxxxxxxxxx'; | |
var serverKey = 'xxxxxxxxxxxxxxxxxxx'; | |
var timeout = 30000; | |
var customerEntityType = 'Customers'; | |
var itemTagName = 'Gloria Name'; | |
var ticketType = 'Delivery 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 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') | |
.map(x => { return { name: getCalculationName(x.type), amount: x.price }; }) | |
.filter(x => x.name); | |
loadItems(order.items.map(x => processItem(x)), items => { | |
createTicket(customer, items, order.fulfill_at, services, ticketId => { | |
gql('mutation m {postTicketRefreshMessage(id:0){id}}', () => { | |
console.log(`Ticket ${ticketId} created...`); | |
}); | |
}); | |
}); | |
}); | |
} | |
function getCalculationName(name) { | |
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, | |
options: item.options | |
} | |
})); | |
}); | |
} | |
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, fulfill_at, services, callback) { | |
var newCustomer = isNewCustomer(customer); | |
gql(getAddTicketScript(items, customer.name, newCustomer, fulfill_at, services), 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:"Default",tag:"${x.name}",price:${x.price},quantity:${x.quantity}}`); | |
var result = options.join(); | |
return `tags:[${result}],` | |
} | |
return ""; | |
} | |
function GetOrderPrice(order) { | |
if (order.price > 0) | |
return `price:${order.price},`; | |
return ""; | |
} | |
function getAddTicketScript(orders, customerName, newCustomer, fulfill_at, services) { | |
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}, | |
${GetOrderPrice(order)} | |
${GetOrderTags(order)} | |
states:[ | |
{stateName:"Status",state:"New"} | |
] | |
}`; | |
}); | |
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}", | |
${entityPart} | |
states:[ | |
{stateName:"Status",state:"Unpaid"}, | |
{stateName:"Source",state:"Gloria"}, | |
{stateName:"Delivery",state:"${newCustomer ? 'Unconfirmed' : 'Waiting'}"} | |
], | |
tags:[{tagName:"Delivery 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, | |
options: item.options.map(x => { return { name: x.name, quantity: x.quantity, price: x.price } }) | |
}; | |
return result; | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment