Last active
November 8, 2018 16:46
-
-
Save thorsten-stripe/9928b11dbf45980af058c3284aafd416 to your computer and use it in GitHub Desktop.
Stripe GPay Voice Demo (follow instructions at: https://github.com/actions-on-google/dialogflow-transactions-nodejs)
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// Copyright 2017, Google, Inc. | |
// Licensed under the Apache License, Version 2.0 (the 'License'); | |
// you may not use this file except in compliance with the License. | |
// You may obtain a copy of the License at | |
// | |
// http://www.apache.org/licenses/LICENSE-2.0 | |
// | |
// Unless required by applicable law or agreed to in writing, software | |
// distributed under the License is distributed on an 'AS IS' BASIS, | |
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | |
// See the License for the specific language governing permissions and | |
// limitations under the License. | |
'use strict'; | |
process.env.DEBUG = 'actions-on-google:*'; | |
const { | |
dialogflow, | |
DeliveryAddress, | |
OrderUpdate, | |
TransactionDecision, | |
TransactionRequirements, | |
} = require('actions-on-google'); | |
const functions = require('firebase-functions'); | |
const app = dialogflow({debug: true}); | |
const GENERIC_EXTENSION_TYPE = | |
'type.googleapis.com/google.actions.v2.orders.GenericExtension'; | |
const UNIQUE_ORDER_ID = '103'; | |
app.intent('transaction_check_action', (conv) => { | |
conv.ask(new TransactionRequirements({ | |
orderOptions: { | |
requestDeliveryAddress: false, | |
}, | |
paymentOptions: { | |
googleProvidedOptions: { | |
prepaidCardDisallowed: false, | |
supportedCardNetworks: ['VISA', 'AMEX'], | |
// Tokenization parameter data from your Stripe Dashboard: | |
// https://dashboard.stripe.com/test/developers | |
tokenizationParameters: { | |
parameters: { | |
"gateway": "stripe", | |
"stripe:publishableKey": 'YOUR_STRIPE_PK', | |
"stripe:version": "2018-09-24" | |
}, | |
tokenizationType: "PAYMENT_GATEWAY" | |
}, | |
}, | |
}, | |
})); | |
}); | |
app.intent('transaction_check_google', (conv) => { | |
conv.ask(new TransactionRequirements({ | |
orderOptions: { | |
requestDeliveryAddress: false, | |
}, | |
paymentOptions: { | |
googleProvidedOptions: { | |
prepaidCardDisallowed: false, | |
supportedCardNetworks: ['VISA', 'AMEX'], | |
// Tokenization with Stripe | |
tokenizationParameters: { | |
parameters: { | |
"gateway": "stripe", | |
"stripe:publishableKey": 'YOUR_STRIPE_PK', | |
"stripe:version": "2018-09-24" | |
}, | |
tokenizationType: "PAYMENT_GATEWAY" | |
}, | |
}, | |
}, | |
})); | |
}); | |
app.intent('transaction_check_complete', (conv) => { | |
const arg = conv.arguments.get('TRANSACTION_REQUIREMENTS_CHECK_RESULT'); | |
if (arg && arg.resultType ==='OK') { | |
// Normally take the user through cart building flow | |
conv.ask(`Looks like you're good to go! ` + | |
`Now say "confirm transaction.`); | |
} else { | |
conv.close('Transaction failed.'); | |
} | |
}); | |
// Commented out to shorten demo. | |
// app.intent('delivery_address', (conv) => { | |
// conv.ask(new DeliveryAddress({ | |
// addressOptions: { | |
// reason: 'To know where to send the order', | |
// }, | |
// })); | |
// }); | |
// app.intent('delivery_address_complete', (conv) => { | |
// const arg = conv.arguments.get('DELIVERY_ADDRESS_VALUE'); | |
// if (arg.userDecision ==='ACCEPTED') { | |
// console.log('DELIVERY ADDRESS: ' + | |
// arg.location.postalAddress.addressLines[0]); | |
// conv.data.deliveryAddress = arg.location; | |
// conv.ask('Great, got your address! Now say "confirm transaction".'); | |
// } else { | |
// conv.close('I failed to get your delivery address.'); | |
// } | |
// }); | |
app.intent('transaction_decision_action', (conv) => { | |
const order = { | |
id: UNIQUE_ORDER_ID, | |
cart: { | |
merchant: { | |
id: 'book_store_1', | |
name: 'Book Store', | |
}, | |
lineItems: [ | |
{ | |
name: 'My Memoirs', | |
id: 'memoirs_1', | |
price: { | |
amount: { | |
currencyCode: 'USD', | |
nanos: 990000000, | |
units: 3, | |
}, | |
type: 'ACTUAL', | |
}, | |
quantity: 1, | |
subLines: [ | |
{ | |
note: 'Note from the author', | |
}, | |
], | |
type: 'REGULAR', | |
}, | |
{ | |
name: 'Memoirs of a person', | |
id: 'memoirs_2', | |
price: { | |
amount: { | |
currencyCode: 'USD', | |
nanos: 990000000, | |
units: 5, | |
}, | |
type: 'ACTUAL', | |
}, | |
quantity: 1, | |
subLines: [ | |
{ | |
note: 'Special introduction by author', | |
}, | |
], | |
type: 'REGULAR', | |
}, | |
{ | |
name: 'Their memoirs', | |
id: 'memoirs_3', | |
price: { | |
amount: { | |
currencyCode: 'USD', | |
nanos: 750000000, | |
units: 15, | |
}, | |
type: 'ACTUAL', | |
}, | |
quantity: 1, | |
subLines: [ | |
{ | |
lineItem: { | |
name: 'Special memoir epilogue', | |
id: 'memoirs_epilogue', | |
price: { | |
amount: { | |
currencyCode: 'USD', | |
nanos: 990000000, | |
units: 3, | |
}, | |
type: 'ACTUAL', | |
}, | |
quantity: 1, | |
type: 'REGULAR', | |
}, | |
}, | |
], | |
type: 'REGULAR', | |
}, | |
{ | |
name: 'Our memoirs', | |
id: 'memoirs_4', | |
price: { | |
amount: { | |
currencyCode: 'USD', | |
nanos: 490000000, | |
units: 6, | |
}, | |
type: 'ACTUAL', | |
}, | |
quantity: 1, | |
subLines: [ | |
{ | |
note: 'Special introduction by author', | |
}, | |
], | |
type: 'REGULAR', | |
}, | |
], | |
notes: 'The Memoir collection', | |
otherItems: [], | |
}, | |
otherItems: [ | |
{ | |
name: 'Subtotal', | |
id: 'subtotal', | |
price: { | |
amount: { | |
currencyCode: 'USD', | |
nanos: 220000000, | |
units: 32, | |
}, | |
type: 'ESTIMATE', | |
}, | |
type: 'SUBTOTAL', | |
}, | |
{ | |
name: 'Tax', | |
id: 'tax', | |
price: { | |
amount: { | |
currencyCode: 'USD', | |
nanos: 780000000, | |
units: 2, | |
}, | |
type: 'ESTIMATE', | |
}, | |
type: 'TAX', | |
}, | |
], | |
totalPrice: { | |
amount: { | |
currencyCode: 'USD', | |
nanos: 0, | |
units: 35, | |
}, | |
type: 'ESTIMATE', | |
}, | |
}; | |
if (conv.data.deliveryAddress) { | |
order.extension = { | |
'@type': GENERIC_EXTENSION_TYPE, | |
'locations': [ | |
{ | |
type: 'DELIVERY', | |
location: { | |
postalAddress: conv.data.deliveryAddress.postalAddress, | |
}, | |
}, | |
], | |
}; | |
} | |
conv.ask(new TransactionDecision({ | |
orderOptions: { | |
requestDeliveryAddress: false, | |
}, | |
paymentOptions: { | |
googleProvidedOptions: { | |
prepaidCardDisallowed: false, | |
supportedCardNetworks: ['VISA', 'AMEX'], | |
// Tokenize with Stripe | |
tokenizationParameters: { | |
parameters: { | |
"gateway": "stripe", | |
"stripe:publishableKey": 'YOUR_STRIPE_PK', | |
"stripe:version": "2018-09-24" | |
}, | |
tokenizationType: "PAYMENT_GATEWAY" | |
}, | |
}, | |
}, | |
proposedOrder: order, | |
})); | |
}); | |
app.intent('transaction_decision_complete', (conv) => { | |
console.log('Transaction decision complete'); | |
const arg = conv.arguments.get('TRANSACTION_DECISION_VALUE'); | |
if (arg && arg.userDecision ==='ORDER_ACCEPTED') { | |
const stripeToken = JSON.parse(new Buffer(arg.order.paymentInfo.googleProvidedPaymentInstrument.instrumentToken, 'base64').toString('ascii')); | |
console.log({stripeToken}); | |
// stripeToken.id can be used to finalise the charge: | |
// https://stripe.com/docs/api/charges/create#create_charge-source | |
const finalOrderId = arg.order.finalOrder.id; | |
// Confirm order and make any charges in order processing backend | |
// If using Google provided payment instrument: | |
// const paymentDisplayName = arg.order.paymentInfo.displayName; | |
conv.ask(new OrderUpdate({ | |
actionOrderId: finalOrderId, | |
orderState: { | |
label: 'Order created', | |
state: 'CREATED', | |
}, | |
lineItemUpdates: {}, | |
updateTime: new Date().toISOString(), | |
receipt: { | |
confirmedActionOrderId: UNIQUE_ORDER_ID, | |
}, | |
// Replace the URL with your own customer service page | |
orderManagementActions: [ | |
{ | |
button: { | |
openUrlAction: { | |
url: 'http://example.com/customer-service', | |
}, | |
title: 'Customer Service', | |
}, | |
type: 'CUSTOMER_SERVICE', | |
}, | |
], | |
userNotification: { | |
text: 'Notification text.', | |
title: 'Notification Title', | |
}, | |
})); | |
conv.ask(`Transaction completed! You're all set!`); | |
} else if (arg && arg.userDecision === 'DELIVERY_ADDRESS_UPDATED') { | |
conv.ask(new DeliveryAddress({ | |
addressOptions: { | |
reason: 'To know where to send the order', | |
}, | |
})); | |
} else { | |
conv.close('Transaction failed.'); | |
} | |
}); | |
exports.transactions = functions.https.onRequest(app); |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment