Hi, first of all thank you very much for creating and releasing this library.
I have been working to integrate the library into a project where we want to use PayPal. The project uses both PayPal instant payment and PayPal payment authorization and here comes the problem.
Currently, the paypal-express
library doesn't support PayPal authorization, nor it provides authorization
, void
and capture
methods. Moreover, integrating such feature at runtime or in a fork requires a lot of monkey patching because it's impossible to supply custom attributes on the fly to existing methods.
My proposal is to relax the method PayPal::Express::Request
definitions in order to allow arbitrary parameters to be supplied at runtime.
Let me show you an example.
https://github.com/nov/paypal-express/blob/master/lib/paypal/express/request.rb#L42-52
Here's the current checkout!
method.
def checkout!(token, payer_id, payment_requests)
params = {
:TOKEN => token,
:PAYERID => payer_id
}
Array(payment_requests).each_with_index do |payment_request, index|
params.merge! payment_request.to_params(index)
end
response = self.request :DoExpressCheckoutPayment, params
Response.new response
end
In order to introduce the Authorization, I should be able to pass the PAYMENTREQUEST_0_PAYMENTACTION
option and set it to Authorization
or Order
. But this is just an example, there is a number of additional fields I might want to supply to the :DoExpressCheckoutPayment
call such as GIFTMESSAGE
, BUTTONSOURCE
, ...
PS. I know that PAYMENTREQUEST_0_PAYMENTACTION
can be supplied using the Paypal::Payment::Request
, but this is just an example.
My proposal is to change the method definition to something like
def checkout!(token, payer_id, payment_requests, options = {})
params = {
:TOKEN => token,
:PAYERID => payer_id
}
merge_request_params(params, payment_requests)
merge_optional_params(params, options)
response = self.request :DoExpressCheckoutPayment, params
Response.new response
end
private
def merge_request_params(params, payment_requests)
Array(payment_requests).each_with_index do |payment_request, index|
params.merge! payment_request.to_params(index)
end
end
def merge_optional_params(params, options)
options.each do |key, value|
params.merge! key.upcase => value
end
end
@request.checkout!(..., ..., [payment_request], :GIFTMESSAGE => "My personal gift to you.")
You already provide the options
argument in some methods, however the options are filtered and custom values not mapped internally into the method are discarded. An other solution can be to pass an additional attribute so that options
(currently reserved for ruby-oriented options) are not mixed with custom options.
The options
value can be filtered or validated even further, but I believe that leaving the responsibility to the programmer can be a reasonable solution.
What do you think?