Document is not rolled back if transaction gets aborted Mongoose - node.js

In my server I'm trying to use transactions to create orders. Before saving the order with Order.create I check and modify quantities in Product records, check for payment details on buyer and seller, aborting the transaction if anything goes wrong ( I omitted that part in the code sample below), but when passing the object from the request body to Order.create as I normally do on document creation it fails not finding requested parameters for the Order schema.
I have found here https://github.com/Automattic/mongoose/issues/6761#issuecomment-437493275 and also the doc https://mongoosejs.com/docs/api.html#model_Model.create say that when inside a transaction the object needs to be passed into an array ( like await SomeModel.create([obj], { session }) ), so I suppose that as we are inside a transaction, if the transaction is aborted then the created record gets rolled back.
In my app it does create the document but it's not rolled back if I abort the transaction . In fact if I query the db with the document id just created I get the result back.
Also now my logic inside the finally statement is not working anymore. There, if the transaction is not aborted the if statement check on session.inTransaction should return true so there I commit the transaction and end the session. If instead the transaction is aborted it should return false and nothing else happens as whenever I abort the transaction I also end the session.
When using await SomeModel.create([obj], { session }) the if statement never returns true so the transaction is never committed and the session is never ended.
Can you see what's wrong with the code here below?
exports.createOrder = async (req, res) => {
const { productIdList, productPromotionList, customerId, shopId } = req.body;
// const order = req.body;
var notAvailableProducts = [];
var notAvailablePromotions = [];
// console.log('createOreder req.body is : ', order);
var amount = 0.00;
var stripeAccountId = '';
var stripeCustomerId = '';
var receiptEmail = '';
var defaultSource = '';
const session = await Order.startSession();
session.startTransaction();
try {
... omitted part
console.log('createOrder req.body is : ', req.body);
// const order =
// await
Order.create(
// req.body, // error
[ req.body], // works but doesn't get rolled back if transaction is aborted
{ session: session },
function (err, result) {
if (err) {
console.log('Mongoose createOrder error: Order.create', err);
res.status(503).send({ error: "Internal error" });
session.abortTransaction();
session.endSession();
return;
}
console.log('Mongoose createOrder: ', result);
res.status(200).send({
message: "Order created successfully!",
data: result,
missingProducts: notAvailableProducts,
missingPromotions: notAvailablePromotions
});
});
await session.abortTransaction();
session.endSession();
}
catch (error) {
console.log('Transaction error is:', error);
await session.abortTransaction();
session.endSession();
res.status(503).send({ error: "Internal error." });
// throw error;
}
finally {
if (session.inTransaction == true) {
console.log('committing session');
await session.commitTransaction();
console.log('ending session');
session.endSession();
} else {
console.log('session was aborted');
}
}
}
set of prints
createOrder req.body is : {
date: 1639251616628,
price: '12.0',
state: 'Waiting',
collectedOnDate: 0,
cancelledOnDate: null,
customerFcmToken: 'dVes2tOhSyKiOg1RJNzViE:APA91bEBPj_5y9G_uuP5lFI5Iobjv_ikpfxnbtNmx5VUY9x74Cgci8Dl8SVSoDe5Gq7x7nw5GfD7DlDo-769MsfALeHcRuiz0CdO2J_m5x1Lof92mSQh5uPy2IpwuI_M5UMZfBktR1PM',
customerId: '61af23dc02edbe24ce0344f4',
customerName: 'vincenzo calia',
shopId: '61ab9198262df7517970aed4',
shopName: 'vincenzo calia',
city: 'Bologna',
region: 'Emilia-Romagna',
country: 'Italy',
productCategoryList: [ 'Safety and locks' ],
productIdList: [ '61af8bec02edbe24ce034963' ],
productPromotionList: [ false ],
productNameList: [ null ],
productPriceList: [ '12' ],
isBuyNow: 'false'
}
session was aborted
Mongoose createOrder: [
{
city: 'Bologna',
region: 'Emilia-Romagna',
country: 'Italy',
date: 2021-12-11T19:40:16.628Z,
price: '12.0',
state: 'Waiting',
collectedOnDate: 0,
cancelledOnDate: null,
customerFcmToken: 'dVes2tOhSyKiOg1RJNzViE:APA91bEBPj_5y9G_uuP5lFI5Iobjv_ikpfxnbtNmx5VUY9x74Cgci8Dl8SVSoDe5Gq7x7nw5GfD7DlDo-769MsfALeHcRuiz0CdO2J_m5x1Lof92mSQh5uPy2IpwuI_M5UMZfBktR1PM',
customerId: '61af23dc02edbe24ce0344f4',
customerName: 'vincenzo calia',
shopId: '61ab9198262df7517970aed4',
shopName: 'vincenzo calia',
productCategoryList: [ 'Safety and locks' ],
productIdList: [ '61af8bec02edbe24ce034963' ],
productIsPromotionList: [],
productNameList: [ null ],
productPriceList: [ '12' ],
isBuyNow: false,
totalRating: 0,
ratings: 0,
_id: new ObjectId("61b4fea0d184bca49c82f2d0"),
createdAt: 2021-12-11T19:40:16.607Z,
updatedAt: 2021-12-11T19:40:16.607Z,
__v: 0,
averageRating: 0,
id: '61b4fea0d184bca49c82f2d0'
}
]
Mongoose Order.findOrderById: {
_id: new ObjectId("61b4fea0d184bca49c82f2d0"),
city: 'Bologna',
region: 'Emilia-Romagna',
country: 'Italy',
date: 2021-12-11T19:40:16.628Z,
price: '12.0',
state: 'Waiting',
collectedOnDate: 0,
cancelledOnDate: null,
customerFcmToken: 'dVes2tOhSyKiOg1RJNzViE:APA91bEBPj_5y9G_uuP5lFI5Iobjv_ikpfxnbtNmx5VUY9x74Cgci8Dl8SVSoDe5Gq7x7nw5GfD7DlDo-769MsfALeHcRuiz0CdO2J_m5x1Lof92mSQh5uPy2IpwuI_M5UMZfBktR1PM',
customerId: '61af23dc02edbe24ce0344f4',
customerName: 'vincenzo calia',
shopId: '61ab9198262df7517970aed4',
shopName: 'vincenzo calia',
productCategoryList: [ 'Safety and locks' ],
productIdList: [ '61af8bec02edbe24ce034963' ],
productIsPromotionList: [],
productNameList: [ null ],
productPriceList: [ '12' ],
isBuyNow: false,
totalRating: 0,
ratings: 0,
createdAt: 2021-12-11T19:40:16.607Z,
updatedAt: 2021-12-11T19:40:16.607Z,
__v: 0,
averageRating: 0,
id: '61b4fea0d184bca49c82f2d0'
}

