#mick23_code

1 messages ยท Page 1 of 1 (latest)

chrome acornBOT
#

๐Ÿ‘‹ Welcome to your new thread!

โฒ๏ธ We'll be here soon! Typically we respond in a few minutes, but sometimes we might take a bit longer if the server is busy or if you have a particularly tricky question.

โฑ๏ธ We close idle threads, which makes them read-only. Once a thread is closed it won't be reopened, but you can always start a new thread if you have another question.

๐Ÿ”— This thread will always be available, even after it's closed. You can find it again using Discord's search, or you can save this link: https://discord.com/channels/841573134531821608/1227356235829874820

๐Ÿ“ Have more to share? Add more details, code, screenshots, videos, etc. below.

chilly burrowBOT
#

Below are links to other discussions we've had with you in the past week in case you want to review that information. If your question is related to one of these previous discussions, please provide a comprehensive summary of the current state and what you need help with now. We help many users simultaneously, so a summary allows us to resolve your issue as soon as possible.

upbeat wadi
#

Hello again

ruby fog
#

Yeah, I'm not following this at all. Conceptually I get the above. But I cannot find any working code snippets to use to get that bit working.

upbeat wadi
#

which bit exactly?

ruby fog
#

In step-3 of the guide though, you'd want to set paymentMethodCreation to manual & call stripe.createPayment

upbeat wadi
#

No, card-element isn't relevant here

ruby fog
#

I'm trying to take this one small step at a time to get working. But all the guides are just trying to shortcut things, and it's actually more confusing than it helps.

upbeat wadi
#

Are you using React or HTML?

ruby fog
#

card-element isn't relevant? Oh. That's even more confusing.

#

Just trying to get a basic helloworld.html example working here

#

i.e. AddCardToAccount.html

upbeat wadi
#

Gotcha.
So in step 2, you're configuring elements by passing options object

ruby fog
#

Drives me nuts the world of software engineering these days with a framework first approach - ain't got enough hrs in the day to keep up with the latset javascript framework of the day.

ruby fog
upbeat wadi
ruby fog
#

I tried to change "setup" to "manual" but got a Chrome Console error saying that this method wasn't supported

upbeat wadi
#

mode would still be setup
paymentMethodCreation is a separate parameter

ruby fog
#

I see.

#

So this is the code I now have, but still not working

#

HTML;

<h1>Add Card - Manual</h1>
<form id="payment-element">
<div id="card-element">
Elements will create form elements here
</div>
<button id="submit">Submit</button>
<div id="error-message">
Display error message to your customers here
</div>
</form>

upbeat wadi
#

What error are you seeing in your console?

ruby fog
#

JavaScript;

<script type="text/javascript">
const options = {
mode: 'setup',
currency: 'gbp',
// Fully customizable with appearance API.
appearance: {/.../},
paymentMethodCreation: "manual",
};
// Set up Stripe.js and Elements to use in checkout form
const elements = stripe.elements(options);
// Create and mount the Payment Element
var cardElement = elements.create('card');
cardElement.mount('#payment-element');
stripe
.createPaymentMethod({
type: 'card',
card: cardElement,
billing_details: {
name: 'test',
},
})
.then(function(result) {
// Handle result.error or result.paymentMethod
});
</script>

chrome acornBOT
ruby fog
winter girder
#

๐Ÿ‘‹ taking over for my teammate. Give me a few minutes to catch up, please

ruby fog
#

Thanks

#

I'm at the stage where I'm just randomly trying different combinations and permutations at the minute to try and get this working.

#

So just to reset where I'm up to for ease.

winter girder
#

Let me recap what you're trying to do to make sure we're on the same page. You are attempting to save a card to a customer without charging them at the same time. Since you want to deduplicate cards, your goal is to create the PaymentMethod first and inspect its fingerprint in order to decide whether or not to attach it to a customer.

ruby fog
#

Yeah basically

#

So I've got the SetupIntent stuff working. But when I was testing, I was noticing that it was creating duplicate Cards in Stripe against that Customer, which is clearly going to be a nightmare waiting to happen.

#

So I thought - Ok, simple, "just" have some kind of duplicate card details check in place, and only allow the customer to actually have 1x unique card. Fairly common sense.

#

But making this happen is what I'm struggling with.

#

I don't know if I've just approaching this stuff in a non-standard way. But in my head it's fairly basic: 1) Create Customer in SaaS App --> 2) Add Card to Account --> 3) Subscribe to relevant Subscription

#

The reason for this approach, rather than the standard checkout is the need for creating a LOT of different subscriptions longer term - Think the complex Microsoft Licencing model - that's the idea. It's not just going to be a basic Bronze/Silver/Gold model.

#

It's all going to be per-seat too

winter girder
#

Okay, I understand you've been advised to use the PaymentElement and the deferred intent flow so you can create a PaymentMethod first, then inspect its fingerprint. If this fingerprint doesn't match the fingerprint of a card already attached to the customer (or if no cards are attached to the customer), you will continue with creating a SetupIntent for this customer and attach this card to them.

ruby fog
#

Yes that's right

winter girder
#

Let's start with your HTML code. I recommend updating <div id="card-element"> to <div id="payment-element">. This is just a name for your div but it'll hopefully remove some confusion if we use the same terminology

