Razorpay not returning payment_id,order_id etc. upon successfull payment - node.js

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.

Related

createAysncThunk in Redux Toolkit catching error when making fetch request

I'm working on the user registration functionality of an application using Typescript and Redux Toolkit. When I make the fetch request to the signup endpoint, a new user is saved to the database I've connected, but I keep entering the catch error block.
export const registerUser = createAsyncThunk(
"user/registerUser",
async (form: { username:string, password:string }, thunkAPI) => {
try {
const response = await fetch('/api/auth/signup', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({
userInfo: {
username: form.username,
password: form.password
}
}),
});
if (response.status === 200) return 200;
else return 400;
} catch (e) {
console.log('Error')
}
}
);
I've tried logging the response to the console a number of ways
const data = await response.json() console.log(data)
But have had no luck. I think this is an error with how I've done my fetch request using createAsyncThunk but haven't been able to figure out what I've missed.
This is the code for the initial state and slice:
interface UserState {
userProfile: {
id: number | null;
},
registration: {
status: 'loaded' | 'loading'
}
}
const initialState : UserState = {
userProfile: {
id: null,
},
registration: {
status: 'loaded'
}
};
export const userSlice = createSlice({
name: 'user',
initialState,
reducers: {
},
extraReducers: (builder) => {
builder.addCase(registerUser.fulfilled, (state) => { state.registration.status = 'loaded' }),
builder.addCase(registerUser.rejected, (state) => { state.registration.status = 'loaded' }),
builder.addCase(registerUser.pending, (state) => { state.registration.status = 'loading' })
}
})
And here is the code for the function where the action is dispatched on the UI
const handleRegister= async () => {
if (!username) return alert('Username field was left empty');
if (!password) return alert('Password field was left empty');
const {payload} : any = await dispatch(registerUser({ username: username, password: password}));
if (payload === 200) {
alert('Successfully registered. Redirecting to dashboard');
return navigate('/dashboard');
} else { return alert('User creation unsuccessful'); }
}
Appreciate any help as I've looked through many other posts but haven't been able to resolve my issue.

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

API Only sends 1 chunk of metadata when called

