-
Notifications
You must be signed in to change notification settings - Fork 2.5k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Fortis: Initial implementation #5349
Conversation
77daa32
to
c643967
Compare
c643967
to
20b9b8b
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Awesome job 🚀
@@ -31,6 +31,7 @@ RuboCop::RakeTask.new | |||
|
|||
namespace :test do | |||
Rake::TestTask.new(:units) do |t| | |||
ENV['RUNNING_UNIT_TESTS'] = 'true' |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Why is this ENV needed ❓
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Oh, this one is a workaround for preventing Net::HTTP refinement from having some effect on unit tests mocs on test/unit/connection_test.rb
331 => 'Credit/Debit/Refund ach Charged Back' | ||
} | ||
|
||
REASON_MAPPING = { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
was the mapping for status and reason needed due the Fortis response does not return a readable message, or was it for another specific reason ❓
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Most of the times Fortis returns an status_mapping and a reason_mapping but not the actual message
end | ||
|
||
def commit(action, post, method = :post, options = {}) | ||
add_location_id(post) if post.present? |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
what is the advantage of sending the location_id
in the post ❓
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Is an optional normally that is usefull to identify the request source (Fortis customer normally are shops with card machines or terminals) and for the store transaction is a must.
@@ -76,7 +76,7 @@ def request(method, body, headers = {}) | |||
http.get(endpoint.request_uri, headers) | |||
when :post | |||
debug body | |||
http.post(endpoint.request_uri, body, RUBY_184_POST_HEADERS.merge(headers)) | |||
http.post(endpoint.request_uri, body, headers.reverse_merge!(RUBY_184_POST_HEADERS)) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Is this change related to the HTTP version ❓
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Exactly, see:
the headers object is a CaseSensitiveHeaders
object that acts like a Hash, the merge
method called on RUBY_182_POST_HEADERS hash will return a new Hash not a CaseSensitveHeaders that I need in the refinement.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Why using reverse merge? Is order of these headers also important?
20b9b8b
to
3142cd0
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Most of my review is around the changes to the http modules to accommodate this gateways quirkiness. It seems like the implementation should leave the existing gateways unaffected, but did you run any of the remote tests against any other gateways to see if they yielded any different results?
} | ||
|
||
def initialize(options = {}) | ||
requires!(options, :user_id, :user_api_key, :developer_id, :location_id) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think based on our discussion, we probably can remove location_id
and make it an optional class field.
@@ -76,7 +76,7 @@ def request(method, body, headers = {}) | |||
http.get(endpoint.request_uri, headers) | |||
when :post | |||
debug body | |||
http.post(endpoint.request_uri, body, RUBY_184_POST_HEADERS.merge(headers)) | |||
http.post(endpoint.request_uri, body, headers.reverse_merge!(RUBY_184_POST_HEADERS)) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Why using reverse merge? Is order of these headers also important?
private :capitalize | ||
end | ||
|
||
class CaseSensitivePost < Net::HTTP::Post; prepend InnocuousCapitalize; end |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Is the prepend
intended to give precedence to the existing behavior, which is capitalizing header fields?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
reponses:
-
no because of order, but because of classes see => hash_object.merge!(case_sensitve_header_hash), en-up being a plain ruby
Hash
, but case_sensitve_header_hash.merge!(hash_object) updatesCaseSensitiveHeaders
instant but is still that class, so I can differentiate in the Refinement. -
yes exactly that
3142cd0
to
2f67c66
Compare
Summary: ------------------------------ Fortis Gateway intial implementation with support for: - Authorize - Purchase - Void - Capture - Refund - Credit - Store - Unstore Remote Test: ------------------------------ Finished in 114.375184 seconds. 22 tests, 53 assertions, 0 failures, 0 errors, 0 pendings, 0 omissions, 0 notifications 100% passed 0.19 tests/s, 0.46 assertions/s Unit Tests: ------------------------------ Finished in 68.455283 seconds. 6138 tests, 80277 assertions, 0 failures, 0 errors, 0 pendings, 0 omissions, 0 notifications 100% passed RuboCop: ------------------------------ 807 files inspected, no offenses detected
38324b9
to
50f3987
Compare
Summary:
Fortis Gateway initial implementation with support for:
Net::HTTP Refinement:
Context:
There is an issue with the Fortis API because their back-end returns an "invalid credentials" error if the HTTP Request headers are not in lower-case format, but Ruby by default follows the HTTP 1.1 RFC 2616 on how to handle headers; Ruby camellize all headers from something like 'user-api-key' to 'User-Api-Key', that is performed by Net::HTTPHeader#capitalize, so to deal with that we had to find a way to force net/http to send lower-case headers.
Enter Refinements:
So with Ruby Refinements, we can monkey patch net/http but only in the context of ActiveMerchant requests without side-effects on other areas of the system, two changes were introduced:
CaseSensitiveHeaders
class, an alias for a hash, allows us to indicate in the Fortis adapter that we will need case-sensitive headers.CaseSensitiveHeaders
.Remote Test:
Finished in 114.375184 seconds.
22 tests, 53 assertions, 0 failures, 0 errors, 0 pendings, 0 omissions, 0 notifications
100% passed
0.19 tests/s, 0.46 assertions/s
Unit Tests:
Finished in 68.455283 seconds.
6138 tests, 80277 assertions, 0 failures, 0 errors, 0 pendings, 0 omissions, 0 notifications
100% passed
RuboCop:
807 files inspected, no offenses detected