Stripe checkout - IE popup is blocked on second payment - javascript

O/S: BrowserStack Live
Browser: IE11
I am using Stripe checkout with js sdk to display a popup when the user clicks a button. The code is as follows:
Payment.prototype = {
pay: function (options, callback) {
let tokenTriggered = false;
_handler = StripeCheckout.configure({
key: Constants[Constants.ENV].STRIPE_KEY,
image: 'image.jpg',
locale: 'auto',
token: function token(token) {
tokenTriggered = true;
const data = {
stripeToken: token.id,
stripeEmail: token.email,
amount: options.amount,
currency: CURRENCY,
capture: options.capture
};
$.ajax({
type: 'POST',
data: JSON.stringify(data),
contentType: 'application/json',
url: '/api/stripe',
success: function success(charge) {
callback(null, charge);
},
error: function error(error) {
callback(error.responseText);
}
});
},
closed: function () {
if (!tokenTriggered) {
// close button click behavior goes here
callback(1);
}
}
});
},
open: function (amount, name, description) {
// Open Checkout with further options:
_handler.open({
name: name,
description: description,
zipCode: true,
currency: 'aud',
amount: amount
});
}
};
The 'pay' function is invoked followed by the 'open' function. The workflow of my app requires the user to pay for stuff twice in one session. In IE11, no Stripe popup is displayed on the second payment. Any ideas?
The following url https://stripe.com/docs/checkout explains that the 'handler.open' code shouldn't be in a callback which it isn't.
The console error is: "SCRIPT70: Permission denied".
** EDIT 07/03/2017 **
This error is only occurring when: a payment is made, another page is navigated to, then another payment is attempted.

I resolved this by initialising the StripeCheckout only once when the site is loaded. I then moved the functionality from "StripeCheckout.configure" into the "handler.open" function and invoked that whenever I need a payment.
init: function () {
_handler = StripeCheckout.configure({
key: Constants[Constants.ENV].STRIPE_KEY,
image: 'image.jpg',
locale: 'auto'
});
},
open: function (options, callback) {
let tokenTriggered = false;
// Open Checkout with further options:
_handler.open({
name: 'An app',
description: options.description,
zipCode: true,
currency: CURRENCY,
amount: options.amount,
token: function token(token) {
tokenTriggered = true;
const data = {
stripeToken: token.id,
stripeEmail: token.email,
amount: options.amount,
currency: CURRENCY,
capture: options.capture
};
$.ajax({
type: 'POST',
data: JSON.stringify(data),
contentType: 'application/json',
url: '/api/stripe',
success: function success(charge) {
// _instantiated = true;
callback(null, charge);
},
error: function error(error) {
callback(error.responseText);
}
});
},
closed: function () {
if (!tokenTriggered) {
// close button click behavior goes here
callback(1);
}
}
});
},

Related

Set isConfirmed to true after timer runs out on SweetAlert2

I am using sweetalert2 when confirming an input from user. I am using a dialog with two buttons , confirm button and cancel button, also I added a timer. When submit button is clicked everything works fine ( ajax is called ) but when timer runs out I want the same result as confirm button. I have tried adding Swal.isConfirmed = true, result=true but didn't get desired one.
Swal.fire({
title: 'Дали сакате да ги зачувате промените?',
showDenyButton: true,
confirmButtonText: 'Зачувај',
confirmButtonColor: '#00CA4E',
denyButtonText: `Откажи`,
denyButtonColor: '#FF605C',
html: '<strong></strong> секунди.<br/>',
timer: 3000,
didOpen: () => {
timerInterval = setInterval(() => {
Swal.getHtmlContainer().querySelector('strong')
.textContent = (Swal.getTimerLeft() / 1000)
.toFixed(0)
}, 100)
},
willClose: () => {
clearInterval(timerInterval);
Swal.isConfirmed = true;
}
}).then((result) => {
/* Read more about isConfirmed, isDenied below */
if (result.isConfirmed) {
console.log('confirmed');
$.ajax({
type: "POST",
url: "#Url.Action("SubstitutionAddPlayers","Scoreboard")",
data: {
jsonSubstitution: substitution,
},
success: function(data) {
},
error: function(req, status, error) {
console.log(msg);
}
})
//Swal.fire('Saved!', '', 'success' )
} else if (result.isDenied) {
//Swal.fire('Changes are not saved', '', 'info')
}
})
I want when timer runs out, result in then to be true and ajax call to be executed.
If a SWAL2 is dismissed from a timer, you can use result.isDismissed the same way as result.isConfirmed in any conditional statement.
if (result.isDismissed) {
// .. code if timer is dismissed
}
if (result.isConfirmed) {
// .. code if timer is confirmed
}
This is the result response if you remove all buttons and let it be:
{isConfirmed: false, isDenied: false, isDismissed: true, dismiss: 'timer'}
So try adding
if (result.isDismissed) {
console.log('confirmed');
$.ajax({
type: "POST",
url: "#Url.Action("
SubstitutionAddPlayers ","
Scoreboard ")",
data: {
jsonSubstitution: substitution,
},
success: function(data) {
},
error: function(req, status, error) {
console.log(msg);
}
})
//Swal.fire('Saved!', '', 'success' )
}
Note: Consider disabling outside click on that specific one maybe.