I have a problem with my API that sends metadata when called from my smart contract of website. Its NFT tokens and my database is postgres and API is node.js
The problem is when I mint 1 NFT metadata works perfect, but if I mint 2 or more it will only ever send 1 chunk of data? So only 1 NFT will mint properly and the rest with no data?
Do I need to set a loop function or delay? Does anyone have any experience with this?
Any help would be much appreciated.
Below is the code from the "controller" folder labeled "nft.js"
const models = require("../../models/index");
const path = require("path");
const fs = require("fs");
module.exports = {
create_nft: async (req, res, next) => {
try {
const dir = path.resolve(__dirname + `../../../data/traitsfinal.json`);
const readCards = fs.readFileSync(dir, "utf8");
const parsed = JSON.parse(readCards);
console.log("ya data ha final ??", parsed);
parsed.forEach(async (item) => {
// return res.json(item)
let newNft = await models.NFT.create({
name: item.Name,
description: item.Description,
background: item.Background,
body: item.Body,
mouth: item.Mouth,
eyes: item.Eyes,
head_gear: item.Head_Gear,
tokenId: item.tokenId,
image: item.imagesIPFS,
});
});
return res.json({
data: "nft created",
error: null,
success: true,
});
} catch (error) {
console.log("server error", error.message);
next(error);
}
},
get_nft: async (req, res, next) => {
try {
const { id } = req.params;
// console.log("id ?????????",id)
// console.log("type of ",typeof(id))
// const n=Number(id)
// console.log("type of ",typeof(id))
const nft = await models.NFT.findByPk(id);
if (!nft) {
throw new Error("Token ID invalid");
}
if (!nft.isMinted) {
throw new Error("Token not minted");
}
console.log(nft);
// }
const resObj = {
name: nft.name,
description: nft.description,
image: `https://gateway.pinata.cloud/ipfs/${nft.image}`,
attributes: [
{ trait_type: "background", value: `${nft.background}` },
{ trait_type: "body", value: `${nft.body}` },
{ trait_type: "mouth", value: `${nft.mouth}` },
{ trait_type: "eyes", value: `${nft.eyes}` },
{ trait_type: "tokenId", value: `${nft.tokenId}` },
{
display_type: "number",
trait_type: "Serial No.",
value: id,
max_value: 1000,
},
],
};
return res.json(resObj);
} catch (error) {
console.log("server error", error.message);
next(error);
}
},
get_nft_all: async (req, res, next) => {
try {
// console.log("id ?????????",id)
// console.log("type of ",typeof(id))
// const n=Number(id)
// console.log("type of ",typeof(id))
const nft = await models.NFT.findAndCountAll({
limit: 10
});
// console.log(nft);
if (!nft) {
throw new Error("Token ID invalid");
}
// if (nft.isMinted) {
// throw new Error("Token not minted");
// }
// console.log(nft);
// }
var resObjarr = [];
for (var i = 0; i < nft.rows.length; i++) {
resObj = {
name: nft.rows[i].name,
description: nft.rows[i].description,
image: `https://gateway.pinata.cloud/ipfs/${nft.rows[i].image}`,
attributes: [
{ trait_type: "background", value: `${nft.rows[i].background}` },
{ trait_type: "body", value: `${nft.rows[i].body}` },
{ trait_type: "mouth", value: `${nft.rows[i].mouth}` },
{ trait_type: "eyes", value: `${nft.rows[i].eyes}` },
{ trait_type: "tokenId", value: `${nft.rows[i].tokenId}` },
{
display_type: "number",
trait_type: "Serial No.",
value: nft.rows[i].id,
max_value: 1000,
},
],
};
resObjarr.push(resObj);
}
console.log(JSON.stringify(resObjarr))
return res.json(resObjarr);
} catch (error) {
console.log("server error", error.message);
next(error);
}
},
mint: async (req, res, next) => {
try {
const { id } = req.params;
const updated = await models.NFT.findByPk(id);
if (!updated) {
throw new Error("NFT ID invalid");
}
if (updated.isMinted) {
throw new Error("NFT Already minted");
}
updated.isMinted = true;
updated.save();
return res.json({
data: "Token minted successfully",
error: null,
success: true,
});
} catch (error) {
console.log("server error", error.message);
next(error);
}
},
};
Below is from the routes folder.
const router = require("express").Router();
const auth=require("../middleware/auth")
const {
create_nft,
get_nft,
get_nft_all,
mint
} = require("../controller/nft");
router.post(
"/create",
create_nft
);
router.get(
"/metadata/:id",
get_nft
);
router.get(
"/metadata",
get_nft_all
);
router.put(
"/mint/:id",
mint
);
module.exports = router;
Looking your code,you may having some kind of asyncrhonous issue in this part:
parsed.forEach(async (item) => {
// return res.json(item)
let newNft = await models.NFT.create({
name: item.Name,
description: item.Description,
background: item.Background,
body: item.Body,
mouth: item.Mouth,
eyes: item.Eyes,
head_gear: item.Head_Gear,
tokenId: item.tokenId,
image: item.imagesIPFS,
});
});
Because .forEach is a function to be used in synchronous context and NFT.create returns a promise (that is async). So things happens out of order.
So one approach is to process the data first and then perform a batch operation using Promise.all.
const data = parsed.map(item => {
return models.NFT.create({
name: item.Name,
description: item.Description,
background: item.Background,
body: item.Body,
mouth: item.Mouth,
eyes: item.Eyes,
head_gear: item.Head_Gear,
tokenId: item.tokenId,
image: item.imagesIPFS,
})
})
const results = await Promise.all(data)
The main difference here is Promise.all resolves the N promises NFT.create in an async context in paralell. But if you are careful about the number of concurrent metadata that data may be too big to process in parallel, then you can use an async iteration provided by bluebird's Promise.map library.
const Promise = require('bluebird')
const data = await Promise.map(parsed, item => {
return models.NFT.create({
name: item.Name,
description: item.Description,
background: item.Background,
body: item.Body,
mouth: item.Mouth,
eyes: item.Eyes,
head_gear: item.Head_Gear,
tokenId: item.tokenId,
image: item.imagesIPFS,
})
})
return data

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)

Stripe: How do I add and store additional form elements with javascript?

