What else should I send for Paypal chained payments? - ruby

I'm working on an App where a user A can buy up to 10 items from different sellers, so I need to send money to different users at the same time and I'm trying to use Paypal Chained Payments.
Right now I'm just playing around with Classic API (Adaptive payments) but I'm just wondering why I'm always getting this error:
"The fee payer PRIMARYRECEIVER can only be used if a primary receiver is specified"
I already specified a primary receiver and I'm still getting that error.
I found these examples: https://paypal-sdk-samples.herokuapp.com/adaptive_payments/pay
and I tried to do a chained payment:
This is my pay request:
require 'paypal-sdk-adaptivepayments'
#api = PayPal::SDK::AdaptivePayments::API.new
# Build request object
#pay = #api.build_pay({
:actionType => "PAY",
:cancelUrl => "https://paypal-sdk-samples.herokuapp.com/adaptive_payments/pay",
:currencyCode => "USD",
:feesPayer => "PRIMARYRECEIVER",
:ipnNotificationUrl => "https://paypal-sdk-samples.herokuapp.com/adaptive_payments/ipn_notify",
:receiverList => {
:receiver => [{
:amount => 1.0,
:email => "platfo_1255612361_per#gmail.com",
:primary => true }] },
:returnUrl => "https://paypal-sdk-samples.herokuapp.com/adaptive_payments/pay",
:sender => {
:useCredentials => true } })
# Make API call & get response
#pay_response = #api.pay(#pay)
And this is the response
{
:responseEnvelope => {
:timestamp => "2013-11-20T05:16:31-08:00",
:ack => "Failure",
:correlationId => "b002d0e27fd33",
:build => "7935900" },
:error => [{
:errorId => 580023,
:domain => "PLATFORM",
:subdomain => "Application",
:severity => "Error",
:category => "Application",
:message => "The fee payer PRIMARYRECEIVER can only be used if a primary receiver is specified",
:parameter => [{
:value => "feesPayer" },{
:value => "PRIMARYRECEIVER" }] }] }
Thanks in advance!

taking a look at your call, you're indeed specifying a primary receiver. however, for chained payment, you will have to specify a secondary receiver.
I just ran a quick test with the following paramters:
actionType = PAY
requestEnvelope.errorLanguage = en_US
cancelUrl = http://abortURL
returnUrl = http://returnURL
ipnNotificationUrl = http://ipnURL
applicationId = Test
memo = Test
currencyCode = USD
receiverList.receiver(0).email = test#test.com
receiverList.receiver(0).amount = 5.00
receiverList.receiver(0).primary = true
feesPayer = PRIMARYRECEIVER
and got the result:
responseEnvelope.timestamp=2013-11-20T05:41:56.751-08:00
responseEnvelope.ack=Failure
responseEnvelope.correlationId=b61a6b31ea2ab
responseEnvelope.build=7935900
error(0).errorId=580023
error(0).domain=PLATFORM
error(0).subdomain=Application
error(0).severity=Error
error(0).category=Application
error(0).message=The fee payer PRIMARYRECEIVER can only be used if a primary receiver is specified
error(0).parameter(0)=feesPayer
error(0).parameter(1)=PRIMARYRECEIVER
However, once I change the FeesPayer to EACHRECEIVER, I get the error message that is causing the chained payment to fail in the first place:
responseEnvelope.timestamp=2013-11-20T05:48:09.202-08:00
responseEnvelope.ack=Failure
responseEnvelope.correlationId=987210ec4d03a
responseEnvelope.build=7935900
error(0).errorId=579008
error(0).domain=PLATFORM
error(0).subdomain=Application
error(0).severity=Error
error(0).category=Application
error(0).message=You must specify only one primary receiver and at least one secondary receiver
error(0).parameter(0)=1
I hope this helps.
Please refer to the PayPal Adaptive Payments SDK available under http://paypal.github.io/#adaptive-payments for some additional examples and inspiration

Related

How can I get the original charge and refund ids of an automatic payout

