Stripe Capture Charge Amount Node and Swift - swift

I am trying to capture a charge with a different amount, but I get an error saying that there's "no such charge" and sometimes that the amount should be lower than the charge, which it is. However, the most frequent error is the "no such charge" one, although the charge is not nil.
This is the Cloud Code function in node.js:
Parse.Cloud.define("cancellationFee", function(request, response){
stripe.charges.capture({
charge: request.params.charge,
amount: 500,
destination: 500
}, function(err, charge) {
if(err){
console.log(err);
response.error(err);
}else{
console.log("Successfully captured cancellation fee");
response.success("captured cancellation fee");
}
});
});
Swift Code
The charge variable is not nil.
PFCloud.callFunctionInBackground("cancellationFee", withParameters: ["charge": chargeID]) { (success: AnyObject?, error: NSError?) -> Void in
if error == nil{
// code
}else{
// code
}
}

For some folks that are still experiencing this problem the correct solution is first passing the charge_id as String and then as a second parameter the amount inside an object like this:
stripe.charges.capture( 'chargeIdExample3242', {amount: 23} );
Source

Are you sure your error isn't due to setting destination to a number? Destination should be an account id. And also should be set when creating a charge, not capturing the charge. You shouldn't be passing any additional parameters to the charge method than the charge you're capturing.
You also shouldn't be setting the charge amount here.

Related

Cloud function http function fails on first run

