How to remove shipping from the PayPal subscribe button and default other values? - paypal

I'm creating a subscription button using the JavaScript SDK from PayPal. Here's the basic code snippet I'm following:
paypal.Buttons({
createSubscription: function(data, actions) {
return actions.subscription.create({
'plan_id': 'P-2UF78835G6983425GLSM44MA'
});
},
onApprove: function(data, actions) {
alert('You have successfully created subscription ' + data.subscriptionID);
}
}).render('#paypal-button-container');
When a user selects Credit Card (non PayPal account option),the next PayPal popup Window has a long form, collecting Credit Card, Billing Address, Shipping Address, Phone Number, and Email. For my needs, I don't need a shipping address and I'd like to be able to default things like Billing Address, Phone, and Email.
The PayPal SDK documentation is large but somehow lacking critical details around this library. My questions are:
How can I exclude shipping address collection from this form?
How can I default the other info I have already collected from the user (phone, email, etc)?
Thanks to Preston PHX, I was able to get the collection of shipping info removed from the mile long form, but for some reason, my subscriber information is not be pre-filled into the PayPal popup window.
Here's my update code section:
createSubscription: function (data, actions) {
return actions.subscription.create({
/* Creates the subscription */
plan_id: 'P-2UF78835G6983425GLSM44MA',
subscriber: {
name: {
given_name: "FirstName",
surname: "LastName",
},
email_address: "test#example.com",
phone: {
phone_type: "MOBILE",
phone_number: {
national_number: "2145551212",
}
},
address: {
address_line_1: "123 Main Street",
address_line_2: "Suite 101",
admin_area_1: "Addison",
admin_area_2: "TX",
postal_code: "75001",
country_code: "US"
}
},
application_context: {
shipping_preference: "NO_SHIPPING"
}
});
},
However, when the popup is rendered, here's what I see:
Note, the shipping elements are no longer rendering, but the form is not getting prefilled.
It would seem that I'm close to doing this right because if I put an phone number in that is not a well-formed phone number, the API spits out errors about the number not being valid.

All available parameters are the same as the create subscription API operation.
Set application_context.shipping_preference to NO_SHIPPING
Phone, email, and other information can be set in the subscriber object.

Related

Sales tax not updated when shipping option is changed if buyer pays with Credit/Debit rather than PayPal?

