How to create custom donation amount using Payapl client side REST-API - javascript

I'm following the client side Client Side Rest API to create a donation button. The amount to charge is static in the code. I was able to pass in a variable after prompting the user to click a button to enter the amount, however, that is incredibly clunky and a default value is needed to prevent the PayPal window from closing as soon as it's opened if no values was entered.
// payment() is called when the button is clicked
payment: function(data, actions) {
// Make a call to the REST api to create the payment
return actions.payment.create({
payment: {
transactions: [
{
amount: { total: promptMe2(), currency: 'USD' }
}
]
}
});
},
You can see that I have the var donationAmount. That is set by default to a value. However, it can be changed by the user with:
<script>
var donationAmount = 16.11;
function promptMe(){
donationAmount = parseFloat(prompt("How much would you like to donate?"));
while (Number.isNaN(donationAmount)){
alert("Invalid number, try again!");
donationAmount = parseFloat(prompt("Amount to donate?"));
}
donationAmount = donationAmount.toFixed(2);
}
I tried to call promptMe() in place of the donationAmount variable (with an added return statement of donationAmount of course) and found that the page would just spam my error message for an invalid amount. When I hardcoded the value in it worked just fine. When I took the error checking out, it didn't even prompt me, it just instantly closed the paypal window. I was able to trigger an alert("Hello"); but that is pretty useless, I need to be able to accept user input and then pass it to Paypal.

Related

How to have a custom handler instead of a PayPal button in React?

I have a website with multiple payment forms. I can switch between them and then I have a button with "Continue to checkout" label that when you click, it does something depending on the payment method chosen. The handler function looks something like this:
const handlePayment = (method) => {
if(method === paymentMethods.STRIPE){
// do something
}
if(method === paymentMethods.PAYPAL){
// do something else
}
}
The problem is I looked at the docs and it's always about showing a PayPal button, I don't want a PayPal button, I want to open the PayPal form directly from my button, when a method is selected.
So want I mean is, I want to do it programmatically. Is there any way to do this? I don't want to do a hacky solution hiding the button or triggering the click or some weird thing...
The React PayPal component is just a wrapper for the JS SDK.
My UI looks something like this: I'd like to open the PayPal payment form when I click on Pay, only if PayPal is selected.
If you use the PayPal JS SDK to open the checkout, you have to use its button, and the user has to click it themselves. PayPal does this intentionally so that the button shown uses their consistent branding.
If you want an alternative, you can integrate without the JS SDK (REST API only) and have your own button which redirects to the PayPal page for approval, which will then return to your site. This is an old integration pattern, for old websites, and not recommended.
Despite your misgivings and desire not to use it, the JS SDK and its button in a container sized to your requirements is in fact the best available solution.
Based on the UI shown, what you might op to do is hide your "Pay" button and replace it with one that says "Pay With PayPal" when that method is selected, which could look like this (sized to fit your container):
Here's sample HTML/JS for that, you can do the same from react-paypal-js :
<script src="https://www.paypal.com/sdk/js?client-id=test&currency=USD"></script>
<div id="paypal-button-container"></div>
<script>
paypal.Buttons({
fundingSource: paypal.FUNDING.PAYPAL,
style: {
color: "blue",
label: "pay"
},
// Set up the transaction
createOrder: function(data, actions) {
return actions.order.create({
purchase_units: [{
amount: {
value: '88.44'
}
}]
});
},
// Finalize the transaction
onApprove: function(data, actions) {
return actions.order.capture().then(function(orderData) {
// Successful capture! For demo purposes:
console.log('Capture result', orderData, JSON.stringify(orderData, null, 2));
var transaction = orderData.purchase_units[0].payments.captures[0];
alert('Transaction '+ transaction.status + ': ' + transaction.id + '\n\nSee console for all available details');
// Replace the above to show a success message within this page, e.g.
// const element = document.getElementById('paypal-button-container');
// element.innerHTML = '';
// element.innerHTML = '<h3>Thank you for your payment!</h3>';
// Or go to another URL: actions.redirect('thank_you.html');
});
}
}).render('#paypal-button-container');
</script>

