Paypal express checkout using activemerchant and ipn - ruby-on-rails

I'm stuck with getting activemerchants paypal express ipn notification to work.
My workflow looks like this:
# authorize the payment user gets redirected..
def auth
...
gateway.setup_authorization(total_as_cents, setup_authorization_params)
...
end
# purchase the authorized sum
def purchase
...
purchase_params = {
token: #order.payment_params[:token],
payer_id: #order.payment_params[:payer_id],
currency: current_tenant.currency.unit,
notify_url: paypal_ipn_callback_url
}
response = gateway.purchase(total_as_cents, purchase_params)
...
end
In the paypal docs it says notify_url is deprecated they use PAYMENTREQUEST_n_NOTIFYURL instead. But I have no clue how to tell this my paypal express gateway.
My ipn callback doesn't get called so I assume the notifyurl param doesn't work anymore.
Paypal is in sandbox mode but that should make no difference right?
Any hints?

I believe that if you are using Paypal Express that means you are doing a deep integration with your system, and you don't need the IPN, you can get the response from
response = gateway.purchase(total_as_cents, purchase_params)
and get all information from it, and that response is an object
ActiveMerchant::Billing::PaypalExpressResponse
The IPN is used for the basic Paypal integration, with no API calls from your app, only Paypal URL redirect with params.

Related

How to handle payment success in stripe?

After a user visits the payments page and successfully makes a payment, Stripe will redirect the customer to whatever url is provided to success_url
Stripe.api_key = 'sk_test_51HYHSFGtUKse83O9J4QeAib3cp8sHzGaOQRrn7sba92Hd8dCHE3AIHe5ModevMK7TVAUCyJU0ADSwIUoX00qxZmBI9r'
session = Stripe::Checkout::Session.create({
payment_method_types: ['card'],
line_items: [{
name: 'Kavholm rental',
amount: 1000,
currency: 'aud',
quantity: 1,
}],
payment_intent_data: {
application_fee_amount: 123,
transfer_data: {
destination: '{{CONNECTED_STRIPE_ACCOUNT_ID}}',
},
},
success_url: 'https://example.com/success',
cancel_url: 'https://example.com/failure',
})
Now the app/platform must arrange 'fulfillment':
After the payment is completed, you’ll need to handle any fulfillment necessary on your end. A home-rental company that requires payment upfront, for instance, would connect the homeowner with the renter after a successful payment.
Also (bold from me):
Do not rely on the redirect to the success_url param alone for fulfilling purchases as:
Malicious users could directly access the success_url without paying and gain access to your goods or services.
Customers may not always reach the success_url after a successful payment. It is possible they close their browser tab before the redirect occurs.
Up to this point, everything is very well explained in the stripe docs and very understandable.
But I want to know: what is the best thing to do next, noting that:
a payment may not go through immediately, so simply loading the success_url might be premature
a webhook can be (easily) configured to listen for events, however if the success_url is loaded even 1 second before the webhook receives a success message, then it won't know that the payment went through successfully (so, for example, displaying "Congrats, your product will be shipped!" message could be presumptuous
Question
So, finally, the question: what is best practice for the flow on from success_url? I am just confused as to what is the best pattern..
Ideas
Here are some things I've considered:
Upon routing to success_url, simply use sleep(5) and then check the webhook in the controller for the success_url so it takes 5 extra seconds to load giving the webhook a chance to receive incoming events, so you can display either "Congrats your product will be shipped!" or "Oh, no, something went wrong with your payment, please try again or contact your bank".
Routing directly to success_url, but then having a message saying "please refresh in a moment" (then listening for a webhook indicating the payment was successful, and then conditionally showing the "Congrats your product will be shipped!" message)
The documentation for fulfilling orders has this in an info box under the code snippet:
Your webhook endpoint redirects your customer to the success_url when you acknowledge you received the event. In scenarios where your endpoint is down or the event isn’t acknowledged properly, your handler redirects the customer to the success_url 10 seconds after a successful payment.
The event referenced above is the checkout.session.completed event sent to your webhook endpoint. The delay is designed to let you confirm the payment is successful and customize the success page based on the result of the Checkout Session's outcome.
In other words, Checkout won't send someone to your success_url until you've responded to the checkout.session.completed event request from your webhook endpoint with a successful (2xx) response, giving you time to customize the success page based on the outcome.
You can, for example, default to a "your payment is being processed" success page, but if you confirm the Checkout Session and payment succeeded after receiving the checkout.session.completed event, you can instead change the page to read "congrats your product will be shipped".
This approach means you can reliably present a success page that always has displays accurate information.

Identifying users in Rails Web push notifications

