1458 lines
53 KiB
JavaScript
1458 lines
53 KiB
JavaScript
import { createRequire } from 'module';
|
|
import path from 'path';
|
|
import { fileURLToPath } from 'url';
|
|
const require = createRequire(import.meta.url);
|
|
const __filename = fileURLToPath(import.meta.url);
|
|
const __dirname = path.dirname(__filename);
|
|
const fs = require('fs');
|
|
import {decode,encode} from 'html-entities';
|
|
//import "dotenv/config";
|
|
import express, { query } from "express";
|
|
// import http from "http";
|
|
import https from "https";
|
|
// import * as paypal from "./paypal-api.js";
|
|
var mysql = require('mysql2');
|
|
// import mysql from "mysql2";
|
|
import * as helperjs from "./helper.js";
|
|
|
|
// const express = require('express');
|
|
// const app = express();
|
|
const { resolve } = require('path');
|
|
const bodyParser = require('body-parser');
|
|
const cookieParser = require('cookie-parser');
|
|
const exec = require("child_process").exec;
|
|
// Replace if using a different env file or config
|
|
// require('dotenv').config({ path: './.env' });
|
|
|
|
|
|
// stripe login --api-key sk_test_51OIu21J7BKlr2pgsABfPagNLQmRYdn8wSDNOj9ph6q0T6ThchqyfRC585qp5iG1bHM3MrxnTHOUGQRGhZ4K6h5Sg00DmDdAv7Q
|
|
// stripe login --api-key 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
|
|
|
|
// stripe listen --forward-to https://www15.appfactory.studio:9295/webhook --skip-verify
|
|
|
|
// const stripe = require('stripe')('sk_test_...');
|
|
|
|
const subdomain = process.argv[2];
|
|
const mypath = path.join(__dirname, '../../../../../system/db/.env');
|
|
require('dotenv').config({ path: mypath })
|
|
|
|
console.log(process.env.MY_DATABASE);
|
|
console.log(mypath);
|
|
console.log(subdomain);
|
|
|
|
// 0|stripe | /home/appfactorystudio/websites/www15/portal/admin/services/stripe/app1/system/db/.env
|
|
// 0|stripe | www15
|
|
// 0|stripe | /home/appfactorystudio/websites/www15/portal/admin/services/stripe/app1/server
|
|
|
|
async function func__config(stripe,req,res,mydata){
|
|
let lookup_keys = mydata.clientdata.lookup_keys;
|
|
const prices = await stripe.prices.list({
|
|
lookup_keys: lookup_keys, //['pro_basic_v1', 'organization_v1', 'enterprise_v1'],
|
|
expand: ['data.product']
|
|
});
|
|
|
|
res.jsonp({
|
|
publishableKey: process.env.STRIPE_PUBLISHABLE_KEY,
|
|
prices: prices.data,
|
|
});
|
|
}
|
|
async function func__create_customer(stripe,req,res,mydata){
|
|
const customers = await stripe.customers.search({
|
|
query: `metadata[\'_reference_num\']:\'${mydata.clientdata.reference_num}\'`,
|
|
});
|
|
|
|
let customer = null;
|
|
if(customers==null || customers.data.length==0){
|
|
customer = await stripe.customers.create({
|
|
email: mydata.clientdata.email,
|
|
metadata: { _reference_num: mydata.clientdata.reference_num }
|
|
});
|
|
}else{
|
|
customer = customers[0];
|
|
}
|
|
|
|
if(mydata.clientdata.payment_intent!=undefined){
|
|
const paymentIntent = await stripe.paymentIntents.update(
|
|
mydata.clientdata.payment_intent.id,
|
|
{
|
|
customer: customer.id,
|
|
metadata: { _reference_num: mydata.clientdata.reference_num }
|
|
}
|
|
);
|
|
|
|
|
|
// let filename1 = `/mnt/node1/${mydata.managed_domain.SystemUser}/tmp/${mydata.clientdata.payment_intent.id}.json`;
|
|
// fs.appendFile(filename1,
|
|
// JSON.stringify({
|
|
// "payment_intent": mydata.clientdata.payment_intent,
|
|
// "customer": customer,
|
|
// "mail_handlers": mydata.clientdata.mail_handlers
|
|
// },null,4),
|
|
// function(err) {
|
|
// if(err) {
|
|
// console.log(`func__create_customer The file was saved! ${filename1}`);
|
|
// return console.log(err);
|
|
// }
|
|
// });
|
|
}
|
|
|
|
res.jsonp({
|
|
data: mydata.clientdata,
|
|
customer: customer,
|
|
customers:customers
|
|
});
|
|
}
|
|
async function func__create_subscription(stripe,req,res,mydata){
|
|
// Simulate authenticated user. In practice this will be the
|
|
// Stripe Customer ID related to the authenticated user.
|
|
const customerId = mydata.clientdata.customer
|
|
|
|
// Create the subscription
|
|
const priceId = mydata.clientdata.priceId;
|
|
|
|
try {
|
|
const subscription = await stripe.subscriptions.create({
|
|
customer: customerId,
|
|
items: [{
|
|
price: priceId,
|
|
}],
|
|
metadata: { _reference_num: mydata.clientdata.reference_num },
|
|
payment_behavior: 'default_incomplete',
|
|
expand: ['latest_invoice.payment_intent'],
|
|
});
|
|
|
|
res.jsonp({
|
|
subscription: subscription,
|
|
subscriptionId: subscription.id,
|
|
clientSecret: subscription.latest_invoice.payment_intent.client_secret,
|
|
});
|
|
} catch (error) {
|
|
return res.status(400).jsonp({ error: { message: error.message } });
|
|
}
|
|
}
|
|
async function func__invoice_preview(stripe,req,res,mydata){
|
|
const customerId = req.cookies['customer'];
|
|
const priceId = process.env[req.query.newPriceLookupKey.toUpperCase()];
|
|
|
|
const subscription = await stripe.subscriptions.retrieve(
|
|
req.query.subscriptionId
|
|
);
|
|
|
|
const invoice = await stripe.invoices.retrieveUpcoming({
|
|
customer: customerId,
|
|
subscription: req.query.subscriptionId,
|
|
subscription_items: [ {
|
|
id: subscription.items.data[0].id,
|
|
price: priceId,
|
|
}],
|
|
});
|
|
|
|
res.jsonp({ invoice });
|
|
}
|
|
async function func__cancel_subscription(stripe,req,res,mydata){
|
|
// Cancel the subscription
|
|
try {
|
|
const deletedSubscription = await stripe.subscriptions.del(
|
|
req.body.subscriptionId
|
|
);
|
|
|
|
res.jsonp({ subscription: deletedSubscription });
|
|
} catch (error) {
|
|
return res.status(400).jsonp({ error: { message: error.message } });
|
|
}
|
|
}
|
|
async function func__update_subscription(stripe,req,res,mydata){
|
|
try {
|
|
const subscription = await stripe.subscriptions.retrieve(
|
|
req.body.subscriptionId
|
|
);
|
|
const updatedSubscription = await stripe.subscriptions.update(
|
|
req.body.subscriptionId, {
|
|
items: [{
|
|
id: subscription.items.data[0].id,
|
|
price: process.env[req.body.newPriceLookupKey.toUpperCase()],
|
|
}],
|
|
}
|
|
);
|
|
|
|
res.jsonp({ subscription: updatedSubscription });
|
|
} catch (error) {
|
|
return res.status(400).jsonp({ error: { message: error.message } });
|
|
}
|
|
}
|
|
async function func__subscriptions(stripe,req,res,mydata){
|
|
// Simulate authenticated user. In practice this will be the
|
|
// Stripe Customer ID related to the authenticated user.
|
|
const customerId = req.cookies['customer'];
|
|
|
|
const subscriptions = await stripe.subscriptions.list({
|
|
customer: customerId,
|
|
status: 'all',
|
|
expand: ['data.default_payment_method'],
|
|
});
|
|
|
|
res.jsonp({subscriptions});
|
|
}
|
|
|
|
const calculate_tax = async (stripe, orderAmount, currency) => {
|
|
const taxCalculation = await stripe.tax.calculations.create({
|
|
currency,
|
|
customer_details: {
|
|
address: {
|
|
line1: "10709 Cleary Blvd",
|
|
city: "Plantation",
|
|
state: "FL",
|
|
postal_code: "33322",
|
|
country: "US",
|
|
},
|
|
address_source: "shipping",
|
|
},
|
|
line_items: [
|
|
{
|
|
amount: orderAmount,
|
|
reference: "ProductRef",
|
|
tax_behavior: "exclusive",
|
|
tax_code: "txcd_30011000"
|
|
}
|
|
],
|
|
});
|
|
|
|
return taxCalculation;
|
|
};
|
|
async function func_single_create_payment_intent(stripe,req,res,mydata){
|
|
// Create a PaymentIntent with the amount, currency, and a payment method type.
|
|
//
|
|
// See the documentation [0] for the full list of supported parameters.
|
|
//
|
|
// [0] https://stripe.com/docs/api/payment_intents/create
|
|
let orderAmount = 1400;
|
|
let paymentIntent;
|
|
const calculateTax = false;
|
|
|
|
try {
|
|
if (calculateTax) {
|
|
let taxCalculation = await calculate_tax(stripe, orderAmount, "usd")
|
|
|
|
paymentIntent = await stripe.paymentIntents.create({
|
|
currency: 'usd',
|
|
amount: taxCalculation.amount_total,
|
|
automatic_payment_methods: { enabled: true },
|
|
metadata: { tax_calculation: taxCalculation.id }
|
|
});
|
|
}
|
|
else {
|
|
paymentIntent = await stripe.paymentIntents.create({
|
|
currency: 'usd',
|
|
amount: orderAmount,
|
|
automatic_payment_methods: { enabled: true }
|
|
});
|
|
}
|
|
|
|
// Send publishable key and PaymentIntent details to client
|
|
res.jsonp({
|
|
paymentIntent: paymentIntent,
|
|
clientSecret: paymentIntent.client_secret,
|
|
});
|
|
} catch (e) {
|
|
return res.status(400).jsonp({
|
|
error: {
|
|
message: e.message,
|
|
}
|
|
});
|
|
}
|
|
}
|
|
|
|
|
|
async function webhook_update(values){
|
|
// let connection = createMySQLConnection();
|
|
// try {
|
|
// let net = parseInt(values.mysql_id);
|
|
// const sql = 'UPDATE `configurations` SET `json` = "'+JSON.stringify(values)+'" WHERE `id` = ' + net;
|
|
// // const values = ['Josh', 7];
|
|
|
|
// // console.log(JSON.stringify(values));
|
|
// const [result, fields] = await connection.execute(sql);
|
|
|
|
// console.log(result);
|
|
// console.log(fields);
|
|
// } catch (err) {
|
|
// console.log(err);
|
|
// }
|
|
}
|
|
function _create_connection(query, cb1){
|
|
let con = createMySQLConnection();
|
|
con.connect(function(err) {
|
|
if (err) throw err;
|
|
con.query(`${query}`, function (err, results) {
|
|
// con.query(`SELECT * FROM subdomain_properties WHERE SubDomain = '${subdomain}'`, function (err, results) {
|
|
if (err){
|
|
console.log(err);
|
|
throw err;
|
|
}
|
|
cb1(results);
|
|
con.end();
|
|
// if(results.length > 0){}
|
|
});
|
|
});
|
|
}
|
|
|
|
function _write_log(string,managed_domain){
|
|
let filename1 = `/mnt/node1/${managed_domain.SystemUser}/logs/node_stripe_test.log`;
|
|
fs.appendFile(filename1,
|
|
`\n\n\n----------------------------------\n${string}`,
|
|
function(err) {
|
|
if(err) {return console.log(err);}
|
|
console.log(`_write_log - The file was saved! ${filename1}`);
|
|
});
|
|
}
|
|
function _write_json_file(filename1,json){
|
|
// let filename1 = `/mnt/node1/${managed_domain.SystemUser}/logs/node_stripe_test.log`;
|
|
fs.appendFile(filename1,JSON.stringify(json),
|
|
function(err) {
|
|
if(err) {return console.log(err);}
|
|
console.log(`_write_log - The file was saved! ${filename1}`);
|
|
});
|
|
}
|
|
function isObjectEmpty(value) {
|
|
for (let prop in value) {
|
|
if (value.hasOwnProperty(prop)) return false;
|
|
}
|
|
return true;
|
|
}
|
|
function getTempWebhookList(){
|
|
let enabled_events = [
|
|
'payment_intent.payment_failed',
|
|
'payment_intent.succeeded',
|
|
'invoice.payment_succeeded',
|
|
'customer.subscription.trial_will_end',
|
|
'customer.subscription.deleted',
|
|
'invoice.finalized',
|
|
'invoice.payment_failed'
|
|
]
|
|
return [
|
|
{
|
|
stripe: null,
|
|
options: {
|
|
endpoint: "/webhook",
|
|
enabled_events: enabled_events
|
|
},
|
|
settings: {
|
|
all_events_on: true,
|
|
"events": {
|
|
"all": {
|
|
email_response:{
|
|
"active": true,
|
|
"title":"",
|
|
"body":"stripe_webook_event_response_v1",
|
|
"subject":"Than you for contacting us",
|
|
"emails":[],
|
|
"template":"stripe_webook_event_response_v1",
|
|
"from":"no-reply",
|
|
"footer":""
|
|
},
|
|
email_alert:{
|
|
"active": true,
|
|
"title":"",
|
|
"body":"stripe_webook_event_alert_v1",
|
|
"subject":"${mycompany_name} - Notification Alert",
|
|
"emails":["james@appfactory.studio"],
|
|
"template":"stripe_webook_event_alert_v1",
|
|
"from":"no-reply",
|
|
"footer":""
|
|
}
|
|
}
|
|
}
|
|
|
|
}
|
|
|
|
},
|
|
{
|
|
stripe: null,
|
|
options: {
|
|
endpoint: "/connect_webhook",
|
|
enabled_events: enabled_events
|
|
},
|
|
settings: {
|
|
all_events_on: true,
|
|
"events": {
|
|
"all": {
|
|
email_response:{
|
|
"active": true,
|
|
"title":"",
|
|
"body":"stripe_webook_event_response_v1",
|
|
"subject":"Than you for contacting us",
|
|
"emails":[],
|
|
"template":"stripe_webook_event_response_v1",
|
|
"from":"no-reply",
|
|
"footer":""
|
|
},
|
|
email_alert:{
|
|
"active": true,
|
|
"title":"",
|
|
"body":"stripe_webook_event_alert_v1",
|
|
"subject":"${mycompany_name} - Notification Alert",
|
|
"emails":["james@appfactory.studio"],
|
|
"template":"stripe_webook_event_alert_v1",
|
|
"from":"no-reply",
|
|
"footer":""
|
|
}
|
|
}
|
|
}
|
|
|
|
}
|
|
}
|
|
]
|
|
}
|
|
function generateRandomFilename(length = 10) {
|
|
const characters = 'abcdefghijklmnopqrstuvwxyz0123456789';
|
|
let result = '';
|
|
|
|
for (let i = 0; i < length; i++) {
|
|
result += characters.charAt(Math.floor(Math.random() * characters.length));
|
|
}
|
|
|
|
return result;
|
|
}
|
|
|
|
function ChangeFileOwnership(file,cb,isLog){
|
|
if (fs.existsSync(file)) {
|
|
isLog = (isLog==undefined) ? false: isLog;
|
|
changeOwner(file,"appfactorystudio","apache", (error) => {
|
|
if (error) {
|
|
console.error('Failed to change ownership:', error);
|
|
} else {
|
|
|
|
fs.chmod(file, 0o775, (err) => {
|
|
if (err) {
|
|
if(isLog) _write_log('Error changing permissions:', mydata.managed_domain);
|
|
} else {
|
|
if(isLog) _write_log('Permissions changed successfully.', mydata.managed_domain);
|
|
if(cb!=undefined && typeof cb === "function"){
|
|
cb();
|
|
}
|
|
}
|
|
});
|
|
if(isLog) _write_log('Ownership changed successfully.', mydata.managed_domain);
|
|
}
|
|
});
|
|
} else {
|
|
if(isLog) console.log('charge.succeeded: File does not exist! - ' + file);
|
|
cb();
|
|
}
|
|
}
|
|
function SendEmailHandlers(file,mydata){
|
|
ChangeFileOwnership(file,function(){
|
|
exec(`php ${__dirname}/run.php "send_email2" "null" "${file}"`, function (error, stdout, stderr) {
|
|
_write_log("error: " + error, mydata.managed_domain);
|
|
_write_log(file, mydata.managed_domain);
|
|
_write_log(stdout, mydata.managed_domain);
|
|
console.log(stderr);
|
|
console.log(stdout);
|
|
|
|
_write_log("+++++++++++++++++++++++++++++++++++++++", mydata.managed_domain);
|
|
|
|
});
|
|
});
|
|
}
|
|
function MailHandlersVariableInsert(myobj,dataObject){
|
|
|
|
|
|
for (const key in myobj.mail_handlers) {
|
|
for (let i = 0; i < myobj.mail_handlers[key].variables.system.length; i++) {
|
|
for (let n = 0; n < myobj.mail_handlers[key].variables.system[i].length; n++) {
|
|
|
|
if(myobj.mail_handlers[key].variables.system[i][n].name=="last4"){
|
|
myobj.mail_handlers[key].variables.system[i][n].value =
|
|
dataObject.payment_method_details.card.last4;
|
|
}
|
|
|
|
if(myobj.mail_handlers[key].variables.system[i][n].name=="brand"){
|
|
myobj.mail_handlers[key].variables.system[i][n].value =
|
|
dataObject.payment_method_details.card.brand;
|
|
}
|
|
|
|
if(myobj.mail_handlers[key].variables.system[i][n].name=="dollar_amount"){
|
|
myobj.mail_handlers[key].variables.system[i][n].value =
|
|
dataObject.amount_captured;
|
|
}
|
|
|
|
if(myobj.mail_handlers[key].variables.system[i][n].name=="currency"){
|
|
myobj.mail_handlers[key].variables.system[i][n].value =
|
|
dataObject.payment_method_details.card.brand;
|
|
}
|
|
|
|
if(myobj.mail_handlers[key].variables.system[i][n].name=="receipt_url"){
|
|
myobj.mail_handlers[key].variables.system[i][n].value =
|
|
dataObject.receipt_url;
|
|
}
|
|
}
|
|
}
|
|
|
|
return myobj;
|
|
}
|
|
}
|
|
function changeOwner(filePath, newOwner, newGroup, callback) {
|
|
const command = `chown ${newOwner}:${newGroup} ${filePath}`;
|
|
|
|
exec(command, (error, stdout, stderr) => {
|
|
if (error) {
|
|
console.error(`Error: ${error.message}`);
|
|
callback(error);
|
|
return;
|
|
}
|
|
|
|
if (stderr) {
|
|
console.error(`stderr: ${stderr}`);
|
|
callback(new Error(stderr));
|
|
return;
|
|
}
|
|
|
|
console.log(`Ownership changed successfully: ${stdout}`);
|
|
callback(null);
|
|
});
|
|
}
|
|
function EventFiredChargeSucceeded(stripe,event,dataObject,mydata){
|
|
// 77777 /mnt/appfactorystudio/modules/payments/
|
|
let file = `/mnt/node1/${mydata.managed_domain.SystemUser}/tmp/${dataObject.payment_intent}.json`;
|
|
fs.readFile(file, 'utf8', (err, data) => {
|
|
if (err) {
|
|
console.error(err);
|
|
return;
|
|
}
|
|
|
|
try {
|
|
let myobj = JSON.parse(data);
|
|
fs.appendFile(`/mnt/node1/${mydata.managed_domain.SystemUser}/logs/node_stripe_test2.log`,
|
|
JSON.stringify(myobj,null,4),
|
|
function(err) {
|
|
if(err) {return console.log(err);}
|
|
// console.log(JSON.stringify(myobj,null,4));
|
|
console.log("NNNN The file was saved!");
|
|
});
|
|
|
|
|
|
myobj = MailHandlersVariableInsert(myobj,dataObject);
|
|
myobj.charge = dataObject
|
|
let directoryPath = `/mnt/node1/${mydata.managed_domain.SystemUser}/modules/payments/${dataObject.customer}`;
|
|
if (!fs.existsSync(directoryPath)) {
|
|
fs.mkdirSync(directoryPath, { recursive: true });
|
|
}
|
|
let newfile = `/mnt/node1/${mydata.managed_domain.SystemUser}/modules/payments/${dataObject.customer}/${dataObject.payment_intent}.json`;
|
|
fs.writeFile(newfile, JSON.stringify(myobj,null,4),"utf-8",function(err){
|
|
// console.log(err);
|
|
ChangeFileOwnership(newfile,function(){
|
|
SendEmailHandlers(newfile,{
|
|
"managed_domain": mydata.managed_domain,
|
|
"mail_handlers": myobj.mail_handlers
|
|
});
|
|
|
|
// fs.unlink(file, (err) => {
|
|
// if (err) {
|
|
// console.error(`Error removing file: ${err}`);
|
|
// return;
|
|
// }
|
|
|
|
// console.log(`File ${file} has been successfully removed.`);
|
|
// });
|
|
});
|
|
});
|
|
} catch (parseErr) {
|
|
console.error('Error parsing JSON:', parseErr);
|
|
}
|
|
});
|
|
}
|
|
async function EventFiredInvoicePaymentSucceeded(stripe,event,dataObject,mydata){
|
|
if(dataObject['billing_reason'] == 'subscription_create') {
|
|
// The subscription automatically activates after successful payment
|
|
// Set the payment method used to pay the first invoice
|
|
// as the default payment method for that subscription
|
|
const subscription_id = dataObject['subscription']
|
|
const payment_intent_id = dataObject['payment_intent']
|
|
|
|
// Retrieve the payment intent used to pay the subscription
|
|
const payment_intent = await stripe.paymentIntents.retrieve(payment_intent_id);
|
|
|
|
try {
|
|
const subscription = await stripe.subscriptions.update(
|
|
subscription_id,
|
|
{
|
|
default_payment_method: payment_intent.payment_method,
|
|
},
|
|
);
|
|
|
|
setTimeout(() => {
|
|
const query = `SELECT * FROM general_data_storage WHERE name="${dataObject['customer']}"`;
|
|
_create_connection(query, function(results){
|
|
if(results.length==0){
|
|
_write_log("NO RESULTS!",mydata.managed_domain);
|
|
return;
|
|
}
|
|
|
|
// ppppp
|
|
// _write_log(JSON.stringify(results),mydata.managed_domain);
|
|
// stripe listen --forward-to https://www15.appfactory.studio:9295/webhook --skip-verify
|
|
|
|
|
|
let myobj = JSON.parse(decode(results[0].json));
|
|
myobj = MailHandlersVariableInsert(myobj,dataObject);
|
|
// let filename1 = `/mnt/node1/appfactorystudio/logs/a_stripe_test.json`;
|
|
// fs.appendFile(filename1, JSON.stringify(dataObject), function(err) {
|
|
// _write_log(`_write_log - MailHandler ${filename1}`);
|
|
// if(err) {return console.log(err);}
|
|
// });
|
|
|
|
let contents = JSON.stringify(myobj);
|
|
let filename = `/mnt/node1/${mydata.managed_domain.SystemUser}/members/zones/${myobj.member.zone}/json/${myobj.member.reference_num}.json`;
|
|
console.log("123--------------------------------------");
|
|
console.log(filename);
|
|
_write_log(filename, mydata.managed_domain);
|
|
fs.appendFile(filename,contents, function(err) {
|
|
if(err) {return console.log(err);}
|
|
// console.log("The file was saved!");
|
|
|
|
// const updateQuery = `UPDATE general_data_storage SET json='${stringupdate}' WHERE name='${dataObject['customer']}'`;
|
|
// _create_connection(updateQuery, function(results1){
|
|
// exec(`php ${__dirname}/run.php "send_email" "${dataObject['customer']}" "${filename}"`, function (error, stdout, stderr) {
|
|
// _write_log("error: " + error, mydata.managed_domain);
|
|
// // _write_log("stdout: " + stdout, mydata.managed_domain);
|
|
// // _write_log("stderr: " + stderr, mydata.managed_domain);
|
|
// // _write_log(JSON.stringify(results[0]), mydata.managed_domain);
|
|
// changeOwner(filename,"appfactorystudio","apache", (error) => {
|
|
// if (error) {
|
|
// console.error('Failed to change ownership:', error);
|
|
// } else {
|
|
|
|
// fs.chmod(filename, 0o775, (err) => {
|
|
// if (err) {
|
|
// _write_log('Error changing permissions:', mydata.managed_domain);
|
|
// } else {
|
|
// _write_log('Permissions changed successfully.', mydata.managed_domain);
|
|
// }
|
|
// });
|
|
// _write_log('Ownership changed successfully.', mydata.managed_domain);
|
|
// }
|
|
// });
|
|
// });
|
|
// });
|
|
});
|
|
|
|
// payment_intent.charges.data[0].payment_method_details.card.last4
|
|
// payment_intent.charges.data[0].payment_method_details.card.brand
|
|
// _write_log(JSON.stringify(myobj.mail_handlers), mydata.managed_domain);
|
|
});
|
|
|
|
// _write_log(JSON.stringify(dataObject), mydata.managed_domain);
|
|
|
|
// console.log("Default payment method set for subscription:" + payment_intent.payment_method);
|
|
// _write_log("invoice.payment_succeeded",mydata.managed_domain);
|
|
// // _write_log(JSON.stringify(payment_intent),mydata.managed_domain);
|
|
// _write_log("last4 = " + payment_intent.charges.data[0].payment_method_details.card.last4, mydata.managed_domain);
|
|
// _write_log("brand = " + payment_intent.charges.data[0].payment_method_details.card.brand, mydata.managed_domain);
|
|
// _write_log("network = " + payment_intent.charges.data[0].payment_method_details.card.network, mydata.managed_domain);
|
|
//charges.payment_method_details.card.last4
|
|
//charges.payment_method_details.card.brand
|
|
// charges.payment_method_details.card.network
|
|
|
|
|
|
},10000);
|
|
|
|
} catch (err) {
|
|
console.log(err);
|
|
console.log(`⚠️ Failed to update the default payment method for subscription: ${subscription_id}`);
|
|
_write_log(`invoice.⚠️ Failed to update the default payment method for subscription: ${subscription_id}`, mydata.managed_domain);
|
|
}
|
|
};
|
|
}
|
|
|
|
|
|
async function func__webhook(stripe,req,res,mydata){
|
|
// Retrieve the event by verifying the signature using the raw body and secret.
|
|
let event;
|
|
|
|
|
|
|
|
// TODO_1: Remove whsec_ce937ab59c83dcecc659324f312e6044cc80246e3932d9b93bee27a3a6a513ef
|
|
const endpointSecret = 'whsec_ce937ab59c83dcecc659324f312e6044cc80246e3932d9b93bee27a3a6a513ef';
|
|
// console.log("###################################################################");
|
|
// console.log(req.body);
|
|
// console.log("###################################################################");
|
|
// console.log(req.header('Stripe-Signature'));
|
|
// console.log("###################################################################");
|
|
// console.log(mydata.webhook.settings.secret);
|
|
// console.log("###################################################################");
|
|
try {
|
|
event = stripe.webhooks.constructEvent(
|
|
req.body,
|
|
req.header('stripe-signature'),
|
|
endpointSecret //mydata.webhook.settings.secret
|
|
);
|
|
} catch (err) {
|
|
// console.log(mydata.webhook);
|
|
// console.log(err);
|
|
console.log(`⚠️ Webhook signature verification failed. ${err.message}`);
|
|
return res.sendStatus(400);
|
|
}
|
|
|
|
// Extract the object from the event.
|
|
const dataObject = event.data.object;
|
|
|
|
// Handle the event
|
|
// Review important events for Billing webhooks
|
|
// https://stripe.com/docs/billing/webhooks
|
|
// Remove comment to see the various objects sent for this sample
|
|
|
|
|
|
/*
|
|
----------------------------------
|
|
Unexpected event type: customer.created
|
|
----------------------------------
|
|
Unexpected event type: payment_intent.created
|
|
----------------------------------
|
|
Unexpected event type: customer.updated
|
|
----------------------------------
|
|
Unexpected event type: customer.subscription.created
|
|
----------------------------------
|
|
Unexpected event type: invoice.created
|
|
========== after succeful payment ================
|
|
----------------------------------
|
|
- Unexpected event type: customer.subscription.updated
|
|
----------------------------------
|
|
- Unexpected event type: payment_method.attached
|
|
----------------------------------
|
|
- Unexpected event type: charge.succeeded
|
|
----------------------------------
|
|
- Unexpected event type: payment_intent.succeeded
|
|
----------------------------------
|
|
- Unexpected event type: invoice.updated
|
|
----------------------------------
|
|
- invoice.payment_succeeded
|
|
|
|
----------------------------------
|
|
- Unexpected event type: invoice.paid
|
|
----------------------------------
|
|
- Unexpected event type: customer.subscription.updated
|
|
----------------------------------
|
|
- Unexpected event type: setup_intent.created
|
|
----------------------------------
|
|
- Unexpected event type: setup_intent.succeeded
|
|
*/
|
|
|
|
let charge_succeded_count = 0;
|
|
switch (event.type) {
|
|
|
|
// random
|
|
case 'invoice.payment_failed':
|
|
// If the payment fails or the customer does not have a valid payment method,
|
|
// an invoice.payment_failed event is sent, the subscription becomes past_due.
|
|
// Use this webhook to notify your user that their payment has
|
|
// failed and to retrieve new card details.
|
|
_write_log("invoice.payment_failed",mydata.managed_domain);
|
|
break;
|
|
case 'invoice.finalized':
|
|
// If you want to manually send out invoices to your customers
|
|
// or store them locally to reference to avoid hitting Stripe rate limits.
|
|
break;
|
|
case 'customer.subscription.deleted':
|
|
if (event.request != null) {
|
|
// handle a subscription cancelled by your request
|
|
// from above.
|
|
_write_log("customer.subscription.deleted",mydata.managed_domain);
|
|
} else {
|
|
// handle subscription cancelled automatically based
|
|
// upon your subscription settings.
|
|
_write_log("customer.subscription.deleted automatic",mydata.managed_domain);
|
|
}
|
|
break;
|
|
case 'customer.subscription.trial_will_end':
|
|
// Send notification to your user that the trial will end
|
|
_write_log("customer.subscription.trial_will_end",mydata.managed_domain);
|
|
break;
|
|
|
|
// customer creation
|
|
case 'customer.created':
|
|
|
|
_write_log(`Event type: ${event.type}`,mydata.managed_domain);
|
|
break;
|
|
case 'payment_intent.created':
|
|
|
|
|
|
|
|
|
|
_write_log(`Event type: ${event.type}`,mydata.managed_domain);
|
|
break;
|
|
case 'customer.updated':
|
|
|
|
_write_log(`Event type: ${event.type}`,mydata.managed_domain);
|
|
break;
|
|
case 'customer.subscription.created':
|
|
|
|
_write_log(`Event type: ${event.type}`,mydata.managed_domain);
|
|
break;
|
|
case 'invoice.created':
|
|
|
|
_write_log(`Event type: ${event.type}`,mydata.managed_domain);
|
|
break;
|
|
|
|
// after payment succeds
|
|
case 'customer.subscription.updated':
|
|
|
|
_write_log(`Event type: ${event.type}`,mydata.managed_domain);
|
|
break;
|
|
case 'payment_method.attached':
|
|
|
|
_write_log(`Event type: ${event.type}`,mydata.managed_domain);
|
|
break;
|
|
case 'charge.succeeded': // singlecharge
|
|
_write_log(`Event type: ${event.type}`,mydata.managed_domain);
|
|
EventFiredChargeSucceeded(stripe,event,dataObject,mydata);
|
|
break;
|
|
case 'payment_intent.succeeded':
|
|
|
|
_write_log(`Event type: ${event.type}`,mydata.managed_domain);
|
|
break;
|
|
case 'invoice.updated':
|
|
|
|
break;
|
|
case 'invoice.payment_succeeded': // recurring
|
|
_write_log(`Event type: ----- ${event.type}`,mydata.managed_domain);
|
|
EventFiredInvoicePaymentSucceeded(stripe,event,dataObject,mydata);
|
|
break;
|
|
case 'invoice.paid':
|
|
_write_log(`Event type: ${event.type}`,mydata.managed_domain);
|
|
break;
|
|
case 'customer.subscription.updated':
|
|
_write_log(`Event type: ${event.type}`,mydata.managed_domain);
|
|
break;
|
|
case 'setup_intent.created':
|
|
_write_log(`Event type: ${event.type}`,mydata.managed_domain);
|
|
break;
|
|
case 'setup_intent.succeeded':
|
|
_write_log(`Event type: ${event.type}`,mydata.managed_domain);
|
|
break;
|
|
|
|
default:
|
|
_write_log(`Unexpected event type: ${event.type}`,mydata.managed_domain);
|
|
// Unexpected event type
|
|
}
|
|
res.sendStatus(200);
|
|
|
|
|
|
}
|
|
async function func__webhookListen(stripe,active_processor,managed_domain,app){
|
|
app.use((req, res, next) => {
|
|
let isWebhook = false;
|
|
for (let i = 0; i < active_processor.webhooks.length; i++) {
|
|
const index = i;
|
|
const webhook = active_processor.webhooks[index];
|
|
const endpoint = webhook.options.endpoint;
|
|
console.log(req.originalUrl)
|
|
if (req.originalUrl === endpoint) {
|
|
isWebhook = true;
|
|
break;
|
|
}
|
|
}
|
|
if(isWebhook==true){
|
|
next();
|
|
}else{
|
|
bodyParser.json()(req, res, next);
|
|
}
|
|
});
|
|
|
|
for (let i = 0; i < active_processor.webhooks.length; i++) {
|
|
const webhook = active_processor.webhooks[i];
|
|
const endpoint = webhook.options.endpoint;
|
|
console.log(endpoint)
|
|
app.post(endpoint, bodyParser.raw({ type: 'application/json' }), async (req, res) => {
|
|
let mydata = {
|
|
managed_domain: managed_domain,
|
|
processor: active_processor,
|
|
webhook: webhook
|
|
};
|
|
func__webhook(stripe,req,res,mydata);
|
|
});
|
|
}
|
|
|
|
|
|
}
|
|
|
|
/**
|
|
* Return true if there's a match for the given url within the webhookEndpoints object given by calling stripe.webhookEndpoints.list
|
|
* @param {string} url
|
|
* @param {object} webhookEndpoints
|
|
* @returns boolean
|
|
*/
|
|
function checkWebhookUrl(url,webhookEndpoints){
|
|
let doesExist = false;
|
|
let webhook = null;
|
|
for (let i = 0; i < webhookEndpoints.data.length; i++) {
|
|
const webh = webhookEndpoints.data[i];
|
|
if(webh.url==url){
|
|
doesExist = true;
|
|
webhook = webh;
|
|
break;
|
|
}
|
|
}
|
|
return {doesExist,webhook};
|
|
}
|
|
async function RunWebooks2(stripe,managed_domain,active_processor,app){
|
|
if(active_processor.webhooks==null || active_processor.webhooks==undefined){
|
|
active_processor.webhooks = getTempWebhookList();
|
|
console.log("webhook is null");
|
|
}else{
|
|
console.log("webhook is NOT null");
|
|
}
|
|
|
|
// whsec_ce937ab59c83dcecc659324f312e6044cc80246e3932d9b93bee27a3a6a513ef
|
|
if(active_processor.webhooks!=undefined && Array.isArray(active_processor.webhooks)){
|
|
const webhookEndpoints = await stripe.webhookEndpoints.list({
|
|
limit: 16,
|
|
});
|
|
// _write_log(JSON.stringify(webhookEndpoints),managed_domain);
|
|
|
|
//if(webhook.stripe!=undefined && webhook.stripe!=null && isObjectEmpty(webhook.stripe)){
|
|
for (let i = 0; i < active_processor.webhooks.length; i++) {
|
|
const index = i;
|
|
const webhook = active_processor.webhooks[index];
|
|
|
|
if(active_processor.stripe==null || active_processor.stripe==undefined){
|
|
let url = managed_domain.Address + ':' + active_processor.service_port + webhook.options.endpoint;
|
|
let obj1 = checkWebhookUrl(url,webhookEndpoints);
|
|
if(obj1.doesExist){
|
|
active_processor.webhooks[index].stripe = obj1.webhook;
|
|
continue;
|
|
}
|
|
|
|
// https://www15.appfactory.studio:9295/stripe_webook
|
|
const endpoint = await stripe.webhookEndpoints.create({
|
|
url: url,
|
|
enabled_events: webhook.options.enabled_events,
|
|
});
|
|
|
|
active_processor.webhooks[index].settings.secret = endpoint.secret;
|
|
active_processor.webhooks[index].settings.webhook = endpoint;
|
|
active_processor.webhooks[index].stripe = endpoint;
|
|
}
|
|
}
|
|
//}
|
|
|
|
// give some time for webhook creation to complete
|
|
setTimeout(() => {
|
|
webhook_update(active_processor);
|
|
func__webhookListen(stripe,active_processor,managed_domain,app);
|
|
},2000);
|
|
}
|
|
}
|
|
|
|
async function RunWebooks(request,response,stripe,managed_domain,active_processor,app){
|
|
const endpointSecret = 'whsec_5JA2kRDbUDoHVOFlDDU7TwyCPmfDUIEU';
|
|
|
|
let event = request.body;
|
|
// Only verify the event if you have an endpoint secret defined.
|
|
// Otherwise use the basic event deserialized with JSON.parse
|
|
if (endpointSecret) {
|
|
// Get the signature sent by Stripe
|
|
const signature = request.headers['stripe-signature'];
|
|
try {
|
|
event = stripe.webhooks.constructEvent(
|
|
request.body,
|
|
signature,
|
|
endpointSecret
|
|
);
|
|
} catch (err) {
|
|
console.log(`⚠️ Webhook signature verification failed.`, err.message);
|
|
return response.sendStatus(400);
|
|
}
|
|
}
|
|
|
|
// Handle the event
|
|
switch (event.type) {
|
|
case 'payment_intent.succeeded':
|
|
const paymentIntent = event.data.object;
|
|
console.log(`PaymentIntent for ${paymentIntent.amount} was successful!`);
|
|
// Then define and call a method to handle the successful payment intent.
|
|
// handlePaymentIntentSucceeded(paymentIntent);
|
|
break;
|
|
case 'payment_method.attached':
|
|
const paymentMethod = event.data.object;
|
|
console.log(paymentMethod);
|
|
// Then define and call a method to handle the successful attachment of a PaymentMethod.
|
|
// handlePaymentMethodAttached(paymentMethod);
|
|
break;
|
|
default:
|
|
// Unexpected event type
|
|
console.log(`Unhandled event type ${event.type}.`);
|
|
}
|
|
|
|
// Return a 200 response to acknowledge receipt of the event
|
|
response.send();
|
|
}
|
|
|
|
/**
|
|
* Create a mysql connect to the database with creditals.
|
|
* Make sure to call connection.end() after calling connection.connect()
|
|
* @returns mysql_connection
|
|
*/
|
|
function createMySQLConnection(){
|
|
return mysql.createConnection({
|
|
host: process.env.MY_HOSTNAME,
|
|
user: process.env.MY_USER,
|
|
password: process.env.MY_PASSWORD,
|
|
database: process.env.MY_DATABASE,
|
|
insecureAuth : true
|
|
});
|
|
}
|
|
|
|
let con = createMySQLConnection();
|
|
con.connect(function(err) {
|
|
if (err) throw err;
|
|
con.query(`SELECT * FROM subdomain_properties WHERE SubDomain = '${subdomain}'`, function (err, results) {
|
|
if (err) throw err;
|
|
// con.end();
|
|
if(results.length > 0){
|
|
let managed_domain = {};
|
|
for(let i=0; i < results.length; i++){
|
|
//console.log(results[i].SubDomain + " : " + results[i].PropertyName + " : " + results[i].PropertyValue);
|
|
managed_domain[results[i].PropertyName] = results[i].PropertyValue;
|
|
}
|
|
|
|
con.query(`SELECT * FROM configurations WHERE category="processors"`, function (err1, results1) {
|
|
if (err1) throw err1;
|
|
con.end();
|
|
if(results1.length > 0){
|
|
let processors = [];
|
|
for(let n=0; n < results1.length; n++){
|
|
let processor = results1[n];
|
|
processor.json = JSON.parse(decode(processor.json));
|
|
if(processor.json.processor=="stripe"){
|
|
processors.push(processor);
|
|
}
|
|
}
|
|
run(managed_domain, processors);
|
|
}else{
|
|
console.log(`No active server for subdomain ${subdomain}`);
|
|
}
|
|
|
|
});
|
|
}else{
|
|
console.log(`Error starting server! No port number found for subdomain ${subdomain}`);
|
|
}
|
|
});
|
|
});
|
|
|
|
let xmp = {
|
|
"real_db": "starterdb",
|
|
"db_user": "wx1234nn8nbslsj9",
|
|
"db_password": "MYblessings1984!",
|
|
"db_host": "localhost",
|
|
|
|
"Subdomain": "wx1234nn8nbslsj9",
|
|
"Username": "wx1234nn8nbslsj9",
|
|
"SystemUser": "wx1234nn8nbslsj9",
|
|
"Domain": "wx1234nn8nbslsj9.appfactory.studio",
|
|
"EmailServer": "server1.appfactory.studio",
|
|
"Address": "https://wx1234nn8nbslsj9.appfactory.studio",
|
|
"CertPrivateKeyLocation": "/etc/letsencrypt/live/wx1234nn8nbslsj9.appfactory.studio/privkey.pem",
|
|
"CertPublicKeyLocation": "/etc/letsencrypt/live/wx1234nn8nbslsj9.appfactory.studio/cert.pem"
|
|
}
|
|
|
|
|
|
|
|
|
|
function run(managed_domain,processors){
|
|
let active_processor = null;
|
|
for(let n=0; n < processors.length; n++){
|
|
if(processors[n].json.active==true){
|
|
active_processor = processors[n];
|
|
break;
|
|
}
|
|
}
|
|
|
|
console.log(active_processor);
|
|
console.log("Starting Stripe Server on port: " + active_processor.json.service_port);
|
|
|
|
let privateKey = fs.readFileSync(managed_domain.CertPrivateKeyLocation, 'utf8');
|
|
let certificate = fs.readFileSync(managed_domain.CertPublicKeyLocation, 'utf8');
|
|
let credentials = {key: privateKey, cert: certificate};
|
|
let app = express();
|
|
let clientId = active_processor.json.client_id;
|
|
let clientSecret = active_processor.json.client_secret;
|
|
let base = "";
|
|
let mode = active_processor.json.mode;
|
|
console.log(clientSecret);
|
|
console.log(managed_domain.CertPrivateKeyLocation);
|
|
console.log(managed_domain.CertPublicKeyLocation);
|
|
const stripe = require('stripe')(clientSecret, {
|
|
apiVersion: '2022-08-01',
|
|
appInfo: { // For sample support and debugging, not required for production:
|
|
name: "stripe-samples/subscription-use-cases/fixed-price",
|
|
version: "0.0.1",
|
|
url: "https://github.com/stripe-samples/subscription-use-cases/fixed-price"
|
|
}
|
|
});
|
|
|
|
// Use JSON parser for parsing payloads as JSON on all non-webhook routes.
|
|
|
|
// app.post('/webhook', express.raw({type: 'application/json'}), (request, response) => {
|
|
// RunWebooks(request,response,stripe,managed_domain,active_processor.json,app);
|
|
// });
|
|
|
|
RunWebooks2(stripe,managed_domain,active_processor.json,app);
|
|
|
|
// const endpointSecret = "whsec_5JA2kRDbUDoHVOFlDDU7TwyCPmfDUIEU"
|
|
const endpointSecret = 'whsec_ce937ab59c83dcecc659324f312e6044cc80246e3932d9b93bee27a3a6a513ef';
|
|
|
|
app.get("/"+active_processor.json.service_end_point, async (req, res) => {
|
|
|
|
// console.log(base);
|
|
let mydata = {
|
|
clientdata: JSON.parse(req.query.data),
|
|
managed_domain: managed_domain,
|
|
processor: active_processor
|
|
};
|
|
try {
|
|
|
|
if(req.query.type=="keys"){
|
|
res.jsonp({keys: {
|
|
client_id: mydata.processor.json.client_id,
|
|
client_secret: mydata.processor.json.client_secret
|
|
}});
|
|
|
|
}else if(req.query.type=="signle-create-payment-intent"){
|
|
func_single_create_payment_intent(stripe,req,res,mydata);
|
|
}else if(req.query.type=="check"){
|
|
res.jsonp({action:true});
|
|
}else if(req.query.type=="config"){
|
|
func__config(stripe,req,res,mydata);
|
|
}else if(req.query.type=="create-customer"){
|
|
func__create_customer(stripe,req,res,mydata);
|
|
}else if(req.query.type=="create-subscription"){
|
|
func__create_subscription(stripe,req,res,mydata);
|
|
}else if(req.query.type=="invoice-preview"){
|
|
func__invoice_preview(stripe,req,res,mydata);
|
|
}else if(req.query.type=="cancel-subscription"){
|
|
func__cancel_subscription(stripe,req,res,mydata);
|
|
}else if(req.query.type=="update-subscription"){
|
|
func__update_subscription();
|
|
}else if(req.query.type=="subscriptions"){
|
|
func__subscriptions(stripe,req,res,mydata);
|
|
}else if(req.query.type=="checking"){
|
|
// func__subscriptions(stripe,req,res,mydata);
|
|
res.jsonp("working 678");
|
|
}else{
|
|
res.jsonp("working 2");
|
|
}
|
|
} catch (err) {
|
|
console.log(err.message)
|
|
res.jsonp(err.message);
|
|
}
|
|
});
|
|
|
|
var httpsServer = https.createServer(credentials, app);
|
|
httpsServer.listen(active_processor.json.service_port);
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
function jumpstarter(){
|
|
if (
|
|
!process.env.STRIPE_SECRET_KEY ||
|
|
!process.env.STRIPE_PUBLISHABLE_KEY ||
|
|
!process.env.STATIC_DIR
|
|
) {
|
|
console.log(
|
|
'The .env file is not configured. Follow the instructions in the readme to configure the .env file. https://github.com/stripe-samples/subscription-use-cases'
|
|
);
|
|
console.log('');
|
|
process.env.STRIPE_SECRET_KEY
|
|
? ''
|
|
: console.log('Add STRIPE_SECRET_KEY to your .env file.');
|
|
|
|
process.env.STRIPE_PUBLISHABLE_KEY
|
|
? ''
|
|
: console.log('Add STRIPE_PUBLISHABLE_KEY to your .env file.');
|
|
|
|
process.env.STATIC_DIR
|
|
? ''
|
|
: console.log(
|
|
'Add STATIC_DIR to your .env file. Check .env.example in the root folder for an example'
|
|
);
|
|
|
|
process.exit();
|
|
}
|
|
|
|
const stripe = require('stripe')(process.env.STRIPE_SECRET_KEY, {
|
|
apiVersion: '2022-08-01',
|
|
appInfo: { // For sample support and debugging, not required for production:
|
|
name: "stripe-samples/subscription-use-cases/fixed-price",
|
|
version: "0.0.1",
|
|
url: "https://github.com/stripe-samples/subscription-use-cases/fixed-price"
|
|
}
|
|
});
|
|
|
|
// Use static to serve static assets.
|
|
app.use(express.static(process.env.STATIC_DIR));
|
|
|
|
// Use cookies to simulate logged in user.
|
|
app.use(cookieParser());
|
|
|
|
// Use JSON parser for parsing payloads as JSON on all non-webhook routes.
|
|
app.use((req, res, next) => {
|
|
if (req.originalUrl === '/webhook') {
|
|
next();
|
|
} else {
|
|
bodyParser.json()(req, res, next);
|
|
}
|
|
});
|
|
|
|
app.get('/', (req, res) => {
|
|
const path = resolve(process.env.STATIC_DIR + '/register.html');
|
|
res.sendFile(path);
|
|
});
|
|
|
|
app.get('/config', async (req, res) => {
|
|
const prices = await stripe.prices.list({
|
|
lookup_keys: ['pro_basic_v1', 'organization_v1', 'enterprise_v1'],
|
|
expand: ['data.product']
|
|
});
|
|
|
|
res.send({
|
|
publishableKey: process.env.STRIPE_PUBLISHABLE_KEY,
|
|
prices: prices.data,
|
|
});
|
|
});
|
|
app.post('/create-customer', async (req, res) => {
|
|
// Create a new customer object
|
|
const customer = await stripe.customers.create({
|
|
email: req.body.email,
|
|
});
|
|
|
|
// Save the customer.id in your database alongside your user.
|
|
// We're simulating authentication with a cookie.
|
|
res.cookie('customer', customer.id, { maxAge: 900000, httpOnly: true });
|
|
|
|
res.send({ customer: customer });
|
|
});
|
|
app.post('/create-subscription', async (req, res) => {
|
|
// Simulate authenticated user. In practice this will be the
|
|
// Stripe Customer ID related to the authenticated user.
|
|
const customerId = req.cookies['customer'];
|
|
|
|
// Create the subscription
|
|
const priceId = req.body.priceId;
|
|
|
|
try {
|
|
const subscription = await stripe.subscriptions.create({
|
|
customer: customerId,
|
|
items: [{
|
|
price: priceId,
|
|
}],
|
|
payment_behavior: 'default_incomplete',
|
|
expand: ['latest_invoice.payment_intent'],
|
|
});
|
|
|
|
res.send({
|
|
subscriptionId: subscription.id,
|
|
clientSecret: subscription.latest_invoice.payment_intent.client_secret,
|
|
});
|
|
} catch (error) {
|
|
return res.status(400).send({ error: { message: error.message } });
|
|
}
|
|
});
|
|
app.get('/invoice-preview', async (req, res) => {
|
|
const customerId = req.cookies['customer'];
|
|
const priceId = process.env[req.query.newPriceLookupKey.toUpperCase()];
|
|
|
|
const subscription = await stripe.subscriptions.retrieve(
|
|
req.query.subscriptionId
|
|
);
|
|
|
|
const invoice = await stripe.invoices.retrieveUpcoming({
|
|
customer: customerId,
|
|
subscription: req.query.subscriptionId,
|
|
subscription_items: [ {
|
|
id: subscription.items.data[0].id,
|
|
price: priceId,
|
|
}],
|
|
});
|
|
|
|
res.send({ invoice });
|
|
});
|
|
app.post('/cancel-subscription', async (req, res) => {
|
|
// Cancel the subscription
|
|
try {
|
|
const deletedSubscription = await stripe.subscriptions.del(
|
|
req.body.subscriptionId
|
|
);
|
|
|
|
res.send({ subscription: deletedSubscription });
|
|
} catch (error) {
|
|
return res.status(400).send({ error: { message: error.message } });
|
|
}
|
|
});
|
|
app.post('/update-subscription', async (req, res) => {
|
|
try {
|
|
const subscription = await stripe.subscriptions.retrieve(
|
|
req.body.subscriptionId
|
|
);
|
|
const updatedSubscription = await stripe.subscriptions.update(
|
|
req.body.subscriptionId, {
|
|
items: [{
|
|
id: subscription.items.data[0].id,
|
|
price: process.env[req.body.newPriceLookupKey.toUpperCase()],
|
|
}],
|
|
}
|
|
);
|
|
|
|
res.send({ subscription: updatedSubscription });
|
|
} catch (error) {
|
|
return res.status(400).send({ error: { message: error.message } });
|
|
}
|
|
});
|
|
app.get('/subscriptions', async (req, res) => {
|
|
// Simulate authenticated user. In practice this will be the
|
|
// Stripe Customer ID related to the authenticated user.
|
|
const customerId = req.cookies['customer'];
|
|
|
|
const subscriptions = await stripe.subscriptions.list({
|
|
customer: customerId,
|
|
status: 'all',
|
|
expand: ['data.default_payment_method'],
|
|
});
|
|
|
|
res.json({subscriptions});
|
|
});
|
|
app.post('/webhook',
|
|
bodyParser.raw({ type: 'application/json' }),
|
|
async (req, res) => {
|
|
// Retrieve the event by verifying the signature using the raw body and secret.
|
|
let event;
|
|
|
|
try {
|
|
event = stripe.webhooks.constructEvent(
|
|
req.body,
|
|
req.header('Stripe-Signature'),
|
|
process.env.STRIPE_WEBHOOK_SECRET
|
|
);
|
|
} catch (err) {
|
|
console.log(err);
|
|
console.log(`⚠️ Webhook signature verification failed.`);
|
|
console.log(
|
|
`⚠️ Check the env file and enter the correct webhook secret.`
|
|
);
|
|
return res.sendStatus(400);
|
|
}
|
|
|
|
// Extract the object from the event.
|
|
const dataObject = event.data.object;
|
|
|
|
// Handle the event
|
|
// Review important events for Billing webhooks
|
|
// https://stripe.com/docs/billing/webhooks
|
|
// Remove comment to see the various objects sent for this sample
|
|
switch (event.type) {
|
|
case 'invoice.payment_succeeded':
|
|
if(dataObject['billing_reason'] == 'subscription_create') {
|
|
// The subscription automatically activates after successful payment
|
|
// Set the payment method used to pay the first invoice
|
|
// as the default payment method for that subscription
|
|
const subscription_id = dataObject['subscription']
|
|
const payment_intent_id = dataObject['payment_intent']
|
|
|
|
// Retrieve the payment intent used to pay the subscription
|
|
const payment_intent = await stripe.paymentIntents.retrieve(payment_intent_id);
|
|
|
|
try {
|
|
const subscription = await stripe.subscriptions.update(
|
|
subscription_id,
|
|
{
|
|
default_payment_method: payment_intent.payment_method,
|
|
},
|
|
);
|
|
|
|
console.log("Default payment method set for subscription:" + payment_intent.payment_method);
|
|
} catch (err) {
|
|
console.log(err);
|
|
console.log(`⚠️ Failed to update the default payment method for subscription: ${subscription_id}`);
|
|
}
|
|
};
|
|
|
|
break;
|
|
case 'invoice.payment_failed':
|
|
// If the payment fails or the customer does not have a valid payment method,
|
|
// an invoice.payment_failed event is sent, the subscription becomes past_due.
|
|
// Use this webhook to notify your user that their payment has
|
|
// failed and to retrieve new card details.
|
|
break;
|
|
case 'invoice.finalized':
|
|
// If you want to manually send out invoices to your customers
|
|
// or store them locally to reference to avoid hitting Stripe rate limits.
|
|
break;
|
|
case 'customer.subscription.deleted':
|
|
if (event.request != null) {
|
|
// handle a subscription cancelled by your request
|
|
// from above.
|
|
} else {
|
|
// handle subscription cancelled automatically based
|
|
// upon your subscription settings.
|
|
}
|
|
break;
|
|
case 'customer.subscription.trial_will_end':
|
|
// Send notification to your user that the trial will end
|
|
break;
|
|
default:
|
|
// Unexpected event type
|
|
}
|
|
res.sendStatus(200);
|
|
}
|
|
);
|
|
|
|
app.listen(4242, () => console.log(`Node server listening on port http://localhost:${4242}!`));
|
|
|
|
|
|
}// end function
|