Advertisement
Guest User

Untitled

a guest
Apr 29th, 2021
162
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
  1. var express = require('express');
  2. var request = require('request');
  3. var querystring = require('querystring');
  4. var libphonenumber = require('libphonenumber - js');
  5. var app = express();
  6. var messageServer = 'localhost';
  7. var messageServerPort = 9000;
  8. var gloriaFoodKey = 'XXXXXXX';
  9. var serverKey = '553181';
  10. var timeout = 30000;
  11. var customerEntityType = 'Customers';
  12. var itemTagName = 'Gloria Name';
  13. var ticketType = 'Ticket';
  14. var departmentName = 'pizza';
  15. var userName = 'Administrator';
  16. var terminalName = 'Server';
  17. var printJobName = 'Print Bill';
  18. var additionalPrintJobs = []; // array of additional print job names
  19. var miscProductName = 'Misc';
  20. var deliveryFeeCalculation = 'Delivery Service';
  21. var tipCalculation = 'Tip';
  22. var accessToken = undefined;
  23. var accessTokenExpires = '';
  24.  
  25. var formatPhoneNumber = true;
  26. var formatPhoneNumberCountry = 'IL'; // set to your ISO country code
  27. var formatPhoneNumberFormat = 'National'; // format type, this should suffice
  28. var formatPhoneNumberHyphen = false;
  29. var formatPhoneNumberNoSpaces = true;
  30.  
  31. Authorize(loop());
  32.  
  33. function Authorize(callback) {
  34.     accessToken = undefined;
  35.     var form = {
  36.         grant_type: 'client_credentials',
  37.         client_secret: serverKey,
  38.         client_id: 'gloria'
  39.     };
  40.     var formData = querystring.stringify(form);
  41.     var contentLength = formData.length;
  42.  
  43.     request({
  44.         headers: {
  45.             'Content-Length': contentLength,
  46.             'Content-Type': 'application/x-www-form-urlencoded'
  47.         },
  48.         uri: 'http://' + messageServer + ':' + messageServerPort + '/Token',
  49.         body: formData,
  50.         method: 'POST'
  51.     }, function (err, res, body) {
  52.         if (err) {
  53.             console.log('Error while trying to authorize >', err.message);
  54.         } else if (res.statusCode === 400) {
  55.             console.log(body);
  56.             if (callback) callback();
  57.         } else {
  58.             var result = JSON.parse(body);
  59.             accessToken = result.access_token;
  60.             accessTokenExpires = new Date(result['.expires']);
  61.             if (callback) callback();
  62.         }
  63.     });
  64. }
  65.  
  66. function gql(query, callback) {
  67.     if (!accessToken) {
  68.         console.log('Valid access Token is needed to execute GQL calls.')
  69.         return;
  70.     }
  71.     var data = JSON.stringify({
  72.         query: query
  73.     });
  74.     request({
  75.         headers: {
  76.             'Content-Type': 'application/json',
  77.             'Accept': 'application/json',
  78.             'Authorization': 'Bearer ' + accessToken
  79.         },
  80.         uri: 'http://' + messageServer + ':' + messageServerPort + '/api/graphql',
  81.         body: data,
  82.         method: 'POST'
  83.     }, function (err, res, body) {
  84.         if (res.statusCode === 401) {
  85.             console.log('Should Authorize...');
  86.             Authorize(() => gql(query, callback));
  87.         } else {
  88.             var data = JSON.parse(body).data;
  89.             if (callback) callback(data);
  90.         }
  91.     });
  92. }
  93.  
  94. function readTickets(callback) {
  95.     request({
  96.         method: 'POST',
  97.         uri: 'https://pos.gloriafood.com/pos/order/pop',
  98.         headers: {
  99.             'Authorization': gloriaFoodKey,
  100.             'Accept': 'application/json',
  101.             'Glf-Api-Version': '2'
  102.         }
  103.     }, function (err, res, body) {
  104.         if (err) {
  105.             console.log(`problem with request: ${err.message}`);
  106.         } else {
  107.             callback(JSON.parse(body));
  108.         }
  109.     });
  110. }
  111.  
  112. function loop() {
  113.     if (!accessToken) {
  114.         console.log('There is no valid access token. Skipping...')
  115.         Authorize();
  116.     } else if (accessTokenExpires < new Date()) {
  117.         console.log('Access Token Expired. Reauthenticating...');
  118.         Authorize(() => loop());
  119.         return;
  120.     } else {
  121.         console.log('Reading Tickets...');
  122.         readTickets((tickets) => processTickets(tickets));
  123.     }
  124.     setTimeout(loop, timeout);
  125. }
  126.  
  127. function processTickets(tickets) {
  128.     if (tickets.count == 0) return;
  129.     tickets.orders.forEach((order) => processOrder(order));
  130. }
  131.  
  132. function processOrder(order) {
  133.     // Format phone number
  134.     if (formatPhoneNumber) {
  135.         order.client_phone = libphonenumber.formatNumber({
  136.             country: formatPhoneNumberCountry,
  137.             phone: order.client_phone
  138.         }, formatPhoneNumberFormat);
  139.  
  140.         if (formatPhoneNumberHyphen) {
  141.             order.client_phone = order.client_phone.replace(/ +/g, '-');
  142.         } else {
  143.             order.client_phone = order.client_phone.replace(/-+/g, '');
  144.         }
  145.  
  146.         if (formatPhoneNumberNoSpaces) {
  147.             order.client_phone = order.client_phone.replace(/ +/g, '');
  148.         }
  149.     }
  150.  
  151.     var street = null;
  152.     var bloc = null;
  153.     var floor = null;
  154.     var apartment = null;
  155.     var intercom = null;
  156.     var moreAddress = null;
  157.     var zipcode = null;
  158.     var city = null;
  159.  
  160.     if (order.client_address_parts != null) {
  161.         street = order.client_address_parts.street;
  162.         bloc = order.client_address_parts.bloc;
  163.         floor = order.client_address_parts.floor;
  164.         apartment = order.client_address_parts.apartment;
  165.         intercom = order.client_address_parts.intercom;
  166.         moreAddress = order.client_address_parts.more_address;
  167.         zipcode = order.client_address_parts.zipcode;
  168.         city = order.client_address_parts.city;
  169.     }
  170.  
  171.     var customer = {
  172.         firstName: order.client_first_name,
  173.         lastName: order.client_last_name,
  174.         email: order.client_email,
  175.         phone: order.client_phone,
  176.         street: street,
  177.         city: city,
  178.         bloc: bloc,
  179.         floor: floor,
  180.         apartment: apartment,
  181.         intercom: intercom,
  182.         moreAddress: moreAddress,
  183.         zipcode: zipcode,
  184.         newCustomer: false
  185.     }
  186.  
  187.     loadCustomer(customer, customer => {
  188.         var services = order.items
  189.             .filter(x => x.type === 'tip' || x.type === 'delivery_fee' || x.type === 'promo_cart')
  190.             .map(x => {
  191.                 return {
  192.                     name: getCalculationName(x.type),
  193.                     amount: Math.abs((x.cart_discount_rate) * 100) || x.price
  194.                 };
  195.             })
  196.             .filter(x => x.name);
  197.         loadItems(order.items.map(x => processItem(x)), items => {
  198.             createTicket(customer, items, order.instructions, order.fulfill_at, services, order.payment, ticketId => {
  199.                 gql('mutation m {postTicketRefreshMessage(id:0){id}}', () => {
  200.                     console.log(`Ticket ${ticketId} created...`);
  201.                 });
  202.             });
  203.         });
  204.     });
  205. }
  206.  
  207. function getCalculationName(name) {
  208.     if (name === 'promo_cart') return promotionDiscount;
  209.     if (name === 'tip') return tipCalculation;
  210.     if (name === 'delivery_fee') return deliveryFeeCalculation;
  211.     return undefined;
  212. }
  213.  
  214. function loadItems(items, callback) {
  215.     var script = getLoadItemsScript(items);
  216.     gql(script, data => {
  217.         callback(items.filter(x => x.type === 'item').map(item => {
  218.             return {
  219.                 id: item.id,
  220.                 name: item.name,
  221.                 type: item.type,
  222.                 sambaName: data[`i${item.id}`][0] ? data[`i${item.id}`][0].name : miscProductName,
  223.                 price: item.price,
  224.                 quantity: item.quantity,
  225.                 instructions: item.instructions,
  226.                 options: item.options,
  227.                 portions: item.portions
  228.             }
  229.         }));
  230.     });
  231. }
  232.  
  233. function isNewCustomer(customer) {
  234.     if (customer.states && customer.states.find(x => x.stateName === 'CStatus')) {
  235.         return customer.states.find(x => x.stateName === 'CStatus').state === 'Unconfirmed';
  236.     }
  237.     return false;
  238. }
  239.  
  240. function createTicket(customer, items, instructions, fulfill_at, services, payment, callback) {
  241.     var newCustomer = isNewCustomer(customer);
  242.     gql(getAddTicketScript(items, customer.name, newCustomer, instructions, fulfill_at, services, payment), data => {
  243.         if (newCustomer)
  244.             callback(data.addTicket.id);
  245.         else printTicketToKitchen(data.addTicket.id, () => callback(data.addTicket.id));
  246.     });
  247. }
  248.  
  249. function printTicketToKitchen(ticketId, callback) {
  250.     gql(getKitchenPrintScript(ticketId), callback);
  251. }
  252.  
  253. function loadCustomer(customer, callback) {
  254.     gql(getIsEntityExistsScript(customer), (data) => {
  255.         if (!data.isEntityExists) {
  256.             createCustomer(customer, callback);
  257.         } else getCustomer(customer.phone, callback);
  258.     });
  259. }
  260.  
  261. function createCustomer(customer, callback) {
  262.     gql(getAddCustomerScript(customer), (data) => {
  263.         gql(getNewCustomerStateScript(customer), () => {
  264.             getCustomer(data.addEntity.name, callback);
  265.         })
  266.     });
  267. }
  268.  
  269. function getCustomer(customerName, callback) {
  270.     gql(getCustomerScript(customerName), (data) => {
  271.         callback(data.getEntity);
  272.     });
  273. }
  274.  
  275. function getLoadItemsScript(items) {
  276.     var part = items.map(item => `i${item.id}: getProducts(itemTag:{name:"${itemTagName}",value:"${item.name}"}){name} `);
  277.     return `{${part}}`;
  278. }
  279.  
  280. function getCustomerScript(name) {
  281.     return `{getEntity(type:"${customerEntityType}",name:"${name}"){name,customData{name,value},states{stateName,state}}}`;
  282. }
  283.  
  284. function getIsEntityExistsScript(customer) {
  285.     return `{isEntityExists(type:"${customerEntityType}",name:"${customer.phone}")}`;
  286. }
  287.  
  288. function getAddCustomerScript(customer) {
  289.     return `
  290.         mutation m{addEntity(entity:{
  291.             entityType:"${customerEntityType}",name:"${customer.phone}",customData:[
  292.                 {name:"First Name",value:"${customer.firstName}"},
  293.                 {name:"Last Name",value:"${customer.lastName}"},
  294.                 {name:"Address",value:"${customer.address}"},
  295.                 {name:"EMail",value:"${customer.email}"},
  296.                 {name:"street",value:"${customer.street}"}
  297.             ]})
  298.             {name}
  299.          }`;
  300. }
  301.  
  302. function getNewCustomerStateScript(customer) {
  303.     return `mutation m{updateEntityState(entityTypeName:"${customerEntityType}",entityName:"${customer.phone}",state:"Unconfirmed",stateName:"CStatus"){name}}`;
  304. }
  305.  
  306. function getKitchenPrintScript(ticketId) {
  307.     return `mutation m {
  308.                     executePrintJob(name: "${printJobName}", ticketId: ${ticketId},
  309.                         orderStateFilters: [{stateName: "Status", state: "New"}],
  310.                         nextOrderStates:[{stateName:"Status",currentState:"New",state:"Submitted"}])
  311.                     {name}
  312.                 }`;
  313. }
  314.  
  315. function GetOrderTags(order) {
  316.     if (order.options) {
  317.         var options = order.options.map(x => `{tagName:"${x.group_name}",tag:"${x.name}",price:${x.price},quantity:${x.quantity}}`);
  318.         if (order.instructions) {
  319.             options.push(`{tagName:"Default",tag:"Instructions",note:"${order.instructions}"}`);
  320.         }
  321.         var result = options.join();
  322.         return `tags:[${result}],`
  323.     }
  324.     return "";
  325. }
  326.  
  327. function GetPortions(order) {
  328.     if (order.portions) {
  329.         var portions = order.portions.map(x => `portion:"${x.name}",`);
  330.         var result = portions.join();
  331.         return `${result}`
  332.     }
  333.     return "";
  334. }
  335.  
  336. function GetOrderPrice(order) {
  337.     if (order.portions) {
  338.         var price = order.portions.map(x => `price:${Math.abs((x.price) + (order.price))},`);
  339.         var result = price.join();
  340.         return `${result}`
  341.     }
  342.     if (order.price > 0)
  343.         return `price:${order.price},`;
  344.     return "";
  345.  
  346. }
  347.  
  348. function getAddTicketScript(orders, customerName, newCustomer, instructions, fulfill_at, services, payment) {
  349.     var orderLines = orders.map(order => {
  350.         return `{
  351.                 name:"${order.sambaName ? order.sambaName : order.name}",
  352.                 menuItemName:"${order.sambaName === miscProductName ? order.name : ''}",
  353.                 quantity:${order.quantity > 0 ? order.quantity : 1},
  354.                 ${GetPortions(order)}
  355.                 ${GetOrderPrice(order)}
  356.                 ${GetOrderTags(order)}
  357.                 states:[
  358.                     {stateName:"Status",state:"Submitted"}
  359.                 ]
  360.             }`;
  361.     });
  362.  
  363.     var entityPart = customerName ?
  364.         `entities:[{entityType:"${customerEntityType}",name:"${customerName}"}],` :
  365.         '';
  366.     var calculationsPart = services ?
  367.         `calculations:[${services.map(x => `{name:"${x.name}",amount:${x.amount}}`).join()}],` :
  368.         '';
  369.  
  370.     var result = `
  371.             mutation m{addTicket(
  372.                 ticket:{type:"${ticketType}",
  373.                     department:"${departmentName}",
  374.                     user:"${userName}",
  375.                     terminal:"${terminalName}",
  376.                     note:"${instructions !== null ? instructions : ''}",
  377.                     ${entityPart}
  378.                     states:[
  379.                         {stateName:"Status",state:"Unpaid"},
  380.                         {stateName:"Source",state:"Gloria"},
  381.                         {stateName:"Payment",state:"${payment}"}
  382.                     ],
  383.                     tags:[{tagName:"Cook Time Minutes",tag:"${Math.ceil(Math.abs(new Date(fulfill_at) - Date.now()) / 60000)}"}],
  384.                     ${calculationsPart}
  385.                     orders:[${orderLines.join()}]
  386.                 }){id}}`;
  387.     return result;
  388. }
  389.  
  390. function processItem(item) {
  391.     var result = {
  392.         id: item.id,
  393.         name: item.name,
  394.         type: item.type,
  395.         price: item.price,
  396.         quantity: item.quantity,
  397.         instructions: item.instructions,
  398.         options: item.options.filter(x => x.type === 'option').map(x => {
  399.             return {
  400.                 group_name: x.group_name,
  401.                 name: x.name,
  402.                 quantity: x.quantity,
  403.                 price: x.price
  404.             }
  405.         }),
  406.         portions: item.options.filter(x => x.type === 'size').map(x => {
  407.             return {
  408.                 name: x.name,
  409.                 price: x.price
  410.             }
  411.         })
  412.     };
  413.     return result;
  414. }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement