¿Cómo Conectar Stripe a Vue?
Tags: stripe, vue, javascript, spanish
Published: 2022-07-06 22:50:00

Hola 🖐🏼, en esta guía, te enseñaré cómo conectar Stripe a Vue. Esta integración es solo para carritos de compras, no para suscripciones. Debido a la complejidad de esta integración, te dejo aquí el enlace a mi sitio web.

{% embed https://codingpr.com/es/sistema-de-pagos-con-stripe-y-vue/ %}

## 1. Configura Stripe.

- Para comenzar con Stripe debes abrir una cuenta con Stripe, después de abrir su cuenta, vaya a la sección de desarrolladores y acceda a sus claves API.
En la sección de desarrolladores, encontrarás dos claves: "publishable key" y "secret key", cópialos en tu archivo .env.

```bash

    VUE_APP_STRIPE_KEY=<YOUR-PUBLISHABLE-KEY>
    
```
## 2. Integración.

- Una vez que haya abierto su cuenta con Stripe, copia el "script tag" de stripe en el "head" de index.html.

```html

    <head>
      <script src="https://js.stripe.com/v3/"></script>
    </head>
    
```

- Inmediatamente después de obtener el subtotal de la transacción, crea el "onclick event" para llamar al servidor y solicitar el payment intent. Usa la función "paymentIntent()" en diferentes partes de tu app, colocalo en el "login form" y el "guest form".

```html

    <!-- template -->
    <v-btn
      v-if="isCart >= 1"
      block
      color="#385F73"
      class="mt-3"
      elevation="2"
      :loading=loading
      rounded
      dark
      @click="paymentIntent"
    >
      Subtotal
    </v-btn>
    
```

```javascript

    // coloque esta función en diferentes partes de su aplicación
    // methods
    paymentIntent () {
      if (this.isLoggedIn) {
        this.$store.dispatch('paymentIntent')
          .catch((_err) => {
            this.loading = false
            const show = true
            const color = 'red darken-3'
            const text = 'Server Error, try again later!'
            this.$store.commit('cartSnack', {
              show, color, text
            })
          })
      } else {
        this.$router.push('/pre-checkout')
      }
    }
    
```
- Para pasar las propiedades del Vue al servidor usamos como intermediario Vuex y Axios. Vuex es el manejador de "state" para aplicacciones de Vuejs y Axios el manejador de HTTP. En el siguiente código, extraiga del estado el objeto de usuario y el carrito de compras. Envíe al servidor el carrito de compras para calcular el total de la transacción según el número de id del producto. Después de enviar estos objetos, reciba la respuesta del servidor con el secreto del cliente y el cálculo de impuestos, envíelos a las mutaciones y guárdelos en el 'state'.

```javascript

    // vuex actions
    async paymentIntent ({ commit, state }) {
      const res = await axios.post('users/secret/', {
        user: state.user,
        cart: state.cart
      })
      if (res.status === 201) {
        commit('CLIENT_SECRET', {
          client_secret: res.data.client_secret,
          tax: res.data.tax
        })
        router.push('/checkout')
      }
    },
    
```

```javascript

    // vuex mutations
    CLIENT_SECRET (state, payload) {
      const secret = state.secret
      secret.clientSecret = payload.client_secret
      secret.tax = payload.tax
    },
    
```

- Inicialice el estado con el secreto del cliente en nulo y el impuesto en 0.

```javascript

    // vuex state
    state: {
      secret: {
        clientSecret: null,
        tax: 0
      },
      user: {},
      cart: []
    },
    
```
## 3. Montaje del Stipe Card Element.

- Una vez tengamos el "client secret" en el "state" podemos utilizardo para montar el Stripe Card Element. El Card Element le mostrará al cliente el formulario en el cual este insertará su número de tarjeta de crédito. Recuerda que Stripe ya tiene el total de la compra. Con el Card Element, el cliente estará autorizando y finalizando la transacción.

```html

      <!-- template -->
      <form
        id="payment-form"
        v-if="isCart >= 1"
      >
        <br>
        <div ref="paymentElement" id="payment-element">
          <!-- El Stripe Elements insertará la forma aquí -->
        </div>
        <br>
        <div id="error-message">
          <!-- Espacio para mostrar errores -->
        </div>
      </form>
      <v-card-actions>
        <v-btn
          v-if="isCart >= 1"
          id="submit"
          :loading="loading"
          block
          color="success"
          class="mt-3"
          elevation="2"
          rounded
          dark
          @click="Submit"
        >
          Pay
        <v-icon class="ml-2">mdi-basket</v-icon>
        </v-btn>
      </v-card-actions>
      
```
- Dentro del "script tag" de Vue, vamos a importar a Vuex para poder acceder al "client secret". Utilize su clave secreta pública de Stripe y la función window.Stripe() para obtener el Stripe Card Element. Su clave secreta pública debe almacenarse en el archivo .env; ¡nunca lo pongas directamente en el código! Una vez que obtengamos el Stripe Card Element, podemos modificar su apariencia Stripe appearance-api.

```javascript

      // importe mapState y mapGetters para acceder
      // variables adicionales
      // script
      import store from '../store'

      const stripe = window.Stripe(
        process.env.VUE_APP_STRIPE_KEY
      )
      const options = {
        clientSecret: store.state.secret.clientSecret,
        // Personaliza tu Stripe theme.
        appearance: { theme: 'stripe' }
      }

      const elements = stripe.elements(options)

      const paymentElement = elements.create('payment')
      
```
- Montamos el Stripe Element usando la función "mounted" de Vue, esta va adentro de "export default".

```javascript

      // export default
      mounted () {
        paymentElement.mount(this.$refs.paymentElement)
        paymentElement.on('change', (event) => {
          this.displayError(event)
        })
      },
      
```
- La Función displayError() le va a mostrar al cliente si su tarjeta de crédito tiene errores como fondos insuficientes entre otros.

```javascript

      // methods
      displayError (event) {
        const displayError = document.getElementById(
          'error-message'
        )
        if (event.error) {
          displayError.textContent = event.error.message
        } else {
          displayError.textContent = ''
        }
      },
      
```
- Finalmente enviamos la transacción a través de la función Submit. Es importante destacar que "/thankyou/" es la dirección URL de nuestra última ruta. Esta se encuentra en el directorio bajo Thankyou.vue. Este Proyecto usa Vue Router para moverse fácilmente entre páginas. Use mapState para extraer propiedades del "state" y envialos con el objeto de "shipping".

```javascript

      // methods
      async Submit () {
        this.loading = true
        const { error } = await stripe.confirmPayment({
          elements,
          confirmParams: {
            // return_url: ruta final del proyecto thankyou.vue
            return_url: 'http://localhost:8080/#/thankyou/',
            shipping: {
              address: {
                city: this.city,
                line1: this.address,
                postal_code: this.zipcode,
                state: this.state,
                country: 'USA'
              },
              name: `${this.first_name} ${this.last_name}`,
              phone: this.phone
            }
          }
        })
        if (error) {
          this.loading = false
          const messageContainer = document.querySelector(
            '#error-message'
          )
          messageContainer.textContent = error.message
        } else {
          // Redirección del cliente a return_url.
        }
      }
      
```
## 4. Extracción de propiedades de Stripe.

- Si necesitas extraer información adicional del cliente, debes hacerlo al final en la página de Thankyou.vue. A través de la función de javascript URLSearchParams(), extraemos el "payment_intent_client_secret" del URL, este será utilizado por la función de Stripe retrievePaymentIntent() para poder accesar al objeto de la transacción y enviar las propiedades a nuestro servidor. Una vez enviados los valores, rescatamos la respuesta y si todo está bien, vamos a usar las variables de entorno COMMIT_CHECKOUT y CLIENT_SECRET para borrar el "state".

```javascript

      // mounted
      async mounted () {
        const stripe = window.Stripe(
          process.env.VUE_APP_STRIPE_KEY
        )
        const clientSecret = new URLSearchParams(
          window.location.search
        ).get(
          'payment_intent_client_secret'
        )
        const {
          paymentIntent, error
        } = await stripe.retrievePaymentIntent(
          clientSecret
        )
        if (error) {
          console.log(error)
          this.message = 'An error has ocurred'
        }
        if (paymentIntent.status === 'succeeded') {
          this.message = paymentIntent.status
          const payment_id = paymentIntent.id
          this.$store.dispatch('checkout', { payment_id })
            .catch((_err) => {
              this.loading = false
              const show = true
              const color = 'red darken-3'
              const text = 'An error has ocurred'
              this.$store.commit('cartSnack',
                {
                  show, color, text
                })
            })
        } else {
          this.message = paymentIntent.status
        }
      }
      
```

```javascript

      // actions
      async checkout ({ commit, state, getters }, payload) {
        const res = await axios.post('orders/order/', {
          order: {
            stripe_id: payload.payment_id,
            subtotal: getters.subTotal,
            total: getters.grandTotal,
            tax: state.secret.tax,
            cart: state.cart,
            rating: state.stars,
            first_name: state.user.first_name,
            last_name: state.user.last_name,
            email: state.user.email,
            phone: state.user.phone,
            address: state.user.address,
            city: state.user.city,
            state: state.user.state,
            zipcode: state.user.zipcode
          }
        })
        if (res.status === 200) {
          // Borrar el estado a excepción del usuario.
          commit('CHECKOUT_SUCCESS')
          commit('CLIENT_SECRET', {
            client_secret: null,
            tax: 0
          })
        }
      },
      
```
- Borra el 'state' cuando el pago se haya completado. Para integrar Stripe en la parte del servidor, visite este blog: [¿Cómo conectar Stripe a Django Rest Framework?](https://codingpr.com/es/sistema-de-pagos-con-stripe-y-django/)

```javascript

      // mutations
      CHECKOUT_SUCCESS (state) {
        state.stars = []
        state.cart = []
      },
      
```