Construye un Sistema de Suscripciones con Vue js y Stripe.
Tags: stripe, vue, spanish, tutorial
Published: 2022-07-20 14:46:00

Hola 🖐🏼, en esta guía, te mostraré cómo crear un sistema de suscripción con Vue.js y Stripe. Nuestro entorno de trabajo es Vue.js Options API, Vue Router y Express.js como administrador de backend. Para la UI/UX, estoy usando Vuetify. Si está buscando la API de composición de Vue 3 y la integración de TypeScript, consulte este turorial [Cree un sistema de suscripción con Vue 3, Vite y Stripe](https://codingpr.com/es/crea-un-sistema-de-suscripcion-con-vue-3/). Debido a lo extenso de este tutorial, les dejo el enlace a mi sitio web.

{% embed https://codingpr.com/es/suscripciones-vue-stripe/ %}

Si no tienes un proyecto, puedes copiar el mío aquí: [vue-stripe-subscriptions](https://github.com/Denisse-AB/vue-options-stripe-subscriptions)

## 1. Configura Stripe.

Primero, configuremos nuestro entorno. Copie en su archivo env su clave publicable de stripe; puede encontrar esta clave en la sección del desarrollador del Stripe 'Dashboard'. Crea dos productos en la sección de productos del 'Dashboard', el plan Básico por cinco dólares y el plan Premium por diez. Copie los ID de los productos en el archivo env.

```shell

    VUE_APP_STRIPE_KEY=<YOUR-PUBLISHABLE-KEY>
    VUE_APP_BASIC_PLAN=<YOUR-BASIC-PLAN>
    VUE_APP_PREMIUM_PLAN=<YOUR-PREMIUM-PLAN>
    
```
- Una vez que haya abierto su cuenta con Stripe , copie la etiqueta del script en el encabezado de index.html.

```html

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

```
## 2. Integración.

Nuestro primer movimiento para integrar Stripe a Vue.js será realizando el evento 'on-click' cuando el cliente quiera suscribirse. Recopilaremos el correo electrónico y el nombre completo del cliente; en producción, debe recopilar información adicional, como la dirección del cliente.

```html

    <v-card-actions>
      <v-btn
        id="stripeBtn"
        class="mb-2"
        block
        :loading="loading"
        @click="Signup"
      >
        Sign Up
      </v-btn>
    </v-card-actions>
    
```

- En el siguiente bloque 'try and catch', enviamos, al backend, la información personal del cliente que recopilamos del formulario de registro. Si recibimos una respuesta, empujaremos el plan 'view' con el id del cliente como parámetro. Consulte los Vue Router Docs sobre cómo configurar el paso de parámetros entre 'views'.

```javascript

    // methods
    import PostService from '../post-service'

    async Signup() {
      const { email, fullname } = this
      try {
        const res = await PostService.createCust(
          email,
          fullname
        )

        if (res.data.customer) {
          this.$router.push({
            name:'Plan',
            params: {
              fullName: fullname,
              customerId: res.data.customer
            },
            props: true
          })
        }

      } catch (error) {
        this.alert1 = true;
        this.alertTxt = 'Error, Try again!'
      }
    }
    
```

- Cree un archivo en el src, el trabajo de este archivo es enviar solicitudes http al backend con Axios.

```javascript

    import axios from 'axios';

    const url = 'http://localhost:3000/api/posts';

    class PostService {
      // Crea el cliente
      static async createCust(email, fullname) {
        const res = await axios.post(url, {
          email, fullname
        });
        return res;
      }
      // Crea la suscripción
      static async createSubs(customerId, priceId) {
        const res = await axios.post(`${url}/subs`, {
          customerId, priceId
        });
        return res;
      }
      // Elimina la suscripción
      static async delete(subscriptionId) {
        const res = await axios.post(`${url}/delete`, {
          subscriptionId,
        });
        return res;
      }
    }
    export default PostService;
    
```

- Después de recibir la respuesta del servidor con la identificación del cliente, Vue Router impulsará el segundo paso; su cliente deberá elegir un plan. Cree dos botones con dos eventos de clic diferentes. Un botón será para suscribirse al plan de cinco dólares y la otra al plan de diez dólares.

```html

    <v-card-actions>
      <v-btn
        id="btnColor"
        :disabled="disabled"
        class="mx-auto mb-2"
        @click="subsPlan1"
      >
        Select
      </v-btn>
    </v-card-actions>
    <v-card-actions>
      <v-btn
        id="btnColor"
        :disabled="disabled2"
        class="mx-auto mb-2"
        @click="subsPlan2"
      >
        Seclect
      </v-btn>
    </v-card-actions>
    
```
- La función 'createSubscription' recibirá los parámetros del plan que elija el cliente más los 'props' del paso uno. Esta función enviará, al backend, el id del cliente y el id del precio y creará la suscripción; Si los datos de respuesta son buenos, el 'checkout view' se impulsará con parámetros.

```javascript

    props: {
      fullName: String,
      customerId: String
    },

    data: () => ({
      disabled: false,
      disabled2: false,
      alert2: false,
      alertTxt: '',
    }),

    methods: {
      async createSubscription(priceId, price, plan) {
        const {fullName, customerId } = this
        try {
          const res = await PostService.createSubs(
            customerId,
            priceId,
          )

          if (res.data) {
            const subscriptionId = res.data.subscriptionId
            const clientSecret = res.data.clientSecret
            this.$router.push({
              name: 'Checkout',
              params: {
                fullName,
                price,
                plan,
                clientSecret,
                subscriptionId
              }
            })
          }

        } catch (err) {
          this.alert2 = true
          this.disabled = false
          this.alertTxt = 'An error has occurred. Try again later'
        }
      },

      async subsPlan1() {
        const priceId = process.env.VUE_APP_BASIC_PLAN
        const price = '5.00'
        const plan = 'Basic'
        this.disabled = true
        this.disabled2 = false
        await this.createSubscription(priceId, price, plan)
      },

      async subsPlan2() {
        const priceId = process.env.VUE_APP_PREMIUM_PLAN
        const price = '10.00'
        const plan = 'Premium'
        this.disabled2 = true
        this.disabled = false
        await this.createSubscription(priceId, price, plan)
      }
    }
    
```

## 3. Montaje del Stipe Card Element.

Este es el último paso de la integración frontend, monta el elemento de la tarjeta y crea el 'Submit event'.

```html

    <!-- Stripe Element-->
    <div
      ref="card"
      class="inputCard"
    />

    <!-- Mensajes de error en este espacio -->
    <div
      id="card-errors"
      role="alert"
    />
    <br>
    <v-alert
      v-model="alert"
      color="red"
      dense
      dismissible
      type="error"
    >
      <!-- alertTxt -->
    </v-alert>
    <v-btn
      id="stripeBtn"
      class="my-3"
      block
      :loading="loading"
      @click="Submit"
    >
      Pay with Stripe
    </v-btn>
    
```
- Utilice el secreto del cliente para acceder a la función de Stripe "confirmCardPayment". Dentro de esta función, envíe el método de pago y la información de facturación del cliente; Consulte la lista de parámetros que puede enviar a stripe. Si la suscripción es exitosa, se impulsará el 'ThankYou view' con el id de la suscripción como parámetro.

```javascript

    import PostService from '../post-service'

    const stripe = window.Stripe(process.env.VUE_APP_STRIPE_KEY)

    // Cree una instancia del Stripe Elements.
    const elements = stripe.elements()
    const style = {
      base: {
        color: '#32325d',
        fontFamily: '"Helvetica Neue", Helvetica, sans-serif',
        fontSmoothing: 'antialiased',
        fontSize: '16px',
        '::placeholder': {
          color: '#aab7c4',
        },
      },
      invalid: {
        color: '#fa755a',
        iconColor: '#fa755a',
      },
    };

    const card = elements.create('card', { style: style })

    export default {
      props: {
        fullName: String,
        price: String,
        plan: String,
        clientSecret: String,
        subscriptionId: String
      },

      mounted() {
        card.mount(this.$refs.card)

        card.on('change', (event) => {
          this.displayError(event)
        })
      },

      methods: {
        displayError(event) {
          const displayError = document.getElementById('card-errors')
          if (event.error) {
            displayError.textContent = event.error.message
          } else {
            displayError.textContent = ''
          }
        },

        async Submit() {
          this.loading = true
          const { clientSecret, fullName, alert, alertTxt, loading } = this
          const result = await stripe.confirmCardPayment(clientSecret, {
            payment_method: {
              type: 'card',
              card: card,
              billing_details: {
                name: fullName,
              }
            }
          })

          if (result.error) {
            alert = true
            alertTxt = result.error.message
            loading = false
          } else {
            // Pago de suscripción exitoso
            // La suscripción se activa automáticamente al momento del pago.
            this.$router.push({
              name: 'ThankYou',
              params: {
                subscriptionId: this.subscriptionId
              }
            })
          }
        }
      }
    }
    
```
Chequea el backend aquí: [Sistema de suscripción con Stripe y Express](https://codingpr.com/es/suscripciones-con-express-stripe/)