I'm developing a Rails application, and I'd like to send web push notifications to specific users when certain actions happen, e.g:
A user started tracking a timer, but the timer has been running for more than 6 hours. Then the app sends that user a web notification.
I've been doing research and found this tutorial, the author implements push notifications for Rails, however there's no insight on how to identify the users.
From what I understood, the users needs to subscribe from their browser to be able to get push notifications, however, considering each user can use the application from multiple browsers, how can I automatically subscribe/unsubscribe a user for notifications in all browsers they use the app from?
So, what I did was adding a notification_subscription model to my User model.
On my javascript, I check if there's a current browser subscription present:
this.serviceWorkerReady()
.then((serviceWorkerRegistration) => {
serviceWorkerRegistration.pushManager.getSubscription()
.then((pushSubscription) => {
if (pushSubscription && _.includes(subscriptionEndpoints, pushSubscription.endpoint)) {
return;
}
this.subscribe();
});
});
I check if the current subscription is already present in the user stored endpoints, and subscribe if it isn't.
On subscription I send the new endpoint to the backend, which adds the new subscription to the user:
$.post(Routes.users_subscriptions_path({ format: 'json' }), {
subscription: subscription.toJSON()
});
Then I can send notifications to users to every endpoint:
def push_notifications_to_user(user)
message = {
title: "A message!",
tag: 'notification-tag'
}
user.notification_subscriptions.each do |subscription|
begin
Webpush.payload_send(
message: JSON.generate(message),
endpoint: endpoint,
p256dh: p256dh,
auth: auth,
api_key: public_key
)
rescue Webpush::InvalidSubscription => exception
subscription.destroy
end
end
end
The webpush gem raises an InvalidSubscription exception if the endpoint is invalid, we can destroy that endpoint to keep only the valid endpoints from the user.
The endpoint is unique by browser so you need an additional authentication scheme on the top of your app to send user's information along with the new endpoint.
You need to attach metadata (i.e. the user ID) to the endpoint when you store it on your server:
#subscription = Subscriptions.new endpoint: params[:endpoint]
#subscription.user = current_user
// or if you send with AJAX the user id together with the endpoint
#subscription.user = User.find params[:user_id]
In the second case I suggest to sign the user ID or use a secret token, otherwise anyone would be able to subscribe to push notifications as if it was another user.
Then you can delete from the database all the endpoints that belong to that user ID to unsubscribe all his devices.
However I don't think it's a good practice: a user may want to receive notifications on a device and not on another one.

After payment success, amount is not reflecting in sand box (adaptive parallel payment)

I am using this gem 'paypal-sdk-adaptivepayments'in ruby on rails. I get success after payment but when i saw my accounts in sandbox no one user get payments and also the merchant account is not debited.
This is my response which I get from paypal after success
<PayPal::SDK::AdaptivePayments::DataTypes::PaymentDetailsResponse:0x00000007d3cfc8 #responseEnvelope=#<PayPal::SDK::AdaptivePayments::DataTypes::ResponseEnvelope:0x00000007d3cc80 #timestamp=Mon, 13 Jul 2015 00:04:03 -0700, #ack="Success", #correlationId="4a4043560f603", #build="17325060">, #cancelUrl="http://localhost:3000/payments/cancel", #currencyCode="USD", #ipnNotificationUrl="http://localhost:3000/payments/ipn_notify", #paymentInfoList=#<PayPal::SDK::AdaptivePayments::DataTypes::PaymentInfoList:0x00000007d33cc0 #paymentInfo=[#<PayPal::SDK::AdaptivePayments::DataTypes::PaymentInfo:0x00000007d33ba8 #receiver=#<PayPal::SDK::AdaptivePayments::DataTypes::Receiver:0x00000007d33ae0 #amount=160.0, #email="jaskaran#yopmail.com", #primary=false, #paymentType="SERVICE", #accountId="MNF7MDPJWJHJL">, #pendingRefund=false>, #<PayPal::SDK::AdaptivePayments::DataTypes::PaymentInfo:0x00000007d33388 #receiver=#<PayPal::SDK::AdaptivePayments::DataTypes::Receiver:0x00000007d33310 #amount=10.0, #email="user4paypal#yopmail.com", #primary=false, #paymentType="SERVICE", #accountId="HEPSP9YS5ZMPQ">, #pendingRefund=false>]>, #returnUrl="http://localhost:3000/payments/success", #status="CREATED", #payKey="AP-2G3459926X3244353", #actionType="PAY", #feesPayer="SENDER", #reverseAllParallelPaymentsOnError=false, #sender=#<PayPal::SDK::AdaptivePayments::DataTypes::SenderIdentifier:0x00000007d325f0 #useCredentials=false>>
Here is status is created, I want to change it completed, Is need to call any api to do this again?
Oh After searching 3 hours. I get the solution. :)
I had to add senderEmail parameter with the payer email. Thats it. In this way paypal let the transaction to be COMPLETED.

Paypal invalid token error when creating a recurring payment profile

