I need help please.
When i call the order i get the customer address filleds all in one line using customer _address string.
I need to poll the customer address every filled separately (street, floor, city) using the customer _address _parts object (see gloriafood documentation pic) from here integration_docs/accepted_orders at master · GlobalFood/integration_docs · GitHub
here is the script im using…
var express = require('express');
var request = require('request');
var querystring = require('querystring');
var libphonenumber = require('libphonenumber-js');
var app = express();
var messageServer = 'localhost';
var messageServerPort = 9000;
var gloriaFoodKey = 'XXXXXXX';
var serverKey = 'XXXX';
var timeout = 30000;
var customerEntityType = 'Customers';
var itemTagName = 'Gloria Name';
var ticketType = 'Ticket';
var departmentName = 'pizza';
var userName = 'איציק';
var terminalName = 'Server';
var printJobName = 'Print Bill';
var additionalPrintJobs = []; // array of additional print job names
var miscProductName = 'Misc';
var deliveryFeeCalculation = 'Delivery Service';
var tipCalculation = 'Tip';
var accessToken = undefined;
var accessTokenExpires = '';
var formatPhoneNumber = true;
var formatPhoneNumberCountry = 'IL'; // set to your ISO country code
var formatPhoneNumberFormat = 'National'; // format type, this should suffice
var formatPhoneNumberHyphen = false;
var formatPhoneNumberNoSpaces = true;
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);
if (callback) callback();
}
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 {
console.log(body);
callback(JSON.parse(body));
}
});
}
app.get('/', function (req, res) {
res.send(`Welcome to Gloria Food integration application.
<br/>
<ul>
<li><a href="/gqltest">Click here to retrieve product list</a></li>
<li><a href="/test">Click here to create a test ticket</a></li>
</ul>`);
});
app.get('/gqltest', function (req, res) {
gql('{getProducts{id,name,price}}', (data) => {
data.getProducts.forEach(x => res.write(`<div>${x.name} $${x.price}</div>`))
res.end();
});
});
app.get('/ctest', function (req, res) {
loadCustomer({ phone: "222-344 1123" }, data => {
res.send(JSON.stringify(data));
})
});
app.get('/test', function (req, res) {
processTickets(JSON.parse(getTestData()));
res.send("Ticket Created! See log for details");
});
app.listen(3000, function () {
console.log('Gloria Food integration app listening on port 3000!');
Authorize(() => loop());
});
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) {
// Format phone number
if (formatPhoneNumber) {
order.client_phone = libphonenumber.formatNumber({ country: formatPhoneNumberCountry, phone: order.client_phone }, formatPhoneNumberFormat);
if (formatPhoneNumberHyphen) {
order.client_phone = order.client_phone.replace(/ +/g, '-');
}
else {
order.client_phone = order.client_phone.replace(/-+/g, '');
}
if (formatPhoneNumberNoSpaces) { order.client_phone = order.client_phone.replace(/ +/g, ''); }
}
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.instructions, 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,
instructions: item.instructions,
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, instructions, fulfill_at, services, callback) {
var newCustomer = isNewCustomer(customer);
gql(getAddTicketScript(items, customer.name, newCustomer, instructions, 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), (data) => {
if (additionalPrintJobs && additionalPrintJobs.length > 0) {
var scripts = additionalPrintJobs.map((x) => getAdditionalPrintScript(x, ticketId)).join('\r\n');
gql(scripts, callback);
} else callback(data);
});
}
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:"כתובת",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 getAdditionalPrintScript(name, ticketId) {
var mName = name.split(' ').join('_');
return `mutation m_${mName} {
n_${mName}:executePrintJob(name: "${name}", ticketId: ${ticketId})
{name}
}`;
}
function GetOrderTags(order) {
if (order.options) {
var options = order.options.map(x => `{tagName:"Default",tag:"${x.name}",price:${x.price},quantity:${x.quantity}}`);
if (order.instructions && order.instructions !== '') {
options.push(`{tagName:"Default",tag:"Instructions",note:"${order.instructions}"}`);
}
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, instructions, 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 notePart = instructions && instructions !== ''
? `note:"${instructions}",`
: '';
var result = `
mutation m{addTicket(
ticket:{type:"${ticketType}",
department:"${departmentName}",
user:"${userName}",
terminal:"${terminalName}",
${notePart}
${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,
instructions: item.instructions,
options: item.options.map(x => { return { name: x.name, quantity: x.quantity, price: x.price } })
};
return result;
}
var getTestData = () => `{
"count": 1,
"orders": [
{
"coupons": [],
"id": 776113,
"restaurant_id": 4172,
"client_id": 188995,
"type": "delivery",
"source": "website",
"sub_total_price": 47.88,
"tax_value": 4.13,
"total_price": 62.41,
"client_first_name": "John",
"client_last_name": "Pink",
"client_email": "john.brown@sambapos.com",
"client_phone": "${Math.floor((Math.random() * 300) + 200)}-456 6699",
"pin_skipped": 0,
"restaurant_name": "John's Excellent Pizza",
"restaurant_phone": "+15558964567",
"restaurant_country": "United States of America",
"restaurant_state": "California",
"restaurant_city": "San Francisco",
"restaurant_street": "10 Market Street",
"restaurant_zipcode": "1234678",
"restaurant_latitude": "37.7944872589999",
"restaurant_longitude": "-122.395311999999",
"instructions": "Deliver ASAP",
"currency": "USD",
"latitude": "37.79448725889753",
"longitude": "-122.395311680426",
"tax_type": "NET",
"tax_name": "Sales Tax",
"fulfill_at": "${ new Date(new Date().getTime() + 25 * 60000).toISOString()}",
"pos_system_id": 1,
"restaurant_key": "8yCPCvb3dDo1k",
"api_version": 2,
"payment": "ONLINE",
"client_address": "21 Market Street, San Francisco",
"items": [
{
"id": 1678316,
"name": "DELIVERY_FEE",
"total_item_price": 5,
"price": 5,
"quantity": 1,
"instructions": null,
"type_id": null,
"type": "delivery_fee",
"tax_rate": 0.1,
"tax_value": 0.5,
"parent_id": null,
"cart_discount_rate": 0,
"cart_discount": 0,
"tax_type": "NET",
"item_discount": 0,
"options": []
},
{
"id": 1678317,
"name": "TIP",
"total_item_price": 5.67,
"price": 5.67,
"quantity": 1,
"instructions": null,
"type_id": null,
"type": "tip",
"tax_rate": 0.05,
"tax_value": 0.2702,
"parent_id": null,
"cart_discount_rate": 0,
"cart_discount": 0,
"tax_type": "GROSS",
"item_discount": 0,
"options": []
},
{
"id": 1678322,
"name": "Pizza Margherita",
"total_item_price": 8.2,
"price": 7,
"quantity": 1,
"instructions": "",
"type_id": 58424,
"type": "item",
"tax_rate": 0.07,
"tax_value": 0,
"parent_id": 1678332,
"cart_discount_rate": 0,
"cart_discount": 0,
"tax_type": "NET",
"item_discount": 8.2,
"options": [
{
"id": 1771325,
"name": "Small",
"price": 0,
"group_name": "Size",
"quantity": 1,
"type": "size"
},
{
"id": 1771326,
"name": "Crispy",
"price": 0,
"group_name": "Crust",
"quantity": 1,
"type": "option"
},
{
"id": 1771327,
"name": "Extra mozzarella",
"price": 1.2,
"group_name": "Extra Toppings (Small)",
"quantity": 1,
"type": "option"
}
]
},
{
"id": 1678324,
"name": "Pizza Prosciutto",
"total_item_price": 11.7,
"price": 8,
"quantity": 1,
"instructions": "User may enter a very long description for the pizza. For example he may want to explain what kind of sauce he wants or how dough should be cooked. So we should handle that case properly.",
"type_id": 58425,
"type": "item",
"tax_rate": 0.07,
"tax_value": 0.819,
"parent_id": 1678332,
"cart_discount_rate": 0,
"cart_discount": 0,
"tax_type": "NET",
"item_discount": 0,
"options": [
{
"id": 1771331,
"name": "Large",
"price": 2,
"group_name": "Size",
"quantity": 1,
"type": "size"
},
{
"id": 1771332,
"name": "Crispy",
"price": 0,
"group_name": "Crust",
"quantity": 1,
"type": "option"
},
{
"id": 1771333,
"name": "Extra mozzarella",
"price": 1.7,
"group_name": "Extra Toppings (Large)",
"quantity": 1,
"type": "option"
}
]
},
{
"id": 1678331,
"name": "Pizza Prosciutto",
"total_item_price": 8.7,
"price": 8,
"quantity": 2,
"instructions": "no salt",
"type_id": 58425,
"type": "item",
"tax_rate": 0.07,
"tax_value": 0.609,
"parent_id": 1678332,
"cart_discount_rate": 0,
"cart_discount": 0,
"tax_type": "NET",
"item_discount": 0,
"options": [
{
"id": 1771343,
"name": "Small",
"price": 0,
"group_name": "Size",
"quantity": 1,
"type": "size"
},
{
"id": 1771344,
"name": "Fluffy",
"price": 0,
"group_name": "Crust",
"quantity": 1,
"type": "option"
},
{
"id": 1771345,
"name": "Corn",
"price": 0.7,
"group_name": "Extra Toppings (Small)",
"quantity": 1,
"type": "option"
}
]
},
{
"id": 1678332,
"name": "2 + 1 Pizza Special",
"total_item_price": 28.6,
"price": 0,
"quantity": 1,
"instructions": null,
"type_id": 251,
"type": "promo_item",
"tax_rate": 0.07,
"tax_value": 1.3566,
"parent_id": null,
"cart_discount_rate": 0.05,
"cart_discount": 1.02,
"tax_type": "NET",
"item_discount": 8.2,
"options": []
},
{
"id": 1678334,
"name": "Spaghetti Bolognese",
"total_item_price": 18,
"price": 9,
"quantity": 2,
"instructions": "",
"type_id": 58426,
"type": "item",
"tax_rate": 0.07,
"tax_value": 1.197,
"parent_id": null,
"cart_discount_rate": 0.05,
"cart_discount": 0.9,
"tax_type": "NET",
"item_discount": 0,
"options": []
},
{
"id": 1678335,
"name": "Spaghetti Frutti di Mare",
"total_item_price": 12,
"price": 12,
"quantity": 1,
"instructions": "",
"type_id": 58427,
"type": "item",
"tax_rate": 0.07,
"tax_value": 0.798,
"parent_id": null,
"cart_discount_rate": 0.05,
"cart_discount": 0.6,
"tax_type": "NET",
"item_discount": 0,
"options": []
},
{
"id": 1678336,
"name": "5% off total larger than 40$",
"total_item_price": 0,
"price": 0,
"quantity": 1,
"instructions": null,
"type_id": 250,
"type": "promo_cart",
"tax_rate": 0.07,
"tax_value": 0,
"parent_id": null,
"cart_discount_rate": 0.05,
"cart_discount": -2.52,
"tax_type": "NET",
"item_discount": 2.52,
"options": []
}
]
}
]
}`;