Stripe connect accounts are configurable to coalesce payouts in a regular payout schedule, e.g. for monthly payouts in our case. For these monthly payouts we need to explain the account owners which of the transactions on our platform (bookings and refunds in our case) produced the overall amount they receive. We store the stripe charge id (resp. refund id) in the booking (resp refund) objects in our database. Thus the question boils down to:
Given a stripe account id, how can you get the list of stripe charge and refund ids that contributed to the last payout?
I've had an extensive exchange with Stripe's support team and there are several puzzle pieces necessary to get there:
Payouts are scoped by accounts
If you query stripe for a list of payouts, you will only receive the payout objects that you, the platform owner, get from stripe. To get the payout objects of a specific account you can use the normal authentication for the platform, but send the stripe account id as a header. So the code snippet to get the last payout looks like this (I'll use ruby snippets as examples for the rest of the answer):
Stripe::Payout.list({limit: 1}, {stripe_account: 'acct_0000001234567890aBcDeFgH'})
=> #<Stripe::ListObject:0x0123456789ab> JSON: {
"object": "list",
"data": [
{"id":"po_1000001234567890aBcDeFgH",
"object":"payout",
"amount":53102,
"arrival_date":1504000000,
"balance_transaction":"txn_2000001234567890aBcDeFgH",
"created":1504000000,
"currency":"eur",
"description":"STRIPE TRANSFER",
"destination":"ba_3000001234567890aBcDeFgH",
"failure_balance_transaction":null,
"failure_code":null,
"failure_message":null,
"livemode":true,"metadata":{},
"method":"standard",
"source_type":"card",
"statement_descriptor":"[…]",
"status":"paid",
"type":"bank_account"
}
],
"has_more": true,
"url": "/v1/payouts"
}
Having the payout id, we can query the list of balance transactions, scoped to a payout:
Stripe::BalanceTransaction.all({
payout: 'po_1000001234567890aBcDeFgH',
limit: 2,
}, {
stripe_account: 'acct_0000001234567890aBcDeFgH'
})
Objects viewed as an account are stripped of most information, compared to those viewed as a platform owner
Even though you now have the payout id, the object is still scoped to the account and you cannot retrieve it as platform owner. But viewed as an account, the payout only shows pseudo charge and refund objects like these (notice the second transaction has a py_7000001234567890aBcDeFgH object as a source instead of a regular ch_ charge object):
Stripe::BalanceTransaction.all({
payout: 'po_1000001234567890aBcDeFgH',
limit: 2,
}, {
stripe_account: 'acct_0000001234567890aBcDeFgH'
})
=> {
:object => "list",
:data => [
{
:id => "txn_4000001234567890aBcDeFgH",
:object => "balance_transaction",
:amount => -53102,
:available_on => 1504000000,
:created => 1504000000,
:currency => "eur",
:description => "STRIPE TRANSFER",
:fee => 0,
:fee_details => [],
:net => -53102,
:source => "po_5000001234567890aBcDeFgH",
:status => "available",
:type => "payout"
},
{
:id => "txn_6000001234567890aBcDeFgH",
:object => "balance_transaction",
:amount => 513,
:available_on => 1504000000,
:created => 1504000000,
:currency => "eur",
:description => nil,
:fee => 0,
:fee_details => [],
:net => 513,
:source => "py_7000001234567890aBcDeFgH",
:status => "available",
:type => "payment"
}
],
:has_more => true,
:url => "/v1/balance/history"
}
You can let stripe automatically expand objects in the response
As an additional parameter, you can give stripe paths of objects which you want stripe to expand in their response. Thus we can walk from the pseudo objects back to the original charge objects via the transfers:
Stripe::BalanceTransaction.all({
payout: 'po_1000001234567890aBcDeFgH',
limit: 2,
expand:['data.source.source_transfer',]
}, {
stripe_account: 'acct_0000001234567890aBcDeFgH'
}).data.second.source.source_transfer.source_transaction
=> "ch_8000001234567890aBcDeFgH"
And if you want to process the whole list you need disambiguate between the source.object attribute:
Stripe::BalanceTransaction.all({
payout: 'po_1000001234567890aBcDeFgH',
limit: 2,
expand:['data.source.source_transfer',]
}, {
stripe_account: 'acct_0000001234567890aBcDeFgH'
}).data.map do |bt|
if bt.source.object == 'charge'
['charge', bt.source.source_transfer.source_transaction]
else
[bt.source.object]
end
end
=> [["payout"], ["charge", "ch_8000001234567890aBcDeFgH"]]
Refunds have no connecting object path back to the original ids
Unfortunately, there is currently no way to get the original re_ objects from the pseudo pyr_ that are returned by the BalanceTransaction list call for refund transactions. The best alternative I've found is to go via the data.source.charge.source_transfer.source_transaction path to get the charge id of the charge on which the refund was issued and use that in combination with the created attribute of the pyr_ to match our database refund object. I'm not sure, though, how stable that method really is. The code to extract that data:
Stripe::BalanceTransaction.all({
payout: 'po_1000001234567890aBcDeFgH',
limit: 100, # max page size, the code to iterate over all pages is TBD
expand: [
'data.source.source_transfer', # For charges
'data.source.charge.source_transfer', # For refunds
]
}, {
stripe_account: 'acct_0000001234567890aBcDeFgH'
}).data.map do |bt|
res = case bt.source.object
when 'charge'
{
charge_id: bt.source.source_transfer.source_transaction
}
when 'refund'
{
charge_id: bt.source.charge.source_transfer.source_transaction
}
else
{}
end
res.merge(type: bt.source.object, amount: bt.amount, created: bt.created)
end
It is now possible to get the refund ids via a "transfer reversal" object:
Stripe::BalanceTransaction.list({
payout: 'po_1000001234567890aBcDeFgH',
expand: [
'data.source.source_transfer', # For charges
'data.source.transfer_reversal', # For refunds
]
}, {
stripe_account: 'acct_0000001234567890aBcDeFgH'
}).auto_paging_each do |balance_transaction|
case balance_transaction.type
when 'payment'
charge_id = balance_transaction.source.source_transfer.source_transaction
when 'payment_refund'
refund_id = balance_transaction.source.charge.source_transfer.source_transaction
end
end
end