Ext js 7 modern, form.submit vs ajax.request

I have a Ext.form.Panel with multiple textareafield and fileinput like this
// https://requestbin.com/r/en0ej96odon2sm/1n6r1tb49KK6eObGMPHlYa1hh4C
Ext.create({
xtype: 'formpanel',
renderTo: document.body,
buttons: {
submit: 'onSubmit',
},
controller: {
onSubmit: function () {
var form = this.getView();
form.submit({
method: 'POST',
url: 'https://en0ej96odon2sm.x.pipedream.net/test1',
success: function () {}
});
},
onSubmitTest: function () {
var form = this.getView();
Ext.Ajax.request({
url: 'https://en0ej96odon2sm.x.pipedream.net/test2',
method: 'POST',
params: {
data: form.getValues(),
},
success: function () {}
});
},
},
items: [{
xtype: 'textareafield',
name: 'testfield',
label: 'testfield',
value: 'test\nasd',
}, {
xtype: 'filefield',
label: 'Upload Test',
name: 'basedata-test',
}, {
xtype: 'button',
text: 'Ajax.request(), linebreaks but no files',
handler: 'onSubmitTest',
}]
});
Post Results:
https://requestbin.com/r/en0ej96odon2sm/1n6mtu8QtyreaisCAmV3csO724Q
Fiddle:
https://fiddle.sencha.com/#view/editor&fiddle/3b9j
So, cause i need fileinput/multipart, I have to use form.submit({}).
But when I do so, I don't get the linebreaks on Server side in my $_POST Var.
When I do a ajax.request({}) everything looks good, but $_FILES are missing, so this is not really an option. (but this is documented).
I also tried adding jsonSubmit to the form (then I get no $_POST at all).
When I add enableSubmissionForm: false I get the newline, but after submit the form disappears (and I don't know why).
Is there a solution for this or am I doing something wrong?
You can use the following override. Hope it will not make the framework unstable ;)
// https://requestbin.com/r/en0ej96odon2sm/1n6r1tb49KK6eObGMPHlYa1hh4C
// Override
Ext.define('overrides.form.Panel', {
override: 'Ext.form.Panel',
privates: {
createSubmissionForm: function (form, values) {
var fields = this.getFields(),
name, input, field, fileTrigger, inputDom;
if (form.nodeType === 1) {
form = form.cloneNode(false);
for (name in values) {
input = document.createElement('textarea');
input.setAttribute('type', 'string');
input.setAttribute('name', name);
input.innerHTML = values[name];
form.appendChild(input);
}
}
for (name in fields) {
if (fields.hasOwnProperty(name)) {
field = fields[name];
if (field.isFile) {
// The <input type="file"> of a FileField is its "file" trigger button.
fileTrigger = field.getTriggers().file;
inputDom = fileTrigger && fileTrigger.getComponent().buttonElement.dom;
if (inputDom) {
if (!form.$fileswap) {
form.$fileswap = [];
}
input = inputDom.cloneNode(true);
inputDom.parentNode.insertBefore(input, inputDom.nextSibling);
form.appendChild(inputDom);
form.$fileswap.push({
original: inputDom,
placeholder: input
});
}
} else if (field.isPassword) {
if (field.getInputType() !== 'password') {
field.setRevealed(false);
}
}
}
}
return form;
}
}
});
Ext.create({
xtype: 'formpanel',
renderTo: document.body,
buttons: {
submit: 'onSubmit',
},
controller: {
onSubmit: function () {
var form = this.getView();
form.submit({
method: 'POST',
url: 'https://en0ej96odon2sm.x.pipedream.net/test1',
success: function () {}
});
},
onSubmitTest: function () {
var form = this.getView();
Ext.Ajax.request({
url: 'https://en0ej96odon2sm.x.pipedream.net/test2',
method: 'POST',
params: {
data: form.getValues(),
},
success: function () {}
});
},
},
items: [{
xtype: 'textareafield',
name: 'testfield',
label: 'testfield',
value: 'test\nasd',
}, {
xtype: 'filefield',
label: 'Upload Test',
name: 'basedata-test',
}, {
xtype: 'button',
text: 'Ajax.request(), linebreaks but no files',
handler: 'onSubmitTest',
}]
});
Not ideal, but you also can do this:
form.submit({
method: 'POST',
//just like the ajax
params: {
data: form.getValues(),
},
url: 'https://en0ej96odon2sm.x.pipedream.net/test1',
success: function () {}
});
Here is a simple workaround for using Ajax.request instead of form.submit
I needed that because I have to set an Authorization header, which can't be done with IFRAME used by the framework
So preventing Ext.data.request.Ajax from setting Content-Type header seems to do the job.
multipart/form-data will be automatically set.
Warning : neither options.headers nor defaultHeaders should already have the 'Content-Type' header
Ext.define('Override.data.request.Ajax', {
override: 'Ext.data.request.Ajax',
setupHeaders: function(xhr, options, data, params) {
if (data instanceof FormData) {
if (Ext.apply({}, options.headers || {}, this.defaultHeaders).hasOwnProperty('Content-Type')) {
console.warn('The Content-Type header must not be set before request if you need to use FormData with this override');
}
/* prevent Ext.data.request.Ajax from setting Content-Type header */
return this.callParent([xhr, options, null, null]);
} else {
return this.callParent(arguments);
}
}
});
And call Ajax.request with a FormData as rawData
var formData = new FormData();
var files = myView.down('filefield').getFiles();
if (files.length > 0) {
formData.append('file', files[0], files[0].name);
}
Ext.Ajax.request({
url: 'your_url',
rawData: formData,
success: function(response) {
// handle success
},
failure: function(response) {
// handle failure
}
});