ruby fog
#

Done. This is the HTML now;

<h1>Add Card - Payment Element</h1>
<form id="payment-form">
<div id="payment-element">
Elements will create form elements here
</div>
<button id="submit">Submit</button>
<div id="error-message">
Display error message to your customers here
</div>
</form>

#

This is currently the JavaScript;

<script type="text/javascript">
const options = {
mode: 'setup',
currency: 'gbp',
// Fully customizable with appearance API.
appearance: {/.../},
paymentMethodCreation: "manual"
};
// Set up Stripe.js and Elements to use in checkout form
const elements = stripe.elements(options);
// Create and mount the Payment Element
var cardElement = elements.create('card');
cardElement.mount('#payment-element');
stripe
.createPaymentMethod({
type: 'card',
card: cardElement,
billing_details: {
name: 'test',
},
})
.then(function(result) {
// Handle result.error or result.paymentMethod
});
</script>

winter girder
#

For context, the CardElement and PaymentElement are totally different. The CardElement accepts just cards, while the PaymentElement is compatible with other payment method types (e.g. US bank accounts, GooglePay, ApplePay, Klarna, etc). The deferred intent flow is only supported by the PaymentElement.

ruby fog
#

Ok, that's good to know, didn't know that.

#

So with the above HTML + JS, this is the output;

#

Getting this error in Chrome Console, but I can't see how as I've commented out all the other SetupIntent code I had working;

Uncaught SyntaxError: Identifier 'options' has already been declared

winter girder
#

In your Javascript code, replace:


cardElement.mount('#payment-element');```

with:
```const paymentElement = elements.create('payment');
paymentElement.mount('#payment-element');```
ruby fog
#

Ignore that last error I mentioned, just found a bit of code that was still uncommented - got rid of that error now

#

Just updated the code - that's looking more normal now, got the card fields to display as expected

#

rookie error when trying to piece together lots of complex docs and copying and pasting stuff

#

Right, so the next question then. What next?

#

I'm assuming that when I fill out the form, it'll create a card, and when I fill it out again, it'll create another duplicate card? (just going to test that now...)

winter girder
#

Yes, that should still happen right now

ruby fog
#

In fact, it won't - as the HTML + JS don't know who the Customer is to attach it to

#

That's where the SaaS Server Side /create-intent piece was handling that previously.

#

So do I need a bit of JS now to get the Fingerprint in the JS, which can then call /my-api/check-if-fingerprint-already-exists, and ifFalse, then /my-api/setup-intent ?

#

Ah I see, so this is this bit then;

.then(function (result) {
// Handle result.error or result.paymentMethod
});

#

Right, this is where my hatred of JavaScipt comes in. I'm much more familiar with IDE driven getters/setters in proper languages

#

So how do I find the docs on what I need to translate into JavaScript which would normally be something like "result.getFingerprintOfCardJustCreated() etc.

winter girder
#

In your Javascript code, replace:

                                type: 'card',
                                        card: cardElement,
                                        billing_details: {
                                        name: 'test',
                                        },
                                })
                                .then(function(result) {
                                // Handle result.error or result.paymentMethod
                                });

with:

form.addEventListener('submit', async (event) => {
event.preventDefault();
elements.submit();

const paymentMethod = await stripe.createPaymentMethod({
elements
})

console.log ("PaymentMethod: " + paymentMethod);
})
}```

so you can see this in action
ruby fog
#

Let me give that a go now

winter girder
#

So now when you submit the PaymentElement with a test card, you should see a request to create a PaymentMethod in your account logs. You'll also see your browser's console log return the newly-created PaymentMethod object.

ruby fog
#

Yeah that's showing now. Is there any way via the Chrome Console to view the object key:value data like you can with JSON?

#

I can see that JSON object in the Stripe Account > Developer > Logs > Request I just made - that is all JSON

#

Again, this is just my lack of JavaScript syntax knowledge

#

I try and avoid JavaScript where ever possible and use actual programming languages

#

Error it's showing in Console is;

PaymentMethod: undefined

winter girder
#

I think for now, just logging console.log(paymentMethod); will suffice for testing/seeing how this will work. What you should do is pass this to your server code to retrieve the PaymentMethod's fingerprint and add the logic to compare this to other fingerprints for cards stored on that customer.

ruby fog
#

Then basically just parse the JSON Object as a requsetParameter using something like the Google GSON Library and extract the "id" which is the Fingerprint ID of the card, and compare with what already exists in the DB. Makes sense.

#

Interestingly I've just tried to parse the JSON in JS and I'm getting this error;

Uncaught (in promise) SyntaxError: "[object Object]" is not valid JSON

#

Code;

                        console.log("PaymentMethod: " + JSON.parse(paymentMethod).id);
#

Figured it out

#

So in the Stripe > Developer > Logs > Request X. The "Response Body" is actually inaccurate, that needs updating to be accurate.

#

Looks like the object that comes back is wrapped in an additional object;

{"paymentMethod":

#

Then the Response Body is what it shows in the Stripe Developer Logs inside that

#

That is really confusing

ruby fog
#

I've managed to get the ID extracted from the JavaScript.

#

I think I have enough to go on for another day to get the next bit working now anyhow.

#

Thanks for the help.