WooCommerce: Fire action after shipping zone is changed

I am currently working on a shop, which picks up shoes from the customer, cleans them and then returns them back to the customer.
It features local pickup only in an assigned area, based on a range of postcodes. But if the user types in a postcode that is not included, the site should show a message that the user is not within this area and needs to send the shoes via mail.
My question is whether there is a PHP or JavaScript hook I can catch when the user changes his postcode, so I can display this message.
I already tried to do this based on input change and to look if the ID of the shipping method is existing. But this does not quite work.
$('#billing_postcode').on('change', function (event) {
event.preventDefault()
if ($('#shipping_method_0_local_pickup2')) {
console.log('Pickup is possible')
} else {
console.log('Pickup is not possible')
}
})

Separating the payment function from PayPal Checkout paypal.Button.render method

PayPal payment method is not getting the updated price details which has to be passed as input parameter for creating payment.
The paypal.Button.render() method gets called initially with the input parameter - price which is 0.00. But when the price gets updated on field change, it is not taking the updated price value, and calling the payment function with the old value - 0.00.
function createPaypalPayment(price, recordId){
angularLoad.loadScript('https://www.paypalobjects.com/api/checkout.js')
.then(function() {
paypal.Button.render({
env: 'sandbox',
payment: function(data, actions) {
createPayment(price, recordId){
/*..some code goes here*/
}
.then(function(response) {
console.log(response)
})
}
});
})
}
Here the I'm using this in an AngularJS service.
How can I get the updated value of price here when I do a field change and call the createPaypalPayment(price, recordId) ?
Thanks
I would suggest you to use Paypal's Server side integration for this. That way you can easily change/update the payment price. Follow this Link.

javascript "callbacks" across redirecting / after reloading

I've got a site (asp.net mvc razor) on wich some functionalities require authorization / login.
These functionalities can be started by clicking on a button for example.
By clicking on such a button, the system checks whether the user is logged in or not.
If not, the user is redirected to the login page where he can sign in.
After that he will be redirected to the initial page again without initiating the users action.
So heres the workflow:
->Page x -> button y -> click -> redirect to login -> login -> redirect to x.
The redirects are simple Url.Action() statements.
What I want to do is to dynamically redirect to the page the click came from and ideally jump to the senders selector in order to simplify things for users.
What possibilities do I have to achieve this?
Only things coming to my mind are quite ugly stuff using ViewBag and strings
Update:
Info: As storing session variables causes problemes concerning concurrent requests this feature is disabled solution wide so I cannot use session variables.
Besides: One of the main problems is, that I cannot sign in without making an ajax call or sending a form. And by sending a form or making an ajax call I loose the information about the original initiator of the action and the parameters.
I solved this by adding by adding this to all such actions in their controllers:
[HttpPost]
public ActionResult ActionA(Guid articleId, Guid selectedTrainerId)
{
//if user is not authenticated then provide the possibility to do so
if (!Request.IsAuthenticated)
{
var localPath = this.ControllerContext.RequestContext.HttpContext.Request.Url?.LocalPath;
var parameter = this.ControllerContext.RequestContext.HttpContext.Request.Params["offeringRateId"];
var returnUrl = localPath + "?articleId=" + parameter;
return PartialView("LoginForOfferingPreview", new LoginForOfferingPreviewViewModel
{
RequestUrl = returnUrl,
//this will be used in the view the request was initiated by in order to repeat the intial action (after login has been successfull)
Requester = OfferingPreviewRequester.CourseTrialAdd,
//this will be used in the view to initiate the request again
RequestParameters = new List<dynamic> { new { articleId = articleId },new { selectedTrainerId = selectedTrainerId }}
});
}
//actual action
SendBasketEvent(new CourseAddMessage
{
BasketId = BasketId,
OfferingRateId = articleId,
SelectedTrainerId = selectedTrainerId,
SelectedTime = selectedTime,
Participants = selectedParticipants,
CurrentDateTime = SlDateTime.CurrentDateTimeUtc(SlConst.DefaultTimeZoneTzdb),
ConnectionId = connectionId
}, connectionId);
return Json(JsonResponseFactory.SuccessResponse());
}
the hereby returned view for login contains following js code that is called if the login has been succesfull:
function onLoginFormSubmit(data) {
//serialize form containing username+pw
var datastring = $("#loginForm").serialize();
$.ajax({
type: "POST",
url: '#Url.Action("Login_Ajax","Account",new {area=""})',
data: datastring,
success: function (data) {
debugger;
// display model errors if sign in failed
if (!!!data.Success) {
$(".buttons-wrap").append('<span id="loginFormError" style="color:red;"></span>');
$("#loginFormError").append(data.ErrorMessage);
}
//call method of initiating view that will decide what to dow now
if (data.Success) {
var parametersObjectAsString = JSON.parse('#Html.Raw(JsonConvert.SerializeObject(Model.RequestParameters))');
window.onLoginForOfferingPreviewSuccess('#Model.RequestUrl', parametersObjectAsString, '#((int)Model.Requester)');;
}
},
error: function () {
}
});
}
this works fine as long sigining does not fail due to wrong username or pw.
If that happens, the view shows the errors but by now signing in again somethign really strange happens:
At first it seems to work exaclty like signing in successfully by the first time but then the ajax calls in window function onLoginForOfferingPreviewSuccess will always reach the error block without beeing able to tell you why.
Fiddler reveals weird http resonse codes like 227,556 or something
Thx

