2 votes

Exécuter les paiements d'abonnement avec Stripe Firebase Extension Webhook ne se déclenche pas

J'ai ajouté dans l'extension Stripe Subscriptions à mon application Firebase/Vue afin de pouvoir gérer les plans d'abonnement de mes clients, mais je rencontre des problèmes avec ce que je crois être le webhook Stripe.

J'ai commencé l'installation de l'extension en configurant le firebase.rules comme indiqué dans le tutoriel :

firebase.rules :

rules_version = '2';
service cloud.firestore {
  match /databases/{database}/documents {
    match /{document=**} {
      allow read, write;
    }
    match /customers/{uid} {
      allow read, write: if request.auth.uid == uid;

      match /checkout_sessions/{id} {
        allow read, write: if request.auth.uid == uid;
      }
      match /subscriptions/{id} {
        allow read, write: if request.auth.uid == uid;
      }
    }

    match /products/{id} {
      allow read: if true;
      allow write: if false;

      match /prices/{id} {
        allow read: if true;
        allow write: if false;
      }
    }
  }
}

J'ai configuré le webhook Stripe comme suit et ajouté le secret du webhook dans l'extension firebase : enter image description here

J'ai également créé une clé restreinte dans le tableau de bord Stripe et je l'ai également ajoutée à l'extension.

Lorsque je teste la création d'un nouveau produit à partir du tableau de bord Stripe, le webhook réussit et une collection est créée dans firebase :

Tableau de bord des produits Stripe : enter image description here

Firestore : enter image description here

Maintenant, le problème :

Le problème survient lorsque j'essaie de créer et de compléter une caisse Stripe. D'après le tutoriel, il semble que je doive le faire en appelant stripe.redirectToCheckout() et il s'occupera de la plupart des choses pour moi, mais je n'arrive pas à trouver le sessionId de la session de caisse. Voici l'exemple qu'ils ont montré :

const docRef = await db
  .collection('customers')
  .doc(currentUser.uid)
  .collection('checkout_sessions')
  .add({
    price: 'price_1GqIC8HYgolSBA35zoTTN2Zl',
    success_url: window.location.origin,
    cancel_url: window.location.origin,
  });
// Wait for the CheckoutSession to get attached by the extension
docRef.onSnapshot((snap) => {
  const { sessionId } = snap.data();
  if (sessionId) {
    // We have a session, let's redirect to Checkout
    // Init Stripe
    const stripe = Stripe('pk_test_1234');
    stripe.redirectToCheckout({ sessionId });
  }
});

Voici ma mise en œuvre :

 async checkoutv2(item) {
      let currentUser = this.getCurrentUser();
      const stripe = window.Stripe(this.publishableKey);

      const docRef = await db
        .firestore()
        .collection("customers")
        .doc(currentUser.uid)
        .collection("checkout_sessions")
        .add({
          unit_amount: item["unit_amount"],
          plan: item["id"],
          description: item["description"],
          interval: item["interval"],
          currency: item["currency"],
          type: item["type"],
          interval_count: item["interval_count"],
          active: item["active"],
          // allow_promotion_codes: true,
          // tax_rates: ["txr_1HCshzHYgolSBA35WkPjzOOi"],
          success_url: window.location.origin,
          cancel_url: window.location.origin,
          mode: "subscription",
          metadata: {},
        });

      // Wait for the CheckoutSession to get attached by the extension
      docRef.onSnapshot((snap) => {
        const { sessionId } = snap.data();
        if (sessionId) {
          // We have a session, let's redirect to Checkout
          // Init Stripe
          stripe.redirectToCheckout({ sessionId });
        } else {
          console.log("NOPE");
        }
      });
    },

Il semble que le CheckOutSession "s'attache" à l'extension après qu'elle ait été ajoutée au Firestore, et qu'un ID de session soit créé et ajouté au document. Mais je ne vois pas cela se produire dans ma version. Le site checkout_sessions sont créés, mais sans sessionId .

enter image description here

Voici ce que snap ressemble à des données : enter image description here

N'a rien sur sessionId Mais il a son propre identifiant, qui est, je crois, l'identifiant que Firestore crée automatiquement pour la collection.

En regardant mes journaux, aucun webhook n'est déclenché. Lorsque je teste des événements de webhooks spécifiques, certains réussissent et d'autres non.

Réussit :

  • Tout ce qui concerne le prix, la création, la mise à jour et la suppression de produits.
  • checkout.session.completed
  • abonnement.client.créé