As it seems that Model.create can't be undone upon aborting a transaction the only way I found to manage it ( not sure it's just a workaround or the proper business logic) is to wrap it in a if statement checking the current state of the session if (session.inTransaction()) {} as I do in the finally statement to commit the transaction or simply end the session.
exports.createOrder = async (req, res) => {
...
if (session.inTransaction()) {
const order = {
city: city,
region: region,
country: country,
date: Date.now,
price: totalOrderAmount,
state: 'Waiting',
collectedOnDate: null,
cancelledOnDate: null,
customerFcmToken: customerFcmToken,
customerId: customerId,
customerName: customerName,
shopId: shopId,
shopName: shopName,
productCategoryList: productCategoryList,
productIdList: productIdList,
productIsPromotionList: productIsPromotionList,
productNameList: productNameList,
productPriceList: productPriceList,
isBuyNow: isBuyNow,
stripePayment: stripePaymentIntent
};
await Order.create(
[order],
{ session: session },
function (err, result) {
if (err) {
console.log('Mongoose createOrder error: Order.create', err);
session.abortTransaction();
responseCode = 503;
responseMessage = 'Internal error';
return;
}
console.log('Mongoose createOrder: ', result);
responseCode = 200;
responseData = result;
message = "Order created successfully!";
}).exec();
}
}
}
catch (error) {
console.log('Transaction error is:', error);
await session.abortTransaction();
session.endSession();
res.status(503).send({ error: "Transaction error." });
// throw error;
}
finally {
if (session.inTransaction()) {
console.log('transacion wasn\'t aborted');
console.log('committing session ');
await session.commitTransaction();
} else {
console.log('transacion wasn aborted');
}
console.log('ending session ');
await session.endSession();
res.status(responseCode).send({
message: responseMessage,
data: responseData,
unavailableProducts: unavailableProducts,
unavailablePromotions: unavailablePromotions
});
}
}

Related

mongoose findOneAndUpdate gives different user