I am testing with a payment processing system and every time a transaction is completed, the payment processor should hit my endpoint with a POST request with payment details so I can save it to my database (Firestore).
Only thing is the function fails on the first try. What I mean is, say a customer pays, the payment processor hits my cloud function, it fails to save to my database. When a second customer makes the transaction a minute, 5 minutes or even 18 minutes later according to my observation, everything works as expected.
Am I facing a cold start problem or what is happening. And how do I solve this.
Here is my function
exports.stkCallback = functions.https.onRequest(async (request, response) => {
if (request.method === 'POST') {
if (request.body.Body.stkCallback.ResultCode === 0) {
const jsonData = request.body.Body.CallbackMetadata;
console.log("USER HAS COMPLETED THE TRANSACTION");
var transactionID;
///This below line logs successfully everytime meaning my payment processor has sent the POST
/// request
console.log("checkoutid:", request.body.Body.CheckoutRequestID)
///I have saved the CheckoutRequestID previously to Firestore so I first query the document
//// with that ID (CheckoutRequestID) and get its data so I can update the transaction as
//// complete
var docRef=db.collection("Transactions").doc(request.body.Body.CheckoutRequestID);
await docRef.get().then((doc) =>{
// eslint-disable-next-line promise/always-return
if (doc.exists) {
//console.log("Document data:", doc.data());
transactionID=doc.id;
transactionData.push(doc.data());
} else {
// doc.data() will be undefined in this case
console.log("No such document!");
}
}).catch((error)=> {
console.log("Error getting document:", error);
});
///Once I get the data I can then go ahead and do other operations.
///Only the above query fails the first time which I don't know why
///By failing Saying No such Document. Which the document does exist
***carrying out other operations using the fetched transactionID and transactionData***
response.sendStatus(200);
} else {
console.log("USER HAS CANCELLED THE TRANSACTION");
response.sendStatus(200);
}
I have refactored my code and reproduced it to the below
const functions = require('firebase-functions');
const admin = require('firebase-admin');
admin.initializeApp();
const db = admin.firestore();
exports.stkCallback = functions.https.onRequest(async (request, response) => {
const accountSid = "#";
const authToken = "#";
const client = require("twilio")(accountSid, authToken);
if (request.method === 'POST') {
if (request.body.Body.ResultCode === 0) {
const jsonData = request.body.Body.CallbackMetadata;
console.log("USER HAS COMPLETED THE TRANSACTION");
var transactionID;
///This below line logs successfully everytime meaning my
/////payment processor has sent the POST request
console.log("checkoutid:",
request.body.Body.CheckoutRequestID)
////The below function is critical to all the other below functions below it as
///it supplies the necessary data all the way down
///It is also the function that fails on the first run
var docRef= await db.collection("Transactions").doc(request.body.Body.CheckoutRequestID).get()
.catch((error)=> {
console.log("Error getting document:", error);
});
//// a log of some data from the above function
//// when it fails, the below log is undefined,
console.log("tyyy",docRef.data().Home)
transactionID=docRef.id;
////the data returned from above function is used to perform other operations.
////Below is just one of them
////consequently, it will fail as some values like doc.data().Uid will be ////undefined
await db.collection("Users").doc(doc.data().Uid).collection("Transactions").doc(transactionID).update({
TransactionComplete: true,
transactionCompletedTimeDb: admin.firestore.FieldValue.serverTimestamp(),
Amount: jsonData.Item[0].Value,
ReceiptNO: jsonData.Item[1].Value,
TransactionDate: jsonData.Item[3].Value,
PhoneNumber: jsonData.Item[4].Value,
UserId: doc.data().Uid
})
// eslint-disable-next-line promise/always-return
.catch((error)=> {
// The document probably doesn't exist.
console.error("Error updating document: ", error);
});
response.sendStatus(200);
} else {
console.log("USER HAS CANCELLED THE TRANSACTION");
response.sendStatus(200);
}
});
Attaching an image of a failed function, do note the time
An image of logs of the same triggered function right after (3 minutes later). As you can see the function completes successfully
This seems like a Cold Start Issue
The mitigation of this issue will depend on many information that you are not sharing with us like the complete function, dependencies that you are using, and instance size.
Spreading a loaded function into multiple small functions will help with the cold start time, also using smaller, updated, and cloud oriented libraries will also help.
Also, the size of the payload could be an important factor here, how big is the size of the payload sent to the function and how big is the size of the info that you are writing into the logs? All these small pieces have an important influence on the performance of a cold start.
As a quick solution for your Issue, I can safely say that creating a Scheduled task that triggers your functions every 30 minutes, for example, would be enough to mitigate your issue in the short term.

How to activate a PayPal subscription?

I've implemented a recurring payments system using PayPal and the SmartButtons. The customer is able to create the subscription through my system, at the end of the checkout I get the subscription created:
{
"orderID": "3JR7411152833961C",
"subscriptionID": "I-J8CHJ9UKB8JU",
"facilitatorAccessToken": "A21AAElq71jrRrKHzaxxOeA4o7cOie83F_N-LKMZoAe2mhmaANy-a784yj9DUbSlQPIxtu_O-7XyzHWab23gKVgwhqK9Hjaow"
}
in order to activate the subscription and get the payment I need to execute it, so I wrote this method:
let executeAgreement = (paymentToken) => {
paypal.billingAgreement.execute(paymentToken, {}, function (error, billingAgreement) {
if (error) {
console.log(error);
throw error;
}
else {
console.log('Billing Agreement Execute Response');
console.log(JSON.stringify(billingAgreement));
}
});
}
the problem's that I got:
response: {
name: 'BUSINESS_VALIDATION_ERROR',
debug_id: '82426af46aee4',
message: 'Validation Error.',
information_link: 'https://developer.paypal.com/docs/api/payments.billing-agreements#errors',
details: [ [Object] ],
httpStatusCode: 400
},
httpStatusCode: 400
}
I send to executeAgreement the subscriptionId, but I guess the problem it's just that, in the created subscription I only reiceve the id of the subscription not the paymentToken, how can I fix?
Essentially: how can I execute/activate the subscription if I've only the subscription id returned by the following method:
opts.createSubscription = function (data, actions) {
that.step = that.steps.PAYPAL_EXTERNAL_WINDOW;
return actions.subscription.create({
plan_id: that.paymentData.plan.id,
application_context: {
user_action: "CONTINUE",
shipping_preference: 'NO_SHIPPING'
}
});
}
the method above return orderId - subscriptionId - facilitatorAccessToken, seems I'm not able to activate the subscription id after the user as approved the recurring payment through the smart payment buttons.
Actually, I-J8CHJ9UKB8JU is already a created and active subscription and you don't need to execute anything.
The notion of executing a billing agreement is something from old documentation that predates the Subscriptions API.
In the current Sbscriptions API, you would simply create and activate a subscription:
https://developer.paypal.com/docs/api/subscriptions/v1/#subscriptions_create
Followed by either a redirection to an approval URL, or use of the Smart Payment Button (which is much better, since it opens up an "in context" approval -- no need for any redirect)
So anyway, you have your active Subscription ID: I-J8CHJ9UKB8JU
Now just save this object and associate it with your customer object.

How to stop the user from entering the duplicate record on default save

I have a custom module where there is an email field. Now i want to stop the user if the email is already in the database.
I want to stop the user on save button and show the error. Like when a required field goes empty.
I tried to get some help but was not able to understand it.
Note: I realized after posting this that you are using suitecrm which this answer will not be applicable toward but I will leave it in case anyone using Sugar has this question.
There are a couple of ways to accomplish this so I'll do my best to walk through them in the order I would recommend. This would apply if you are using a version of Sugar post 7.0.0.
1) The first route is to manually create an email address relationship. This approach would use the out of box features which will ensure your system only keeps track of a single email address. If that would work for your needs, you can review this cookbook article and let me know if you have any questions:
https://support.sugarcrm.com/Documentation/Sugar_Developer/Sugar_Developer_Guide_9.2/Cookbook/Adding_the_Email_Field_to_a_Bean/
2) The second approach, where you are using a custom field, is to use field validation. Documentation on field validation can be found here:
https://support.sugarcrm.com/Documentation/Sugar_Developer/Sugar_Developer_Guide_9.2/Cookbook/Adding_Field_Validation_to_the_Record_View/index.html
The code example I would focus on is:
https://support.sugarcrm.com/Documentation/Sugar_Developer/Sugar_Developer_Guide_9.2/Cookbook/Adding_Field_Validation_to_the_Record_View/#Method_1_Extending_the_RecordView_and_CreateView_Controllers
For your example, I would imagine you would do something like this:
Create a language key for your error message:
./custom/Extension/application/Ext/Language/en_us.error_email_exists_message.php
<?php
$app_strings['ERROR_EMAIL_EXISTS_MESSAGE'] = 'This email already exists.';
Create a custom controller for the record creation (you may also want to do this in your record.js):
./custom/modules//clients/base/views/create/create.js
({
extendsFrom: 'RecordView',
initialize: function (options) {
this._super('initialize', [options]);
//reference your language key here
app.error.errorName2Keys['email_exists'] = 'ERROR_EMAIL_EXISTS_MESSAGE';
//add validation tasks
this.model.addValidationTask('check_email', _.bind(this._doValidateEmail, this));
},
_doValidateEmail: function(fields, errors, callback) {
var emailAddress = this.model.get('your_email_field');
//this may take some time so lets give the user an alert message
app.alert.show('email-check', {
level: 'process',
title: 'Checking for existing email address...'
});
//make an api call to a custom (or stock) endpoint of your choosing to see if the email exists
app.api.call('read', app.api.buildURL("your_custom_endpoint/"+emailAddress), {}, {
success: _.bind(function (response) {
//dismiss the alert
app.alert.dismiss('email-check');
//analyze your response here
if (response == '<email exists>') {
errors['your_email_field'] = errors['your_email_field'] || {};
errors['your_email_field'].email_exists = true;
}
callback(null, fields, errors);
}, this),
error: _.bind(function (response) {
//dismiss the alert
app.alert.dismiss('email-check');
//throw an error alert
app.alert.show('email-check-error', {
level: 'error',
messages: "There was an error!",
autoClose: false
});
callback(null, fields, errors);
})
});
},
})
Obviously, this isn't a fully working example but it should get you most of the way there. Hope this helps!

Getting nil values when request ride details Uber

I'm trying to fetch details of rides that didn't originate in my app but keep getting nil values.
I first login using the Uber iOS SDK and request history / all-trip scopes. I then fetch the ride history. Using request-ids from ride history, I fetch ride details.
In every ride object returned, all values except status, requestID and ProductID are always nil.
I'm aware this is a privileged scope, and haven't requested full access yet. My user should work as it's on the dev dashboard though.
Any idea? Thanks!
let ridesClient = RidesClient()
//Fetch history of most recent rides
ridesClient.fetchTripHistory(offset: 0, limit: 20) { (history, response) in
if (response.error == nil){ //Success
if let history = history {
//Loop into trips
for trip in history.history {
//Fetch trip details
ridesClient.fetchRideDetails(requestID: trip.requestID, completion: { (ride, response) in
//Ride object is valid but everything in it is nil
})
}
}
}
else { //Error
print(response.error?.description as Any)
}
}
Screenshot to trip object
You are getting a valid response back from the /v1.2/requests/51c4db1d-2f3d-4c8a-8577-e02490c30e22 endpoint call. This trip is completed - so you will be able to get only trip status. If you are getting "null" values when you call this endpoint - there are no any issues with the call and response you are getting back - it is intentionally made to be "null".

Storekit requestProducts returns empty products array, nothing returned invalid

I am trying to get IAP working with Appcelerator Titanium 3.1. I have all the signing/certificates/provisioning profiles/contracts working. I was getting an invalid product ID, and fixed that issue. Now, the product array is simply returned empty when calling requestProducts().
When I requestProducts('valid_product')
Response: {"type":"callback","products":[{}],"source":{},"success":true}
When I requestProducts('invalid_product')
Response: {"products":[],"type":"callback","source":{},"invalid":["invalid_product"],"success":true}
Note that I do not get an invalid product returned when I request a valid product (setup in itunesconnect under IAP for this app), I simply get an empty string for the product array.
Why could this be happening? I have tried this for IAP products in the "Waiting for Review" status, as well as "Ready to Submit" status. I have not yet submitted the binary for review.
Any help would be immensely appreciated.
Regards,
Daniel
EDIT, code posted below
function requestProduct(identifier, success) {
showLoading();
Storekit.requestProducts([identifier], function (evt) {
hideLoading();
Ti.API.info('ReqProduct:' + JSON.stringify(evt));
if (!evt.success) {
alert('ERROR: We failed to talk to Apple!');
}
else if (evt.invalid) {
alert('ERROR: We requested an invalid product!');
}
else {
alert('success. product: ' + JSON.stringify(evt.products[0]));
success(evt.products[0]);
}
});
}
calling the above function as follows:
var product;
requestProduct('22credits', function(data) {
Ti.API.info(JSON.stringify(data));
product = data;
});