How can redirect to the accounting dashboard when I finish importing an extract?

In the odoo accounting module, there is an option to import bank statements.
When the import is complete it automatically redirects you to the reconciliation view, but I want to redirect it to the accounting dashboard.
Looking I found that the redirection is done by this JavaScript code:
enterprise-13.0/account_bank_statement_import_csv/static/src/js/import_bank_stmt.js:58
exit: function () {
this.do_action({
name: _t("Reconciliation on Bank Statements"),
context: {
'statement_line_ids': this.statement_line_ids
},
type: 'ir.actions.client',
tag: 'bank_statement_reconciliation_view'
});
},
I have tried to modify the code to redirect to the accounting dashboard, but I have not been successful.
exit: function () {
var self = this;
console.log("JavaScript redirection after importing");
// var model_obj = new instance.web.Model('ir.model.data');
// var view_id = false;
// model_obj.call('get_object_reference', ['ir.ui.view', 'account.account_journal_dashboard_kanban_view']).then(function (result) {
// view_id = result[1];
// });
// console.log('view_id');
// console.log(view_id);
// this._rpc({
// model: 'account.move',
// method: 'redirect_return', // Python code that returns the data of the view action.
// }).then(function (result) {
// self.do_action(result);
// });
this.do_action({
name: _t("Reconciliation on Bank Statements"),
context: {
'statement_line_ids': this.statement_line_ids
},
type: 'ir.actions.client',
tag: 'bank_statement_reconciliation_view'
});
},
Your help please.
You can use this._rpc to get the view id then call do_action to redirect.
self._rpc({
model: "ir.model.data",
method: 'get_object_reference',
args: ['account', 'view_account_invoice_report_graph']
}).then(function (result) {
self.do_action({
name: _t('Invoices Analysis'),
type: 'ir.actions.act_window',
res_model: 'account.invoice.report',
views: [[result[1], 'graph']],
view_mode: 'graph',
});
});
You can also use the action external id to read action data
self._rpc({
model: "ir.model.data",
method: 'get_object_reference',
args: ['account', 'action_account_invoice_report_all']
}).then(function (result) {
self._rpc({
model: "ir.actions.act_window",
method: 'read',
args: [[result[1]]]
}).then(function (actions){
self.do_action(actions[0]);
});
});