I was trying to $pull an object inside my cart collections. but after I make a request and sent a specific _id it gives me a different person.
this was the _id I sent from my client side.
{ id: '62a849957410ef5849491b1b' } /// from console.log(req.params);
here's my mongoose query.
export const deleteItem = (req,res) => {
const { id } = req.params;
console.log(id);
try {
if(!mongoose.Types.ObjectId.isValid(id)) return res.status(404).json({ message: 'ID not found' });
ClientModels.findOneAndUpdate(id, {
$pull: {
cart: {
product_identifier: req.body.cart[0].product_identifier
}
}
},{
new: true
}).then(val => console.log(val)).catch(temp => console.log(temp));
} catch (error) {
res.status(404).json(error);
}
}
after the request here's the callback.
{
_id: new ObjectId("62a77ab16210bf1afd8bd0a9"),
fullname: 'Gino Dela Vega',
address: '008 Estrella.st santo cristo',
email: 'gamexgaming1997#gmail.com',
google_id: 'none',
birthday: '1997-12-30',
number: 9922325221,
gender: 'Male',
username: 'ginopogi',
password: '$2b$12$YCc1jclth.ux4diwpt7EXeqYyLOG0bEaF.wvl9hkqNVptY.1Jsuvi',
cart: [],
wishlist: [],
toBeDeliver: [],
Delivered: [],
__v: 0
}
as you guys can see after sending a specific _id to find a user...the callback gives me a different user reason that I can't pull the specific object inside cart. (the object I was trying to pull is on another user)
Probably because findOneAndUpdate expect a filter as first parameter, try to switch to findByIdAndUpdate if you want to filter by a specific _id:
export const deleteItem = (req, res) => {
...
ClientModels.findByIdAndUpdate(
id,
{
$pull: {
cart: {
product_identifier: req.body.cart[0].product_identifier,
},
},
},
{
new: true,
}
)
.then((val) => console.log(val))
.catch((temp) => console.log(temp));
} catch (error) {
res.status(404).json(error);
}
};

Must provide source or customer stripe live mode

this is my first time using stripe and I am getting an error Must provide source or customer. once I went live. In the test mode I used "tok_mastercard" as my source but clearly when I went live it isn't valid. What am I missing here please help.
This is my POST request in the backend
stripe.charges
.create({
amount: req.renter.rent * 100,
currency: "usd",
source: req.body.token,
application_fee_amount: req.renter.rent * 0.05 * 100,
transfer_data: {
//the destination needs to not be hard coded it needs to
//come from what property the renter is in
destination: req.renter.stripeConnectId,
// destination: "acct_1GOCMqDfw1BzXvj0",
},
})
.then((charge) => {
console.log(req.renter);
res.send(charge);
})
.catch((err) => {
console.log(err);
});
});
this is my two functions in the frontend using react-native and node
handleCardPayPress = async () => {
try {
this.setState({ loading: true, token: null });
const token = await stripe.paymentRequestWithCardForm({
// Only iOS support this options
smsAutofillDisabled: true,
requiredBillingAddressFields: "full",
prefilledInformation: {
billingAddress: {
name: "",
line1: "",
line2: "",
city: "",
state: "",
country: "US",
postalCode: "",
email: "",
},
},
});
this.setState({ loading: false, token });
} catch (error) {
this.setState({ loading: false });
}
};
makePayment = async () => {
try {
//Mate the payment
const response = await unitApi.post("/payments", {
data: {
amount: this.state.renter.rent,
currency: "usd",
token: this.state.token,
},
});
Alert.alert("Success!", `Confirmation ID: ${response.data.id}`, [
{ text: "Done" },
]);
console.log(response.data);
// navigate("Home");
} catch (err) {
//failiur and showing the error message
console.log(err);
Alert.alert("Failed!", "Card declined.", [{ text: "Declined" }]);
}
};
Odds are pretty good that this.state.token doesn't contain what you think it does in the unitApi.post() function call; I'd recommend logging that and seeing if that helps, and also logging req.body.token server-side.

Cannot read property 'ClientSession' of undefined [duplicate]

