I'm work on debugging an application that is currently running on Ruby 2.5.8 with ActiveMerchant 1.117.0.
I am able to create and save the subscription successfully. However, when I try to authorize the saved card I keep getting reasonCode 102. The error from the Cybersource gateway side is the subscription () could not be found.
I'm attempting to authorize with the function:
def authorize(token, amount, order_id, line_items)
response = gateway.authorize(amount, token, order_id: order_id, line_items: line_items)
if !response.success?
raise Exceptions::ChargeFailed.new(response.message, response: response)
end
response
end
The error would lead me to believe that the formatting here is not correct. Can anyone point me to some working ActiveMerchant CyberSource examples for authorizing a subscription or point out what might be wrong here?
After some digging, it appears that the logic for token assignment changed inside of the ActiveMerchant CyberSource gem
The original logic was:
if reference
_, subscription_id, _ = reference.split(";")
xml.tag! 'subscriptionID', subscription_id
end
The latest versions this shifted towards:
if reference
subscription_id = reference.split(";")[6]
xml.tag! 'subscriptionID', subscription_id
end
The application that I am working with previously had been formatting the CyberSource profile / subscription id as ;#{token};. In order to work with these latest updates the token needs to be formatted as ;;;;;;#{token}.
Related
I have implemented Braintree subscription payment in rails app. Everything works fine in development, however when I switched to production (I have registered with Braintree and got a real account, and I change all the key in environment)
I have tried to submit an invalid card information to test the app, the page keeps showing error.
I look at the application logs and it said
NoMethodError (undefined method `customer' for #<Braintree::ErrorResult:0x007f6ed80f1d80>):
Here's my create method, I follow your tutorial and it works fine in development
def create
if current_user.braintree_id?
customer = Braintree::Customer.find(current_user.braintree_id)
else
result = Braintree::Customer.create(
email: current_user.company_email,
company: current_user.company_name,
payment_method_nonce: params[:payment_method_nonce]
)
customer = result.customer
current_user.update(braintree_id: customer.id)
end
result = Braintree::Subscription.create(
payment_method_token: customer.payment_methods.find{ |pm| pm.default? }.token,
plan_id: params[:plan_id]
)
if result.success?
result.subscription.transactions.each do |transaction|
current_user.transactions.create(braintree_transaction_id: transaction.id,
plan_name: params[:plan_name],
price: transaction.amount.to_f,
start_date: transaction.subscription_details.billing_period_start_date,
end_date: transaction.subscription_details.billing_period_end_date,
subscription_id: result.subscription.id
)
end
current_user.update(braintree_subscription_id: result.subscription.id,
next_billing_date: result.subscription.next_billing_date,
billing_period_start_date: result.subscription.billing_period_start_date,
billing_period_end_date: result.subscription.billing_period_end_date,
status: result.subscription.status,
next_billing_period_amount: result.subscription.next_billing_period_amount,
paid_through_date: result.subscription.paid_through_date,
plan_id: params[:plan_id],
plan_name: params[:plan_name])
flash[:info] = "You've been subscribed successfully"
redirect_to #current_user
else
flash[:warning] = "Invalid card information"
render 'new'
end
end
The weird thing is it doesn't render the flash warning of unsuccessful result and redirect to the original new_subscription_path, instead the website url redirect to this
https://herokuappname.herokuapp.com/subscription.1
and the page error shows
This page isn’t working herokuappname.herokuapp.com is currently unable to handle this request.
HTTP ERROR 500
So, I want to know whether it is the customer method error (which I don't think so because it doesn't have any problem in development mode) or any other problem such as why the page url so weird?
I looked at the Braintree control panel, and the reason that the subscription failed was because the bank declined the transactions due to incorrect card information, which I entered incorrect card in order to test it, if it is invalid card info, why didn't it display the flash notice and redirect back to the new_subscription_path, instead it redirects to the subscription.1 url which I have mentioned above?
Full disclosure: I work at Braintree. If you have any further questions, feel free to contact support.
I'm not sure if you used the same invalid card number for testing in production as in sandbox, but I'll try to answer your questions with the information we have on hand:
NoMethodError (undefined method `customer' for #):
By attempting to create a customer with a payment method with an invalid card, the result of that API call was an ErrorResult object. ErrorResult objects are either a validation error, processor decline, gateway rejection, or other exception messages, and do not contain a customer method. Hence, the undefined method error.
You should add some error handling around all of your Braintree API calls so that you can address any errors throughout the subscription process.
I'm using stripe to verify a profile before any transactions happen, so I want to see webhooks that have type account.updated and check the verification.status.
Im receiving a 404 error '(Status 404) (Request req_AwRiJSFxaOn1Jq) No such event: evt_1AaW9jFzjmmh0zTvsNSlfDLv
I realize that i need a stripe account header for the specific account that the webhook is being made for. I cant figure out how to add an account header to my stripe.rb code. I saved the stripe_account_id in the database on account creation so i can pull that id out from the database. The part that confuses me is when the webhook sends to my app the account_id is in the webhook, so it seems I have to pull that part out of the webhook and paste into stripe.rb {:stripe_account => CONNECTED_STRIPE_ACCOUNT_ID}. how is this possible?
This is the webhook that was sent from stripe in console (this is test data so i dont mind that people can see this cause its getting deleted soon anyways)
stripe.rb
require 'stripe'
Rails.configuration.stripe = {
:publishable_key => ENV["STRIPE_PUBLISHABLE_KEY"],
:secret_key => ENV["STRIPE_SECRET_KEY"]
}
Stripe.api_key = ENV["STRIPE_SECRET_KEY"]
StripeEvent.configure do |events|
events.all do |event|
# target specific events here
puts "this is working so far"
if event.type == 'account.updated'
account_event = event.data.object
puts "account updated working"
puts "#{account_event}"
end
end
end
I received the webhook in stripe connected account dashboard and my app console.
You're likely missing the Stripe-Account header, so it's trying to fetch the Event from your Account, rather than from the Stripe Account in which it exists.
EDIT: Sorry, I totally misunderstood your question. I think you need to configure the StripeEvent receiver to use the Stripe Account.
I am installing the Mollie payments API. Unfortunately, I get an unpermitted parameters: _method, authenticity_token (in the log). Here I would expect that a new window is opened that connects with Mollie.
I call the API by:
if #reservation
mollie = Mollie::API::Client.new('test_gUejkz43UkdeCauC22J6UNqqVRdpwW')
payment = mollie.payments.create(
amount: 10.00,
description: 'My first API payment',
redirectUrl: 'http://localhost:3000'
)
The reservation is made and the site does not give an active error, which makes me think the API is not called. Does anyone see what I am doing wrong? I installed the gem, I use Rails 4 and use require 'Mollie/API/Client' on top of the controller.
Any suggestionis highly appreciated! Thanks
I am using the official Paypal Ruby adaptive payments gem in conjunction with the embedded payment flow to collect one time payments on my site.
The payment itself is working correctly, however in my callback I wish to check if the payment went through. When I query the payment using the code suggested here, success is true even if I cancel the payment.
require 'paypal-sdk-adaptivepayments'
#api = PayPal::SDK::AdaptivePayments::API.new
# Build request object
#payment_details = #api.build_payment_details({
:payKey => "AP-xxxxxxxxxxxxxxxx" })
# Make API call & get response
#payment_details_response = #api.payment_details(#payment_details)
# Access Response
if #payment_details_response.success?
# Comes in here every time as #payment_details_response.success? always = true
else
#payment_details_response.error
end
How do I go about checking if the payment was cancelled? (By cancelled the payment I mean click the X on the popup)
Update:
I've found a workaround for now, but its strange how the success? is always true
if #payment_details_response.paymentInfoList.paymentInfo[0].transactionStatus
&& #payment_details_response.paymentInfoList.paymentInfo[0].transactionStatus == "COMPLETED"
#success
else
#fail
end
With the Adaptive Payments platform you have to sort of think about things in 2 parts:
API Call
Transaction(s)
The API call could very well be successful while the transaction(s) is not completed, and that seems to be what you're running into here, so what you've done would be correct in my opinion.
I'm trying to use OAuth2 for Server to Server Applications in conjunction with Google's Content API for Shopping using the google-api-client gem and Ruby on Rails 3.2.5. Also, I have already set up my merchant account as prescribed in the Content API documentation.
This was the best way I found to be able to:
create/update products in the background
have created products fall under my company's Google Products 'umbrella'
not require every user to authenticate/authorize when their token expires
Using lines 1 - 23 from this sample as a starting point, I've begun to write the following module for use in background jobs:
require 'httparty'
require 'google/api_client'
module GoogleProducts
GOOGLE_CONFIG = YAML.load_file(File.join(Rails.root, "config", "google.yml"))[Rails.env]
CLIENT_ID = "XXXXXXXXXXXX#developer.gserviceaccount.com"
MERCHANT_ID = "XXXXXXX"
SCOPE = "https://www.googleapis.com/auth/structuredcontent"
KEY_FILE_PATH = File.join(Rails.root, "config", "my-privatekey.p12")
KEY_FILE_PASS = "XXXXXXXXXX"
def self.add_item(item_id)
self.fetch_token
xml = self.gen_item_xml(item_id)
headers = {"Content-type" => "application/atom+xml", "Content-Length" => xml.length.to_s}
url = "https://content.googleapis.com/content/v1/#{MERCHANT_ID}/items/products/generic?access_token=#{$gp_token}"
response = HTTParty.post(url, :body => xml, :headers => headers).parsed_response
end
def self.gen_item_xml(item_id)
#building product xml
end
private
def self.fetch_token
api_client = Google::APIClient.new(:authorization => :oauth2)
key = Google::APIClient::PKCS12.load_key(KEY_FILE_PATH, KEY_FILE_PASS)
asserter = Google::APIClient::JWTAsserter.new(CLIENT_ID, SCOPE, key)
begin
api_client.authorization = asserter.authorize
#todo - store in something other than a global
$gp_token = api_client.authorization.access_token
rescue Signet::AuthorizationError => e
puts e.message
ensure
return $gp_token
end
end
end
Everything seemingly works fine - the authentication, the handling of the auth token - until I attempt to actually add an item, which I get the following when I do:
<errors xmlns='http://schemas.google.com/g/2005'>
<error>
<domain>GData</domain>
<code>ServiceForbiddenException</code>
<internalReason>Could not find authenticated customer</internalReason>
</error>
</errors>
Any ideas?
After much anguish and mental toil, I've finally solved my issue!
Since I am using OAuth 2 Server to Server authentication the suggestion hjblok gave didn't apply (thanks for giving it a shot, though!).
I simply added the email address that was associated with my Service Account key from the Google API Console (e.g. XXXXXXXXXXXX#developer.gserviceaccount.com) to my Google Merchant account (Settings > Users on the merchant admin page), and it worked.
If there's any clarification needed, please feel free to comment!
The Google Content API documentation says you need to set it up in the Settings page of the Google Merchant Center:
https://developers.google.com/shopping-content/getting-started/usingapi-products
EDIT rewrote the answer after diving into the Google's API documentation
Did you already try to use Google's OAuth 2.0 playground? I was able to successfully access https://content.googleapis.com/content/v1/#{MERCHANT_ID}/items/products/generic.
In "Step 1" I've chosen the "Content API for Shopping" and then authorized the API with my account.
Then in "Step 2" I've "exchanged authorization code for tokens", which results in a "refresh token" and an "access token".
Then in "Step 3" I've invoked a GET request to https://content.googleapis.com/content/v1/1234567/items/products/generic. Because 1234567 is not a valid MERCHANT_ID it returns an Error. But the Error Messages contains a MERCHANT_ID which actually belongs to your account.
I repeated "Step 3" but now with the correct MERCHANT_ID. Which returns a HTTP/1.1 200 OK with the requested items in the body.
Furthermore I'm not sure, but doesn't Google API expect an Authorization header to be present with the access_token ($gp_token)? Within the OAuth 2.0 playground this Authorization header is used to sent the access_token.
I also found the Structured Content API demo page (https://google-content-api-tools.appspot.com/demo/demo.html), which is more specific to the Content API for Shopping.