So, I'm currently using this:
<!DOCTYPE html>
<html>
<body>
<div id="webchat"></div>
<script src="https://cdn.botframework.com/botframework-webchat/preview/botchat.js"></script>
<script>
window.WebChat.renderWebChat({
directLine: window.WebChat.createDirectLine({ secret: 'YOUR_BOT_SECRET_FROM_AZURE_PORTAL' })
}, document.getElementById('webchat'));
</script>
</body>
</html>
and it works fine, however I have multiple QnA Knowledge base for different client applications. SO I would like to pass custom parameter for 'applicationname' to decide the QNA KB in my BOT frame work(V4) in OnTurnAsync method.
I tried
var d1 = window.WebChat.createDirectLine({ token })
window.WebChat.renderWebChat({
directLine: d1,
styleSet,
postActivity: activity => {
var newActivity = Object.assign({}, activity, {channelData: { "userparam": "test" } });
return dl.postActivity(newActivity);
}
}, document.getElementById('webchat'));
})();
but Context.Activity.ChannelData in bot returning Null
and also tried
var d1 = window.WebChat.createDirectLine({ token })
window.WebChat.renderWebChat({
directLine: d1,
user: { id: 'userid', userparam:'test'},
styleSet
}, document.getElementById('webchat'));
})();
still Context.Activity.From.Properties["userparam"] returns Null
From Cilent Side
var d1 = window.WebChat.createDirectLine({ token })
window.WebChat.renderWebChat({
directLine: Object.assign({}, d1, {
postActivity: activity => {
var newActivity = Object.assign({}, activity, { channelData: { "param1": "test" } });
return d1.postActivity(newActivity);
}
}),
styleSet,
botAvatarInitials: 'CAB',
userAvatarInitials: 'You'
}, document.getElementById('webchat'));
})();
from BOt Framework
var channelObj = turnContext.Activity.ChannelData.ToString();
var channeldata = Newtonsoft.Json.Linq.JObject.Parse(channelObj);
var customdata = channeldata["param1"].ToString();
The other answer provided is helpful but it overwrites channelData. For others finding this answer and just wanting to send custom parameters, this will be helpful:
const originalDirectline = props.webchat.createDirectLine({
token,
})
const directLine = Object.assign({}, originalDirectline, {
postActivity: (activity: any) => {
const newActivity = Object.assign({}, activity)
newActivity.customParam = "custom value"
return originalDirectline.postActivity(newActivity)
}
})
Related
I'm trying to pass user name from website to chatbot using directline feature. I'm using python sdk and following the below link.
https://github.com/microsoft/BotFramework-WebChat/tree/master/samples/04.api/a.welcome-event
my js file looks like
(async function() {
var myHeaders = new Headers();
myHeaders.append("Authorization", "Bearer <token here>");
myHeaders.append("Content-Type", "application/json");
var raw = JSON.stringify({
"user": {
"id": "dl_123"
},
"trustedOrigins": []
});
var requestOptions = {
method: 'POST',
headers: myHeaders,
body: raw,
redirect: 'follow'
};
fetch("https://directline.botframework.com/v3/directline/tokens/generate", requestOptions)
.then(response => response.text())
.then(result => {console.log(result)
var token = JSON.parse(result).token
console.log("token",token)
const store = window.WebChat.createStore({}, ({ dispatch }) => next => action => {
if (action.type === 'DIRECT_LINE/CONNECT_FULFILLED') {
dispatch({
type: 'WEB_CHAT/SEND_EVENT',
payload: {
name: 'webchat/join',
value: "user_name_here"
}
});
}
return next(action);
});
window.WebChat.renderWebChat(
{
directLine: window.WebChat.createDirectLine({ token }),
store
},
document.getElementById('webchat')
);
document.querySelector('#webchat > *').focus();
})})().catch(err => console.error(err));
and my python code looks like
if turn_context.activity.name != "webchat/join":
response = MessageFactory.text(f"Hai {turn_context.activity.value} Welcome to Portal")
but it show none in the place of turn_context.activity.value
I actually want to print username passed from js file here. how to do that.
const styleSet = window.WebChat.createStyleSet({
bubbleBackground: '#99ccff',
bubbleFromUserBackground: '#33adff',
rootHeight: '100%',
rootWidth: '100%'
});
styleSet.textContent = {
...styleSet.textContent,
fontFamily: "'Arial','Helvetica',sans-serif",
fontWeight: 'bold'
};
var channelObj = turnContext.Activity.ChannelData.ToString();
var channelData = Newtonsoft.Json.Linq.JObject.Parse(channelObj);
var customdata = channelData["TenantId"].ToString();
var d1 = window.WebChat.createDirectLine({ token })
window.WebChat.renderWebChat({
directLine: Object.assign({}, d1, {
postActivity: activity => {
var newActivity = object.assign({}, activity, { channelData: {
"TenantId": "#ViewBag.Tennatid"
}
});
alert("TenantId");
return d1.postActivity(newActivity);
}
}),
userID: 'YOUR_USER_ID',
username: 'Web Chat User',
locale: 'en-US',
// Passing 'styleSet' when rendering Web Chat
styleSet,
},
document.getElementById('webchat'));
I am successfully making a Platform Transaction on my Platform. All transfers go as expected apart from the Platform Fees. They reflect on the Merchant Seller's side, as well as the Buyer's, but not on the Platform Account.
Transaction details snapshot
The Partner Commission of -$9.33 USD does not show on the Platform account. In fact this transaction does not reflect in any way. There is no way of telling that it ever happened at all from the Paypal Sandbox App Account.
What could it be that I am missing?
Thank you all in advance.
CLIENT SIDE : index.html
<html>
<head>
<meta charset="utf-8"/>
<!-- Optimal rendering on mobile devices. -->
<meta name="viewport" content="width=device-width, initial-scale=1">
<!-- Optimal Internet Explorer compatibility -->
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
<!-- Sample CSS styles for demo purposes. You can override these styles to match your web page's branding. -->
<link rel="stylesheet" type="text/css" href="https://www.paypalobjects.com/webstatic/en_US/developer/docs/css/cardfields.css"/>
<!-- JavaScript SDK -->
<script src="https://www.paypal.com/sdk/js?components=buttons,hosted-fields&client-id=Ae4XWCzGDY24rKpazdCnRnT1wUjnQ_2PzLF5aOhviaUfQ7_O34rr8NqrunXe7PxCi-sEt7noZfr1ojbs" data-client-token="eyJicmFpbnRyZWUiOnsiYXV0aG9yaXphdGlvbkZpbmdlcnByaW50IjoiZWNkYWE1MzZjNjQ5Nzg1YjU2ZWQ5NGMyZGU2ZjRjMGQzY2FiMDY0MzkyNTA3YTkxZTU2MjI3MDlhZTMzOWUyNHxtZXJjaGFudF9pZD1yd3dua3FnMnhnNTZobTJuJnB1YmxpY19rZXk9NjNrdm4zN3Z0MjlxYjRkZiZjcmVhdGVkX2F0PTIwMjEtMDMtMjlUMTM6Mjg6MTMuOTQxWiIsInZlcnNpb24iOiIzLXBheXBhbCJ9LCJwYXlwYWwiOnsiaWRUb2tlbiI6ImV5SnJhV1FpT2lJNVpqWmxOalV5T0RGallXWmhORFU1WkRReU9EWmhPRE5pWVdZMVl6aGtPRFUwWVdNNE5XRmtJaXdpZEhsd0lqb2lTbGRVSWl3aVlXeG5Jam9pVWxNeU5UWWlmUS5leUpwYzNNaU9pSm9kSFJ3Y3pvdkwyRndhUzV6WVc1a1ltOTRMbkJoZVhCaGJDNWpiMjBpTENKemRXSWlPaUpvZEhSd2N6b3ZMM2QzZHk1d1lYbHdZV3d1WTI5dEwzZGxZbUZ3Y0hNdllYVjBhQzlwWkdWdWRHbDBlUzkxYzJWeUwwSlhRazEyZVhoclJsWjBkWHBCZUd4RmNGZENiMVJRTkhSNGFHOVRVMnh0YVZWWmNtbDZhM3BrWkdjaUxDSmhZM0lpT2xzaVkyeHBaVzUwSWwwc0ltRjFaQ0k2SWtGbE5GaFhRM3BIUkZreU5ISkxjR0Y2WkVOdVVtNVVNWGRWYW01Ulh6SlFla3hHTldGUGFIWnBZVlZtVVRkZlR6TTBjbkk0VG5GeWRXNVlaVGRRZUVOcExYTkZkRGR1YjFwbWNqRnZhbUp6SWl3aVlYVjBhRjkwYVcxbElqb3hOakUzTURJME5EazBMQ0poYlhJaU9sdGRMQ0poZWlJNkluTmlMbk5zWXlJc0ltVjRjQ0k2TVRZeE56QXlOVE01TkN3aWMyVnpjMmx2Ymw5cGJtUmxlQ0k2SWxoMVNuUnBiMDU0WWs1YU1HOVFUVzVpTWtkNVpXdHRRMWh3UXlJc0ltbGhkQ0k2TVRZeE56QXlORFE1TkN3aWFuUnBJam9pVlRKQlFVbGtiVVZETTJjekxVTkpOelpDYWtSdk56WjNUVFpoZDJ4VWJuWmFNMGhsVW5kWmNXRmxTazUyZW1SWFpWTmlhMUUyVERoUU5qbFdUako0Y21kR1prTkNUVGxHYVdGRGNVNHhSUzFqTVZobVEzSndZWFJPTWxGWVltczFZbE4yVlZveVpYTlRTRzU1VG1aaWRWUkxZamxQUjB0cWNGRjZSbWR5V0ZFaUxDSmpiR2xsYm5SZmFXUWlPaUpCWlRSWVYwTjZSMFJaTWpSeVMzQmhlbVJEYmxKdVZERjNWV3B1VVY4eVVIcE1SalZoVDJoMmFXRlZabEUzWDA4ek5ISnlPRTV4Y25WdVdHVTNVSGhEYVMxelJYUTNibTlhWm5JeGIycGljeUo5LkhObzlndU5SQVktSDZTR2tUR0xxRUFtbDNWRkJwNHRwNjdSSVJPN1NMbm5PRUtkWGFHSjhfYkJfR3N5dWxZeGQ4Slhnd3duTWV4ejZYaElEUnVtVzVkaDloQm9CbFctTGtNUEZ6cmVDZnk3SnVnbmZPYk9PaWRhV19Wd1IyRXpLSTZ1UzZWaFhKbEFvaWI1U3dfYjNXYlVHR2tudUM5cjZDZ0xlWnNTaDVQZDRuaFc1M0pplatformlHQTZkOVc3ZU5VZXBKNUJwd1FJWkRVYmJyY2JXelFDMzRFN0tQbndjOENIQWh3UGNSZWpWaktWWVlLSE9lUF9KeWpEbFZDWXM4NU5YVEExYV9ldDdFUHZmcmN1NzF0S3FhR0hNV21XWE9KS245UGZ2Zk10b2ZfRWN3SmhVd2RBU1ZqZmU4VjlzM3ZidzRJRGZHMFRjYzY1d2hIaFp4Sl94dyIsImFjY2Vzc1Rva2VuIjoiQTIxQUFJNTNiLVl0Qk1neFlmb1NQZHJKUUsxZTBCYVZSZm01X3BPNlg4bnktZ292S1l3dy11YU1fWm8wM0YxQXdzenZfYjF4RmZJTkE1YkNfUEZya3A0bkxxMzljdWdndyJ9fQ=="></script>
<!-- Include the PayPal JavaScript SDK -->
<script src="https://www.paypal.com/sdk/js?client-id=Ae4XWCzGDY24rKpazdCnRnT1wUjnQ_2PzLF5aOhviaUfQ7_O34rr8NqrunXe7PxCi-sEt7noZfr1ojbs¤cy=USD" data-namespace="paypal_sdk"></script>
</head>
<body>
<!-- JavaScript SDK -->
<script src="https://www.paypal.com/sdk/js?components=hosted-fields&client-id=Ae4XWCzGDY24rKpazdCnRnT1wUjnQ_2PzLF5aOhviaUfQ7_O34rr8NqrunXe7PxCi-sEt7noZfr1ojbs&merchant-id=H82BJAGD75E6C¤cy=USD&intent=capture" data-partner-attribution-id="FLAVORsb-z1ivv5077605_MP" data-client-token="eyJicmFpbnRyZWUiOnsiYXV0aG9yaXphdGlvbkZpbmdlcnByaW50IjoiZWNkYWE1MzZjNjQ5Nzg1YjU2ZWQ5NGMyZGU2ZjRjMGQzY2FiMDY0MzkyNTA3YTkxZTU2MjI3MDlhZTMzOWUyNHxtZXJjaGFudF9pZD1yd3dua3FnMnhnNTZobTJuJnB1YmxpY19rZXk9NjNrdm4zN3Z0MjlxYjRkZiZjcmVhdGVkX2F0PTIwMjEtMDMtMjlUMTM6Mjg6MTMuOTQxWiIsInZlcnNpb24iOiIzLXBheXBhbCJ9LCJwYXlwYWwiOnsiaWRUb2tlbiI6ImV5SnJhV1FpT2lJNVpqWmxOalV5T0RGallXWmhORFU1WkRReU9EWmhPRE5pWVdZMVl6aGtPRFUwWVdNNE5XRmtJaXdpZEhsd0lqb2lTbGRVSWl3aVlXeG5Jam9pVWxNeU5UWWlmUS5leUpwYzNNaU9pSm9kSFJ3Y3pvdkwyRndhUzV6WVc1a1ltOTRMbkJoZVhCaGJDNWpiMjBpTENKemRXSWlPaUpvZEhSd2N6b3ZMM2QzZHk1d1lYbHdZV3d1WTI5dEwzZGxZbUZ3Y0hNdllYVjBhQzlwWkdWdWRHbDBlUzkxYzJWeUwwSlhRazEyZVhoclJsWjBkWHBCZUd4RmNGZENiMVJRTkhSNGFHOVRVMnh0YVZWWmNtbDZhM3BrWkdjaUxDSmhZM0lpT2xzaVkyeHBaVzUwSWwwc0ltRjFaQ0k2SWtGbE5GaFhRM3BIUkZreU5ISkxjR0Y2WkVOdVVtNVVNWGRWYW01Ulh6SlFla3hHTldGUGFIWnBZVlZtVVRkZlR6TTBjbkk0VG5GeWRXNVlaVGRRZUVOcExYTkZkRGR1YjFwbWNqRnZhbUp6SWl3aVlYVjBhRjkwYVcxbElqb3hOakUzTURJME5EazBMQ0poYlhJaU9sdGRMQ0poZWlJNkluTmlMbk5zWXlJc0ltVjRjQ0k2TVRZeE56QXlOVE01TkN3aWMyVnpjMmx2Ymw5cGJtUmxlQ0k2SWxoMVNuUnBiMDU0WWs1YU1HOVFUVzVpTWtkNVpXdHRRMWh3UXlJc0ltbGhkQ0k2TVRZeE56QXlORFE1TkN3aWFuUnBJam9pVlRKQlFVbGtiVVZETTJjekxVTkpOelpDYWtSdk56WjNUVFpoZDJ4VWJuWmFNMGhsVW5kWmNXRmxTazUyZW1SWFpWTmlhMUUyVERoUU5qbFdUako0Y21kR1prTkNUVGxHYVdGRGNVNHhSUzFqTVZobVEzSndZWFJPTWxGWVltczFZbE4yVlZveVpYTlRTRzU1VG1aaWRWUkxZamxQUjB0cWNGRjZSbWR5V0ZFaUxDSmpiR2xsYm5SZmFXUWlPaUpCWlRSWVYwTjZSMFJaTWpSeVMzQmhlbVJEYmxKdVZERjNWV3B1VVY4eVVIcE1SalZoVDJoMmFXRlZabEUzWDA4ek5ISnlPRTV4Y25WdVdHVTNVSGhEYVMxelJYUTNibTlhWm5JeGIycGljeUo5LkhObzlndU5SQVktSDZTR2tUR0xxRUFtbDNWRkJwNHRwNjdSSVJPN1NMbm5PRUtkWGFHSjhfYkJfR3N5dWxZeGQ4Slhnd3duTWV4ejZYaElEUnVtVzVkaDloQm9CbFctTGtNUEZ6cmVDZnk3SnVnbmZPYk9PaWRhV19Wd1IyRXpLSTZ1UzZWaFhKbEFvaWI1U3dfYjNXYlVHR2tudUM5cjZDZ0xlWnNTaDVQZDRuaFc1M0pplatformlHQTZkOVc3ZU5VZXBKNUJwd1FJWkRVYmJyY2JXelFDMzRFN0tQbndjOENIQWh3UGNSZWpWaktWWVlLSE9lUF9KeWpEbFZDWXM4NU5YVEExYV9ldDdFUHZmcmN1NzF0S3FhR0hNV21XWE9KS245UGZ2Zk10b2ZfRWN3SmhVd2RBU1ZqZmU4VjlzM3ZidzRJRGZHMFRjYzY1d2hIaFp4Sl94dyIsImFjY2Vzc1Rva2VuIjoiQTIxQUFJNTNiLVl0Qk1neFlmb1NQZHJKUUsxZTBCYVZSZm01X3BPNlg4bnktZ292S1l3dy11YU1fWm8wM0YxQXdzenZfYjF4RmZJTkE1YkNfUEZya3A0bkxxMzljdWdndyJ9fQ=="></script>
<!-- Buttons container -->
<div id="paypal-button-container"></div>
<!-- Implementation -->
<script>
let orderId;
// Displays PayPal buttons
paypal_sdk.Buttons({
style: {
layout: 'horizontal'
},
// Call your server to set up the transaction
createOrder: function(data, actions) {
return fetch('/demo/checkout/api/paypal/platform_store_order/create/', {
method: 'post'
}).catch(error => {
console.error('ERR -> fetch : ' + error.message);
}).then(function(res) {
return res.json();
}).catch(error => {
console.error('ERR -> res : ' + error.message);
}).then(function(orderData) {
return orderData.id;
}).catch(error => {
console.error('ERR -> orderData : ' + error.message);
});
},
// Call your server to finalize the transaction
onApprove: function(data, actions) {
return fetch('/demo/checkout/api/paypal/order_platform_store/', {
method: 'POST',
headers: {
'Accept': 'application/json',
'Content-Type': 'application/json'
},
body: JSON.stringify({'orderID': data.orderID, 'payerID': data.payerID})
}).then(function(res) {
return res.json();
}).then(function(orderData) {
// Three cases to handle:
// (1) Recoverable INSTRUMENT_DECLINED -> call actions.restart()
// (2) Other non-recoverable errors -> Show a failure message
// (3) Successful transaction -> Show confirmation or thank you
// This example reads a v2/checkout/orders capture response, propagated from the server
// You could use a different API or structure for your 'orderData'
var errorDetail = Array.isArray(orderData.details) && orderData.details[0];
if (errorDetail && errorDetail.issue === 'INSTRUMENT_DECLINED') {
return actions.restart(); // Recoverable state, per:
// https://developer.paypal.com/docs/checkout/integration-features/funding-failure/
}
if (errorDetail) {
var msg = 'Sorry, your transaction could not be processed.';
if (errorDetail.description) {
msg += '\n\n' + errorDetail.description;
}
if (orderData.debug_id){
msg += ' (' + orderData.debug_id + ')'
};
return alert(msg); // Show a failure message
}
// Show a success message
alert('Transaction : ' + JSON.stringify(orderData));
});
}
}).render("#paypal-button-container");
</script>
</body>
</html>
NODE app.js
const path = require("path");
var express = require("express");
var cors = require("cors");
var app = express();
var request = require("request");
const port = process.env.PORT || 3000;
app.use(cors());
var bodyParser = require("body-parser");
app.use(
bodyParser.urlencoded({
extended: true,
})
);
app.use(bodyParser.json());
// Add your credentials:
// Add your client ID and secret
var CLIENT = "Ae4XWCzGDY24rKpazdCnRnT1wUjnQ_2PzLF5aOhviaUfQ7_O34rr8NqrunXe7PxCi-sEt7noZfr1ojbs";
var SECRET = "EMmNF1LZSOooLUAxEt5csF-rMyIseuV5D6qOoKMzbyUEDaQEhO_DjLarbVsF_vLiXnGHi8qFL13gebg_";
var PAYPAL_API = "https://api-m.sandbox.paypal.com";
const paypal = require("#paypal/checkout-server-sdk");
let environment = new paypal.core.SandboxEnvironment(CLIENT, SECRET);
let client = new paypal.core.PayPalHttpClient(environment);
app.get("/", function (req, res) {
res.sendFile(path.join(__dirname + "/index.html"));
});
// Set up the payment:
// 1. Set up a URL to handle requests from the PayPal button
app.post("/demo/checkout/api/paypal/order/create/", async function (req, res) {
let ordersCreateRequest = new paypal.orders.OrdersCreateRequest();
ordersCreateRequest.requestBody({
"intent": "CAPTURE",
"purchase_units": [
{
"amount": {
"currency_code": "USD",
"value": "9.88",
},
},
],
});
// Call API with your client and get a response for your call
let createOrder = async function () {
let response = await client.execute(ordersCreateRequest);
return response;
};
let platformOrder = await createOrder();
let orderId = platformOrder.result.id;
// 2. Call /v2/checkout/orders to set up the Order
res.json({
id: orderId,
});
});
// Set up the payment:
// 1. Set up a URL to handle requests from the PayPal button
app.post("/demo/checkout/api/paypal/platform_store_order/create/", async function (req, res) {
let ordersCreateRequest = new paypal.orders.OrdersCreateRequest();
ordersCreateRequest.requestBody({
"intent": "CAPTURE",
"purchase_units": [
{
"amount": {
"currency_code": "USD",
"value": "31.13",
},
"payee": {
"email_address": "platform#business.example.com",
},
"payment_instruction": {
"disbursement_mode": "INSTANT",
"platform_fees": [
{
"amount": {
"currency_code": "USD",
"value": "9.33",
},
},
],
},
},
],
});
// Call API with your client and get a response for your call
let createOrder = async function () {
let response = await client.execute(ordersCreateRequest);
return response;
};
let platformOrder = await createOrder();
let orderId = platformOrder.result.id;
res.json({
id: orderId,
});
});
// 1. Set up a URL to handle requests from the PayPal button.
app.post("/demo/checkout/api/paypal/order_platform_store/", async function (req, res) {
// 2. Get the payment ID and the payer ID from the request query.
var orderID = req.body.orderID;
request.post(
PAYPAL_API + "/v2/checkout/orders/" + orderID + "/capture",
{
headers: {
"Content-Type": "application/json",
"Authorization": "Bearer A21AAJ8sH_Uq73w8XonQYB9rc1STsZpoK_Q14PkHbRgxtbYUN6FvCg-FbOKYIDlt0Zzo8xVQMvSuCAaRgjSfGoEPYRbxk62xQ",
"PayPal-Partner-Attribution-Id": "FLAVORsb-z1ivv5077605_MP",
},
},
function (err, response, body) {
if (err) {
console.error(err);
return res.sendStatus(500);
}
res.json(response);
}
);
});
app.listen(port, () => console.log(`Listening on port ${port}!`));
Are you a PayPal partner? It's required to use this in the live environment: https://developer.paypal.com/docs/platforms/test-go-live/#2-go-live
If you are, PayPal will guide you in testing this in both sandbox and live modes.
If you are not, you can't use this anyway.
I am trying to make an order and payment on a Node.js Environment to a user user#email.example.com but no funds get transferred. No errors are thrown.
What could it be that I am missing?
Thank you all in advance.
THE CLIENT SIDE
<!DOCTYPE html>
<html lang="en">
<head>
<!-- Add meta tags for mobile and IE -->
<meta name="viewport" content="width=device-width, initial-scale=1">
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
<title> PayPal Smart Payment Buttons Integration | Server Demo </title>
</head>
<body>
<!-- Set up a container element for the button -->
<div id="paypal-button-container"></div>
<!-- Include the PayPal JavaScript SDK -->
<script src="https://www.paypal.com/sdk/js?client-id=abc-50mQSYBJpg_OWguVkwn0qCDB-ZAFupw-kq6-k_O1havNEFGH¤cy=USD"></script>
<script>
// Render the PayPal button into #paypal-button-container
paypal.Buttons({
// Call your server to set up the transaction
createOrder: function(data, actions) {
return fetch('/demo/checkout/api/paypal/order/create/', {
method: 'post'
}).catch(error => {
console.error('ERR -> fetch : ' + error.message);
}).then(function(res) {
return res.json();
}).catch(error => {
console.error('ERR -> res : ' + error.message);
}).then(function(orderData) {
return orderData.id;
}).catch(error => {
console.error('ERR -> orderData : ' + error.message);
});
},
// Call your server to finalize the transaction
onApprove: function(data, actions) {
return fetch('/demo/checkout/api/paypal/order?orderID=' + data.orderID, {
method: 'get'
}).then(function(res) {
return res.json();
}).then(function(orderData) {
// Three cases to handle:
// (1) Recoverable INSTRUMENT_DECLINED -> call actions.restart()
// (2) Other non-recoverable errors -> Show a failure message
// (3) Successful transaction -> Show confirmation or thank you
// This example reads a v2/checkout/orders capture response, propagated from the server
// You could use a different API or structure for your 'orderData'
var errorDetail = Array.isArray(orderData.details) && orderData.details[0];
if (errorDetail && errorDetail.issue === 'INSTRUMENT_DECLINED') {
return actions.restart(); // Recoverable state, per:
// https://developer.paypal.com/docs/checkout/integration-features/funding-failure/
}
if (errorDetail) {
var msg = 'Sorry, your transaction could not be processed.';
if (errorDetail.description) msg += '\n\n' + errorDetail.description;
if (orderData.debug_id) msg += ' (' + orderData.debug_id + ')';
return alert(msg); // Show a failure message
}
// Show a success message
alert('Transaction completed by ' + JSON.stringify(orderData));
});
}
}).render('#paypal-button-container');
</script>
</body>
</html>
THE NODE SERVER
const path = require("path");
var express = require("express");
var cors = require("cors");
var app = express();
var request = require("request");
const port = process.env.PORT || 3000;
app.use(cors());
var bodyParser = require("body-parser");
app.use(
bodyParser.urlencoded({
extended: true,
})
);
app.use(bodyParser.json());
app.get("/", function (req, res) {
res.sendFile(path.join(__dirname + "/index.html"));
});
// Add your credentials:
// Add your client ID and secret
var CLIENT = "abc-50mQSYBJpg_OWguVkwn0qCDB-ZAFupw-kq6-k_O1havNEFGH";
var SECRET = "1234upB-ns0xj5678bpJrkvnkMG4ZUZEHd-0GbPrTe991045673Th1RrqYBqIjhl9Tdm";
var PAYPAL_API = "https://api-m.sandbox.paypal.com";
// Set up the payment:
// 1. Set up a URL to handle requests from the PayPal button
app.post("/demo/checkout/api/paypal/order/create/", function (req, res) {
// 2. Call /v2/checkout/orders to set up the Order
request.post(
PAYPAL_API + "/v2/checkout/orders",
{
auth: {
user: CLIENT,
pass: SECRET,
},
body: {
intent: "CAPTURE",
payer: {
payment_method: "paypal",
},
purchase_units: [
{
amount: {
currency_code: "USD",
value: "10.00",
},
payee: {
email_address: "user#email.example.com",
},
},
],
redirect_urls: {
return_url: "https://mighty-oasis-92039.herokuapp.com/",
cancel_url: "https://mighty-oasis-92039.herokuapp.com/",
},
},
json: true,
},
function (err, response) {
if (err) {
console.error(err);
return res.sendStatus(500);
}
// 3. Return the payment ID to the client
res.json({
id: response.body.id,
});
}
);
});
/** START EXECUTE PAYMENT */
// 1. Set up a URL to handle requests from the PayPal button.
app.get("/demo/checkout/api/paypal/order/", function (req, res) {
// 2. Get the payment ID and the payer ID from the request query.
var orderID = req.query.orderID;
// 3. Call /v2/checkout/orders/{id}/capture to Capture payment for order.
request.post(
PAYPAL_API + "/v2/checkout/orders/" + orderID + "/capture",
{
auth: {
user: CLIENT,
pass: SECRET,
},
json: true,
},
function (err, response) {
if (err) {
console.error(err);
return res.sendStatus(500);
}
// 4. Return a success response to the client
res.json({
status: "success",
});
}
);
});
/** END EXECUTE PAYMENT */
app.listen(port, () => console.log(`url-shortener listening on port ${port}!`));
Every webchat session, I retrieve a token from a restify service which is talking to https://webchat.botframework.com/api/tokens. I use a directline secret to get the token. The token is retrieved correctly. When I use the token manually (by entering it in the html), webchat renders. When I pass a Javascript variable in the function I am unable to create the directline. Some guidance appreciated. A workaround would be to use secret in html but I rather not do that
I tried multiple syntaxes to pass the variable in: window.WebChat.createDirectLine({ webChatToken }) or (webChatToken) or ({ webChatToken }) or (token: webChatToken) and ({ token: webChatToken })
The only thing that worked was entering the token manually in the html.
I use the restify server already in my index.js (for a sample bot) to listen for and process token requests:
// Create HTTP server and Cors
let server = restify.createServer();
server.pre(cors.preflight);
server.use(cors.actual);
server.listen(process.env.port || process.env.PORT || 3978, function() {
});
// Listen for bot requests.
server.post('/api/messages', (req, res) => {
adapter.processActivity(req, res, async (context) => {
await bot.run(context);
});
});
// Listen for token requests.
server.get('/api/token',
async function(req, res) {
const result = await fetch('https://webchat.botframework.com/api/tokens', {
method: 'GET',
headers: {
Authorization: `Bearer ${ process.env.directLineSecret }`
}
});
const token = await result.json();
console.log(token);
res.send(token);
});
And the webchat client in html and Javascript code. In this example it is talking to a local instance of the restify server.
<div id="webchat" role="main"></div>
<script>
//get token
const webChatToken = getToken();
window.WebChat.renderWebChat({
directLine: window.WebChat.createDirectLine({ webChatToken }),
renderMarkdown: markdownIt.render.bind(markdownIt),
store,
// styling
styleOptions: {
},
userID: 'N/A',
username: 'Web Chat User',
locale: 'nl-nl'
}, document.getElementById('webchat'));
async function getToken() {
const res = await fetch('http://localhost:3978/api/token');
const token = await res.json();
return token;
}
</script>
I expect a working webchat client. In chrome dev extention I see "POST https://directline.botframework.com/v3/directline/conversations 403 (Forbidden).
The corresponding response of the directline api:
{
"error": {
"code": "BadArgument",
"message": "Invalid token or secret"
}
}
The Direct Line options has a token property, not a webChatToken property. You need to set the token value to webChatToken in the options object. Take a look at the code snippet below and the Direct Line Documentetion for more details on initializing Web Chat and the Direct Line client.
(async function () {
const res = await fetch('http://localhost:3978/api/token', { method: 'GET' });
const webChatToken = await res.json();
window.WebChat.renderWebChat({
directLine: window.WebChat.createDirectLine({ token: webChatToken })
}, document.getElementById('webchat'));
document.querySelector('#webchat > *').focus();
})().catch(err => console.error(err));
Hope this helps!