stripe.confirmCardSetup(client_secret) not resulting in error - node.js

So I'm letting my user create a subscription with a free trial.
Node
const subscriptionWithTrial = async (req, res) => {
const {email, payment_method, user_id} = req.body;
const customer = await stripe.customers.create({
payment_method: payment_method,
email: email,
invoice_settings: {
default_payment_method: payment_method,
},
});
const subscription = await stripe.subscriptions.create({
customer: customer.id,
items: [{ plan: process.env.STRIPE_PRODUCT }],
trial_period_days: 14,
expand: ['latest_invoice.payment_intent', 'pending_setup_intent'],
});
res.json({subscription});
}
app.post('/subWithTrial', payment.subscriptionWithTrial);
React
const handleSubmitSubTrial = async (event) => {
if (!stripe || !elements) {
console.log("stripe.js hasn't loaded")
// Stripe.js has not yet loaded.
// Make sure to disable form submission until Stripe.js has loaded.
return;
}
const result = await stripe.createPaymentMethod({
type: 'card',
card: elements.getElement(CardElement),
billing_details: {
email: email,
},
});
stripe.createToken(elements.getElement(CardElement)).then(function(result) {
});
if (result.error) {
console.log(result.error.message);
} else {
try {
const res = await axios.post('/subWithTrial', {'payment_method': result.paymentMethod.id, 'email': email, 'user_id': auth0Context.user.sub});
const {pending_setup_intent, latest_invoice} = res.data.subscription;
if (pending_setup_intent) {
const {client_secret, status} = res.data.subscription.pending_setup_intent;
if (status === "requires_action") {
stripe.confirmCardSetup(client_secret).then(function(result) {
if (result.error) {
console.log('There was an issue!');
console.log(result.error);
} else {
// The setup has succeeded. Display a success message.
console.log('Success');
}
I'm using card number 4000008260003178 so I'm pretty sure it's supposed to require authentication (which works) then result into result.error for insufficient funds on line stripe.confirmCardSetup(client_secret).then(function(result) { if (result.error) {. But this doesn't happen. Instead it gives me console.log('Success');

This is expected. stripe.confirmCardSetup doesn't actually attempt to move money, it just sets the card up to do future off-session payments without needing 3DS.
Since you created your subscription with a 14 day trial, the actual first invoice payment won't happen till that's up. Meaning that in this case the test card is able to be set up correctly and won't see the payment failure till the trial period is up 14 days later.

Related

Razorpay not returning payment_id,order_id etc. upon successfull payment

I have one function that is responsible of creating order using razorpay and verify that order .
The code for that function is : -
const paymentMethod = async ()=>{
if(!isAuthenticated())
{
toast.error('Please signin to continue');
history.push('/signin')
// return <Redirect to='/signin' />
return;
}
try{
// console.log(JSON.stringify(total));
const obj = {
amount:total
}
let data = await fetch('http://localhost:3100/api/checkout',{
method:'POST',
headers:{
"content-type":"application/json",
Accept:"application/json"
},
body: JSON.stringify(obj)
})
let {order} = await data.json()
console.log(order)
console.log(order.amount)
const options = {
key: "rzp_test_cXj3ybg8fawS9Y",
amount: order.amount,
currency: "INR",
name: "YO! Merchandise",
description: "Pay Please",
image:yo,
order_id: order.id,
callback_url: "http://localhost:3100/api/paymentverification",
prefill: {
name: "Aakash Tiwari",
email: "tiwaryaakash00#gmail.com",
contact: "8750043604"
},
notes: {
address: "Razorpay Corporate Office"
},
theme: {
color: "#13C962"
}
};
let rzp1 = await new window.Razorpay(options);
rzp1.open();
}
catch(err){
console.log(err)
}
}
But this function when call callback_url upon successfull payment it is not passing the payment_id,order_id etc. other neccessary details.
when i try to console.log there the req.body is always empty.

Once I completed Stripe payment and then create-payment-intent can't fetch

I have a payment system with stripe payment intents and I want to create a succesfull paymnent . but once i payment then show this eorror in server side
C:\Project_Programing_hero\assainment-list\assainment-12\best-tech-server\node_modules\stripe\lib\Error.js:40
return new StripeInvalidRequestError(rawStripeError);
^
StripeInvalidRequestError: This value must be greater than or equal to 1.
on client side in checkoutFrom.js
useEffect(() => {
console.log(typeof (totalPrice));
fetch('http://localhost:5000/create-payment-intent', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify({ price: parseInt(totalPrice) }),
})
.then(response => response.json())
.then(data => {
console.log('Success:', data);
const dataClientSecret = data?.clientSecret;
if (dataClientSecret) {
setClientSecret(dataClientSecret)
}
})
}, [totalPrice])
const handleSubmit = async (event) => {
event.preventDefault()
if (!stripe || !elements) {
return;
}
const card = elements.getElement(CardElement);
if (card == null) {
return;
}
const { error, paymentMethod } = await stripe.createPaymentMethod({
type: 'card',
card,
});
if (error) {
console.log('[error]', error);
setCardError(error.message)
} else {
console.log('[PaymentMethod]', paymentMethod);
setCardError('')
}
// confirm card payment
setCardSuccess('')
setProcessing(true)
const { paymentIntent, error: intentError } = await stripe.confirmCardPayment(
`${clientSecret}`,
{
payment_method: {
card: card,
billing_details: {
name: customerName,
email: email
},
},
},
);
if (intentError) {
setCardError(intentError?.message)
setProcessing(false)
} else {
setCardError('')
setTransitionId(paymentIntent.id)
console.log(paymentIntent);
setCardSuccess('Congrats,Your payment is compiled')
// store payment to database
const payment = {
order: _id,
transitionId: paymentIntent.id
}
axios.patch(`http://localhost:5000/order/${_id}`, payment)
.then(res => {
setProcessing(false)
console.log(res.data);
})
}
}
โ€œThis value must be greater than or equal to 1โ€ error shows that the amount [0] param set in the payment intent creation request is smaller than 1. In the endpoint /create-payment-intent at your server, you will need to ensure request.price is greater than or equal to 1, and correctly assign into amount param. For example,
const paymentIntent = await stripe.paymentIntents.create({
amount: request.price,
currency: 'usd',
automatic_payment_methods: {enabled: true},
});
Apart from the server side, you should also make sure that the totalPrice at frontend is greater than or equal to 1 before passing to server.
body: JSON.stringify({ price: parseInt(totalPrice) }),
[0] https://stripe.com/docs/api/payment_intents/create#create_payment_intent-amount

Load confirmation URL in Embedded app itself in Shopify

I have an embedded app in shopify which is an paid app ,Once user approves the billing ,i want the app to show the confirmation url in the embedded app itself instead it loads externally.
getsubscriptionurl.js
export const getSubscriptionUrl = async (ctx, shop) => {
const { client } = ctx;
console.log(`process.env.HOST - ${process.env.HOST}`);
console.log(`shop - ${shop}`);
console.log(`${process.env.HOST}/?shop=${shop}`);
const confirmationUrl = await client
.mutate({
mutation: RECURRING_CREATE(),
variables: {
returnUrl: `www.abc.com`,
}
})
.then(response => response.data.appSubscriptionCreate.confirmationUrl);
console.log("me "+ confirmationUrl);
return ctx.redirect(confirmationUrl);
};
server.js
app.prepare().then(async () => {
const server = new Koa();
const router = new Router();
server.keys = [Shopify.Context.API_SECRET_KEY];
server.use(
createShopifyAuth({
async afterAuth(ctx) {
// Access token and shop available in ctx.state.shopify
const { shop, accessToken, scope } = ctx.state.shopify;
const host = ctx.query.host;
ACTIVE_SHOPIFY_SHOPS[shop] = {scope:scope,accessToken:accessToken};
const response = await Shopify.Webhooks.Registry.register({
shop,
accessToken,
path: "/webhooks",
topic: "APP_UNINSTALLED",
webhookHandler: async (topic, shop, body) =>
delete ACTIVE_SHOPIFY_SHOPS[shop],
});
if (!response.success) {
console.log(
`Failed to register APP_UNINSTALLED webhook: ${response.result}`
);
}
// Redirect to app with shop parameter upon auth
// ctx.redirect(`/?shop=${shop}&host=${host}`);
server.context.client = await handlers.createClient(shop, accessToken);
await handlers.getSubscriptionUrl(ctx, shop);
},
})
);
You can't basically show the confirmation URL in your app, Shopify won't trust app developers to take sensitive info like payment details, so must open the confirmation URL into a new tab, where the merchant is viewing a Shopify payment page(made by shopify) that contains the payment details to be entered and on confirm the page will redirect the merchant to the return URL as you specified before.
For testing purposes
you can send a test param within the query to allow you to test without entering any payment details
const CREATE_SUB_MUTATION_RECURRING_ONLY = gql`
mutation RecurringSubscription(
$returnUrl: URL!
$test: Boolean!
$planName: String!
$amount: Decimal!
) {
appSubscriptionCreate(
test: $test
name: $planName
returnUrl: $returnUrl
lineItems: [
{
plan: {
appRecurringPricingDetails: {
price: { amount: $amount, currencyCode: USD }
interval: EVERY_30_DAYS
}
}
}
]
) {
userErrors {
field
message
}
confirmationUrl
appSubscription {
id,
currentPeriodEnd
}
}
}
`;
Now to test just pass true to test
result = await graphQlClient?.mutate({
mutation: CREATE_SUB_MUTATION_RECURRING_ONLY,
variables: {
returnUrl,
test,
planName: PLANS_DATA[planName].planName,
amount: PLANS_DATA[planName].price,
},
});

Strapi how to extra api in controller

I have completed a shopping cart and can pay to stripe, but I want to be able to know who bought it, so I want to add a feature that allows me to see the user in the strapi backend
I hope to know how to combine those that two functions.
I have tried their functions separately I will work for the different page
../controllers/order.js
const stripe = require('stripe')('xxxvxx');
const { parseMultipartData, sanitizeEntity } = require('strapi-utils');
module.exports = {
create: async ctx => {
const {
address,
amount,
product,
token,
} = ctx.request.body;
// Charge the customer
try {
// stripe charge
await stripe.customers
.create({
email: ctx.state.user.email,
source: token
})
.then((customer) => {
return stripe.charges.create({
// Transform cents to dollars.
amount: amount * 100,
currency: 'usd',
description: `Order ${new Date()} by ${ctx.state.user.id}`,
customer: customer.id
});
});
// Register the order in the database
try {
const order = await strapi.services.order.create({
user: ctx.state.user.id,
address,
amount,
product,
});
//email
if (order.id){
await strapi.plugins['email'].services.email.send({
to: ctx.state.user.email,
subject: 'Thank you for your purchase',
text: `
usd${order.amount} is charged from your credit card on Stripe.
usd${order.address} is charged from your credit card on Stripe.
`,
});
}
return order;
} catch (err) {
console.log(err)
}
} catch (err) {
console.log(err)
}
}
};
Want to combine it
async create(ctx) {
let entity;
if (ctx.is('multipart')) {
const { data, files } = parseMultipartData(ctx);
data.users_permissions_user = ctx.state.user.id;
entity = await strapi.services.about.create(data, { files });
} else {
ctx.request.body.users_permissions_user = ctx.state.user.id;
entity = await strapi.services.about.create(ctx.request.body);
}
return sanitizeEntity(entity, { model: strapi.models.about });
In the new strapi
user => users_permissions_user
the answer is // Register the order in the database
user: ctx.state.user.id,
try
users_permissions_user: ctx.state.user.id,

Stripe "no such price"

I created a product with tiered pricing in my Stripe dashboard. I copied the price API IDs and put them in my app's frontend. When I run my code, the backend generates the error: No such price: 'PRICE_1HPYAGLJZYBC5S5KGBKT8UDY'. This price id matches one of the prices on my Stripe dashboard, but I never set the product so I'm wondering if that's the issue. Here is my client js:
function createSubscription({ customerId, paymentMethodId, priceId }) {
return (
fetch('/create-subscription', {
method: 'post',
headers: {
'Content-type': 'application/json',
},
body: JSON.stringify({
customerId: customerId,
paymentMethodId: paymentMethodId,
priceId: priceId,
}),
})
.then((response) => {
return response.json();
})
// If the card is declined, display an error to the user.
.then((result) => {
if (result.error) {
// The card had an error when trying to attach it to a customer
throw result;
}
return result;
})
// Normalize the result to contain the object returned
// by Stripe. Add the addional details we need.
.then((result) => {
console.log("RETURNING SUBSCRIPTION")
return {
// Use the Stripe 'object' property on the
// returned result to understand what object is returned.
subscription: result,
paymentMethodId: paymentMethodId,
priceId: priceId,
};
})
);
}
And here is my backend code:
app.post('/create-subscription', async function(req, res) {
console.log(req.body);
User.findOne({"_id": req.session.auth_user._id}, async function(err, user) {
if (user.stripe_id) {
console.log("RETRIEVING CUSTOMER");
var customer = await stripe.customers.retrieve(user.stripe_id);
if (user.stripe_subscription) {
console.log("RETRIEVING SUBSCRIPTION");
var subscription = await stripe.subscriptions.retrieve(user.stripe_subscription);
update_customer(customer, subscription);
}
else {
console.log("CREATING SUBSCRIPTION");
var subscription = await stripe.subscriptions.create({
customer: customer.id,
items: [{
price: req.body.priceId,
}]
});
user.stripe_subscription = subscription.id;
user.save(function(err) {
update_customer(customer, subscription);
})
}
}
else {
console.log("CREATING CUSTOMER");
var customer = await stripe.customers.create({
email: req.body.email,
});
user.stripe_id = customer.id;
user.save( async function(err, user) {
if (user.stripe_subscription) {
console.log("RETRIEVING SUBSCRIPTION");
var subscription = await stripe.subscriptions.retrieve(user.stripe_subscription);
update_customer(customer, subscription);
}
else {
console.log("CREATING SUBSCRIPTION");
var subscription = await stripe.subscriptions.create({
customer: customer.id,
items: [{
price: req.body.priceId,
}]
});
user.stripe_subscription = subscription.id;
user.save(function(err) {
update_customer(customer, subscription);
});
}
});
}
});
async function update_customer(customer, subscription) {
const paymentMethod = await stripe.paymentMethods.attach(
req.body.paymentMethodId,
{customer: customer.id}
);
console.log(subscription);
res.send(subscription);
}
});
Check the price ID, it looks like something in your frontend converts all the string to uppercase. Usually price id start in lowercase ('price....') and then the string is a mix between numbers and lowercase and uppercase characters.
Incase anyone faces this issue in the future. I had the same issue, but mine was caused by the stripe secret being wrong.
It's wise to:
Double check the price,
Trim the string,
Check your config keys all through
Hope this helps someone ๐Ÿš€
In my case I was following the docs and
the docs had it like this: Price = "{{price_1234}}"
So I changed it to this: Price = "price_1234" and it worked.
In my case, the API keys were not correct.
If like me, you just followed the tutorial from the docs, the API keys from the code snippets that are proposed are not correct.
You have to setup the ones from the dashboard page (for the test environment: https://dashboard.stripe.com/test/dashboard)

Resources