vue-stripe / vue-stripe

Stripe Checkout & Elements for Vue.js
https://vuestripe.com
MIT License
1.08k stars 148 forks source link

Question, FEE #11

Closed drosendo closed 6 years ago

drosendo commented 6 years ago

Thanks for this amazing script! really simple :)

More of a question than a bug, I cant seem to figure out how can I get the fee that was charged after i get the token. this.$checkout.open({})

Any help you can give me to retrievng the FEE, i see there is balance_transtion just cant figure how to integrate it into this flow... https://stripe.com/docs/api#balance_transaction_object

Appreciate the help.

Cheers,

jofftiquez commented 6 years ago

@drosendo Hi thanks, Im glad you liked it. :)

If I understand you correctly, you haven't sent token to your server yet? If that's the case you need to manage the token in the server side in order to make payments, subscriptions, etc.

From this nodejs example here you'll see the create charge guide.

var stripe = require("stripe")(
  "sk_test_rElPTRFcbfuBfHvswuv4B7s4"
);

stripe.charges.create({
  amount: 2000,
  currency: "usd",
  source: "tok_visa", // obtained with Stripe.js
  description: "Charge for liam.johnson@example.com"
}, function(err, charge) {
  // asynchronously called
});

In this snippet you'll have to pay attention to the source field, there you will put the token you obtained from vue-stripe-checkout.

I you have more questions, please just ask away :)

tcdvm commented 6 years ago

Hey there!

Thanks so much for the script! I think I might have a similar question to @drosendo but I'm not sure and it might just come down to my lack of understanding of the deeper particulars of javascript, so if the solution is obvious, forgive the ignorance.

Basically what I'm trying to do is pass an "amount" (maybe this is the Fee that @drosendo that is talking about too?) as a POST argument to the server along with the token. I'm passing the token with axios in the (token) => {...} function:

token: (token) => {
          axios.post('http://127.0.0.1:5000/charge', {
            stripeToken: token.id,
            amount: someamount * 100})
}

The problem is that I can't figure out a way to add the "someamount" to the arrow function. I've tried adding it as an argument "(token, amount = this.amount)", converting the arrow function to a "real" function (token: function(token, amount = this.amount) {...}) but can't seem to pass the value - it always comes out as null. The "token" argument seems to be the only thing that is passed and unfortunately it doesn't have the amount to be charged in it.

Would you happen to have a work around or suggestion? Thanks!

Best wishes, -thomas.

jofftiquez commented 6 years ago

Hello @tcdvm

Thank you for using my plugin. :)

In you code here:

token: (token) => {
  axios.post('http://127.0.0.1:5000/charge', {
  stripeToken: token.id,
  amount: someamount * 100})
}

May I know where you declared the someamount? And what error or output are you seeing?

tcdvm commented 6 years ago

Hey there! Thank you for creating the plugin! Really handy finding it. I figured out a workaround but maybe you have a more elegant way of dealing with it?

someamount is declared in the data of a Vue instance which is bound to a text field. It's what's passed to the $checkout.open for the stripe modal.