I am trying to setup a recurring payment profile via the ExpressCheckout API of Paypal in Ruby on Rails with the help of paypal-express gem but i keep getting error code 11502 (Invalid token) => Paypal error code documentation
The documentation is a bit unclear because there it is not saying what's missing:
One or more subscription detail fields are missing from the request.
I have checked the required field in the documentation here but i don't think i missed any. No need for shipping details as we don't ship a product.
Here is a log of what is being sent to Paypal when i am doing the checkout and then creating the recurring profile:
SetExpressCheckout
Parameters:
{:RETURNURL=>"http://localhost:3000/paypal/validate",
:CANCELURL=>"http://localhost:3000/paypal/cancel",
:REQCONFIRMSHIPPING=>0, :NOSHIPPING=>1, :ALLOWNOTE=>0,
:PAYMENTREQUEST_0_AMT=>"88.00", :PAYMENTREQUEST_0_TAXAMT=>"0.00",
:PAYMENTREQUEST_0_SHIPPINGAMT=>"0.00",
:PAYMENTREQUEST_0_CURRENCYCODE=>"HKD", :PAYMENTREQUEST_0_DESC=>"Plus x
2-month subscription x 2 staff", :LOCALECODE=>:fr}
Response:
TOKEN=EC%2d0H440138VJ9552235&TIMESTAMP=2015%2d04%2d25T08%3a38%3a42Z&CORRELATIONID>=48742557da98&ACK=Success&VERSION=88%2e0&BUILD=16428450
CreateRecurringPaymentsProfile
Parameters:
{:TOKEN=>"EC-0H440138VJ9552235", :BILLINGPERIOD=>:Month,
:BILLINGFREQUENCY=>2, :TOTALBILLINGCYCLES=>0, :AMT=>"88.00",
:CURRENCYCODE=>"HKD", :SHIPPINGAMT=>"0.00", :TAXAMT=>"0.00",
:DESC=>"Plus x 2-month subscription x 2 staff", :MAXFAILEDPAYMENTS=>0,
:PROFILESTARTDATE=>"2015-04-25 16:39:24"}
Response:
TIMESTAMP=2015%2d04%2d25T08%3a39%3a26Z&CORRELATIONID=533964ff183a1&ACK=Failure&VE>RSION=88%2e0&BUILD=16398710&L_ERRORCODE0=11502&L_SHORTMESSAGE0=Invalid%20Token&L_>LONGMESSAGE0=The
%20token%20is%20invalid&L_SEVERITYCODE0=Error
Do you guys have any ideas of what could be wrong? I can execute a payment without any issue, the issue appear when creating a recurring profile.
Never mind!
I found what was wrong misread the gem wiki (https://github.com/nov/paypal-express/wiki/Recurring-Payment) and mistakenly mix instant payment request with recurring profile creation so there was no billing_agreement_description nor billing_agreements in the data sent to paypal...

Twilio check if phone number has been blacklisted

I am currently integrating into the twilio rest api and need to perform a check on a users phone number to determine if that user has blacklisted themselves or not. I have little experience with this api and scouring through the documentation and google has turned up nothing.
In our application we are going to have a notification center and if the user has blacklisted themselves I do not want to give them the ability to turn on their SMS notifications. Potentially a user could have SMS notifications on but twilio would block any messages. I know there is the ability to get a status code back from twilio when an SMS is queued that shows the user is blacklisted (https://www.twilio.com/docs/api/rest/message). However, I will not be sending messages on the notifications screen and need a direct way (if at all possible) to check twilio to determine if a number is blacklisted. Any help is much appreciated. Let me know if anymore information will be of help.
Megan from Twilio.
I'd be curious to see if you ever tried your own workaround. But I wanted to note for others in a similar situation how you could grab the blacklist error and then do whatever you may want with it.
In Ruby it would look something like this:
require 'rubygems'
require 'twilio-ruby'
account_sid = 'YOUR_ACCOUNT_SID'
auth_token = 'YOUR_AUTH_TOKEN'
#client = Twilio::REST::Client.new account_sid, auth_token
begin
#message = #client.messages.create(
from: 'TWILIO_NUMBER',
to: 'USER_NUMBER',
body: 'Howdy!'
)
rescue Twilio::REST::RestError => e
if e.code == 21610
# User is blacklisted
# Store info however you choose
puts e.message
end
end
We check for blacklisting specifically using the code '21610'. For more information about errors you can visit the reference page.
Hope this helps!
Twilio recommends developers to store the opt-out/in statuses in their side. I have stored it in DB. There are 2 ways to collect the unsubscribed users list.
1) Use SMS webhooks. You can find how to configure your Twilio number to receive webhook events here
#PostMapping(value = "/twilio", consumes = MediaType.APPLICATION_FORM_URLENCODED_VALUE,
produces = MediaType.APPLICATION_ATOM_XML_VALUE)
public String twilioConsumer(TwilioEventDTO twilioEventDTO) {
// twilioEventDTO.getBody() => returns the body of the SMS user replied.
twilioService.consume(twilioEventDTO);
return new MessagingResponse.Builder().build().toXml();
}
2) Since I implemented webhooks later, I had to collect already unsubscribed users. When you send sms to the number that has been opted-out, Twilio API throws an exception with the status number of 21610. You can catch it and store the number in DB.
try {
Message result = Message.creator(
new PhoneNumber(toPhoneNumber),
new PhoneNumber(fromPhoneNumber),
messageBody)
.create();
response = result.getStatus().name();
} catch (ApiException e) {
if (e.getCode().equals(21610))
updateSubscription(toPhoneNumber, false);
logger.warn("Error on sending SMS: {}", e.getMessage());
}
P.S.: examples written in Java - Spring Boot framework.

Resources