Currently I try to integrate amazon payment.
I want to display the button, created with the function:
OffAmazonPayments.Button("AmazonPayButton", myAmznMerchantID
and after the User has logged in, I want to display the AdressBook Widget and the Payment Widget on the same Page.
The Button and the Widgets are displayed correctly, but when I try to confirm the Payment, I'm getting the Error-Constrains Message:
PaymentPlanNotSet The buyer has not been able to select a Payment
method for the given Order Reference.
But the Payment was selected.
I hope you can help me, to find my failure in this Javascript code:
window.onAmazonLoginReady = function () {
amazon.Login.setClientId(myAmznClientID);
};
window.onAmazonPaymentsReady = function() {
var __accessToken = 0;
var __orderReferenceId = 0;
show_amazon_Button();
function show_amazon_Button() {
OffAmazonPayments.Button("AmazonPayButton", ibuiAmazonPaymentsInfos.ibAmznMerchantID, {
type: "PwA",
color: "Gold",
size: "small", // "medium",
language: "de-DE",
authorization: function () {
loginOptions = { scope: "profile:user_id", popup: true };
authRequest = amazon.Login.authorize(loginOptions, function(response) {
if (response.error) {
//show Error
return;
} else {
__accessToken = response.access_token;
show_Adress_Widget();
}
});
},
onError: function(error) {
//handleError
}
});
}
function show_Adress_Widget() {
new OffAmazonPayments.Widgets.AddressBook({
sellerId: ibuiAmazonPaymentsInfos.ibAmznMerchantID,
onOrderReferenceCreate: function (orderReference) {
__orderReferenceId = orderReference.getAmazonOrderReferenceId();
//do Stuff
},
onAddressSelect: function (orderReference) {
show_Amazon_Wallet();
},
design: {
designMode: 'responsive'
},
onError: function (error) {
//handle Error
}
}).bind("readOnlyAddressBookWidgetDiv");
}
function show_Amazon_Wallet() {
new OffAmazonPayments.Widgets.Wallet({
sellerId: myAmznMerchantID,
onOrderReferenceCreate: function(orderReference) {
//do Stuff
},
design: {
designMode: 'responsive'
},
onPaymentSelect: function(orderReference) {
//activate buy button
},
onError: function(error) {
//handle error
}
}).bind('AmazonWalletWidgetDiv');
}
} //onAmazonPaymentsReady
In PHP I create the OrderReference over:
$params = array(
'order_reference_id' => $orderReferenceId,
'amount' => $amount,
'seller_order_id' => $buchungsKopf->getBuchung_nr(),
);
$responseObject = $client->setOrderReferenceDetails($params);
And even if I had selected a payment method before, I'm getting the "PaymentPlanNotSet" in the responseObject.
Same error, when I try to confirm the orderReference
$responseObject2 = $client->confirmOrderReference($params);
Before I had integrate the AdressWidget, I was able to do the payment.
Can you see what I'm doing wrong?
It seems I have found my failure.
When I want to display both Widgets (Adress and Wallet) on the same page, then I can not use the onOrderReferenceCreate-Method in the OffAmazonPayments.Widget.Wallet.
It seems like then it create a new order reference wich is not the same as the orderreference created by the AdressBook Widget.
Now I have delete this part of the Wallet Widget and everything seems to work fine.
Related
I am writing a chrome extension that makes requests to an API and I have noticed that after I create a notification from background script using chrome's notification API, the listeners on the buttons from the notification are executed multiple times. on the first run only once and then increasing. I figured that the listeners just add up on the page but I couldn't find a way to sort of refresh the background page.
This is the function that creates the notification and it's listeners.
var myNotificationID
const displayNotification=(userEmail, password, website,username) =>{
chrome.notifications.create("", {
type: "basic",
iconUrl: "./icon128.png",
title: "PERMISSION",
requireInteraction: true,
message: "question",
buttons: [{
title: "YES",
}, {
title: "NO",
}]
}, function(id) {
myNotificationID = id;
})
chrome.notifications.onButtonClicked.addListener(function(notifId, btnIdx) {
if (notifId === myNotificationID) {
if (btnIdx === 0) {
console.log('inserting')
try{
fetch (`http://localhost:8080/users/${userEmail}/accounts`,{
})
}catch(err){
}
} else if (btnIdx === 1) {
console.log('clearing')
chrome.notifications.clear(myNotificationID)
}
}
});
}
And this is where the function is called
chrome.runtime.onMessage.addListener((message, sender, response)=>{
if(message.message === 'showNotification'){
console.log('received insert')
displayNotification(message.userEmail,message.password, message.currentSite,message.username)
response({status:"received"})
}
})
the fetch within the listener is executed multiple times but the log from the onMessage listener is only displayed once, so the listener is the problem here.
I tried chrome.notifications.onButtonClicked.removeListener(), but as i mentioned there was no success.
Are there any other ways in which i could clean the listeners from the background script once they are used?
Using a notification store:
const notificationsByID = {};
chrome.notifications.onButtonClicked.addListener((notifId, btnIdx) => {
// Avoid access to the notification if not registered by displayNotification
if (!notificationsByID[ notifId ]) { return null; }
if (btnIdx === 0) {
console.log('inserting')
try{
fetch (`http://localhost:8080/users/${ notificationsByID[ notifId ].userEmail }/accounts`,{ /**/ });
}catch(err){
console.log(err);
}
delete notificationsByID[ notifId ]; // Cleanup
} else if (btnIdx === 1) {
console.log('clearing')
chrome.notifications.clear(myNotificationID);
delete notificationsByID[ notifId ]; // Cleanup
}
});
chrome.notifications.onClosed.addListener((notifId) => {
if (notificationsByID[ notifId ]) { delete notificationsByID[ notifId ]; }
});
const displayNotification=(userEmail, password, website,username) =>{
chrome.notifications.create("", {
type: "basic",
iconUrl: "./icon128.png",
title: "PERMISSION",
requireInteraction: true,
message: "question",
buttons: [{ title: "YES", }, { title: "NO", }]
}, function(id) {
// Insertion
notificationsByID[ id ] = { userEmail, password, website,username };
})
}
I want to remove a data from firebase but all documents I have found all said use .remove() function as I show as codesnippet here. But this is not work at Ionic 3. Is that function is changed or what is the point that I didn't see.
selectBook(indexOfBook : Book){
this.actionSheetCtrl.create({
title: indexOfBook.nameOfBook,
buttons:[{
text:'Edit',
handler: () =>{
// TODO:Send the user to EditPage
}
},
{
text:'Delete',
role: 'destructive',
handler: () => {
this.getBookRef$.remove(indexOfBook.key);//**************************************
}
},
{
text:'Cancel',
role:'cancel',
handler: () =>{
console.log("The user has selected the cancel button");
}
}
]
}).present();
}
is there a way to automatically submit the form after the user has chosen a payment method with the Braintree Drop-in?
The problem is that the user is asked to choose a payment method, then press Ok, then again Ok, then press the actual Checkout button on my page.
It is a very weird behavior.
Here's the code I use to create the Drop-In.
<script>
var form = document.querySelector('#payment-form');
var nonceInput = document.querySelector('#nonce');
braintree.dropin.create({
authorization: '{{ $client_token }}',
container: '#dropin-container',
paypal: {
flow: 'vault',
currency: 'EUR',
buttonStyle: {
color: 'blue',
shape: 'rect',
size: 'medium'
}
},
card: {
cardholderName: true
}
}, function (err, dropinInstance) {
if (err) {
// Handle any errors that might've occurred when creating Drop-in
console.error(err);
return;
}
form.addEventListener('submit', function (event) {
event.preventDefault();
dropinInstance.requestPaymentMethod(function (err, payload) {
if (err) {
// Handle errors in requesting payment method
return;
}
$.fancybox.open({
src : '#processing-loading',
type : 'inline',
opts : {
toolbar: false,
buttons: false,
smallBtn: false
}
});
// Send payload.nonce to your server
nonceInput.value = payload.nonce;
form.submit();
});
});
});
</script>
I want to show the edit page of the record by clicking the custom button instead of the "standard edit button"
My Code:
Script Version: Suite Script 2.0
User Event Script:
function beforeLoad(context) {
log.debug('Test', 'Before Load Event Initiated');
var frm = context.form;
frm.clientScriptFileId = 2250;
//Values from System/ScriptContext
var record = context.newRecord;
if (context.type == context.UserEventType.VIEW) {
frm.addButton({
id: 'custpage_cust_edit_btn',
label: 'Deactivate Record',
functionName: 'customRecordEditMode(' + record.id + ')'
});
}
}
Client Script:
function customRecordEditMode(recordID) {
debugger;
try {
window.location.href = "https://system.sandbox.netsuite.com/app/common/custom/custrecordentry.nl?rectype=194&id=" + recordID + "&e=T";
} catch (exception) {
alert("Error:", exception.message);
}
}
ERROR Message:
I'm Getting the Following Error Message:
but the url of the record is same as in when we click the standard "Edit" Button. (i,e) rectype=194&id=237&e=T
thanks in advance
I'm not exactly sure why you would be getting this error with the raw URL, but instead of using the raw URL, have you tried utilizing the N/url module?
require(['N/url', 'N/record'], function(url, r) {
var output = url.resolveRecord({
recordType: r.Type.SALES_ORDER,
recordId: 6,
isEditMode: true
});
});
or perhaps even better would be the N/redirect module:
require(['N/redirect', 'N/record'], function(redirect, r) {
redirect.toRecord({
"type": r.Type.TASK,
"id": 6,
"isEditMode": true
});
});
Which interface or component do you suggest to display the state of parallel async calls? (The language is not so important for me, just the pattern, I can rewrite the same class / interface in javascript...)
I load model data from REST service, and I want to display pending label before the real content, and error messages if something went wrong... I think this is a common problem, and there must be an already written component, or best practices, or a pattern for this. Do you know something like that?
Here is a spaghetti code - Backbone.syncParallel is not an existing function yet - which has 2 main states: updateForm, updated. Before every main state the page displays the "Please wait!" label, and by error the page displays an error message. I think this kind of code is highly reusable, so I think I can create a container which automatically displays the current state, but I cannot decide what kind of interface this component should have...
var content = new Backbone.View({
appendTo: "body"
});
content.render();
var role = new Role({id: id});
var userSet = new UserSet();
Backbone.syncParallel({
models: [role, userSet],
run: function (){
role.fetch();
userSet.fetch();
},
listeners: {
request: function (){
content.$el.html("Please wait!");
},
error: function (){
content.$el.html("Sorry, we could not reach the data on the server!");
},
sync: function (){
var form = new RoleUpdateForm({
model: role,
userSet: userSet
});
form.on("submit", function (){
content.$el.html("Please wait!");
role.save({
error: function (){
content.$el.html("Sorry, we could not save your modifications, please try again!");
content.$el.append(new Backbone.UI.Button({
content: "Back to the form.",
onClick: function (){
content.$el.html(form.$el);
}
}));
},
success: function (){
content.$el.html("You data is saved successfully! Please wait until we redirect you to the page of the saved role!");
setTimeout(function (){
controller.read(role.id);
}, 2000);
}
});
}, this);
form.render();
content.$el.html(form.$el);
}
}
});
I created a custom View to solve this problem. (It is in beta version now.)
Usage: (Form is a theoretical form generator)
var content = new SyncLabelDecorator({
appendTo: "body",
});
content.load(function (){
this.$el.append("normal html without asnyc calls");
});
var User = Backbone.Model.extend({
urlRoot: "/users"
});
var UserSet = Backbone.Collection.extend({
url: "/users",
model: User
});
var Role = Backbone.RelationalModel.extend({
relations: [{
type: Backbone.HasMany,
key: 'members',
relatedModel: User
}]
});
var administrator = new Role({id :1});
var users = new UserSet();
content.load({
fetch: [role, users],
sync: function (){
var form = new Form({
title: "Update role",
model: role,
fields: {
id: {
type: "HiddenInput"
},
name: {
type: "TextInput"
},
members: {
type: "TwoListSelection",
alternatives: users
}
},
submit: function (){
content.load({
tasks: {
save: role
},
sync: function (){
this.$el.html("Role is successfully saved.");
}
});
}
});
this.$el.append(form.render().$el);
}
});
Code:
var SyncLabelDecorator = Backbone.View.extend({
options: {
pendingMessage: "Sending request. Please wait ...",
errorMessage: "An unexpected error occured, we could not process your request!",
load: null
},
supported: ["fetch", "save", "destroy"],
render: function () {
if (this.options.load)
this.load();
},
load: function (load) {
if (load)
this.options.load = load;
this._reset();
if (_.isFunction(this.options.load)) {
this.$el.html("");
this.options.load.call(this);
return;
}
_(this.options.load.tasks).each(function (models, method) {
if (_.isArray(models))
_(models).each(function (model) {
this._addTask(model, method);
}, this);
else
this._addTask(models, method);
}, this);
this._onRun();
_(this.tasks).each(function (task) {
var model = task.model;
var method = task.method;
var options = {
beforeSend: function (xhr, options) {
this._onRequest(task, xhr);
}.bind(this),
error: function (xhr, statusText, error) {
this._onError(task, xhr);
}.bind(this),
success: function (data, statusText, xhr) {
this._onSync(task, xhr);
}.bind(this)
};
if (model instanceof Backbone.Model) {
if (method == "save")
model[method](null, options);
else
model[method](options);
}
else {
if (method in model)
model[method](options);
else
model.sync(method == "fetch" ? "read" : (method == "save" ? "update" : "delete"), model, options);
}
}, this);
},
_addTask: function (model, method) {
if (!_(this.supported).contains(method))
throw new Error("Method " + method + " is not supported!");
this.tasks.push({
method: method,
model: model
});
},
_onRun: function () {
this.$el.html(this.options.pendingMessage);
if (this.options.load.request)
this.options.load.request.call(this);
},
_onRequest: function (task, xhr) {
task.abort = function () {
xhr.abort();
};
},
_onError: function (task, xhr) {
this._abort();
this.$el.html(this.options.errorMessage);
if (this.options.load.error)
this.options.load.error.call(this);
},
_onSync: function (task, xhr) {
++this.complete;
if (this.complete == this.tasks.length)
this._onEnd();
},
_onEnd: function () {
this.$el.html("");
if (this.options.load.sync)
this.options.load.sync.call(this);
},
_reset: function () {
this._abort();
this.tasks = [];
this.complete = 0;
},
_abort: function () {
_(this.tasks).each(function (task) {
if (task.abort)
task.abort();
});
}
});