Please help with GlobalFood integration javascript

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 ) 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": []
                }
            ]
        }
    ]
}`;

This is a learning site so we like to help people. If you have some code you are working on, let use see it and let us know what the problem is and we’ll see if we can help.

1 Like

Thanks for the reply.
I’m using the following script to pull orders from gloriafood ordering system to my pos.
When i call the customer address All filleds comes in one line and i need it every filled separately.
Gloriafood integration alow to do that but i dont know how.

I will also show you the gloriafood documentation here

When working on a problem, I always like to break things into smaller pieces. It sounds like you’re having an issue hitting their endpoint? I would recommend reducing this to a single task - hit that endpoint and display the data. You could do a really simple JS file, or you could even test it with an app like Postman.

this is the part that puuls the all address using the client_address string

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}
    }`;
}

this is how i recive the data… "client_address_parts":{"street":"Ein mor","city":"Eilat","floor":"Flor","apartment":"6"}

How can i call the client _addres_parts object??
Please help

OK, so you are dealing with GraphQL with that. I like GQL but I haven’t spent a lot of time on it. That will take me a while to work through, or maybe someone smarter than I will jump in.

thank you so much…

@kevinSmith .
Finally I found the way to make it work as i asked here.
Thanks for your reply…:blush:
Here is the working script…

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 = 'XXXXXXXXX';
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 street = null;
var bloc = null;
var floor = null;
var apartment = null;
var intercom = null;
var moreAddress = null;
var zipcode = null;
var city = null;

if (order.client_address_parts != null){
    street = order.client_address_parts.street;
    bloc = order.client_address_parts.bloc;
    floor = order.client_address_parts.floor;
    apartment = order.client_address_parts.apartment;
    intercom = order.client_address_parts.intercom;
    moreAddress = order.client_address_parts.more_address;
    zipcode = order.client_address_parts.zipcode;
    city = order.client_address_parts.city;
}
	
    var customer = {
        firstName: order.client_first_name,
        lastName: order.client_last_name,
        email: order.client_email,
        phone: order.client_phone,
        address: order.client_address,
        street: street,
        city: city,
        floor: floor,
        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:"address",value:"${customer.address}"},
            {name:"EMail",value:"${customer.email}"},
            {name:"street",value:"${customer.street}"},
            {name:"city",value:"${customer.city}"}
            {name:"floor",value:"${customer.floor}"}
        ]})
        {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": []
                }
            ]
        }
    ]
}`;
1 Like

This topic was automatically closed 182 days after the last reply. New replies are no longer allowed.