Card not saving for a Stripe Customer - ruby

I am having an issue with the card token not saving against a customer using the Ruby Stripe integration and Stripe.js
We get what looks to be a valid card token from Stripe.js (e.g. tok_4VeYrrjJpCwGG6)
Then I am calling the following;
customer = Stripe::Customer.retrieve(customer_id) #customer_id is correct and valid
customer.card = stripeToken # e.g. the tok_ I gave as an example
customer.save
If I log out the result of customer.save I get something like;
{
"id":"cus_4QR8ZuPUPlgA0G",
"object":"customer",
"created":1405685697,
"livemode":false,
"description":null,
"email":"my_email",
"delinquent":true,
"metadata":{},
"subscriptions": {
"object":"list",
"total_count":0,
"has_more":false,
"url":"/v1/customers/cus_4QR8ZuPUPlgA0G/subscriptions",
"data":[],
"count":0
},
"discount":null,
"account_balance":0,
"currency":"eur",
"cards"{
"object":"list",
"total_count":0,
"has_more":false,
"url":"/v1/customers/cus_4QR8ZuPUPlgA0G/cards",
"data":[],
"count":0
},
"default_card":null,
"subscription":null
}
Everything is as I would expect bar the card hasn't been added.
Could anyone advise what I am possibly doing wrong here?

To add a new card to an already existing customer you have to make use of the create card API call. Please take a look at https://stripe.com/docs/api/ruby#create_card for details on how to go about this.
In your particular case, you can update the user with:
customer = Stripe::Customer.retrieve(customer_id)
customer.sources.create(:source => stripeToken)
Let me know if that helps solve your problem.

Related

Plaid Api wont let me authenticate account with account/routing number

Using Plaid version "2020-09-14". I am following these instructions https://plaid.com/docs/auth/coverage/same-day/
I'm using node js to generate a link token and i successfully do:
var plaid = require('plaid');
const client = new plaid.Client({
clientID: process.env.PLAID_CLIENT_ID,
secret: process.env.PLAID_SECRET,
env: process.env.PLAID_ENV
});
console.log('client is ',client)
app.post('/api/create_link_token', async function (req, res) {
try{
const response = await client.createLinkToken({
user: {
client_user_id: '123-test-user-id',
},
client_name: 'Plaid Test App',
products: ['auth'],
country_codes: ['US'],
webhook: 'https://webhook.example.com',
language: 'en'
})
return res.send({link_token: response.link_token})
} catch (error) {
// handle error
console.log('error',error)
return res.send({err: error.message})
}
});
I get a link token everytime I run this. Then, i use said link token to try to authenticate the user's bank by using same day micro deposits (my company is setup for this through Plaid).
What keeps happening is the screen pops up that asks you to search for your bank and I do not want that. I want the screen to popup just like the one at the top of the page in the link I listed above. It asks the user for their name first, then routing, then account numbers.
How do I make the Plaid api show me the screen that prompts the user for their accounting/routing numbers without trying to authenticate them automatically with their bank username and password?
Thanks
You can't, at least right now, using publicly released Plaid APIs. (You're not the first person to ask for this, and we're working on some stuff that should help, but it isn't yet available to the developer general public.)

Update viewer fields and connection on Store

I'm trying to update the values and connections on my current viewer within the Relay store.
So without calling the mutation signIn if I print:
console.log(viewer.name) // "Visitor"
console.log(viewer.is_anonymous) // true
on Mutations we got the method updater which gives us the store, so in my mutation I'm doing something like this:
mutation SignInMutation($input: SignInInput!){
signIn(input: $input){
user {
id
name
email
is_anonymous
notifications{
edges{
node {
id
...NotificationItem_notification
}
}
}
}
token
}
}
So my updater method has:
const viewer = store.get(viewer_id);
const signIn = store.getRootField('signIn');
viewer.copyFieldsFrom(signIn.getLinkedRecord('user'))
After this I updated the store I got the name email is_anonymous fields updated with the data that just came from the graphql endpoint (I mean now name is "Erick", is_anonymous is now false, which is great), but If I try to do viewer.notifications and render it, the length of the viewer.connections seem to be 0 even when it has notifications.
How can I update my current viewer and add the notifications from the MutationPayload into the store without the need to force fetch?
Im using the latest relay-modern and graphql.
PS: Sorry for the bad formation, but is just impossible to format the code the way OF wants me to, i formated it to 4 spaces and still gave me errors.
With some reorganisation of your GraphQL schema it might be possible to remove the need to interact directly with the Relay store after your sign-in mutation. Consider:
viewer {
id
currentUser {
name
email
}
}
When a user that is not logged in, currentUser would return null.
You could then modify your login mutation to be:
mutation SignInMutation($input: SignInInput!){
signIn(input: $input){
viewer {
id
currentUser {
name
email
token
}
}
}
}
Knowing the 'nullability' of the currentUser field provides an elegant way of determining if the user is logged in or not.
Based on the presence of the token field implies that you are using JWT or similar to track login status. You would need to store this token in local storage and attach it to the headers of the outgoing Relay requests to your GraphQL endpoint if it is present.
Storing the token itself would have to be done in the onCompleted callback of where you make the mutation request (you will have access to the payload returned by the server in the arguments of the callback function).
As an alternative to the token, you could also explore using cookies which would provide the same user experience but likely require less work to implement then JWT tokens.

Braintree, How do I delete a users credit card with the nonce from the client?

