project link: https://chuanshuoge2-stripe-node.herokuapp.com/
left sales form, right response from Stripe account
set price, click purchase, form open enter test visa #
transaction, card, customer info processed by Stripe account
set #, click history, top few transactions are displayed
app is published to heroku, Stripe account keys are stored privately in config
In Stripe account, all transactions are logged
look into transaction detail
project folder
--config
--keys.js
--keys_dev.js
--keys_prod.js
--public
--img
--marketplace.png
--sale.png
--views
--layouts
--main.handlebars
--index.handlebars
--.gitignore
--app.js
--package.json
----------------------------------------------
package.json
{
"name": "node-stripe",
"version": "1.0.0",
"description": "",
"main": "app.js",
"scripts": {
"start": "node app.js"
},
"author": "",
"license": "ISC",
"dependencies": {
"body-parser": "^1.18.3",
"express": "^4.16.3",
"express-handlebars": "^3.0.0",
"stripe": "^6.10.0"
}
}
app.js
const express = require('express');const keys = require('./config/keys')
const stripe = require('stripe')(keys.stripeSecretKey);
const bodyParser = require('body-parser');
const exphbs = require('express-handlebars');
const path = require('path');
const app = express();
//Handlebars Middleware
app.engine('handlebars', exphbs({ defaultLayout: 'main' }));
app.set('view engine', 'handlebars');
//Body parser Middleware
app.use(bodyParser.json());
app.use(bodyParser.urlencoded({ extended: false }));
//Set static Folder
app.use(express.static(path.join(__dirname, './public')));
//Index Route
app.get('/', (req, res) => {
res.render('index', { stripePublishableKey: keys.stripePublishableKey });
})
//Charge Route
app.post('/charge', (req, res) => {
console.log(req.body);
//create/update customer
stripe.customers.create({
email: req.body.token.email,
source: req.body.token.id
})
//create charge
.then(customer => stripe.charges.create(
{
amount: req.body.price*100,
description: 'one step charge',
currency: 'cad',
customer: customer.id,
metadata: { order_id: req.body.orderId },
}
))
.then(charge => res.send('Transaction successful'))
.catch(err => res.send(err.message))
});
//transaction history route
app.post('/history', (req, res) => {
console.log(req.body);
stripe.balance.listTransactions({ limit: req.body.num }, function (err, transactions) {
// asynchronously called
if (!err) {
console.log(transactions);
res.send(transactions.data);
} else {
console.log('error');
}
});
});
const port = process.env.PORT || 5000;
app.listen(port, () => {
console.log('server started on port ', port);
});
----------------------------------
index.handlebars
<section><div class="row">
<div class="col-md-6 text-center">
<img src="/img/sale.png" alt="sale" class="img-fluid" />
<form>
Price: $<input type="number" id="price" placeholder="123.45"
onchange=priceChange()><br /><br />
<script src="https://checkout.stripe.com/checkout.js"></script>
<script src="https://unpkg.com/axios/dist/axios.min.js"></script>
<button id="customButton" class="btn-primary btn-block">Purchase</button><br />
Show # of transactions: <input type="number" id="transactionNum" placeholder="3"
onchange=transactionNumChange()><br /><br />
<button id="historyButton" class="btn-success btn-block">Transaction Histories</button><br />
<script>
var handler = StripeCheckout.configure({
key: '{{stripePublishableKey}}',
image: '/img/marketplace.png',
locale: 'auto',
token: function (token) {
//when form is submitted, form will wait for token to be generated before close
document.getElementById('transactionId').innerHTML = token.id.slice(4);
document.getElementById('transactionTime').innerHTML = new Date(token.created * 1000).toUTCString();
document.getElementById('cardId').innerHTML = token.card.id.slice(5);
document.getElementById('clientIP').innerHTML = token.client_ip;
//generate order ID
orderId = parseInt(Math.random() * 10000);
//send to server
axios.post('/charge', { token: token, price: price, orderId: orderId })
.then(function (response) {
document.getElementById('serverRes').innerHTML = 'Purchase request sent. ' + response.data;
console.log(response);
})
.catch(function (error) {
document.getElementById('serverRes').innerHTML = error.statusText;
console.log(error);
});
}
});
//purchase button click event
document.getElementById('customButton').addEventListener('click', async function (e) {
// Open Checkout with further options:
await handler.open({
name: 'Purchase',
description: 'Credit card',
currency: 'cad',
amount: price * 100,
});
e.preventDefault();
});
//history button click event
document.getElementById('historyButton').addEventListener('click', function (e) {
//send to server
axios.post('/history', { num: transactionNum })
.then( function (response) {
var serverText = document.getElementById('serverRes');
serverText.innerHTML = '<br/>';
for (var i = 0; i < response.data.length; i++) {
var time = new Date(response.data[i].created * 1000).toUTCString();
serverText.innerHTML = serverText.innerHTML
+ 'ID: '+ response.data[i].id + '<br/>'
+ 'Time: ' + time + '<br/>'
+ 'Amount: ' + response.data[i].amount/100 + '<br/>'
+ 'Fee: ' + response.data[i].fee / 100 + '<br/>'
+ 'Net: ' + response.data[i].net / 100 + '<br/><br/>'
}
console.log(response);
})
.catch(function (error) {
document.getElementById('serverRes').innerHTML = error.statusText;
console.log(error);
});
e.preventDefault();
});
// Close Checkout on page navigation:
window.addEventListener('popstate', function () {
handler.close();
});
</script>
</form>
</div>
<div class="col-md-6">
use card # 4242 4242 4242 4242 M/Y 12/34 CYC 111 to test<br />
<span class="text-warning">server response:</span> <span id="serverRes"></span><br />
<span class="text-info">transactionId:</span> <span id="transactionId"></span><br />
<span class="text-info">transactionTime:</span> <span id="transactionTime"></span><br />
<span class="text-info">cardId:</span> <span id="cardId"></span><br />
<span class="text-info">clientIP:</span> <span id="clientIP"></span><br />
</div>
</div>
</section>
<script>
var price = 123.45;
var orderId = 1234;
var transactionNum = 3;
function priceChange() {
price = parseFloat(document.getElementById("price").value).toFixed(2);
}
function transactionNumChange() {
transactionNum = parseInt(document.getElementById("transactionNum").value)
}
</script>
--------------------------------------
main.handlebars
<!DOCTYPE html><html lang="en">
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width-device-width, initial-scale=1.0" />
<meta http-equiv="X-UA-Compatible" content="ie=edge" />
<link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/4.1.0/css/bootstrap.min.css" integrity="sha384-9gVQ4dYFwwWSjIDZnLEWnxCjeSWFphJiwGPXr1jddIhOegiu1FwO5qRGvFXOdJZ4" crossorigin="anonymous">
<title>stripe transactions</title>
</head>
<body>
<nav class="navbar navbar-expand-md navbar-dark bg-dark">
<div class="container">
<a href="/" class="navbar-brand">
<h3 class="d-inline align-middle">Stripe</h3>
</a>
</div>
</nav>
<div class="container">
{{{body}}}
</div>
</body>
</html>
----------------------------------------------
keys.js
if (process.env.NODE_ENV === 'production') {
module.exports = require('./keys_prod');
} else {
module.exports = require('./keys_dev');
}
keys_prod.js
module.exports = {
stripePublishableKey: process.env.STRIPE_PUBLISHABLE_KEY,
stripeSecretKey: process.env.STRIPE_SECRET_KEY
}
------------------------------------
.gitignore
node_modules
key_dev.js
reference:
http://chuanshuoge2.blogspot.com/2018/09/stripe-api.html
No comments:
Post a Comment