In the PayPal JavaScript SDK when the order is created the client passes the shipping cost options. If the purchaser changes the shipping option from within the PayPal window, the sales tax must be recalculated because sales tax applies to shipping for this product. The sales tax is not passed in the order creation but the onShippingChange event is fired/invoked after the address is first applied in PayPal; and then the new values, including sales tax, are passed through return actions.order.patch().
If the purchaser pays through clicking the PayPal button, all works fine because the onShippingChange event is fired/invoked when the shipping option is changed. However, when the purchaser uses the Credit/Debit button to pay, the onShippingChange event is fired/invoked only once and not again when the shipping option is changed. If the user changes the shipping option, the cost appears to be taken from the data passed in the order creation and since the onShippingEvent is not run again, the sales tax remains based upon the initial shipping option.
The only difference in these two scenarios is which button the purchaser uses to pay: either PayPal for an account, or Credit/Debit to pay as a guest. All the JS code is the same.
Am I doing something wrong that is causing the onShippingChange event code to not be invoked? Thank you.
A couple things I've noticed while working on this. One is that the messages of "contacting merchant" and "processing" vary, such that when the shipping option is changed when paying with credit/debit, the message is only "processing". When paying with PayPal the message is "contacting merchant." Another is that even after the values are updated, with the sales tax inaccurate, the total cost shown in the top right corner of the PayPal window differs from the total in larger font in the message by difference in shipping options. The one in large font never changes when the shipping option is changed.
In the image below, the shipping option was changed from $9.25 priority to $4.00 standard. The initial total was $28.83. When shipping was changed to standard, the cost changed as $(28.83-9.25+4.00) = $23.58. Sales tax was not adjusted; and it should be $23.27.
I asked a similar question a day or so ago, but thought the values were correct in both payment scenarios but now see they are not.
Update:
After messing around with various options it occurred to me that I don't need to provide shipping options in the PayPal window. If the buyer wants to change the option, he'll have to cancel and change the order in the web page. That eliminates the issue of onShippingChange not firing. Not ideal; but good enough for our little case, especially since few buyers will be changing their shipping option in PayPal, for they see all that cost info. before clicking a payment button.
paypal.Buttons({
// Sets up the transaction when a payment button is clicked
createOrder: function(data, actions) {
return actions.order.create({
purchase_units: [{
reference_id: "HardCopy_0001",
amount: {
value: order.discSub.toFixed(2)
},
shipping: {
options: [
{
id: "STD",
label: "USPS Standard",
type: "SHIPPING",
selected: order.el_shipOptsInp[0].checked,
amount: {
value: order.shipStdVal.toFixed(2),
currency_code: "USD"
}
},
{
id: "PRI",
label: "USPS Priority",
type: "SHIPPING",
selected: order.el_shipOptsInp[1].checked,
amount: {
value: order.shipPriVal.toFixed(2),
currency_code: "USD"
}
}
]
}
}],
});
},
// Finalize the transaction after payer approval
onApprove: function(data, actions) {
return actions.order.capture().then(function(orderData) {
/* ... */
});
},
onShippingChange: function (data, actions) {
try {
// Reject non-US addresses
if (data.shipping_address.country_code !== 'US') {
return actions.reject();
}
const taxRate = data.shipping_address.state === 'PA' ? order.taxRate : 0,
shippingAmount = parseFloat(data.selected_shipping_option.amount.value),
tax_total = taxRate === 0 ? 0 : Math.round( (order.discSub + shippingAmount) * order.taxRate * 100)/100,
oTotal = order.discSub + shippingAmount + tax_total;
if ( data.selected_shipping_option.id === "STD" ) {
if ( !order.el_shipOptsInp[0].checked ) {
order.el_shipOptsInp[0].checked = true;
order.change();
}
} else if ( !order.el_shipOptsInp[1].checked ) {
order.el_shipOptsInp[1].checked = true;
order.change();
}
return actions.order.patch([{
op: "replace",
//path: "/purchase_units/#reference_id==\'default\'/amount",
path: "/purchase_units/#reference_id=='HardCopy_0001'/amount",
value: {
value: oTotal.toFixed(2),
currency_code: "USD",
breakdown: {
item_total: {
currency_code: "USD",
value: order.discSub.toFixed(2)
},
shipping: {
currency_code: "USD",
value: shippingAmount.toFixed(2)
},
tax_total: {
currency_code: "USD",
value: tax_total.toFixed(2)
}
}
}
}
]);
} catch (err) {
console.log("We apologize. There was an error in the onShippingChange event. Reason is provided below.");
console.log(err);
order.error();
return actions.reject();
}
},
onError: function(err) {
console.log(err);
// For example, redirect to a specific error page
//window.location.href = "/your-error-page-here";
order.error();
}
}).render('#paypal-button-container');

PayPal Subscription Button Coupons