this.$checkout.open({
      amount: this.someamount * 100,
      token: (token) => {...}

The actual POST to the server (local flask server) happens in the (token) => { ... } which is where you indicated to do it. The issue I'm running into is that the "amount" or "this.someamount" isn't in the scope for the arrow function and I don't quite know how to put in there. I finally tried putting it in a global variable declared in the beginning of "checkout()" and that gets into that function. It's kind of hamfisted but it works so I can submit it to the flask server in (token) => {...}.

So, I think my understanding of javascript just isn't up to snuff without stuffing the value into a global variable but if you have any thoughts, would be glad to hear it!

Thanks again, -thomas.

jofftiquez commented 6 years ago

Hi @tcdvm I'm a little bit confused, correct me if i'm wrong. So you just want the amount to be dynamic based on the value from the input?

If yes, doing this is enough:

this.$checkout.open({
      amount: this.someamount * 100,
      token: (token) => {...}
tcdvm commented 6 years ago

Sorry! I don't think I'm doing a good job explaining. Here's my full code:

Hope that explains it! Thanks so much!!

<template>
  <div>
    <input type="text" placeholder="Enter amount" v-model="someamount" id="amount">
    <p>Amount is: {{ someamount }}</p>
    <button @click="checkout">Pay</button>
  </div>
</template>

<script>
import axios from 'axios'

export default {
  data () {
    return {
      someamount: null
    }
  },
  methods: {
    checkout () {
      this.$checkout.open({
        currency: 'USD',
        amount: this.sponsoramt * 100, // this is ok and the amount is correctly displayed in the Stripe modal
        token: (token) => {
          console.log(token) // this is filled with the token object (which doesn't contain the amount AFAIK)
          console.log(this.someamount) // ------- This is null/None ----------, same with this.amount
          axios.post(`http://127.0.0.1:5000/charge`, {
            stripeToken: token.id,
            amount: someamount * 100 // This value is null/None so I can't create the appropriate charge on the server side
          })
            .then(response => {
              console.log(response)
            })
            .catch(error => {
              console.log(error)
            })
        }
      })
    }
  }
}
</script>
jofftiquez commented 6 years ago

Hi @tcdvm thanks for the code and explanation. Let me just do a reproduction of your code.

jofftiquez commented 6 years ago

@tcdvm After copying and testing your code, I did not get the same problem that you are describing.

Here's what I got:

Sample code.

Vue.use(VueStripeCheckout, {
      key: 'pk_test_INH6o8QUdJyZM1TuGKs5PIsT',
      image: 'https://cdn.meme.am/images/100x100/15882140.jpg',
      locale: 'auto',
      panelLabel: 'Subscribe {{amount}}'
    });

    var vm = new Vue({
      el: '#app',
      data() {
        return {
          token: null,
          someamount: null
        }
      },
      methods: {
        submit(token) {
          console.log('token', token);
          console.log('Submit this token to your server to perform a stripe charge, or subscription.');
        },
        checkout() {
          this.$checkout.open({
            name: 'Shut up and take my money!',
            currency: 'USD',
            amount: this.someamount * 100,
            token: (token) => {
              console.log('token -> ', token);
              console.log('this.someamount -> ', this.someamount);
              this.token = token;
            } 
          });
        }
      }

This snippet is the same code in my demo. Just ignore the other stuff. What I did was I just added a text input, I also mocked your someamout data.

Here's the output:

Imgur

tcdvm commented 6 years ago

Well. Goddamnit. You're right it works. I swear to god I used this exact syntax and I inexplicably kept getting null values and I tried to debug it for hours (usually via random changes and prayer). I feel like an idiot and I feel bad that I wasted your time! Thanks so much for the plugin and for taking the time to work through my apparently non-existent problem...

jofftiquez commented 6 years ago

@tcdvm It's ok we all went through these kind of situations HAHA. Thanks for using my plugin :) Kudos!

Denny143 commented 5 years ago

Hi @jofftiquez , Thanks for the plugin, its pretty awesome and easy to use. I am trying to implement this module in my Nuxt application. Everything seems to work fine till the point where the tokens are created. When I tried to use axios to send the token id and secret key, the charges are not created. I am not sure what I am missing. Pardon me if my question is too basic. Any help would be much appreciated: Here is my code "checkoutstripe.vue"

`

`
jofftiquez commented 5 years ago

@Denny143, first of all, what's a black matter gun? 😄

Before anything else, I just want to point out that the problem might not be related to this plugin, the ultimate goal of this plugin is to generate a token from stripe. Once you successfully generated a token, this plugin's job is done at that point. However, I still want to help you, so kindly do the following:

  1. Use proper formatting for your sample code. So I and others could read it easily.
  2. Check the response of your request using axios. I there's any error kindly include it here.

There's a really high chance that the problem is in your backend code. What stack are you using?

Denny143 commented 5 years ago

@jofftiquez , sorry about the " sell black matter gun" lol:).. its just a funny label ( that I forgot to edit) on the button and sorry about the formatting. Please find the my formatted sample code for "checkoutstripe.vue" component below:


  <div>
    <v-btn @click="checkout">Sell black matter gun</v-btn>
  </div>
</template>

export default {
methods: {
    checkout () {
              this.$checkout.open({
                    image: 'https://i.imgur.com/1PHlmFF.jpg',
                    locale: 'en',
                    currency: 'BZD',
                    name: 'Blips and Chitz!',
                    description: 'An entire afternoon at Blips and Chitz!',
                    amount: 9999999,
                    panelLabel: 'Pay Roy for {{amount}}',
                    token: (token) => {
                            // handle the token
                          axios.post("https://api.stripe.com/v1/charges", { 
                                   payload: { amount: 999,
                                                    currency: "cad",
                                                   description: "Example charge",
                                                    source: token.id },
                                    headers: {
                                   // TODO: replace with real PLATFORM_SECRET_KEY
                                                 Authorization: "Bearer _secret key_ " }

            })
    },
 }
}```

The error response that I am getting is during POST process of the token to Stripe server. Error message:" Stripe API back-end requires a secret key for creating the charges".

When you mean "stack" are you referring to back-end? In this case I am trying to send the token for creating charges directly to Stripe API.

 Again, sorry if my question is too basic , I am trying to integrate the stripe payments for the first time and try and get it working. 
jofftiquez commented 5 years ago

@Denny143 It seems that you're using the old version. Tho the version is irrelevant to your problem.

Yes, the back-end.

Based on the error you provided.

Stripe API backend requires a secret key for creating the charges

It seems that you're providing the STRIPE SECRET KEY in your backend code. You should add that to the initialization stage. You can see that in their documentation.

Denny143 commented 5 years ago

Thanks @jofftiquez, I am using firebase as the backend to host my site. I found a good document on how to setup a firebase function for stripe payment here. But I am struggling how to tie up the tokens produced through your plugin to be sent via firebase and create a stripe charge

jofftiquez commented 5 years ago

If you're using firebase function, you should use http-trigger, then make a POST request to the function url. Just add the token to the request body.

The link you sent, it's a good source. Follow it.

Denny143 commented 5 years ago

Thanks again @jofftiquez , I followed the instruction on that tutorial and was able to figure out how to create a http-trigger function using firebase function and successfully deployed it. But I am still getting a POST 404 error from Stripe server. Here is my modified checkoutstripe.vue component:


  <div>
    <v-btn @click="checkout">Purchase</v-btn>
  </div>
</template>

<script>
const FIREBASE_FUNCTION =
  "https://xxxxxxxxx.xxxxxxxxxxxx/charge"- http-link for the firebase cloud function

export default {
  computed: {},
  methods: {
    checkout() {
      // this.$checkout.close()
      // is also available.
      this.$checkout.open({
        image: "https://i.imgur.com/1PHlmFF.jpg",
        locale: "en",
        currency: "BZD",
        name: "Blips and Chitz!",
        description: "An entire afternoon at Blips and Chitz!",
        amount: 999,
        panelLabel: "Play Roy for {{amount}}",
        token: token => {
          console.log(token)
          // Pass the received token to our Firebase function
          fetch(FIREBASE_FUNCTION, {
            mode: "no-cors",
            method: "POST",
            token: token,
            amount: 999,
            currency: "cad"
          })
        }
      })
    }
  }
}
</script>
-------------------
and here is my cloud function for creating charges:

const functions = require("firebase-functions")
const admin = require("firebase-admin")
admin.initializeApp(functions.config().firebase)
const express = require("express")
const cors = require("cors")({ origin: true })
const app = express()

// TODO: Remember to set token using >> firebase functions:config:set stripe.token="SECRET_STRIPE_TOKEN_HERE"
const stripe = require("stripe")(functions.config().stripe.token)

function charge(req, res) {

  const body = JSON.parse(req.body)
  const token = body.token.id
  const amount = body.amount
  const currency = body.currency

  // Charge card
  stripe.charges
    .create({
      amount,
      currency,
      description: "Firebase  Example",
      source: token
    })
    .then(charge => {
      send(res, 200, {
        message: "Success",
        charge
      })
    })
    .catch(err => {
      console.log(err)
      send(res, 500, {
        error: err.message
      })
    })
}

function send(res, code, body) {
  res.send({
    statusCode: code,
    headers: {
      "Access-Control-Allow-Origin": "http://localhost:3000",
      "Access-Control-Allow-Methods": "GET,POST"
    },
    body: JSON.stringify(body)
  })
}

app.use(cors)
app.post("/", (req, res) => {
  // Catch any unexpected errors to prevent crashing
  try {
    charge(req, res)
  } catch (e) {
    console.log(e)
    send(res, 500, {
      error: `The server received an unexpected error. Please try again and contact the site admin if the error persists.`
    })
  }
})

exports.charge = functions.https.onRequest(app)```

I am not sure if I am passing the token and relevant data properly. 
jofftiquez commented 5 years ago

Hi @Denny143 would mind sending me a hangout chat request at jofftiquez@gmail.com so we can discuss this on a chat? Thanks.