Best way of calculating stripe taxamo price including tax

Hi I'm curious of how to best calculate the price including VAT for a product pre checkout. Currently the only way I found is creating a order containing the item and then fetching the tax and price from the order. This however creates a lot of redundant orders and seems sub optimal. Is there a way to do this calculation without creating an order?
def get_price
location = current_user.location
location_data = APP_CONFIG['country_list'][location]
currency = location_data['currency']
country_code = location_data['code']
product_id = APP_CONFIG['stripe_reconstruction_ids'][currency]
product = Stripe::Product.retrieve(product_id)
product_sku = product['skus']['data'][0]['id']
ip = request.remote_ip
order = Stripe::Order.create(
:currency => currency,
:customer => current_user.stripe_id,
:items => [
{
:type => 'sku',
:parent => product_sku,
:quantity => 1,
:currency => currency
}
],
:email => current_user.email,
:metadata => {
:buyer_ip => ip,
:billing_country_code => country_code,
:product_type => 'e-service'
}
)
render :json => order, :status => 200 and return
rescue => error
logger.error error.message
render :json => { message: "Could not fetch the correct price." }, :status => 500 and return
end
UPDATE
After talking to the stripe support my proposal seems to be the best way to do this at the moment. I suggested to them that it would be nice if developers could set a flag on the order that it was just for pricing information to avoid creating an order that would not later be used for a payment. They said they would deliver this suggestion to their developers. Perhaps we will have a better way to do this in the future.
You can use Taxamo's API Calculate tax endpoint (Ruby client lib is available).
Note that if setting buyer_ip private token must be used, otherwise field is ignored.
Example curl call:
curl -X 'POST' -H "Content-Type: application/json" -d \
'{
"transaction": {
"currency_code": "EUR",
"transaction_lines": [
{
"custom_id": "line1",
"product_type": "e-service",
"amount": 100
}
],
"billing_country_code": "SOME_COUNTRY_CODE",
"buyer_ip": "SOME_IP"
},
"private_token": "YOUR_PRIVATE_TOKEN"
}' \
https://api.taxamo.com/api/v1/tax/calculate | python -m json.tool

Mandrill template merge fail

I'm using mandrill to send emails from my API (in ruby with the mandrill-api gem), like signup confirmation email.
I have a merge tag in the template to put the username :
Hello *|USERNAME|*,
Thank you very much for installing the app! ...
...
My ruby code looks like that :
m = Mandrill::API.new ENV['MANDRILL_KEY']
template_name = "app-registration-welcome-email"
template_content = [{}]
message = {
:from_name=> "From Name",
:to=>[
{
:email => user.email,
:name => user.name,
}
],
:global_merge_vars => [{
:name => "username",
:content => user.name
}],
:merge_language => "mailchimp",
:merge => true,
:merge_vars => [{
:rcpt => user.email,
:vars => [{
:name => "username",
:content => user.name
}],
}],
:track_opens => true,
}
m.messages.send_template template_name, template_content, message
Unfortunately, when i receive the email, all is fine (to, name, from, ...) but the merge tag isn't replaced in the body and i still have *|USERNAME|* displayed.
What am I missing here?
You should only need to set USERNAME once, either in :global_merge_vars or :merge_vars.
If you're sending to just one recipient, it doesn't matter which you do.
If there are multiple recipients, use :merge_vars.
Try building message and then puts message.to_json and drop it into the debugger at https://mandrillapp.com/api/docs/messages.JSON.html#method=send-template (Click the 'Try it' button.) See if that gives you any clues.
You might also try using "USERNAME" instead of "username" as your variable name. The docs say merge vars are case-insensitive, but it's worth removing one more possible mismatch.