Problem: pass some parameters in ajax call (post)

I have 2 functions: one to add and another to delete. I would like to reuse the same ajax call to send the parameters that are added or deleted. How can I optimize my function?
Here is my code at the moment
jQuery(document).ready(function () {
function ajaxCall(action, callback) {
jQuery.ajax('/index.php', {
type: 'POST',
dataType: 'json',
data: {
option: 'quotes',
view: 'request',
task: action,
format: 'raw',
tmpl: 'component'
},
success: function (response) {
if (response.error == true) {
alert(response.errors.join('\n'));
}
else if (response.status == "DONE") {
callback(false);
}
},
error: function (xhr) {
console.log("Error: ", JSON.stringify(xhr));
callback(true);
}
});
}
jQuery('#ajax_add').click(function (event) {
event.stopPropagation();
var id = jQuery('#id').val();
var price = jQuery('#price').val();
//I want to send two variables: id, price
ajaxCall("addData", function (error) {
if (error) {
alert("Error!.");
}
else {
alert("It's OK!");
}
});
});
});
The function to delete is similar to "addData" function, it also calls "ajaxCall" and will send parameters to remove.
I'm blocked and I do not know how to solve it, I hope you can give me some help, thanks
You could add a new argument to the ajaxCall function and send the parameters as an object them merge them with the data you've in the function like :
function ajaxCall(action, params, callback) {
Then in the ajax call :
jQuery.ajax('/index.php', {
type: 'POST',
dataType: 'json',
data: $.extend(params, {
option: 'quotes',
view: 'request',
task: action,
format: 'raw',
tmpl: 'component'
}),
...
The call inside the event will be like :
ajaxCall("addData", {id: id, price: price}, function (error) {

Get hold of json content that is being sent to Jquery

That's how I reach when I send some values that are specified in my input and therefore they need to send to a API.
When I try to send them to the monkey, my monkey tells me that nothing has been sent.
At my console.log(token), it tells me what data is available and I also agree that it all fits together. But the problem is just that it has to come over to my API.
function PayStripe() {
// Open Checkout with further options:
handler.open({
name: 'XXX ',
description: 'XX abonnement',
currency: "dkk",
amount: $('#HiddenPrice').val() * 100,
email: $('#Email').val()
});
};
// Close Checkout on page navigation:
$(window).on('popstate', function () {
handler.close();
});
var handler = StripeCheckout.configure({
key: 'pk_test_xxxx',
locale: 'auto',
token: function (token) {
token.subscriptionId = $('#SubscriptionId').val();
token.City = $('#City').val();
token.Postnr = $('#Postnr').val();
token.Mobil = $('#Mobil').val();
token.Adresse = $('#Adresse').val();
token.CVRVirksomhed = $('#CVRVirksomhed').val();
console.log(token.subscriptionId);
console.log(token);
$.ajax({
type: "POST",
url: "/api/Stripe",
contentType: "application/json",
data: token,
success: function (data) {
//window.location.href = '/Subscriptions/Succes';
alert(data + "Succes")
},
error: function (data) {
console.log(data + "Error");
},
dataType: 'json'
});
// You can access the token ID with `token.id`.
// Get the token ID to your server-side code for use.
}
});
Where the problem lies is that the API is by no means able to get informed information from jquery. so it's like it can not / will receive it.
[HttpPost]
[Route("api/Stripe")]
[Produces("application/json")]
public async Task<IActionResult> Post([FromForm] JObject token)
When I grab the token that I need for example. then I do this here:
var SubscriptionId = (int)token.GetValue("subscriptionId");
When you set contentType: "application/json", you need to stringify the data to json yourself
data: JSON.stringify(token),

Categories

Resources