I am using MongoDB Atlas cloud(https://cloud.mongodb.com/) and Mongoose library.
I tried to create multiple documents using transaction concept, but it is not working.
I am not getting any error. but, it seems rollback is not working properly.
app.js
//*** more code here
var app = express();
require('./models/db');
//*** more code here
models/db.js
var mongoose = require( 'mongoose' );
// Build the connection string
var dbURI = 'mongodb+srv://mydb:pass#cluster0-****.mongodb.net/mydb?retryWrites=true';
// Create the database connection
mongoose.connect(dbURI, {
useCreateIndex: true,
useNewUrlParser: true,
});
// Get Mongoose to use the global promise library
mongoose.Promise = global.Promise;
models/user.js
const mongoose = require("mongoose");
const UserSchema = new mongoose.Schema({
userName: {
type: String,
required: true
},
pass: {
type: String,
select: false
}
});
module.exports = mongoose.model("User", UserSchema, "user");
myroute.js
const db = require("mongoose");
const User = require("./models/user");
router.post("/addusers", async (req, res, next) => {
const SESSION = await db.startSession();
await SESSION.startTransaction();
try {
const newUser = new User({
//*** data for user ***
});
await newUser.save();
//*** for test purpose, trigger some error ***
throw new Error("some error");
await SESSION.commitTransaction();
//*** return data
} catch (error) {
await SESSION.abortTransaction();
} finally {
SESSION.endSession();
}
});
Above code works without error, but it still creates user in the DB. It suppose to rollback the created user and the collection should be empty.
I don't know what I have missed here. Can anyone please let me know whats wrong here?
app, models, schema and router are in different files.
You need to include the session within the options for all read/write operations which are active during a transaction. Only then are they actually applied to the transaction scope where you are able to roll them back.
As a bit more complete listing, and just using the more classic Order/OrderItems modelling which should be pretty familiar to most people with some relational transactions experience:
const { Schema } = mongoose = require('mongoose');
// URI including the name of the replicaSet connecting to
const uri = 'mongodb://localhost:27017/trandemo?replicaSet=fresh';
const opts = { useNewUrlParser: true };
// sensible defaults
mongoose.Promise = global.Promise;
mongoose.set('debug', true);
mongoose.set('useFindAndModify', false);
mongoose.set('useCreateIndex', true);
// schema defs
const orderSchema = new Schema({
name: String
});
const orderItemsSchema = new Schema({
order: { type: Schema.Types.ObjectId, ref: 'Order' },
itemName: String,
price: Number
});
const Order = mongoose.model('Order', orderSchema);
const OrderItems = mongoose.model('OrderItems', orderItemsSchema);
// log helper
const log = data => console.log(JSON.stringify(data, undefined, 2));
// main
(async function() {
try {
const conn = await mongoose.connect(uri, opts);
// clean models
await Promise.all(
Object.entries(conn.models).map(([k,m]) => m.deleteMany())
)
let session = await conn.startSession();
session.startTransaction();
// Collections must exist in transactions
await Promise.all(
Object.entries(conn.models).map(([k,m]) => m.createCollection())
);
let [order, other] = await Order.insertMany([
{ name: 'Bill' },
{ name: 'Ted' }
], { session });
let fred = new Order({ name: 'Fred' });
await fred.save({ session });
let items = await OrderItems.insertMany(
[
{ order: order._id, itemName: 'Cheese', price: 1 },
{ order: order._id, itemName: 'Bread', price: 2 },
{ order: order._id, itemName: 'Milk', price: 3 }
],
{ session }
);
// update an item
let result1 = await OrderItems.updateOne(
{ order: order._id, itemName: 'Milk' },
{ $inc: { price: 1 } },
{ session }
);
log(result1);
// commit
await session.commitTransaction();
// start another
session.startTransaction();
// Update and abort
let result2 = await OrderItems.findOneAndUpdate(
{ order: order._id, itemName: 'Milk' },
{ $inc: { price: 1 } },
{ 'new': true, session }
);
log(result2);
await session.abortTransaction();
/*
* $lookup join - expect Milk to be price: 4
*
*/
let joined = await Order.aggregate([
{ '$match': { _id: order._id } },
{ '$lookup': {
'from': OrderItems.collection.name,
'foreignField': 'order',
'localField': '_id',
'as': 'orderitems'
}}
]);
log(joined);
} catch(e) {
console.error(e)
} finally {
mongoose.disconnect()
}
})()
So I would generally recommend calling the variable session in lowercase, since this is the name of the key for the "options" object where it is required on all operations. Keeping this in the lowercase convention allows for using things like the ES6 Object assignment as well:
const conn = await mongoose.connect(uri, opts);
...
let session = await conn.startSession();
session.startTransaction();
Also the mongoose documentation on transactions is a little misleading, or at least it could be more descriptive. What it refers to as db in the examples is actually the Mongoose Connection instance, and not the underlying Db or even the mongoose global import as some may misinterpret this. Note in the listing and above excerpt this is obtained from mongoose.connect() and should be kept within your code as something you can access from a shared import.
Alternately you can even grab this in modular code via the mongoose.connection property, at any time after a connection has been established. This is usually safe inside things such as server route handlers and the like since there will be a database connection by the time that code is called.
The code also demonstrates the session usage in the different model methods:
let [order, other] = await Order.insertMany([
{ name: 'Bill' },
{ name: 'Ted' }
], { session });
let fred = new Order({ name: 'Fred' });
await fred.save({ session });
All the find() based methods and the update() or insert() and delete() based methods all have a final "options block" where this session key and value are expected. The save() method's only argument is this options block. This is what tells MongoDB to apply these actions to the current transaction on that referenced session.
In much the same way, before a transaction is committed any requests for a find() or similar which do not specify that session option do not see the state of the data whilst that transaction is in progress. The modified data state is only available to other operations once the transaction completes. Note this has effects on writes as covered in the documentation.
When an "abort" is issued:
// Update and abort
let result2 = await OrderItems.findOneAndUpdate(
{ order: order._id, itemName: 'Milk' },
{ $inc: { price: 1 } },
{ 'new': true, session }
);
log(result2);
await session.abortTransaction();
Any operations on the active transaction are removed from state and are not applied. As such they are not visible to resulting operations afterwards. In the example here the value in the document is incremented and will show a retrieved value of 5 on the current session. However after session.abortTransaction() the previous state of the document is reverted. Note that any global context which was not reading data on the same session, does not see that state change unless committed.
That should give the general overview. There is more complexity that can be added to handle varying levels of write failure and retries, but that is already extensively covered in documentation and many samples, or can be answered to a more specific question.
Output
For reference, the output of the included listing is shown here:
Mongoose: orders.deleteMany({}, {})
Mongoose: orderitems.deleteMany({}, {})
Mongoose: orders.insertMany([ { _id: 5bf775986c7c1a61d12137dd, name: 'Bill', __v: 0 }, { _id: 5bf775986c7c1a61d12137de, name: 'Ted', __v: 0 } ], { session: ClientSession("80f827fe077044c8b6c0547b34605cb2") })
Mongoose: orders.insertOne({ _id: ObjectId("5bf775986c7c1a61d12137df"), name: 'Fred', __v: 0 }, { session: ClientSession("80f827fe077044c8b6c0547b34605cb2") })
Mongoose: orderitems.insertMany([ { _id: 5bf775986c7c1a61d12137e0, order: 5bf775986c7c1a61d12137dd, itemName: 'Cheese', price: 1, __v: 0 }, { _id: 5bf775986c7c1a61d12137e1, order: 5bf775986c7c1a61d12137dd, itemName: 'Bread', price: 2, __v: 0 }, { _id: 5bf775986c7c1a61d12137e2, order: 5bf775986c7c1a61d12137dd, itemName: 'Milk', price: 3, __v: 0 } ], { session: ClientSession("80f827fe077044c8b6c0547b34605cb2") })
Mongoose: orderitems.updateOne({ order: ObjectId("5bf775986c7c1a61d12137dd"), itemName: 'Milk' }, { '$inc': { price: 1 } }, { session: ClientSession("80f827fe077044c8b6c0547b34605cb2") })
{
"n": 1,
"nModified": 1,
"opTime": {
"ts": "6626894672394452998",
"t": 139
},
"electionId": "7fffffff000000000000008b",
"ok": 1,
"operationTime": "6626894672394452998",
"$clusterTime": {
"clusterTime": "6626894672394452998",
"signature": {
"hash": "AAAAAAAAAAAAAAAAAAAAAAAAAAA=",
"keyId": 0
}
}
}
Mongoose: orderitems.findOneAndUpdate({ order: ObjectId("5bf775986c7c1a61d12137dd"), itemName: 'Milk' }, { '$inc': { price: 1 } }, { session: ClientSession("80f827fe077044c8b6c0547b34605cb2"), upsert: false, remove: false, projection: {}, returnOriginal: false })
{
"_id": "5bf775986c7c1a61d12137e2",
"order": "5bf775986c7c1a61d12137dd",
"itemName": "Milk",
"price": 5,
"__v": 0
}
Mongoose: orders.aggregate([ { '$match': { _id: 5bf775986c7c1a61d12137dd } }, { '$lookup': { from: 'orderitems', foreignField: 'order', localField: '_id', as: 'orderitems' } } ], {})
[
{
"_id": "5bf775986c7c1a61d12137dd",
"name": "Bill",
"__v": 0,
"orderitems": [
{
"_id": "5bf775986c7c1a61d12137e0",
"order": "5bf775986c7c1a61d12137dd",
"itemName": "Cheese",
"price": 1,
"__v": 0
},
{
"_id": "5bf775986c7c1a61d12137e1",
"order": "5bf775986c7c1a61d12137dd",
"itemName": "Bread",
"price": 2,
"__v": 0
},
{
"_id": "5bf775986c7c1a61d12137e2",
"order": "5bf775986c7c1a61d12137dd",
"itemName": "Milk",
"price": 4,
"__v": 0
}
]
}
]
I think this is the quickest way to start performing transaction with mongoose
const mongoose = require("mongoose");
// starting session on mongoose default connection
const session = await mongoose.startSession();
mongoose.connection.transaction(async function executor(session) {
try {
// creating 3 collections in isolation with atomicity
const price = new Price(priceSchema);
const variant = new Variant(variantSchema);
const item = new Item(itemSchema);
await price.save({ session });
await variant.save({ session });
// throw new Error("opps some error in transaction");
return await item.save({ session });
} catch (err) {
console.log(err);
}
});

How to perform update in mongoose

I am trying to update my record,but its not happening in my case and i am not sure about the case where it went rong,can any one suggest me help.Thanks
My mongoose code,
exports.updatestudent = function (req, res) {
var student = new Student(req.body);
var data = {};
var id = req.params;
var params = req.body;
var item = {
'name': params.name,
'rollnumber': params.rollnumber,
'class': params.class,
'city': params.city
};
Student.update({ _id: id },{ $set: item }, function (err, result) {
if (err) {
console.log('err');
}
if (result) {
data = { status: 'success', error_code: 0, result: result, message: 'Article updated successfully' };
res.json(data);
}
});
};
my schema,
var StudentSchema = new Schema({
name: {
type: String
},
rollnumber: {
type: String
},
class: {
type: String
},
city: {
type: String
},
status: {
type: String
},
_id: {
type: Schema.ObjectId
}
});
/**
* Hook a pre validate method to test the local password
*/
mongoose.model('student', StudentSchema, 'student');
my result in postman,
{
"status": "success",
"error_code": 0,
"result": {
"ok": 0,
"n": 0,
"nModified": 0
},
"message": "Article updated successfully"
}
I am trying to update my record,but its not happening in my case and i am not sure about the case where it went rong,can any one suggest me help.Thanks
It seems you forgot to specify the key.
Replace
var id = req.params;
By
var id = req.params.id;
Make sure that you are getting your id in var id = req.params;
And I am sure you will not get your id like this
check your req.params; values and give your correct id in the query
Update
var item = {};
if (params.name) {
item.name = params.name;
}
if (params.rollnumber) {
item.rollnumber = params.rollnumber
}
Student.update({
_id: id
}, {
$set: item
}, function(err, result) {
if (err) {
console.log('err');
}
if (result) {
data = {
status: 'success',
error_code: 0,
result: result,
message: 'Article updated successfully'
};
res.json(data);
}
});

Creating a customer in BrainTree with a credit card

I'm reading the docs about creating a customer. I need to create one with a credit card, a cvc number but I get an error and I don't know how I must create it.
I show my code
if(user.local.subscription == undefined){
//creamos cliente
gateway.customer.create({
creditCard : {
number : cardnumber,
expirationDate : "12/15"
}
}, function (err, result) {
if(err){
//return res.status(500).json({ error : "Error creating customer"});
console.log(err);
}
console.log(result);
/*user.subscription = result;
userId = result.customer.id;*/
});
}
var braintree = require("braintree");
var gateway = braintree.connect({
environment: braintree.Environment.Sandbox,
merchantId: "your sanboxmerchant",
publicKey: "your sandbox public key",
privateKey: "sandbox privatekey"
});
gateway.customer.create({
creditCard : {
cardholder_name : 'james bliz',
number : "4111111111111111",
cvv : '123',
expirationDate : "12/17"
}
}, function (err, result) {
if(err){
//return res.status(500).json({ error : "Error creating customer"});
console.log(err);
}
console.log(result);
/*user.subscription = result;
userId = result.customer.id;*/
});
the answer should be somthing like this
{ customer:
{ id: '29931379',
merchantId: 'qn5442rvm794nc6q',
firstName: null,
lastName: null,
company: null,
email: null,
phone: null,
fax: null,
website: null,
createdAt: '2015-05-12T10:33:41Z',
updatedAt: '2015-05-12T10:33:42Z',
customFields: '',
creditCards: [ [Object] ],
addresses: [],
paymentMethods: [ [Object] ] },
success: true }
take the required field from it i think you will need only the customer id from tha result object.

Resources