react-paypal-js runs onApprove function but no money is sent - javascript

I tried to do some 1€ payments with a paypal.
And it it shows me that it's successful.
It does everything what is in my onApprove function and no error is showing but when i check my 2 paypal account there is no money sent!
Neither the balance of one account reduce nor the other gain balance.
Any ideas?
const initialOptions = {
'client-id': 'MY_CLIENT_ID',
components: 'buttons',
'data-namespace': 'PayPalSDK',
currency: 'EUR',
intent: 'capture',
'enable-funding': ['sofort', 'giropay'],
'disable-funding': ['card', 'sepa'],
};
<PayPalButtons
key={Math.random()}
createOrder={(data, actions) => {
return actions.order.create({
purchase_units: [
{
description: 'Restaurant',
amount: {
value: carttotal,
currency_code: 'EUR',
}
},
],
application_context: {
shipping_preference: 'NO_SHIPPING',
},
});
}}
onApprove={(data, actions) => {
actions.order.capture().then(() => {
axios
.post(
'/api/paypal',
{
cartItems: cartItems,
}
)
}
}}
onCancel={() => {
toast.error('Cancel', {
position: toast.POSITION.BOTTOM_RIGHT,
});
}}
onError={() => {
//setPaid(false);
toast.error('Error', {
position: toast.POSITION.BOTTOM_RIGHT,
});
}}
/>

You are using actions.order.create() to create the order for approval on the client side, but there is no call to actions.order.capture() after approval, so no transaction is created.
(If you need to store the result or do anything automated with the transaction result, you should not use either of those server-side functions, but rather the v2/checkout/orders API to create and capture on a backend, paired with a frontend that calls those backend routes.)

Related

Vue js vuex unable to display my data in my loop

but i can't show the comments with v-for and i don't understand why my comment data is not working.
I know there is an error but I can't find it.
My request returns a data , but i can't display it my loop.
Thanks for your help
In store/index.js
state :{
dataComments:[]
}
mutation: {
getComments(state, dataComments) {
console.log(dataComments)
state.dataComments = dataComments;
},
}
action: {
getArticleComments: ({ commit }, dataArticles) => {
return new Promise(() => {
instance.get(`/comment/${dataArticles.article_id}`)
.then(function () {
commit('getComments');
})
.catch(function (error) {
console.log(error)
})
})
},
}
in my views/home.vue
export default {
name: "Home",
data: function () {
return {
articles: [],
comments: [],
}
},
methods: {
getArticleComments(comment) {
this.$store
.dispatch("getArticleComments",comment)
.then((res) => {
this.comments = res.data;
});
},
}
<div class="pos-add">
<button
#click="getArticleComments(article)"
type="button"
class="btn btn-link btn-sm">
Show comments
</button>
</div>
<!-- <div v-show="article.comments" class="container_comment"> -->
<div class="container_comment">
<ul class="list-group list-group comments">
<li
class="
list-group-item
fst-italic
list-group-item-action
comment
"
v-for="(comment, indexComment) in comments"
:key="indexComment"
>
{{ comment.comment_message }}
<!-- {{ comment.comment_message }} -->
</li>
</ul>
</div>
Your action getArticleComments does not return anything and I would avoid changing the action to return data. Instead remove the assignment to this.comments in home.vue
Actions do not return data, they get data, and call mutations that update your store.
Your store should have a getter that exposes the state, in this case the dataComments.
getters: {
dataComments (state) {
return state.dataComments;
}
}
Then in your home.vue you can use the helper mapGetters
computed: {
...mapGetters([
'dataComments'
])
}
You want your views to reference your getters in your store, then when any action updates them, they can be reactive.
More here: https://vuex.vuejs.org/guide/getters.html
As far as I see, you don't return any data in your getArticleComments action. To receive the comments you should return them, or even better, get them from your store data directly.
First make sure that you pass the response data to your mutation method:
getArticleComments: ({ commit }, dataArticles) => {
return new Promise(() => {
instance.get(`/comment/${dataArticles.article_id}`)
.then(function (res) {
commit('getComments', res.data);
})
.catch(function (error) {
console.log(error)
})
})
},
After dispatching you could either return the response data directly or you could access your store state directly. Best practice would be working with getters, which you should check in the vue docs.
getArticleComments(comment) {
this.$store
.dispatch("getArticleComments",comment)
.then((res) => {
// in your case there is no res, because you do not return anything
this.comments =
this.$store.state.dataComments;
});
},

Error: MercadoPago.js - Could not find HTML element for provided id: MPHiddenInputPaymentMethod

I have an Nuxt desktop app here, am i am facing this problem with MERCADO PAGO API.
This is part of the Mercado documentation : https://www.mercadopago.com.br/developers/pt/guides/online-payments/checkout-api/v2/testing
The problem is:
I make use of the index.vue that makes use of the default form from the documentation itself:
<template>
<div >
<form id="form-checkout" >
<input type="text" name="cardNumber" id="form-checkout__cardNumber" />
<input type="text" name="cardExpirationMonth" id="form-checkout__cardExpirationMonth" />
<input type="text" name="cardExpirationYear" id="form-checkout__cardExpirationYear" />
<input type="text" name="cardholderName" id="form-checkout__cardholderName"/>
<input type="email" name="cardholderEmail" id="form-checkout__cardholderEmail"/>
<input type="text" name="securityCode" id="form-checkout__securityCode" />
<select name="issuer" id="form-checkout__issuer"></select>
<select name="identificationType" id="form-checkout__identificationType"></select>
<input type="text" name="identificationNumber" id="form-checkout__identificationNumber"/>
<select name="installments" id="form-checkout__installments"></select>
<button type="submit" id="form-checkout__submit">Pagar</button>
<progress value="0" class="progress-bar">Carregando...</progress>
</form>
</div>
</template>
nuxt.config:
export default{
head:{
...
script: [
{ src: 'https://sdk.mercadopago.com/js/v2' },
{src: "/js/index.js", },
}
}
and the "/js/index.js file in static folder:
//i know the YOU_PUBLIC_KEY must be from the Mercado Pago account, i have one already
const mp = new MercadoPago('YOUR_PUBLIC_KEY', {
locale: 'pt-BR',
})
const cardForm = mp.cardForm({
amount: '100.5',
autoMount: true,
processingMode: 'aggregator',
form: {
id: 'form-checkout',
cardholderName: {
id: 'form-checkout__cardholderName',
placeholder: 'Cardholder name',
},
cardholderEmail: {
id: 'form-checkout__cardholderEmail',
placeholder: 'Email',
},
cardNumber: {
id: 'form-checkout__cardNumber',
placeholder: 'Card number',
},
cardExpirationMonth: {
id: 'form-checkout__cardExpirationMonth',
placeholder: 'MM'
},
cardExpirationYear: {
id: 'form-checkout__cardExpirationYear',
placeholder: 'YYYY'
},
securityCode: {
id: 'form-checkout__securityCode',
placeholder: 'CVV',
},
installments: {
id: 'form-checkout__installments',
placeholder: 'Total installments'
},
identificationType: {
id: 'form-checkout__identificationType',
placeholder: 'Document type'
},
identificationNumber: {
id: 'form-checkout__identificationNumber',
placeholder: 'Document number'
},
issuer: {
id: 'form-checkout__issuer',
placeholder: 'Issuer'
}
},
callbacks: {
onFormMounted: error => {
if (error) return console.warn('Form Mounted handling error: ', error)
console.log('Form mounted')
},
onFormUnmounted: error => {
if (error) return console.warn('Form Unmounted handling error: ', error)
console.log('Form unmounted')
},
onIdentificationTypesReceived: (error, identificationTypes) => {
if (error) return console.warn('identificationTypes handling error: ', error)
console.log('Identification types available: ', identificationTypes)
},
onPaymentMethodsReceived: (error, paymentMethods) => {
if (error) return console.warn('paymentMethods handling error: ', error)
console.log('Payment Methods available: ', paymentMethods)
},
onIssuersReceived: (error, issuers) => {
if (error) return console.warn('issuers handling error: ', error)
console.log('Issuers available: ', issuers)
},
onInstallmentsReceived: (error, installments) => {
if (error) return console.warn('installments handling error: ', error)
console.log('Installments available: ', installments)
},
onCardTokenReceived: (error, token) => {
if (error) return console.warn('Token handling error: ', error)
console.log('Token available: ', token)
},
onSubmit: (event) => {
event.preventDefault();
const cardData = cardForm.getCardFormData();
console.log('CardForm data available: ', cardData)
},
onFetching: (resource) => {
console.log('Fetching resource: ', resource)
// Animate progress bar
const progressBar = document.querySelector('.progress-bar')
progressBar.removeAttribute('value')
return () => {
progressBar.setAttribute('value', '0')
}
},
}
})
Anyone can help me with this? And is facing more problems with the MERCADO PAGO's API?
Thanks for the atention!
Use iframe to render custom vanilla HTML/CSS/JS.
I'm using vue/quasar2 and my workaround was using an Iframe to render a custom page which can use this lib, you can see the directory structure here.
I created a page to and use an iframe tag to render the custom page:
<template>
<q-page class="flex flex-center">
<iframe width="100%" height="545vh" style="border: none;" :src='`static_site/index.html?obj=${JSON.stringify(getQueryParameters())}`'/>
</q-page>
</template>
<script>
import { defineComponent } from 'vue';
export default defineComponent({
name: 'PageIndex',
setup () {
function getQueryParameters () {
return {
name: "name",
email: "name#gmail.com",
valor: "20"
}
}
return {
getQueryParameters,
}
}
})
</script>
I'm using the query parameters ( obj ) in the iframe src to pass down information from vue to the lib. In the callbacks section of the cardForm function, I used the URLSearchParams object to catch the information I sended, you can see it here.
OBS: I just found this workaround yesterday and haven't tested in production yet, but in dev it's working fine, will test soon in production and update this answer, hope it's useful to you.

Errors: "[Vue warn]: Property or method "posts" is not defined on the instance but referenced during render." and also for "books"

enter image description hereI am making an app in Nuxt and vue using storyblok as my CMS. However, I have been receiving errors when trying to link the storyblok array to my arrays called in my template using v-for.
Here is the template:
<template>
<div>
<!-- instance header -->
<InstanceHeader title="Books" />
<div class="pageContainer">
<div class="booksInfoPost">
<div class="booksInfoPost__subHeader"><h3>Top Books</h3></div>
<div class="booksInfoPost__topBooks">
<BooksInfoPostTop
v-for="book in books"
:key ="book.id"
:bookCover="book.bookCover"
:title="book.title"
:author="book.author"
:content="book.content"
:id="book.id"
/>
</div>
<div class="booksInfoPost__subHeader"><h3>Book Titles</h3></div>
<BooksInfoPost
v-for="book in posts"
:key ="book.id"
:bookCover="book.bookCover"
:title="book.title"
:author="book.author"
:content="book.content"
:id="book.id"
/>
</div>
</div>
Here is my script:
export default {
components: {
InstanceHeader,
BooksInfoPostTop,
BookTitles,
BooksInfoPost
},
data() {
/* return {
books: [],
posts: []
} */
},
async asyncData(context) {
return {
bookTitles: context.app.$storyapi
.get("cdn/stories", { version: "draft", starts_with: 'books/book-titles'})
.then(response => {
console.log(response);
return {
posts: response.data.stories.map(bp => {
return {
id: bp.slug,
bookCover: bp.content.bookCover,
title: bp.content.title,
author: bp.content.author
};
}),
}
}),
topBooks: context.app.$storyapi
.get("cdn/stories", { version: "draft", starts_with: 'books/top-books'})
.then(response => {
console.log(response);
return {
books: response.data.stories.map(b => {
return {
id: b.slug,
bookCover: b.content.bookCover,
title: b.content.title,
author: b.content.author
};
}),
}
})
}
}
}
I noticed this error more when I tried calling two APIs from storyblok. When I called one API call I did not see this error. I have also tried using Axios but I am getting errors using that method as well. I am not the most experienced developer and If anyone can help I'll appreciate it. Thanks
export default {
components: {
InstanceHeader,
BooksInfoPostTop,
BookTitles,
BooksInfoPost
},
async asyncData(context) {
const result = {};
const mapBooks = b => {
return {
id: b.slug,
bookCover: b.content.bookCover,
title: b.content.title,
author: b.content.author
};
};
const { data } = await context.app.$storyapi
.get("cdn/stories", {
version: "draft",
starts_with: 'books/book-titles'
});
result.posts = data.stories.map(mapBooks);
const result = await context.app.$storyapi
.get("cdn/stories", {
version: "draft",
starts_with: 'books/top-books'
});
result.books = result.data.stories.map(mapBooks);
return result; // it has right property names {books:[], posts:[]}
}
}
Well as you mentioned in the comment it was a little mess before. So i tidied it up. The idea is that you need direct property names instead of nested objects. This way it should work, if it is not working check the network tab for the errors.

Stripe Subscription JS issues

I use the following code to create a stripe customer and create a subscription for that customer
stripe.subscriptions.create({
customer: customer_id,
items: [
{
plan: plan_id
},
],
trial_period_days: 7,
expand: ['latest_invoice.payment_intent'],
}, function (err, subscription) {
stripe.customers.create({
email: email,
source: token,
metadata: {
userid: userId
}
}, function (err, customer) {
I want users to subscription to subscribe to a 1 week free trial, Monthly plan (they pay after 7 days)
I am running into the following issues
Stripe does not validate the credit card number on prod. You can enter any credit card number and the payment goes through
Can someone please help?
Here's the client code
submit(event) {
event.preventDefault();
if ( this.props.planid) {
setTimeout(() => {
this.setState({loading: true});
}, 0);
var planId = this.props.planid;
this.props.stripe.createToken({name: "Name"}).then( token => {
axios.post("/charge/process/" + planId, {
token: token.id
}).then(response => {
if (response.data.status === "ok") {
this.setState({complete: true, loading: false})
} else if (response.data.error) {
this.setState({error: response.data.error, loading: false});
}
}).catch(error => {
this.setState({error: "There was an error.", loading: false});
});
})
} else {
this.setState({error: "Invalid plan id", loading: false});
}
}
render() {
if (this.state.loading) return (<Spinner />)
if (this.state.complete) return (<p align="center">Thanks for purchasing! You can now access the book summaries.</p>);
var error = "";
if (this.state.error) {
error = (<p>{this.state.error}</p>);
}
return (
<div className="CheckoutForm" style={{width: "400px", margin: "0 auto", "textAlign": "center"}}>
{error}
<fieldset>
<legend className="card-only">Pay with card</legend>
<div className="container">
<div id="example4-card" className="StripeElement StripeElement--empty">
<div style={{width: "300px", margin: "0 auto"}}>
<CardElement/>
<br/>
<br/>
<button onClick={this.submit.bind(this)} className="btn btn-primary purchasebtn">Purchase</button>
</div>
</div>
</div>
</fieldset>
</div>
);
}

Sending data in Laravel using Axios & Vue

I have been following the Stripe integration tutorial by Laracasts and it's become apparent to me that a lot has changed since Laravel 5.4 was released. I have been able to still find my way along but I have hit a bump trying to submit a payment form using Vue and Axios.
The product is being retrieved from a database and displayed in a select dropdown - this works. My issue is the data is not being properly sent to the store function in the PurchasesController. When I try to make a purchase the form modal appears fine, I fill it out with the appropriate test data and submit it, but in Chrome inspector I can see that /purchases returns a 404 error and when I check the network tab the error is: No query results for model [App\Product]
Here is the original Vue code:
<template>
<form action="/purchases" method="POST">
<input type="hidden" name="stripeToken" v-model="stripeToken">
<input type="hidden" name="stripeEmail" v-model="stripeEmail">
<select name="product" v-model="product">
<option v-for="product in products" :value="product.id">
{{ product.name }} — ${{ product.price /100 }}
</option>
</select>
<button type="submit" #click.prevent="buy">Buy Book</button>
</form>
</template>
<script>
export default {
props: ['products'],
data() {
return {
stripeEmail: '',
stripeToken: '',
product: 1
};
},
created(){
this.stripe = StripeCheckout.configure({
key: Laravel.stripeKey,
image: "https://stripe.com/img/documentation/checkout/marketplace.png",
locale: "auto",
token: function(token){
axios.post('/purchases', {
stripeToken: token.id,
stripeEmail: token.email
})
.then(function (response) {
alert('Complete! Thanks for your payment!');
})
.catch(function (error) {
console.log(error);
});
}
});
},
methods: {
buy(){
let product = this.findProductById(this.product);
this.stripe.open({
name: product.name,
description: product.description,
zipCode: true,
amount: product.price
});
},
findProductById(id){
return this.products.find(product => product.id == id);
}
}
}
</script>
And my PurchasesController.
<?php
namespace App\Http\Controllers;
use Log;
use App\Product;
use Illuminate\Http\Request;
use Stripe\{Charge, Customer};
class PurchasesController extends Controller
{
public function store()
{
Log::info("Product Info: " . request('product'));
Log::info("Stripe Email: " . request('stripeEmail'));
Log::info("Stripe Token: " . request('stripeToken'));
$product = Product::findOrFail(request('product'));
$customer = Customer::create([
'email' => request('stripeEmail'),
'source' => request('stripeToken')
]);
Charge::create([
'customer' => $customer->id,
'amount' => $product->price,
'currency' => 'aud'
]);
return 'All done';
}
}
I realise that product isn't being passed through to /purchases above so I have tried this:
axios.post('/purchases', {
stripeToken: token.id,
stripeEmail: token.email,
product: this.product
})
Unfortunately I still get the same No query results for model [App\Product] error even with that. Is there another/better way of passing data from Vue/Axios that I could use instead? If anyone is able to assist it would be much appreciated.
Thank you in advance.
Edit
The solution was to recast this to be a new variable and it started functioning again. Here is the relevant portion of the Vue Code that worked for me:
created(){
let module = this; // cast to separate variable
this.stripe = StripeCheckout.configure({
key: Laravel.stripeKey,
image: "https://stripe.com/img/documentation/checkout/marketplace.png",
locale: "auto",
token: function(token){
axios.post('/purchases', {
stripeToken: token.id,
stripeEmail: token.email,
product: module.product
})
.then(function (response) {
alert('Complete! Thanks for your payment!');
})
.catch(function (error) {
console.log(error);
});
}
});
},
Are you sure when assigning the product ID to data (using product: this.product) that this keyword is really your Vue instance? You might need to bind it manually calling .bind(this) on the .post(...) call.
See https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Function/bind

Categories

Resources