#faizel_api

1 messages ¡ Page 1 of 1 (latest)

topaz boltBOT
#

👋 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/1311964356883251282

📝 Have more to share? Add more details, code, screenshots, videos, etc. below.

distant jay
#

hi

#

@silver lily

#

hi

#

this is my card submit function

async submit() {
console.log('From Submit',this.clientSecret);
if (!this.isChecked) {
this.validateTerms = true;
return;
}
this.validateTerms = false;

        this.isLoading = true;

        window.addEventListener('beforeunload', this.handleBeforeUnload);
        window.addEventListener('popstate', this.handlePopState);

        const { setupIntent, error } = await this.stripe.confirmCardSetup(
            this.clientSecret,
            {
                payment_method: {
                    card: this.cardNumberElement,
                },
            }
        );

        if (!error) {
            await this.createSubscription(setupIntent.payment_method);
        } else {
            this.message = error.message;
            this.isLoading = false;
        }
    },
#

this is my create subscription frontend function afer card submit success

async createSubscription(token) {
console.log('Create Subscription',this.clientSecret);
this.message='';
await this.$inertia.post(route('subscriptions.multiplan.store'),{
plans : this.cart.length ? this.cart : [this.plan],
token,
accept_terms:this.isChecked,
tax_id:this.taxInfo().tax_id,
billing_address:this.taxInfo().billing_address
},
{
onSuccess: () => {
this.isLoading = false;
// this.isGeneratingInvoice = true;
if(this.$page.url.includes('isBack=1')){
this.startCheckingTransaction();
}
},
onError:(e) => {
if(e.requiredAction) {
this.handleRequiresAction(e);
}else {
this.message = e.message;
this.isLoading = false;
}
},
onFinish:()=>{
if(!this.isLoading){
this.isGeneratingInvoice = true;
}
}
}
);
},

#

this is my subscription creation and card store function from backend

public function multiPlanStore()
{
    try {
        $validatedData = request()->validate([
            'plans' => ['required'],
            'token' => ['required'],
            'accept_terms' => ['required'],
            'tax_id' => ['nullable'],
            'billing_address' => ['nullable'],
        ]);



        $user = auth()->user();

        $user->createOrGetStripeCustomer();
        $paymentMethodId = $validatedData['token'];
        $user->updateDefaultPaymentMethod($paymentMethodId);

        $planCollection = collect($validatedData['plans']);

        foreach ($planCollection as $plan) {
            try {
                $subscription = auth()->user()->newSubscription(
                    $plan['slug'] . '_' . $plan['price']['billing_period'],
                    $plan['price']['stripe_price_id']
                )
                    ->create(request('token'));

                $subscription->stripe_product = $plan['stripe_product_id'];
               
            } catch (IncompletePayment $exception) {
                return back()->withErrors([
                    'requiredAction' => true,
                    'clientSecret' => $exception->payment->client_secret,
                    'message' => $exception->getMessage(),
                ]);
            }
        }

        $user->update([
            'tax_id' => $validatedData['tax_id'],
            'billing_address' => $validatedData['billing_address'],
        ]);

        return to_route('auth.payment', ['isBack' => true]);
    } catch (CardException $e) {
        return to_route('settings.payment-methods')->with(['error' => $e->getMessage()]);
    } catch (Exception $e) {
        return back()->with(['error' => $e->getMessage()]);
    }
}
#

this is my handleRequiredAction from frontend if the subscription hit to incomepletepayment exception

async handleRequiresAction(e) {
emitter.emit('open-3d-dialog', {
text: 'For your security, your card issuer or bank is requesting a second OTP verification. Please proceed with this additional step, which helps ensure your transaction is safe and secure. Thank you for your understanding.',
confirmLabel: 'Confirm',
cancelLabel: 'Cancel',
confirmBtnClass:'!bg-primary',
onConfirm:async () => {
emitter.emit('close-3d-dialog');
const {error} = await this.stripe.confirmCardPayment(e.clientSecret);
if (error) {
this.message = error.message;
this.isLoading = false;
} else {
this.startCheckingTransaction();
}
},
onCancel:()=>{
this.isGeneratingInvoice=false;
this.successCheckingTransaction=false;
this.isLoading=false;
this.message = e.message;
}
});
},

silver lily
#

hello! can you describe your payment flow here at a high level? For example, whe your customer lands on your page, you collect the payment method from them to create a payment. At what point are you expecting 3DS to not be shown?

distant jay
#

ok

#

when customer land to card information page

  • we collect the payment infos and create setup intent and get 3d secure modal which is ok
  • but when we create a subscription from backend (it fails even after the 3d secure modal is asked and confirmed) so as you see the code handled i provided is also handle for incomplete payment and the 3d secure modal is happen again on frontend when confirmpayment (which is in handleRequiredAction) but as i know it shouldn't be right ? because we already confirmed 3d secure on setup intent
#

our live users is getting issue with always getting 3d secure modal twice always.

#

i'm a developer and i have no idea to find solution. that's why i ask support here.

silver lily
#

can you share why you want to create the SetupIntent first, then create a subscription? If the customer is already on session, and creating / paying for a subscription, you should use the Subscription's SetupIntent and/or PaymentIntent to collect the payment method instead so as not to have a double authentication.

This is likely the flow that you're looking for : https://docs.stripe.com/payments/accept-a-payment-deferred?platform=web&type=subscription

Build an integration where you can render the Payment Element prior to creating a PaymentIntent or SetupIntent.

distant jay
#

u mean i don't need to create setup intent ?

#

as my knowledge, setup intent is required for me because i implemented like this on frontend to confirm cardsetup.

const { setupIntent, error } = await this.stripe.confirmCardSetup(
this.clientSecret,
{
payment_method: {
card: this.cardNumberElement,
},
}
);

silver lily
#

Please take a moment to review the guide I just shared. It will help you understand how everything works.

distant jay
#

so

#

my current implementation which is getting setup intent first and confirmcardsetup is making double 3d secure .

#

so you suggest me to do with new solution which is collection payment details before creating an setup intent

#

am i right ?

silver lily
#

yep, but try it out first and see if it fits your requirements

distant jay
#

alright

#

let me try

#

is this thread automatically close ?

#

i need some time to try it out

#

can i come back here when i know update

silver lily
#

you can start a new thread i.e. ask a new question if you come back later and the thread is closed

distant jay
#

ok

#

can i mention you in new thread to contact you ? or can i dm you

silver lily
#

my colleague who is on shift when you ask a new question should be able to help you

distant jay
#

btw

#

this is the flow i've currently using