PayPal as secondary payment option in Braintree

We're currently struggling with Braintree PayPal payment in combination with regular bank transfer via IBAN. Basically, we present two subscription options to the visitor: PayPal (via Braintree) and IBAN transaction.
The PayPal method works fine but when we don't select PayPal but IBAN bank transfer, we're getting the following console error:
We understand that this is the correct behaviour since the PayPal fields are not filled, but how is it possible to have PayPal as an optional payment method without throwing an error when the fields are not filled?
We're using the basic js implemetion via DropUI.
<div class="bt-drop-in-wrapper" id="showpaypalfields">
<div id="bt-dropin" class="paypaldiv"></div>
</div>
<script src="https://js.braintreegateway.com/js/braintree-2.27.0.min.js"></script>
<script>
var client_token = "123TOKEN";
braintree.setup(client_token, "dropin", {
container: "bt-dropin"
});
</script>
UPDATE:
Both forms are visible on the page instantly, they are not loaded afterwards via Ajax or any kind. So, the PayPal option via Braintree should only validate if for example a checkbox is set. For example, the checkbox given in the screenshot below (toggles visibility of both fieldsets).
UPDATE #2:
For anyone interested in the final solution:
var btInstance;
$('input#paymentmethod-1').change(function(){
if ( $(this).is(':checked') == true ) {
teardown();
}
});
$('input#paymentmethod-2').change(function(){
if ( $(this).is(':checked') == true ) {
setup();
}
});
function setup() {
if (btInstance) {
return;
} else {
var client_token = "<ps:braintreetoken />";
braintree.setup(client_token, "dropin", {
container: "bt-dropin",
onReady: function (bt) {
btInstance = bt;
}
});
}
}
function teardown() {
if (!btInstance) {
return;
}
btInstance.teardown(function () {
btInstance = null;
});
}
Full disclosure: I work at Braintree. If you have any further questions, feel free to contact support.
Drop-in UI is still loaded when you select the Lastschrift payment option, which is why you're receiving the validation errors.
One way to avoid these validation errors is to use the 'teardown' method in the 'onReady' callback in braintree.js to remove the Drop-in UI if a customer selects Lastschrift.
Alternatively, you can separate each of these payment methods into entirely different form elements on your page.

Categories