We're working on an mobile app developed in Titanium Studio 3.2.0 and Titanium SDK 3.2.0.GA and Alloy 1.2.2 from Appcelerator. The app is being deployed to both Android (2.3.x and greater) and iOS(6.x or greater). To work with PayPal we're using the Titanium's PayPal module.
When we started the payment test on Android we started to get the following message: You PayPal account is restricted or locked. Go to www.paypal.com to resolve this issue:
In iOS I'm getting the message: An invalid parameter was sent: SENDER.
I don't understand why my test account was locked, I tried to create a new test account and the same thing happened. It's weird because it used to work fine in iOS and suddenly after trying to test in Android now it's not working on both.
Here's the code I use:
function createPayPalButton()
{
Titanium.Paypal = require('ti.paypal');
var price = paypalPrice;
var PaypalHolderView = Ti.UI.createView({
width: "200dp",
height : '50dp',
top : '10dp',
layout : 'horizontal',
borderRadius : '5dp',
backgroundColor : 'transparent'
});
var ppArgs = {
width: Ti.UI.FILL,
height:"50dp",
bottom:"20dp",
textStyle: Titanium.Paypal.PAYPAL_TEXT_PAY,
appId:"APP-80W284485P519543T",
buttonStyle: Ti.Paypal.BUTTON_194x37,
paypalEnvironment: Ti.Paypal.PAYPAL_ENV_SANDBOX,
feePaidByReceiver: false,
transactionType: Ti.Paypal.PAYMENT_TYPE_DONATION,
enableShipping: false,
payment: {
subtotal: price,
tax: 0,
shipping: 0,
currency:"USD",
recipient:"asama#x.com", // we're using a fake email, but we're not sure if this property should contain the email of the owner of the PayPal account.
itemDescription:"Donation",
merchantName:"OurMobileAppName" // not sure if we should reference to the package of our app i.e. to use com.mycompany.myapp or to just leave it as myapp
}
};
var ppButton = Titanium.Paypal.createPaypalButton(ppArgs);
PaypalHolderView.add(ppButton);
$.MainContainer.add(PaypalHolderView);
ppButton.addEventListener("paymentCancelled", function(e){
Ti.API.info("Payment Canceled e: " + JSON.stringify(e));
});
ppButton.addEventListener("paymentSuccess", function(e){
Ti.API.info('paymentSuccess e: ' + JSON.stringify(e));
callback.success(e);
});
ppButton.addEventListener("paymentFailed", function(e){
Ti.API.info('paymentFailed e: ' + JSON.stringify(e));
});
ppButton.addEventListener("paymentError", function(e){
Ti.API.info("Payment Error e: " + JSON.stringify(e));
});
}
Is this normal behaviour in Sandbox mode? Did I perform too many transactions? Can I unlock this test accounts?
In the end the PayPal support team didn't response back at all and we were left to find what was wrong.
What we discovered is that although our account for Production was activated to receive payments, the Sandbox account had to be activated separately, after doing that and updating our code for creating the PayPal button as follows:
var ppArgs = {
width: Ti.UI.FILL,
height:"50dp",
bottom:"20dp",
appId:"APP-80W284485P519543T",
textStyle: Titanium.Paypal.PAYPAL_TEXT_PAY, // Causes the button's text to change from "Pay" to "Donate"
buttonStyle: Ti.Paypal.BUTTON_194x37,
paypalEnvironment: Ti.Paypal.PAYPAL_ENV_SANDBOX,
feePaidByReceiver: false,
enableShipping: false,
payment: {
paymentType : Titanium.Paypal.PAYMENT_TYPE_SERVICE, // we added this
subtotal: price,
tax: 0,
shipping: 0,
currency:"USD",
recipient:"your_recipient#fake.com"
}
};
We were able to make test purchases after this.
Related
We are using the PayPal JS SDK ^5.1.0 and I'm using it to generate a pay button like described in the docs:
const paypal = await loadScript({
"client-id": conf.client_id,
"currency": conf.currency_code
});
await paypal.Buttons({
// Sets up the transaction when a payment button is clicked
createOrder: (coData, actions) => {
if (price.getTotal()) {
data.data.amount = price.getTotal();
return actions.order.create({
purchase_units: [{
description: config.registrationCenterDisplayName,
amount: {
value: price.getTotal().toFixed(2) // Can also reference a variable or function
},
}],
application_context: {
shipping_preference: 'NO_SHIPPING'
}
});
} else {
throw new Error('Amount can not be 0');
}
},
// Finalize the transaction after payer approval
onApprove: (oaData, actions) => {
return actions.order.capture().then(function(orderData) {
// Successful capture! For dev/demo purposes:
console.log('Capture result', orderData, JSON.stringify(orderData, null, 2));
const transaction = orderData.purchase_units[0].payments.captures[0];
data.data.id = transaction.id;
data.data.status = transaction.status;
dataValid = true;
submit();
});
}
}).render(buttonWrapper[0]);
It seems not to work well with error case i live. How can I provoke failed transactions or capture erros in sandbox mode?
I found the negative testing mode of a sandbox, but it does not change the behaviour for the button. I still get only positive responses.
I opened also an issue in the github repo: https://github.com/paypal/paypal-js/issues/273
Thx a lot for any help! I might overlook something very obvious...
For client-side captures, actions.order.capture().then( is only triggered when a capture is successful.
Failure cases are handled by the JS SDK itself, there is no need to test anything as it is not your code.
For server-side capturing (not your question) and using the JS SDK for approval, see the demo code here. Negative testing can be used from server API calls for failures if desired.
I have a paypal checkout button on my website along with funding icons. This is part of the code for it:
style: {
label: 'checkout',
fundingicons: true, // optional
size: 'responsive', // small | medium | large | responsive
shape: 'rect', // pill | rect
color: 'gold' // gold | blue | silver | black
},
payment: function (data, actions) {
return actions.payment.create({
payment: {
transactions: [
{
amount: {
total: amount,
currency: currency
},
invoice_number: '{$invoice}',
custom: '{$invoice}'
}
],
"redirect_urls": {
"return_url": , // these are both filled correctly
"cancel_url":
}
}
});
As you can see, the invoice field is explicitly defined, however, when getting sent back IPN messages, my ipn.php file is failing due to the lack of an invoice number being sent to it.
What makes this even weirder is that whenever the txn_type is express_checkout the invoice is there, but when it's web_accept, which is most of the time, neither the invoice nor the custom field are getting passed (I added the custom field when the IPN messages started failing).
The api we use for the button is https://www.paypalobjects.com/api/checkout.js
Is there something I'm missing or is it just that the api is deprecated and this is another sign to switch over?
EDIT:
After testing this out on other browsers it seems that adblock is blocking part of the checkout.js dependencies from loading:
Firefox: Cross-Origin Request Blocked
Opera: Failed to load resource: net::ERR_BLOCKED_BY_ADBLOCKER
Edge: POST https://www.paypal.com/xoplatform/logger/api/logger net::ERR_BLOCKED_BY_CLIENT
No error message from chrome.
EDIT 2:
sample IPN of type web_accept
mc_gross=300.00&protection_eligibility=Ineligible&payer_id=SOMEREALID&
payment_date=11:32:11 Sep 27, 2021 PDT&payment_status=Completed&charset=windows-1252&
first_name=&mc_fee=9.00¬ify_version=3.9&custom=&payer_status=unverified&
business=our_business_email&quantity=1&
verify_sign=sign_in_alpha_numeric&
payer_email=random_alpha_numeric#dcc2.paypal.com&txn_id=1KM93595HU1361254&payment_type=instant&
last_name=NotProvided&receiver_email=same_as_business_email&payment_fee=&
shipping_discount=0.00&receiver_id=more_alpha_numeric&insurance_amount=0.00&
txn_type=web_accept&item_name=&discount=0.00&mc_currency=CAD&item_number=&
residence_country=OUR_COUNTRY_CODE&receipt_id=1111-1111-1111-1111&shipping_method=Default&
transaction_subject=&payment_gross=
In the example IPN given:
mc_gross=300.00&protection_eligibility=Ineligible&payer_id=SOMEREALID&
payment_date=11:32:11 Sep 27, 2021 PDT&payment_status=Completed&charset=windows-1252&
first_name=&mc_fee=9.00¬ify_version=3.9&custom=&payer_status=unverified&
business=our_business_email&quantity=1&
verify_sign=sign_in_alpha_numeric&
payer_email=random_alpha_numeric#dcc2.paypal.com&txn_id=1KM93595HU1361254&payment_type=instant&
last_name=NotProvided&receiver_email=same_as_business_email&payment_fee=&
shipping_discount=0.00&receiver_id=more_alpha_numeric&insurance_amount=0.00&
txn_type=web_accept&item_name=&discount=0.00&mc_currency=CAD&item_number=&
residence_country=OUR_COUNTRY_CODE&receipt_id=1111-1111-1111-1111&shipping_method=Default&
transaction_subject=&payment_gross=
Note: #dcc2.paypal.com
This is from a direct credit card integration, perhaps using the classic NVP DoDirectPayment API, or Virtual Terminal [or Payflow with PayPal as the processor, as it happens]
So, not related to the button code in the question -- rather a separate integration to this PayPal account.
I'm trying to integrate Google Pay at my page, as expected doing that first at Sandbox environment but I face a problem that when I click the Google Pay button it opens the live domain and asks me to enter a real card, although I setup up all related to Sandbox environment.
Here is the code following BT documentation.
var createGooglePaymentComponent = function(clientInstance){
var button = document.querySelector('#google-pay-button');
var paymentsClient = new google.payments.api.PaymentsClient({
environment: 'TEST' // Or 'PRODUCTION'
});
braintree.googlePayment.create({
client: clientInstance,
googlePayVersion: 2,
}, function (googlePaymentErr, googlePaymentInstance) {
paymentsClient.isReadyToPay({
apiVersion: 2,
apiVersionMinor: 0,
allowedPaymentMethods: googlePaymentInstance.createPaymentDataRequest().allowedPaymentMethods,
}).then(function(response) {
if (response.result) {
button.addEventListener('click', function (event) {
event.preventDefault();
var paymentDataRequest = googlePaymentInstance.createPaymentDataRequest({
transactionInfo: {
currencyCode: 'USD',
totalPriceStatus: 'FINAL',
totalPrice: '100.00',
}
});
var cardPaymentMethod = paymentDataRequest.allowedPaymentMethods[0];
cardPaymentMethod.parameters.billingAddressRequired = true;
paymentsClient.loadPaymentData(paymentDataRequest).then(function(paymentData) {
googlePaymentInstance.parseResponse(paymentData, function (err, result) {
if (err) {
// Handle parsing error
}
// Send result.nonce to your server
});
}).catch(function (err) {
});
});
}
}).catch(function (err) {
});
});
};
Here is a screenshot of what I get:
Any idea why does that happen?
Using Google Pay in the TEST environment will return a TEST payment credential which won't actually charge the payment method that you provide. It's understandable that you don't want to be using real payment details.
If you want to be able to choose from a list of predefined test cards, follow the instructions here: https://developers.google.com/pay/api/web/guides/resources/test-card-suite
In short, you will need to join the googlepay-test-mode-stub-data Google Group which will then display a list of test accounts when accessing the Google Pay payment sheet with that user.
I'm setting up in app purchases in my Ionic app and I've been having some trouble getting the test purchases working correctly. It would seem that as soon as I execute this particular function, it automatically runs the code as if it was approved, even though the confirmation to get the subscription hasn't occurred yet:
this.platform.ready().then(() => {
// Register the products for consumption
this.products.forEach(product => {
this.store.register({
id: product.id,
alias: product.alias,
type: product.type
});
// When a purchase is approved, see what we get here
this.store.when(product.id).approved((order) => {
// Purchase was successful, setup the appropriate subscription
this._subscriptions.updateSubscription(this.user.id, this.selectedPlan.amount, 'activate').then(() => {
if(this.selectedPlan.amount === 1) {
this.subscriptionGrammar = 'month';
} else if(this.selectedPlan.amount > 1) {
this.subscriptionGrammar = 'months';
}
order.finish();
});
});
});
});
I was under the impression that utilizing the .when().approved() would only fire once the payment "goes through". Since I'm using test transactions, I'm not sure how that would affect it, but I would suspect it should only do that once I hit "Confirm" on the Google dialog that pops up in my app?
Is there something I'm missing here?
I am needing to send a tweet for from my iphone/ipad app using Appcelerator Titanium & javascript. I found the following example on github (code also posted below for this):
https://gist.github.com/2eabc31db388144b3abc
I have created my app details (key,secret etc) in my twitter developer account and using the code from the example i get the twitter login and authorisation popup but once you click authorise, all i get is a webview showing the callback url (that i was required to put in the twitter app settings). So the app is stuck on a webview showing the callback url but does nothing after. If i close the popup window it just goes back to my app without sending a tweet.
Can anyone help?
code in app.js:
var win = Ti.UI.createWindow({ backgroundColor: '#fff' });
var shareButton = Ti.UI.createButton({
width: 90, bottom: 10, height: 30,
title: 'Tweet!"'
});
win.add(shareButton);
win.open();
var social = require('social');
var twitter = social.create({
site: 'Twitter',
consumerKey: 'XXXXXXXXXXXXXXXX',
consumerSecret: 'XXXXXXXXXXXXXXXXXXXXX'
});
shareButton.addEventListener('click', function() {
twitter.share({
message: 'Hello, world!',
success: function() {
alert('Tweeted!');
},
error: function(error) {
alert('Oh no! ' + error);
}
});
});
As Aaron answered on the Q&A, when using Social.js, you should not use a callback URL. The code itself will watch the web view for what it needs.