Server side there is a function to delete a payment method (result = Braintree::PaymentMethod.delete("the_token")) but it takes a payment method token. How do I get the payment methods token with the nonce from the client?
edit: I'm not using the drop in UI. I have a custom list of credit cards the user has (using the Javascript v3 SDK). I want to have a button to delete cards. The JS SDK dosnt give the credit cards token, just a nonce. What is the process for turning the data available to the client into something I can use to delete the card on the server?
edit2: The list of credit cards on the clent side uses the VaultManager from the JavaScript v3 SDK. It returns a fetchPaymentMethodsPayload.
This is the client side code:
_loadPaymentMethods() {
this.paymentService.getBraintreeToken().then( token => {
this.braintreeClient.create({
authorization: token
}, (clientErr, clientInstance) => {
if (clientErr) {
// Handle error in client creation
return;
}
var options = {
client: clientInstance,
};
this.vaultManager.create(options, (err, vaultInstance) => {
if (err) {
console.log(err);
return;
}
vaultInstance.fetchPaymentMethods({ defaultFirst: true }, (err, paymentMethods) => {
paymentMethods.forEach( paymentMethod => {
if(paymentMethod.type == 'CreditCard') {
this.cards.push(paymentMethod);
if(paymentMethod.default) {
this.card = paymentMethod;
}
}
});
});
});
});
});
}
Full disclosure: I work at Braintree. If you have any further questions, feel free to contact support.
If using VaultManager on the client-side to populate your cards, you will not have the functionality to allow a user to delete one of those cards. The reason for this goes back to what you said, that nonces are what's returned on the fetchPaymentMethodsPayload method. VaultManager can populate a nonce that's associated with an already created card, since it's only passing that nonce into a Transaction.sale() call. Since the nonce is populated when the form is rendered, you can not search for that nonce compared to a payment method in the vault, since it will not exist previously and nonces are meant for one time use. This is why nonces aren't passed into PaymentMethod.find() calls.
To accomplish your task you would need to build out custom logic that mimics what Vault Manager does; however, would need to returns the tokens. One way would be as mentioned in my comment: by finding the customer object and grabbing the customer's payment methods, and then pulling out the tokens associated with those payment methods.
I noticed that when you create a payment method with same creds, it won't get duplicated. So it's kinda like "find or create", you can then use that result to get the token and then do a gateway.payment_method.delete( result.payment_method.token )

Parse.com - setting up push notifications for single users

I'm working on a hybrid app using Ionic framework with Parse as a back end and I'm struggling to set up push notifications for single users. I'm sending the notifications through Parse's Cloud Code, and I have sending push notifications to all users working okay using the following;
Parse.Cloud.afterSave(
'_User',
function(request, response) {
Parse.Cloud.useMasterKey();
var installationQuery = new Parse.Query(Parse.Installation);
Parse.Push.send(
{
where: installationQuery,
data: {
alert: 'Test notification'
}
}, {
success: function () {
// Push was successful
},
error: function (error) {
// Push failed
}
}
);
}
);
Currently, when a user registers an entry is made into the Installation class (using phonegap-parse-plugin), adding their user ID as a channel. I did this with the intention of adding the channel as a query constraint when determining which users to push notifications to, but adding query.contains('channels', 'user-' + request.user.id); to the above doesn't push any notifications (but reports success in Cloud Code).
I've also read about adding the user as a pointer to the installation class, but that would mean a device could only have one user.
What is the best way to allow me to send push notifications to a single user via Cloud Code? Thank you!
Can you see the results of the Installation query where you add the constraint;
query.contains('channels', 'user-' + request.user.id);
The problem might be the empty result. Check it. One of suggestion to singe push single target is just use the user id. Save the user id in installation table and send push notification based on query constraint where equal to. Hope this helps.
Regards.

Parse Cloud Code to send push notification to group of other users

I have an app where one user can invite other users to join an event by push notification. Let's say when creating an event, the user add other users to this event, then save the event to Parse.
So basically I have an array of user_id and I will call a function from cloud code to push notification to those Id, after saving the event.
1)Will the following Cloud code work?
Parse.Cloud.afterSave( "Event", function(request) {
//Get value from Ticket Object
var ids = request.object.get("inviteeIds");
//Set push query
var pushQuery = new Parse.Query(Parse.Installation);
pushQuery.containedIn("objectId",ids);
//Send Push message
Parse.Push.send({
where: pushQuery,
data: {
alert: "New Event Added",
sound: "default"
}
},{
success: function(){
response.success('true');
},
error: function (error) {
response.error(error);
}
});
});
I am not sure if the containedIn function exist or not:
pushQuery.containedIn("objectId",ids);
When I search I only find documentation about equalTo function, e.g:
query.equalTo('injuryReports', true);
2) I also read about Channel, but I still not understand how to apply it in my situation. From the documentation:
Devices start by subscribing to one or more channels, and
notifications can later be sent to these subscribers.
In my case how can I create a Channel and then add ids of friends who I want to invite to this Channel?
If possible, I would like to use Cloud Code rather than pushing from mobile device.
1)Will the following Cloud code work?
Why don't you try it and see for yourself, then come back with the errors, if any? Anyway, there's no response in afterSave. It will return a success regardless of what happens in it.
Otherwise it may work. Try running it.
I am not sure if the containedIn function exist or not:
Parse.Query.containedIn
2) I also read about Channel, but I still not understand how to apply it in my situation
Basically you subscribe to a particular channel in the client. Like this (Android)
ParsePush.subscribeInBackground("channelName");
Then in the Cloud
Parse.Push.send({
channels: channelList,
data: {
// etc
}
});
Obviously you'll need to know the channels you want to target.
You can subscribe multiple users to the same channel (for example you can have a dedicated channel for a particular event) or you can have one channel per user (for example you can name it something like channel_<userId> and only subscribe that user to it). Up to you what you need or what you want.
One last thing...
So basically I have an array of user_id
Keep in mind that objects stored in the database have a limited size. If your object gets too big and has too much data, you won't be able to add any more to it.

Resources