I am using Paypal buttons to subscribe customers to a plan.
I am trying to apply coupons on the Paypal buttons without any luck.
This is the code that generate the Paypal button on the frontend:
paypal.Buttons({
style: {
shape: 'pill',
color: 'blue',
layout: 'vertical',
label: 'subscribe'
},
createSubscription: function (data, actions) {
return actions.subscription.create({
"plan_id": "<PAYPAL_PLAN_ID>"
});
},
onApprove: function (data, actions) {
console.log('success');
}
}).render('#paypal-button-container');
On the documentation I saw that I need to define a javascript variable and I tried
var discnt=10;
And:
var discount_amount=10;
None of this variables are working.
Even if the discount will work this way, I want to give the marketing team to define Coupons on their own, and give it to the customers.
Anyone might know how to add coupons to paypal.Buttons?
In addition to the plan_id , you can pass a plan object which overrides the provided plan's details with a different amount, and with a description that reflects the text "discount" or "coupon applied" somewhere.
Parameters for a subscription create call are documented here: https://developer.paypal.com/api/subscriptions/v1/#subscriptions-create-request-body
So for instance, something like
return actions.subscription.create({
"plan_id": "<PAYPAL_PLAN_ID>",
"plan" : {
"name" : "My Service - $10 coupon",
"billing_cycles" {
/* New billing cycles object with lower amount */
}
}
}

How to reference a paypal webhook to a user?

I'm trying to figure out the best way to associate the webhook to a user of the webapp.
Upon a paypal transaction I receive the webhook from paypal
but it doesn't have a reliable reference that I can use
to associate with the user in the app.
My solution would be to:
On the onApprove function use javascript code to submit a form with the subscriptionID
hidden on an input and send it to the server.
After receiving the subscriptionID on the server, create the webhook database entry with the subscriptionID field of the user that made the transaction.
And when I receive the webhook from paypal I can reference the user through the
subcriptionID.
Anyone around went through this one with a better option?
I was thinking if there is a way to insert the userID of the webapp in the paypal webhook.
Would be more clean.
Havent' found anything tho.
Here is the paypal webhook client call:
<script>
paypal.Buttons({
style: {
shape: 'pill',
color: 'gold',
layout: 'vertical',
label: 'subscribe'
},
createSubscription: function(data, actions) {
return actions.subscription.create({
/* Creates the subscription */
plan_id: '************************'
});
},
onApprove: function(data, actions) {
alert(data.subscriptionID); // You can add optional success message for the subscriber here
}
}).render('#paypal-button-container-******************'); // Renders the PayPal button
</script>
Thanks
When you create the subscription, pass a unique custom_id
thanks Preston. This is defenitely the best option. I was having trouble because I was adding a new field with a random name to associate to the userID of the app. It turns out that you really need to use the custom_id key in order to receive it in the webhook calls.
Final solution was the following:
<script>
paypal.Buttons({
style: {
shape: 'pill',
color: 'gold',
layout: 'vertical',
label: 'subscribe'
},
createSubscription: function(data, actions) {
return actions.subscription.create({
/* Creates the subscription */
plan_id: '************************',
custom_id: 'appUserID'
});
},
onApprove: function(data, actions) {
alert(data.subscriptionID); // You can add optional success message for the subscriber here
}
}).render('#paypal-button-container-******************'); // Renders the PayPal button
</script>
Then the custom_id field will be available in all of the webhook calls. Perfect!

Paypal Smart Button Check Postal Code onApprove

The problem:
I am trying to figure out how to check the if postal code (entered during the paypal smart button check-out) meets specific requirements.
I have the createOrder, and onApprove object attributes I would like to check the postal code before i capture the payment so i can reject it, and cancel the order.
paypal.Buttons(
{
createOrder: function(data, actions) {
// This function sets up the details of the transaction, including the amount and line item details.
return actions.order.create({
purchase_units:
[
{
description: "Raffle Tickets",
custom_id: $('#cartID').val(),
soft_descriptor: "soft_descriptor",
amount: {
currency_code: "CAD",
value: cartVal,
breakdown: {
item_total: {
currency_code: "CAD",
value: cartVal
}
}
},
items: itemList
}
]
});
},
onApprove: function(data, actions) {
//id like to check the postal code here, or maybe do an ajax call then on success, call the
//capture function below to finalize the payment.
// This function captures the funds from the transaction.
return actions.order.capture().then(function(details) {
// This function shows a transaction success message to your buyer.
$('#details').val(JSON.stringify(details));
$('#frmConfirm').submit();
});
}
}).render('#paypal-button-container');
return actions.order.get().then(function(data,actions) {
console.log(data);
/* if logic on data.payer.address.postal_code goes here */
actions.order.capture().then(function(details) {
$('#details').val(JSON.stringify(details));
$('#frmConfirm').submit();
}
});
You mentioned AJAX; there are server-side equivalent APIs, if you want to switch from this client-side implementation to one that uses code on the server to validate. In that case the front-end would look more like this: https://developer.paypal.com/demo/checkout/#/pattern/server , and there is a v2/orders API call to get the details of the approved order before capturing it.

How do I remove a "Ship to" section from Checkout Popup?

Is there any option, when creating a payment with Paypal API, that allows to remove a "Ship to" section from Checkout popup? I mean just not to displayit in popup.
I do not use a shipping_address option anywhere in payment_json object when creating a configuration for a payment. But the section still persists.
I'm adding this answer since I came here while searching for disabling the shipping to information by using PayPal Smart Payment Button. This answer may help them.
You have to add the below line to remove Ship to address.
application_context: { shipping_preference: 'NO_SHIPPING' }
Eg:
paypal.Buttons({
createOrder: function(data, actions) {
return actions.order.create({
purchase_units: [{ amount: { value: 1.00 } }],
application_context: { shipping_preference: 'NO_SHIPPING' }
});
}
}).render("#paypal-button-container");
You need to use Payment Experience API.
Create new web_profile, and set presentation with
"no_shipping": 1,
"address_override": 0