Undefined method 'dateTime' for Google::ApiClient

Im working on a sinatra based application, in which I get events from a google calendar and display all events as a list. However I have encountered an unusual error when I tried to get the start and end dates of All day events.
Since all day events have an object of type Date, and timed events have an object of type dateTime , these two objects won't get displayed, the error I get is:
no such method named dateTime
It works fine when there is only timed events (dateTime object) events but not when there is an all day event (date object).
Any help would be great.
Code:
require 'rubygems'
require 'google/api_client'
require 'date'
# modified from 1m
# Update these to match your own apps credentials
service_account_email = "" # Email of service account
key_file = "" # File containing your private key
key_secret = 'notasecret' # Password to unlock private key
# Get the Google API client
client = Google::APIClient.new(:application_name => 'GCalendar',
:application_version => '1.0.0')
# Load your credentials for the service account
key = Google::APIClient::KeyUtils.load_from_pkcs12(key_file, key_secret)
client.authorization = Signet::OAuth2::Client.new(
:token_credential_uri => 'https://accounts.google.com/o/oauth2/token',
:audience => 'https://accounts.google.com/o/oauth2/token',
:scope => 'https://www.googleapis.com/auth/calendar',
:issuer => service_account_email,
:signing_key => key)
motd = Array.new
summary = ""
description = ""
tickerEvent = " "
# Start the scheduler
# Request a token for our service account
client.authorization.fetch_access_token!
# Get the calendar API
calendar = client.discovered_api('calendar','v3')
today = DateTime.now().to_s
# Execute the query
result = client.execute(:api_method => calendar.events.list,
:parameters => {'calendarId' => 'idNo',
'timeMin' => today,
'singleEvents' => true,
'orderBy' => 'startTime'})
events = result.data.items
events.each do |e|
if(DateTime.now() >= e.start.dateTime)
summary = e.summary
description = e.description
tickerEvent = summary.to_s + " - " +description.to_s
motd.push(tickerEvent)
elsif(DateTime.now() >= e.end.dateTime)
motd.delete(e)
end
end
motd.clear
end
Is there a way to check whether the event is a Date type or a DateTime type?
In the google api the start dateTime and end dateTime looks like (This is a timed event):
"start": {
"dateTime": "2013-12-03T12:30:00+13:00",
"timeZone": "Pacific/Auckland"
},
"end": {
"dateTime": "2013-12-03T13:00:00+13:00",
"timeZone": "Pacific/Auckland"
},
whereas an all day event looks like:
"start": {
"date": "2014-01-17"
},
"end": {
"date": "2014-01-18"
},
they are of different types, this is what is causing the error.
Cheers
The method is event.start.date_time not event.start.dateTime.
For events that do not have a time associated with them, event.start.date_time will return nil. You can then call event.start.date, which should return just the date.

How to add a Person using the Highrise Ruby gem?

I am trying to use https://github.com/tapajos/highrise/ to update user accounts when people sign up to an app. However I am not getting very far.
In console I am doing:
person = Highrise::Person.create(:name => "charlie")
Which saves fine, but if I do something like
person = Highrise::Person.create(:name => "charlie", :email => "charlie#222.com")
then I get:
Unprocessable Entity
I can not get my head around this, I essentially want to add a full record:
person = Highrise::Person.create(:name => "charlie", :params => {:contact_data => {:email_addresses => "charlie#222.com"}})
but still i get the same error and can not find any examples online
You were on the right track with that last attempt. Give this a try:
person = Highrise::Person.create(
:first_name => "Charlie", :last_name => "Bravo",
:contact_data => {
:email_addresses => [{
:email_address => {:address => "charlie#222.com"}
}]
}
)
This matches the structure of the create a person request, as defined in the Highrise API. https://github.com/37signals/highrise-api/blob/master/sections/people.md#create-person
Also you can refer to ruby api's test spec for more examples https://github.com/tapajos/highrise/blob/f44cb3212c6d49549330c46454fe440ac117fa1b/spec/highrise/person_spec.rb#L40

Resources