I need help with calling a Javascript method from .NET c# backend.
From what I understand, I need to take paymentIntent from my backend and post it to client side, and call stripe.confirmCardPayment
This is how Javascript looks like:
// Pass the failed PaymentIntent to your client from your server
stripe.confirmCardPayment(intent.client_secret, {
payment_method: intent.last_payment_error.payment_method.id
}).then(function(result) {
if (result.error) {
// Show error to your customer
console.log(result.error.message);
} else {
if (result.paymentIntent.status === 'succeeded') {
// The payment is complete!
}
}
});
This is how my .NET c# code looks like:
try
{
var service = new PaymentIntentService();
var options = new PaymentIntentCreateOptions
{
Amount = 1099,
Currency = "usd",
Customer = "{{CUSTOMER_ID}}",
PaymentMethod = "{{PAYMENT_METHOD_ID}}",
Confirm = true,
OffSession = true,
};
service.Create(options);
}
catch (StripeException e)
{
switch (e.StripeError.ErrorType)
{
case "card_error":
// Error code will be authentication_required if authentication is needed
Console.WriteLine("Error code: " + e.StripeError.Code);
var paymentIntentId = e.StripeError.PaymentIntent.Id;
var service = new PaymentIntentService();
var paymentIntent = service.Get(paymentIntentId);
Console.WriteLine(paymentIntent.Id);
break;
default:
break;
}
}
This flow is covered in this guide to accepting a payment. On each of the server-side code examples you can select the ".NET" tab to see the code for your preferred server language.
You haven't shown how you're initially collecting payment details, so I assume you're using a payment method already attached to a known customer. YOu've also not shown how you're sending the payment data back to the client, but in your javascript snippets it looks like you have the entire intent object. I wouldn't recommend that, and suggest instead sending only what you need. Here, say, just a client_secret and payment_method_id to use in confirmCardPayment.
Related
This is a follow up to the successful call using Netsuite Token Based Authentication (TBA) REST webservice,
I would like to get some guidance on how to create a NEW ENTRY RECORD.
Here is my custom type record entry list (please see screenshot)
https://gist.github.com/axilaris/4386c3537d04737d3775c156562b7545 <-- here is the python code for the TBA that has worked successful. I would like to know how to construct the next step on how to create a new entry.
This is a custom record with an ID like this customrecord1589
FYI - here is my other question on query Netsuite - REST API - Making query with Token Based Authentication (TBA) - (in Python)
But this question would be creating a new entry record
Within your restlet you need to use the N/record module to create a new custom record, here is what is should look similar to:
/**
* #NApiVersion 2.1
* #NScriptType Restlet
*/
define(["N/log", "N/record"], function (log, record) {
function post(context) {
return JSON.stringify(createCustomRecord(context));
}
function createCustomRecord(context) {
let success = true;
try {
let custRec = record.create({
type: "customrecord1589",
isDynamic: true,
});
//Set one or more fields here
custRec.setValue({
fieldId: "custrec123",
value: context.custrec123,
});
custRec.save();
} catch (e) {
log.error("Error creating record", e);
success = false;
}
return { success: success };
}
return {
post: post,
};
});
The Problem:
I have been unable to use Firebase (Google) Cloud Functions to collect and utilize device tokens for the cloud messaging feature.
Context:
I am a self-taught android-Java developer and have no JavaScript experience. Despite that, I believe I have code that should work and am not sure what the problem is. To my understanding, it could be one of three things:
Somehow my Firebase Realtime Database references are being called incorrectly and I am not retrieving data as expected.
I may need to use Promises to wait for all calls to be made before proceeding, however I don't really understand how I would incorporate that into the code I have.
I may be using multiple return statements incorrectly (which I am also fuzzy on).
My error message on the Firebase Realtime Database console is as follows:
#firebase/database: FIREBASE WARNING: Exception was thrown by user callback. Error: Registration token(s) provided to sendToDevice() must be a non-empty string or a non-empty array.
at FirebaseMessagingError.FirebaseError [as constructor] (/srv/node_modules/firebase-admin/lib/utils/error.js:42:28)
at FirebaseMessagingError.PrefixedFirebaseError [as constructor] (/srv/node_modules/firebase-admin/lib/utils/error.js:88:28)
at new FirebaseMessagingError (/srv/node_modules/firebase-admin/lib/utils/error.js:254:16)
at Messaging.validateRegistrationTokensType (/srv/node_modules/firebase-admin/lib/messaging/messaging.js:729:19)
at Messaging.sendToDevice (/srv/node_modules/firebase-admin/lib/messaging/messaging.js:328:14)
at admin.database.ref.once.snapshot (/srv/index.js:84:12)
at onceCallback (/srv/node_modules/#firebase/database/dist/index.node.cjs.js:4933:51)
at /srv/node_modules/#firebase/database/dist/index.node.cjs.js:4549:22
at exceptionGuard (/srv/node_modules/#firebase/database/dist/index.node.cjs.js:698:9)
at EventList.raise (/srv/node_modules/#firebase/database/dist/index.node.cjs.js:9684:17)
The above indicates I am not retrieving data either at all or by the time the return is called. My JavaScript function code is:
'use strict';
const admin = require('firebase-admin');
admin.initializeApp();
exports.pushNotification = functions.database.ref('/Chat Messages/{chatId}/{pushID}').onCreate((snapshot, context) => {
const valueObject = snapshot.after.val();
return admin.database().ref(`/Chat Basics/${valueObject.chatKey}/Chat Users`).once('value', statusSnapshot => {
var index = 0;
var totalkeys = statusSnapshot.numChildren();
var msgIDs = [];
statusSnapshot.forEach(msg=>{
msgIDs.push(msg.key.toString());
if(index === totalkeys - 1){
const payload = {
notification : {
title: valueObject.userName,
body: valueObject.message,
sound: "default"
}
}
sendNotificationPayload(valueObject.uid, payload);
}
index++;
});
});
});
function sendNotificationPayload(uid, payload){
admin.database()
.ref(`/User Token Data/${uid}`)
.once('value', snapshot=> {
var tokens = [];
//if(!snapshot.exists())return;
snapshot.forEach(item =>{
tokens.push(item.val())
});
admin.messaging()
.sendToDevice(tokens, payload)
.then(res => {
return console.log('Notification sent')
})
.catch(err => {
return console.log('Error in sending notification = '+err)
});
});
}
This code is mostly inspired by what was said to be a working example here from another Stack Overflow question here. I have successfully tested sending a notification to a single device by manually copying a device token into my function, so the function does run to completion. My Java code seems to be irrelevant to the problem, so I have not added it (please ask in the comments if you would like it added for further context).
What I Have Tried:
I have tried implementing promises into my code, but I don't think I was doing it properly. My main reference for this was here. I have also looked at the documentation for literally everything related to this topic, however my knowledge of JS is not sufficient to really apply barebones examples to my code.
My Firebase Realtime Database Nodes:
#1: Loop through chat members to collect user IDs:
"Chat Basics" : {
"1607801501690_TQY41wIfArhHDxEisyupZxwyHya2" : {
"Chat Users" : {
"JXrclZuu1aOwEpCe6KW8vSDea9h2" : true,
"TQY41wIfArhHDxEisyupZxwyHya2" : true
},
#2: Collect user tokens from collected IDs (ignore that tokens are matching):
"User Token Data" : {
"JXrclZuu1aOwEpCe6KW8vSDea9h2" : "duDR3KH3i3I:APA91bH_LCeslZlqL8akYw-LrM9Dv__nx4nU1TquCS0j6bGF1tlIARcheREuNdX1FheC92eelatBC8LO4t6gt8liRdFHV-NDuNLa13oHYxKgl3JBPPlrMo5rB5XhH7viTo4vfYOMftRi",
"TQY41wIfArhHDxEisyupZxwyHya2" : "duDR3KH3i3I:APA91bH_LCeslZlqL8akYw-LrM9Dv__nx4nU1TquCS0j6bGF1tlIARcheREuNdX1FheC92eelatBC8LO4t6gt8liRdFHV-NDuNLa13oHYxKgl3JBPPlrMo5rB5XhH7viTo4vfYOMftRi"
}
Conclusion:
Concrete examples would be much appreciated, especially since I am crunching right now. Thanks for your time and help!
Update:
After some more testing, it looks like the problem is definitely due to my lack of understanding of promises in two areas. Firstly, only one user is collected before the final return is called. Secondly, the final return is called before the 2nd forEach() loop can store snapshot data to an array.
For this code then, how may I modify (or rebuild) it so that it collects all keys before proceeding to retrieve token data from all keys - ultimately before returning the notification?
Just as with every question I post, I managed to figure out how to do it (tentatively) a few hours later. Below is a full example of how to send a notification to chat users based on a message sent (although it does not yet exclude the sender) to a given chat. The order of operations are as such:
User message is saved and triggers event. Relevant data the message contains are:
username, chat key, message
These are retrieved, with (username + message) as the (title + body) of the
notification respectively, and the chat key is used for user id reference.
Loop through chat user keys + collect.
Loop through array of chat user keys to collect array of device tokens.
Send notification when complete.
The code:
//Use firebase functions:log to see log
exports.pushNotification = functions.database.ref('/Chat Messages/{chatId}/{pushId}').onWrite((change, context) => {
const valueObject = change.after.val();
return admin.database().ref(`/Chat Basics/${valueObject.chatKey}/Chat Users`).once('value', statusSnapshot => {
var index = 0;
var totalkeys = statusSnapshot.numChildren();
var msgIDs = [];
statusSnapshot.forEach(msg=>{
msgIDs.push(msg.key.toString());
if(index === totalkeys - 1){
const payload = {
notification : {
title: valueObject.userName,
body: valueObject.message,
sound: "default"
}
}
let promises = [];
var tokens = [];
for(let i=0; i < msgIDs.length; i++){
let userId = msgIDs[i];
let promise = admin.database().ref(`/User Token Data/${userId}`).once('value', snapshot=> {
tokens.push(snapshot.val());
})
promises.push(promise);
}
return Promise.all(promises).then(() => {
return admin.messaging().sendToDevice(tokens, payload);
});
}
index++;
return false;
});
});
});
Im trying to sign a BlockCypher transaction on the bitcoin testnet using bitcoinjs as described here but I keep getting the error:
{"error": "Couldn't deserialize request: invalid character 'x' in literal true (expecting 'r')"}
I have searched around and can find no documentation on what the problem is. Below is the code im using to try and sign the transaction.
var bitcoin = require("bitcoinjs-lib");
var buffer = require('buffer');
var keys = new bitcoin.ECPair.fromWIF('cMvPQZiG5mLARSjxbBwMxKwzhTHaxgpTsXB6ymx7SGAeYUqF8HAT', bitcoin.networks.testnet);
const publicKey = keys.publicKey;
console.log(keys.publicKey.toString("hex"));
var newtx = {
inputs: [{addresses: ['ms9ySK54aEC2ykDviet9jo4GZE6GxEZMzf']}],
outputs: [{addresses: ['msWccFYm5PPCn6TNPbNEnprA4hydPGadBN'], value: 1000}]
};
// calling the new endpoint, same as above
$.post('https://api.blockcypher.com/v1/btc/test3/txs/new', JSON.stringify(newtx))
.then(function(tmptx) {
// signing each of the hex-encoded string required to finalize the transaction
tmptx.pubkeys = [];
tmptx.signatures = tmptx.tosign.map(function(tosign, n) {
tmptx.pubkeys.push(keys.publicKey.toString("hex"));
return keys.sign(new buffer.Buffer(tosign, "hex")).toString("hex");
});
// sending back the transaction with all the signatures to broadcast
$.post('https://api.blockcypher.com/v1/btc/test3/txs/send', tmptx).then(function(finaltx) {
console.log(finaltx);
}).catch(function (response) {
console.log(response.responseText);
});
}).catch(function (response) {
console.log(response.responseText);
});
It seems this line return keys.sign(new buffer.Buffer(tosign, "hex")).toString("hex"); is the problem but im not sure on what is wrong.
This question was discussed and answered here. This post and this one are to be looked into in particular.
As far as I understand, according to the issue respective one was opened at BlockCypher repo. Although its status is still opened till this date, current BlockCypher JS docs respective API description contains altered version of the line
return keys.sign(new buffer.Buffer(tosign, "hex")).toString("hex");
with toDER() conversion prior to toString(), consequently it looks like this now
return keys.sign(new buffer.Buffer(tosign, "hex")).toDER().toString("hex");
How do i set the "end conversation" flag using the Dialogflow Fulfillment Library WebhookClient class? I'm using the inline editor powered by Cloud Functions for Firebase, in case that matters.
The situation is that a particular intent cannot be visited more than 3 times. On the first and second visits you get a response, and it allows you to say something and continue; on the third visit, it should give a response then end the conversation/close the mic/kill the app (whatever the proper term is for this)
For non-ending responses i'm using WebhookClient.add(), and i'm using a mix of rich responses, and strings for Text to Speech.
From what I read on github (https://github.com/dialogflow/dialogflow-fulfillment-nodejs), i assumed WebhookClient.end() would be what i wanted. But when i use that, the sript crashes and i get nothing.
The following is all inside exports.dialogflowFirebaseFulfillment = functions.https.onRequest((request, response) => {...}
const agent = new WebhookClient({ request, response });
const fbContext = 'fallbackcount';
function fallback(agent) {
//all fallbacks use this fulfillment, we give up after 3 bunk responses
//check if we've been here before - we will find a context with a counter if we have
let countContext = agent.getContext(fbContext);
let fbcount = 0;
if (countContext)
{
if (typeof countContext.parameters !== "undefined" )
{
if(typeof countContext.parameters.count !== "undefined" )
{
fbcount = countContext.parameters.count;
}
}
}
console.log("current tracking" + fbcount.toString());
switch(fbcount) {
case 0:
{
agent.add(`Fallback response 1");
break;
}
case 1:
{
agent.add("Fallback response 2");
break;
}
default:
{
//intention: die on third bunk response
//reality: following line causes a problem and i get no response, and the app doesn't close
agent.end("Fallback response 3 - Goodbye!");
}
}
let newcount = fbcount + 1;
console.log("new tracking " + newcount.toString());
agent.setContext({
name: fbContext,
lifespan: 1,
parameters:{count: newcount}
});
}
What am i doing wrong?
Please note that this is NOT a duplicate of Actions on Google: Unable to Close Convo in DialogFlow Fulfillment as he is asking regarding the actions-on-google library, wheras I am using dialogflow-fulfillment-nodejs
I have also seen Dialogflow API V2 "End of conversation" flag in webhook request and that appears to be dealing in raw json, which i believe should be avoidable from what i've seen in docs
I don't know if this is the correct way to do it in this case, but I guess you could use a payload response to close the conversation, in which you set the "expectedUserResponse" to "false":
const googlePayloadJson = {
"expectUserResponse": false
};
let payload = new Payload(agent.ACTIONS_ON_GOOGLE, {});
payload.setPayload(googlePayloadJson);
agent.add(payload);
This worked for me:
function close(message){
let conv = agent.conv();
conv.close(message);
agent.add(conv);
}
How do i customize a PersistedModel in loopback ? Let's say i have two models Post and Comment. A Post hasMany Comment but it can have at most 3 comments. How can i implement that without using hooks? Also i need to do it inside a transaction.
I'm coming from java and this is how i would do that:
class Post {
void addComment(Comment c) {
if(this.comments.size() < 3)
this.comments.add(c)
else
throw new DomainException("Comment count exceeded")
}
}
then i would write a service ...
class PostService {
#Transactional
public void addCommentToPost(postId, Comment comment) {
post = this.postRepository.findById(postId);
post.addComment(comment)
this.postRepository.save(post);
}
}
I know i could write something like:
module.exports = function(app) {
app.datasources.myds.transaction(async (models) => {
post = await models.Post.findById(postId)
post.comments.create(commentData); ???? how do i restrict comments array size ?
})
}
i want to be able to use it like this:
// create post
POST /post --> HTTP 201
// add comments
POST /post/id/comments --> HTTP 201
POST /post/id/comments --> HTTP 201
POST /post/id/comments --> HTTP 201
// should fail
POST /post/id/comments --> HTTP 4XX ERROR
What you are asking here is actually one of the good use cases of using operation hooks, beforesave() in particatular. See more about it here here
https://loopback.io/doc/en/lb3/Operation-hooks.html#before-save
However, I'm not so sure about the transaction part.
For that, I'd suggest using a remote method, it gives you complete freedom to use the transaction APIs of loopback.
One thing to consider here is that you'll have to make sure that all comments are created through your method only and not through default loopback methods.
You can then do something like this
// in post-comment.js model file
module.exports = function(Postcomment){
Postcomment.addComments = function(data, callback) {
// assuming data is an object which gives you the postId and commentsArray
const { comments, postId } = data;
Postcomment.count({ where: { postId } }, (err1, count) => {
if (count + commentsArray.length <= 10) {
// initiate transaction api and make a create call to db and callback
} else {
// return an error message in callback
}
}
}
}
You can use validateLengthOf() method available for each model as part of the validatable class.
For more details refer to Loopback Validation
i think i have found a solution.
whenever you want to override methods created by model relations, write a boot script like this:
module.exports = function(app) {
const old = app.models.Post.prototype.__create__comments;
Post.prototype.__create__orders = function() {
// **custom code**
old.apply(this, arguments);
};
};
i think this is the best choice.