You know that idea you always keep at the bottom of your backlog for that elusive day you’ll find enough time to address? For me, it’s the possibility to connect a chatbot to an SAP system. And it only took a global lockdown to finally get to it. Let’s do this !
Creating a Google Chatbot connected to the SAP Graph API
Note: The Google Chat application, and the developer platform, are only available to G Suite accounts. You will not be able to develop or test a bot with only an @gmail.com account. |
High-Level Diagram
Warning: if you have multiple Google Accounts, always make sure that the correct account is selected at the top right of the Google Apps Scripts screen |
Warning: at time of publication, the new UI editor in Google Apps Scripts does not yet support the Publish function. Make sure to use the classic editor as in the screenshots |
The Google Chat bot Template. Source: Google
Getting the Deployment ID from the Apps Scripts App. Source: Google
Warning: if you have multiple Google Accounts, make sure that the correct one is selected at the top right of the Google Apps Scripts screen |
Create a new Project to Enable the API. Source: Google
Select the Project in the API Console. Source: Google
Activate the Chat API. Source: Google
Click Configuration for Google Chat API. Source: Google
Google Chat API Configuration. Source: Google
Search for your chatbot. Source: Google
Testing the chatbot. Source: Google
Search for the Sales Orders service. Source: SAP
Running the Default Sales Orders query. Source: SAP
Running the Sales Orders query for the top 5 by Gross Amount. Source: SAP
Note: Copy / pasting the authorization token is only a shortcut for this tutorial. In production, the token should be short-lived and user-specific. Therefore, they couldn’t / shouldn’t be hard-coded. |
The authorization token under the Headers tab. Source: SAP
Note: all the code listed in the current document can be found in this GitHub repository |
var TOKEN = <<TOKEN>>;
function testAPI() {
// URL to the API
var url = 'https://api.graph.sap/beta/SalesOrders'; // SAP Graph API
// Pass security credentials
var headers = {'Authorization':'Bearer ' + TOKEN }
// Pass headers
var options = {
'method': 'GET',
'contentType': 'application/json',
'headers': headers
};
// Perform the call and parse the JSON result
var response = UrlFetchApp.fetch(url, options);
var data = JSON.parse(response.getContentText());
// Only keep the ‘value’ element of the response
var valueList = data['value'];
console.log(valueList);
}
Logs from test API call. Source: Google
/**
* Responds to a MESSAGE event in Google Chat.
*
* @param {Object} event the event object from Google Chat
*/
function onMessage(event) {
var widgets = buildCardMenu();
return createCardResponse(widgets);
}
/**
* Build Card for default Menu
*/
function buildCardMenu() {
// Prepare a collection of buttons
var buttonList = [];
// Add button for Sales Orders
var button = {textButton: {
text: 'Sales Orders<br/>',
onClick: {
action: {
actionMethodName: 'displaySalesOrders'
}
}
}};
buttonList.push(button);
// Collect all buttons and add header
var widgets = [{
textParagraph: {
text: '<b>Please select a command</b><br/>'
}
}, {
buttons: buttonList
}];
return widgets;
}
/**
* Create Card Response
* @param{object} widgets - content for the card
*/
function createCardResponse(widgets) {
return {
cards: [{
sections: [{
widgets: widgets
}]
}]
};
}
Google Chat Bot showing a Menu Card
/**
* Default Values
*/
var TOKEN = <<TOKEN>>;
/**
* Responds to a CARD_CLICKED event triggered in Google Chat.
* @param {object} event the event object from Google Chat
* @return {object} JSON-formatted response
* @see https://developers.google.com/hangouts/chat/reference/message-formats/events
*/
function onCardClick(event) {
// React to buttons clicked on the cards based on the actionMethodName
var content = '';
var widgets = '';
switch( event.action.actionMethodName ) {
case 'displaySalesOrders':
content = getSalesOrders();
widgets = buildCardList(content);
break;
default:
return { 'text': 'Unknown command' };
}
return createCardResponse(widgets);
}
/**
* Build Card Format for Lists
* @param(array) content - list of values with id / amount / currency code
*/
function buildCardList(content) {
// Build a array of buttons with item as id / amount / currency_code
// Use id as parameter for the button
var buttons = [];
// Process each of the order items in the content array
for( var i = 0; i < content['values'].length; i++ ) {
var content_line = content['values'][i];
// Convert id / amount / currency as string
// Such as 1234: 245 USD
// Each line becomes a button for the use to click
var button_text = {textButton: {
text: content_line['id'] + ' : ' + content_line['amount'] + ' ' + content_line['currency'] + '<br/>',
onClick: {
action: {
actionMethodName: 'displaySalesOrderById',
parameters: [{
key: 'id',
value: content_line['id']
}]
}
}
}};
buttons.push(button_text);
}
// Collect all buttons and add header
var widgets = [{
textParagraph: {
text: '<b>' + content['type'] + '</b>'
}
}, {
buttons: buttons
}];
return widgets;
}
/**
* Get Sales Orders from the SAP Graph API
*/
function getSalesOrders() {
// Build the call to the SAP Graph API
// URL to the API
var url = 'https://api.graph.sap/beta/SalesOrders?$top=5&$orderby=grossAmount desc';
// Pass the security credentials
var headers = {'Authorization':'Bearer ' + TOKEN }
// Pass headers
var options = {
'method': 'GET',
'contentType': 'application/json',
'headers': headers
};
// Perform the call and parse the JSON result
var response = UrlFetchApp.fetch(url, options);
var data = JSON.parse(response.getContentText());
// Only keep the ‘value’ element of the response
var value_list = data['value'];
// Build the return list as an array with id / amount / currency
var order_list = [];
for( var i = 0; i < value_list.length; i++ )
{
order_list.push( {'id' : value_list[i]['id'],
'amount' : value_list[i]['grossAmount'],
'currency' : value_list[i]['currency_code']} );
}
// Build header and combine with order list
var content = { 'type' : 'Top 5 Sales Orders by Gross Amount',
'values' : order_list };
return content;
}
Google Chat Bot showing a List Card
/**
* Responds to a CARD_CLICKED event triggered in Google Chat.
* @param {object} event the event object from Google Chat
* @return {object} JSON-formatted response
* @see https://developers.google.com/hangouts/chat/reference/message-formats/events
*/
function onCardClick(event) {
// React to buttons clicked on the cards based on the actionMethodName
var content = '';
var widgets = '';
// Distribute actions based on the actionMethodName
switch( event.action.actionMethodName ) {
case 'displaySalesOrders': // Display Sales Orders
content = getSalesOrders();
widgets = buildCardList(content);
break;
case 'displaySalesOrderById': // Display one Sales Order with Id
content = getSalesOrderById(event.action.parameters[0]['value']);
widgets = buildCardDetails(content);
break;
default:
return { 'text': 'Unknown command' };
}
// Convert response to the right card format
return createCardResponse(widgets);
}
/**
* Get Sales Orders for specific Sales Order Id from the SAP Graph API
* @param {id} Identification of the Sales Order
*/
function getSalesOrderById(id) {
// Build the call to the SAP Graph API
// URL to the API
var url = 'https://api.graph.sap/beta/SalesOrders/' + id; // SAP Graph API
// Pass security credentials
var headers = {'Authorization':'Bearer ' + TOKEN }
// Pass headers
var options = {
'method': 'GET',
'contentType': 'application/json',
'headers': headers
};
// Perform the call and parse the JSON result
var response = UrlFetchApp.fetch(url, options);
var data = JSON.parse(response.getContentText());
// Collect all values as field name / value pairs as an array
// Example: {‘field’:’Sales Order ID’, ‘value’: 1234 }
var order_list = [];
order_list.push( {'field' : 'Sales Order ID', 'value' : data['id'] } );
order_list.push( {'field' : 'Gross Amount' , 'value' : data['grossAmount'] } );
order_list.push( {'field' : 'Tax Amount' , 'value' : data['taxAmount'] } );
order_list.push( {'field' : 'Net Amount' , 'value' : data['netAmount'] } );
order_list.push( {'field' : 'Currency' , 'value' : data['currency_code'] } );
order_list.push( {'field' : 'Customer ID' , 'value' : data['customerID'] } );
order_list.push( {'field' : 'Contact ID' , 'value' : data['contactID'] } );
order_list.push( {'field' : 'Ship To ID' , 'value' : data['shipToID'] } );
order_list.push( {'field' : 'Owner ID' , 'value' : data['ownerID'] } );
order_list.push( {'field' : 'Order Date' , 'value' : data['orderDate'] } );
// Build header and combine with field list
var content = { 'type' : 'Details for Sales Order: ' + id,
'values' : order_list };
return content;
}
/**
* Build Card Details
*/
function buildCardDetails(content) {
// Build the return card showing each field and value
// Values were passed in content as a array of field name / value pairs
// Example: {‘field’:’Sales Order ID’, ‘value’: 1234 }
// Convert to a string, such as Sales Order ID : 1234
var text = "";
for( var i = 0; i < content['values'].length; i++ ) {
var content_line = content['values'][i];
text += content_line['field'] + ' : ' + content_line['value'] + '<br/>';
}
// Return the header and the content
var widgets = [{
textParagraph: {
text: '<b>' + content['type'] + '</b><br/>' + text
}
}];
return widgets;
}
Google Chat Bot showing a Details Card
List of executions and status from the Apps Script Dashboard. Source: Google
You must be a registered user to add a comment. If you've already registered, sign in. Otherwise, register and sign in.
Subject | Kudos |
---|---|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
User | Count |
---|---|
6 | |
5 | |
3 | |
3 | |
3 | |
3 | |
2 | |
2 | |
2 | |
2 |