I am trying store data from additional inputs in the form, not just the credit card information.
Here is what the form looks like:
form image
The payment works and the booking gets stored in the database. I am struggling to figure out how to also get the additional form inputs "a link to your project" and "additional info" stored in the DB as well.
Here is what the code likes on the server:
router.route('/pay')
.post(async (req, res, next) => {
let artist = req.session.artist;
let price = req.session.price;
let user = req.session.user;
let email = req.session.userEmail;
price *= 100;
const {
paymentMethodId,
paymentIntentId,
currency,
useStripeSdk
} = req.body;
try {
let intent;
if (paymentMethodId) {
// Create new PaymentIntent with a PaymentMethod ID from the client.
intent = await stripe.paymentIntents.create({
amount: price,
currency: currency,
receipt_email: email,
payment_method: paymentMethodId,
confirmation_method: 'manual',
confirm: true,
// If a mobile client passes `useStripeSdk`, set `use_stripe_sdk=true`
// to take advantage of new authentication features in mobile SDKs
use_stripe_sdk: useStripeSdk
});
// After create, if the PaymentIntent's status is succeeded, fulfill the order.
} else if (paymentIntentId) {
// Confirm the PaymentIntent to finalize payment after handling a required action
// on the client.
intent = await stripe.paymentIntents.confirm(paymentIntentId);
// After confirm, if the PaymentIntent's status is succeeded, fulfill the order.
}
let newBooking = await Booking.create({
artist,
user,
price,
projectLink: req.body.projectLink,
additionalInfo: req.body.additionalInfo
});
console.log(newBooking)
let data = {
intent: generateResponse(intent)
};
res.send(data);
} catch (e) {
// Handle "hard declines" e.g. insufficient funds, expired card, etc
// See https://stripe.com/docs/declines/codes for more
res.send({
error: e.message
});
}
});
And here is what it looks like on the client:
var stripe = Stripe('pk_test_ycz...');
// A reference to Stripe.js
var stripe;
var orderData = {
items: [{
id: "photo-subscription"
}],
currency: "usd"
};
// Disable the button until we have Stripe set up on the page
document.querySelector(".disable").disabled = true;
fetch("/stripe-key")
.then(function (result) {
return result.json();
})
.then(function (data) {
return setupElements(data);
})
.then(function ({
stripe,
card,
clientSecret
}) {
document.querySelector(".disable").disabled = false;
var form = document.getElementById("payment-form");
form.addEventListener("submit", function (event) {
event.preventDefault();
const projectLink = document.getElementById('projectLink').value;
const additionalInfo = document.getElementById('additionalInfo').value;
pay(stripe, card, clientSecret, projectLink, additionalInfo);
console.log(projectLink, additionalInfo)
});
});
var setupElements = function (data) {
stripe = Stripe(data.publishableKey);
/* ------- Set up Stripe Elements to use in checkout form ------- */
var elements = stripe.elements();
var style = {
base: {
color: "#32325d",
fontFamily: '"Helvetica Neue", Helvetica, sans-serif',
fontSmoothing: "antialiased",
fontSize: "16px",
"::placeholder": {
color: "#aab7c4"
}
},
invalid: {
color: "#fa755a",
iconColor: "#fa755a"
}
};
var card = elements.create("card", {
style: style
});
card.mount("#card-element");
return {
stripe: stripe,
card: card,
clientSecret: data.clientSecret
};
};
var handleAction = function (clientSecret, projectLink, additionalInfo) {
stripe.handleCardAction(clientSecret).then(function (data) {
if (data.error) {
showError("Your card was not authenticated, please try again");
} else if (data.paymentIntent.status === "requires_confirmation") {
fetch("/pay", {
method: "POST",
headers: {
"Content-Type": "application/json"
},
body: JSON.stringify({
paymentIntentId: data.paymentIntent.id
})
})
.then(function (result) {
return result.json();
})
.then(function (json) {
if (json.error) {
showError(json.error);
} else {
orderComplete(clientSecret);
}
});
}
});
};
/*
* Collect card details and pay for the order
*/
var pay = function (stripe, card) {
changeLoadingState(true);
// Collects card details and creates a PaymentMethod
stripe
.createPaymentMethod("card", card)
.then(function (result) {
if (result.error) {
showError(result.error.message);
} else {
orderData.paymentMethodId = result.paymentMethod.id;
return fetch("/pay", {
method: "POST",
headers: {
"Content-Type": "application/json"
},
body: JSON.stringify(orderData)
});
}
})
.then(function (result) {
return result.json();
})
.then(function (response) {
if (response.intent.error) {
showError(response.intent.error);
} else if (response.intent.requiresAction) {
// Request authentication
handleAction(response.intent.clientSecret);
} else {
orderComplete(response.intent.clientSecret);
}
});
};
On the server side, I have used req.body for both inputs on Booking.create(...) but I'm not sure how to get that from the client using Stripe's code. On the client side, I tried adding the form data to the fetch API call on /pay but couldn't figure out how to get it to work. If anyone has any ideas, that would be awesome. Thanks
You're not passing the additional info you want as part of the body of fetch("/pay"), which is how it would get to the server side. You should add them as arguments to your client side pay() function, and then pass them in the body of that fetch request.

Resources