#jeanbaptisten

1 messages · Page 1 of 1 (latest)

keen prairieBOT
lusty iris
#

Hi, let me help you with this.

#

Are you using Stripe Connect?

gentle ermine
#

Thank you 🙂
I'm not sure of what is stripe connect, all I can say is that I'm using Stripe API

lusty iris
#

Have you followed any guides when integrating Stripe?

gentle ermine
#

Not so much to be honest, we were 3 on this task and we mainly read the stripe docs

lusty iris
#

What Stripe docs exactly?

gentle ermine
lusty iris
#

Your diagram looks like a standard Stripe integration, but it's not enough for me to identify the problem. Does this happen all the time?

gentle ermine
lusty iris
#

Could you please share a part of the code that does this?
Also, could you please share the PaymentIntent ID pi_xxx?

gentle ermine
#

I can't do it right now sorry, I'll send you what I can as soon as possible
Thank you so much for your time thought 🙏

lusty iris
#

Happy to help.

gentle ermine
#

Thank you ! I'm gonna send what I can

gentle ermine
#

Well, first I'd like to send you two screenshots that I will use to explain the beginning of the user journey (not sure about the word "journey")

#

Here is what I can tell:

  • In the screenshots I've sent, you can see the beginning of the user process. The user give us informations about his booking then click on the button "Réservez" (meaning "booking" in french).
    Then, a modal appears with the usual stripe payment interface.
    When everything is good, the user can click on the blue button to book.

  • This button will send a request to our api to create a booking :

  // >> FRONT APP <<
  const response = await useAPI().bookings.createNewBooking(
    {
      boxCategory: selectedBox.value,
      centerId: centerId.value,
      startingDay: selectedDayStr.value,
      beginHour: form.selectedTime || '',
      formula: selectedFormula.value,
      creditCardId: selectedCreditCard.value?.id || '',
      promoCodeLabel: promoData.value?.label
    },
    cardSubmitFunction
  )

The cardSubmitFunction is a function returned by the card payment interface.
Here is the card payment interface component: (without the style, it's not necessary)

<template>
  <section class="payment-container">
    <div ref="paymentElementDOM" class="payment-element"></div>
  </section>
</template>

<script lang="ts" setup>
const emit = defineEmits(['submitFunctionLoaded'])

const props = defineProps({
  amount: {
    type: Number,
    default: 0
  }
})

const paymentElementDOM = ref<HTMLElement>()

onMounted(async () => {
  mountCardElem()
})

onBeforeUnmount(() => {
  paymentElementDOM.value?.remove()
})

async function mountCardElem() {
  if (!paymentElementDOM.value) return
  emit('submitFunctionLoaded', await usePayment().mountPaymentInput(paymentElementDOM.value, props.amount))
}
</script>
#

The function given by the mountPaymentInput method is :

    // >> FRONT APP <<
    mountPaymentInput: async (elementWrapper: HTMLElement, amount: number): Promise<TPaymentSubmitFunction> => {
      const stripeJs = await StripeHelper.getStripeJs()
      const elements: StripeElements = stripeJs.elements({
        mode: 'payment',
        currency: 'eur',
        payment_method_types: ['card'],
        amount: amount * 100,
        setup_future_usage: 'on_session'
      })
      const paymentElement: StripePaymentElement = elements.create('payment')
      paymentElement.mount(elementWrapper)

      //This function need to be called to validate and submit card informations
      return StripeHelper.getPaymentSubmitFunction(elements, stripeJs)
    },
#

We can get back to the payAndConfirmBooking function called by the click of the stripe payment interface.
The createNewbooking method is this one:

    // >> FRONT APP <<
    createNewBooking: async (
      payload: IBookBoxPayload,
      cardSubmitFunction: TPaymentSubmitFunction,
      alert: IAlertControl = { mode: AlertModes.ON_ERROR }
    ): Promise<IRequestResult<IBookingResponse>> => {
      if (!_session.isLoggedIn) {
        useAlertStore().handleRequestResult(alert, NOT_LOGGED_IN_REQUEST_ERROR)
        return { data: null, error: NOT_LOGGED_IN_REQUEST_ERROR }
      }

      const response = await _request.post<IBookingResponse>(_path, {
        body: payload,
        headers: { Authorization: `Bearer ${_session.accessToken}` },
        alert
      })

      if (!response.data) return response

      if (response.data.paymentStatus === PaymentProviderStatuses.REQUIRE_AUTHENTICATION && response.data.clientSecret) {
        let error: IRequestError | null
        if (payload.creditCardId) error = (await usePayment().confirmPayment(response.data.clientSecret, payload.creditCardId)).error
        else error = (await cardSubmitFunction(response.data.clientSecret, { mode: 'all' })).error
        if (error) return { data: null, error: { status: 400, message: error.message } }
      }

      return response
    }
#

The first API call will create the booking, then store the payment response in the booking like this:

    // >> BACK APP <<
    // try to debit the card, else create a payment intent
    if (creditCardId)
      paymentResponse = await this.paymentsService.debitCreditCard(user, VmcCompanies.CENTER, creditCardId, booking.quote.totalTTC, documentData)
    else {
      paymentResponse = await this.paymentsService.createPaymentIntent(user, VmcCompanies.CENTER, booking.quote.totalTTC, documentData)
    }

    // set booking's payment information accordingly to the result
    savedBooking.booker.setPaymentId(paymentResponse.paymentId)
    savedBooking.setPaymentStatus(paymentResponse.status === PaymentProviderStatuses.SUCCESS ? PaymentStatuses.PAID : PaymentStatuses.NOT_PAID)

These informations will be sent to the front app and will be handled in the rest of the createNewBooking.

#

I hope all my explainations are good, I didn't implement the whole solution tbh, we were 3 on this task.
Feel free if you need anything else 🙂

lusty iris
#

Hey @gentle ermine, thanks for a detailed explanation, but unfortunately I won't have time to dive deep into such a question. Do you mind reaching out to Stripe Support and saying you talked to us on Discord, and my engineering team will take over and take the time to look into your issue carefully.
https://support.stripe.com/?contact=true

gentle ermine
#

Thank you 🙏

lusty iris
#

Happy to help.