Échec (code d'état d'erreur 400) :

  • abonnement.client.mis.à.jour
  • customer.subscription.deleted (LOG : Le gestionnaire de Webhook pour l'événement Stripe [evt_00000000000000] de type [customer.subscription.deleted] a échoué : No such subscription : 'sub_00000000000000')

Quelqu'un peut-il dire ce qui se passe ? J'utilise la version de l'API de Stripe : 2017-06-05. J'ai ajouté ce qui suit à mon index.html :

  <!-- Firebase App (the core Firebase SDK) is always required and must be listed first -->
    <script src="https://www.gstatic.com/firebasejs/7.14.6/firebase.js"></script>
    <script src="https://www.gstatic.com/firebasejs/7.14.6/firebase-functions.js"></script>

    <!-- If you enabled Analytics in your project, add the Firebase SDK for Analytics -->
    <script src="https://www.gstatic.com/firebasejs/7.14.5/firebase-analytics.js"></script>

    <!-- Add Firebase products that you want to use -->
    <script src="https://www.gstatic.com/firebasejs/7.14.5/firebase-auth.js"></script>
    <script src="https://www.gstatic.com/firebasejs/7.14.5/firebase-firestore.js"></script>

    <script src="https://cdn.firebase.com/libs/firebaseui/3.5.2/firebaseui.js"></script>
    <link
      type="text/css"
      rel="stylesheet"
      href="https://cdn.firebase.com/libs/firebaseui/3.5.2/firebaseui.css"
    />

Mon paquet.json :

{
  "name": "mathpath",
  "version": "0.1.0",
  "private": true,
  "description": "## Project setup ``` npm install ```",
  "author": "",
  "scripts": {
    "serve": "vue-cli-service serve",
    "build": "vue-cli-service build",
    "lint": "vue-cli-service lint",
    "start": "node index.js",
    "bd": "vue-cli-service build && firebase deploy"
  },
  "main": "babel.config.js",
  "dependencies": {
    "aws-sdk": "^2.719.0",
    "axios": "^0.19.2",
    "bootstrap": "^4.5.0",
    "bootstrap-vue": "^2.1.0",
    "core-js": "^3.6.5",
    "dns": "^0.2.2",
    "express": "^4.17.1",
    "firebase": "^7.17.1",
    "firebase-admin": "^9.0.0",
    "firebaseui": "^4.6.0",
    "fs": "0.0.1-security",
    "jquery": "^3.5.1",
    "katex": "^0.12.0",
    "markdown-it": "^11.0.0",
    "markdown-it-katex": "^2.0.3",
    "mathjax-node": "^2.1.1",
    "pg": "^8.2.2",
    "pg-hstore": "^2.3.3",
    "sequelize": "^6.3.0",
    "showdown": "^1.9.1",
    "showdown-katex": "^0.8.0",
    "slugify": "^1.4.5",
    "stripe": "^8.83.0",
    "uniqid": "^5.2.0",
    "vue": "^2.6.11",
    "vue-katex": "^0.4.0",
    "vue-router": "^3.3.4",
    "vue-stripe-checkout": "^3.5.7",
    "vue-youtube-embed": "^2.2.2",
    "vuefire": "^2.2.3",
    "vuex": "^3.5.1"
  },
  "devDependencies": {
    "@babel/polyfill": "^7.7.0",
    "@vue/cli-plugin-babel": "~4.4.0",
    "@vue/cli-plugin-eslint": "~4.4.0",
    "@vue/cli-service": "~4.4.0",
    "babel-eslint": "^10.1.0",
    "bootstrap": "^4.3.1",
    "eslint": "^6.7.2",
    "eslint-plugin-vue": "^6.2.2",
    "mutationobserver-shim": "^0.3.3",
    "popper.js": "^1.16.0",
    "portal-vue": "^2.1.6",
    "sass": "^1.19.0",
    "sass-loader": "^8.0.0",
    "vue-cli-plugin-bootstrap-vue": "~0.6.0",
    "vue-template-compiler": "^2.6.11"
  },
  "eslintConfig": {
    "root": true,
    "env": {
      "node": true
    },
    "extends": [
      "plugin:vue/essential",
      "eslint:recommended"
    ],
    "parserOptions": {
      "parser": "babel-eslint"
    },
    "rules": {
      "no-console": "off",
      "no-restricted-syntax": [
        "error",
        {
          "selector": "CallExpression[callee.object.name='console'][callee.property.name!=/^(log|warn|error|info|trace)$/]",
          "message": "Unexpected property on console object was called"
        }
      ]
    }
  },
  "browserslist": [
    "> 1%",
    "last 2 versions",
    "not dead"
  ],
  "license": "ISC"
}

1voto

ielvis Points 11

Je rencontrais le même problème.

Voici quelques éléments que j'ai modifiés avant qu'il ne commence à fonctionner, je ne suis pas sûr de ce qui l'a réparé :

  • J'ai éteint mon émulateur firebase et testé sur les données de production. Il semblait fonctionner dans l'émulateur avant le correctif (à l'exception des problèmes mentionnés dans le message original) mais je n'ai pas encore testé s'il fonctionne dans l'émulateur après le correctif.
  • J'ai supprimé toutes mes données de test et mon webhook dans Stripe et j'ai recommencé à zéro.
  • Mise à jour de toutes mes dépendances firebase et vue-stripe-checkout :

"firebase" : "7.19.1", "firebase-admin" : "^9.1.1", "firebase-functions" : "^3.11.0", "firebase-tools" : "^8.10.0", " firebaseui " : "^4.6.1", "vue-stripe-checkout" : "^3.5.7"

  • Mise à jour de l'API Stripe dans le tableau de bord Stripe du 2020-03-20 au 2020-08-27.
  • J'ai supprimé l'extension et je l'ai réinstallée en utilisant le CLI au lieu de la console. La seule chose que j'ai changée lors de la configuration de l'extension a été de définir la collection de clients comme "users" puisque c'est la convention dans mon application : https://firebase.google.com/products/extensions/firestore-stripe-subscriptions

Une fois tout cela fait, j'ai créé un produit d'abonnement test dans Stripe et je l'ai vu apparaître dans ma collection de produits. Cela fonctionnait déjà avant la correction. Ce qui est nouveau, c'est que je vois maintenant un sessionId dans la deuxième réponse snap.data(). La première réponse ressemblait à celle d'avant le correctif, et j'ai pensé qu'elle échouait à nouveau, mais après une seconde ou deux, une nouvelle réponse est apparue avec le paramètre sessionId supplémentaire.

J'utilise également Vue. Je prends ensuite cette session et je l'engage dans un état de mise à jour. J'attends que cette session change et j'appelle ensuite la fonction checkoutRef. Cette fois, la collection de l'utilisateur est mise à jour avec le nouvel abonnement.

Pour moi ce code est dans store-auth.js

async checkoutUser({ commit }, payload) {
    let userId = firebaseAuth.currentUser.uid;

    const docRef = await firebaseDb
      .collection("users")
      .doc(userId)
      .collection("checkout_sessions")
      .add({
        price: "YOUR_PRICE_ID",
        success_url: window.location.origin,
        cancel_url: window.location.origin,
        mode: "subscription"
      });

    docRef.onSnapshot(snap => {
      const test = snap.data();

      const { sessionId } = snap.data();
      if (sessionId) {
        commit("setSession", sessionId);
      }
    });
  },

Et ceci partout où vous utilisez vue-stripe-checkout. Pour moi, c'est sur PagePlans.vue.

    <stripe-checkout
    ref="checkoutRef"
    :pk="publishableKey"
    :mode="mode"
    :items="items"
    :successUrl="successUrl"
    :cancelUrl="cancelUrl"
    :session-id="sessionId"

  watch: {
    currentSession: {
      handler(newValue, oldValue) {
        this.sessionId = newValue

        this.$refs.checkoutRef.redirectToCheckout({scenarioId: newValue.sessionId})
      }
    }
  },
  computed: {
    ...mapGetters("auth", ["currentSession"]),
  },
  methods: {
    ...mapActions("auth", [
      "checkoutUser",
    ]),
    async checkout() {
      await this.checkoutUser()
    }
  }

0voto

culco Points 21

Pour les fonctions cloud de Firebase, j'ai jeté un coup d'œil dans les journaux et j'ai vu qu'il s'agissait d'un problème d'accès.

Modifiez votre clé API restreinte et donnez aux clients la permission de

Autorisations limitées de l'API de Stripe :
Stripe Restricted API permissions

Fonction Firebase pour Stripe :
Firebase Function for Stripe

0voto

superquest Points 74

J'ai eu ce même problème en utilisant l'extension stripe firebase. Dans la configuration de l'extension stripe firebase, mettez l'option checkout_sessions à l'intérieur de la customers et dans mon code j'utilisais la collection users collection.

Ça a commencé à fonctionner une fois que j'ai utilisé users dans les deux endroits.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X