flowcommerce-activemerchant 0.1.3 → 0.1.4
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/.version +1 -0
- data/LICENSE +21 -0
- data/lib/active_merchant/billing/gateways/flow.rb +137 -87
- metadata +4 -2
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA1:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: fd3cd7c71165eb856d2df8a62f381c4a345216c2
|
|
4
|
+
data.tar.gz: 2da46342bd287ac1400862e00ab21d61d43b62e7
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 3531b26248d5a5015dc02786d73176b7e80b1e7ebac09a786a8ff4198fb22f0f478eb61080b643e8c38d16d794a3fd66cacc44477bb1775504731fa913cd7429
|
|
7
|
+
data.tar.gz: b9c3740fc926e3060403e9adfd64610d45a2534bf1d4ca0fcf19fa833a45fce930a8e8d2af43a477ee7a34dcb2296e823392949700bfee6c75b0f4936b10badc
|
data/.version
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
0.1.4
|
data/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
The MIT License (MIT)
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2017 - 2018 Flow Commerce Inc.
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
# @Flow.io (2017)
|
|
1
|
+
# @Flow.io (2017)
|
|
2
2
|
# Active Merchant adapter for Flow api
|
|
3
3
|
|
|
4
4
|
require 'flowcommerce-reference'
|
|
@@ -6,7 +6,15 @@ require 'flowcommerce-reference'
|
|
|
6
6
|
module ActiveMerchant
|
|
7
7
|
module Billing
|
|
8
8
|
class FlowGateway < Gateway
|
|
9
|
-
|
|
9
|
+
unless defined?(::ActiveMerchant::Billing::FlowGateway::VERSION)
|
|
10
|
+
VERSION = File.read(File.expand_path("../../../../.version", File.dirname(__FILE__))).chomp
|
|
11
|
+
|
|
12
|
+
FORM_TYPES = [
|
|
13
|
+
:authorization_copy_form, :direct_authorization_form, :merchant_of_record_authorization_form,
|
|
14
|
+
:paypal_authorization_form, :redirect_authorization_form, :inline_authorization_form,
|
|
15
|
+
:card_authorization_form, :ach_authorization_form
|
|
16
|
+
]
|
|
17
|
+
end
|
|
10
18
|
|
|
11
19
|
self.display_name = 'Flow.io Pay'
|
|
12
20
|
self.homepage_url = 'https://www.flow.io/'
|
|
@@ -14,6 +22,7 @@ module ActiveMerchant
|
|
|
14
22
|
self.supported_countries = FlowCommerce::Reference::Countries::ISO_3166_2
|
|
15
23
|
self.supported_cardtypes = FlowCommerce::Reference::PaymentMethods::SUPPORTED_CREDIT_CARDS
|
|
16
24
|
|
|
25
|
+
|
|
17
26
|
def initialize options = {}
|
|
18
27
|
@flow_api_key = options[:api_key] || ENV['FLOW_API_KEY']
|
|
19
28
|
@flow_organization = options[:organization] || ENV['FLOW_ORGANIZATION']
|
|
@@ -24,153 +33,194 @@ module ActiveMerchant
|
|
|
24
33
|
super
|
|
25
34
|
end
|
|
26
35
|
|
|
36
|
+
# Create a new authorization.
|
|
27
37
|
# https://docs.flow.io/module/payment/resource/authorizations#post-organization-authorizations
|
|
28
|
-
def authorize
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
data = {
|
|
34
|
-
token: response.token,
|
|
35
|
-
amount: amount,
|
|
36
|
-
currency: options[:currency],
|
|
37
|
-
cvv: payment_method.verification_value,
|
|
38
|
-
customer: {
|
|
39
|
-
name: {
|
|
40
|
-
first: payment_method.first_name,
|
|
41
|
-
last: payment_method.last_name
|
|
42
|
-
}
|
|
43
|
-
}
|
|
44
|
-
}
|
|
38
|
+
def authorize cc_or_token, order_number, opts={}
|
|
39
|
+
unless opts[:currency]
|
|
40
|
+
return error_response('Currency is a required option')
|
|
41
|
+
end
|
|
45
42
|
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
# order_number allready present at flow
|
|
49
|
-
data[:order_number] = options[:order_id]
|
|
50
|
-
::Io::Flow::V0::Models::MerchantOfRecordAuthorizationForm.new data
|
|
51
|
-
else
|
|
52
|
-
::Io::Flow::V0::Models::DirectAuthorizationForm.new data
|
|
53
|
-
end
|
|
54
|
-
|
|
55
|
-
response = flow_instance.authorizations.post @flow_organization, authorization_form
|
|
56
|
-
rescue => exception
|
|
57
|
-
return Response.new false, exception.message, { exception: exception }
|
|
43
|
+
unless opts[:discriminator]
|
|
44
|
+
return error_response 'Discriminator is not defined, please choose one [%s]' % FORM_TYPES.join(', ')
|
|
58
45
|
end
|
|
59
46
|
|
|
60
|
-
|
|
47
|
+
unless FORM_TYPES.include?(opts[:discriminator].to_sym)
|
|
48
|
+
return error_response 'Discriminator [%s] not found, please choose one [%s]' % [opts[:discriminator], FORM_TYPES.join(', ')]
|
|
49
|
+
end
|
|
61
50
|
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
51
|
+
body = {
|
|
52
|
+
amount: opts[:amount] || 0.0,
|
|
53
|
+
currency: opts[:currency],
|
|
54
|
+
discriminator: opts[:discriminator],
|
|
55
|
+
token: store(cc_or_token),
|
|
56
|
+
order_number: order_number
|
|
57
|
+
}
|
|
69
58
|
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
59
|
+
response = flow_instance.authorizations.post @flow_organization, body
|
|
60
|
+
|
|
61
|
+
Response.new true, 'Flow authorize - Success', { response: response }, { authorization: response.id }
|
|
62
|
+
rescue => exception
|
|
63
|
+
error_response exception
|
|
64
|
+
end
|
|
65
|
+
|
|
66
|
+
# https://docs.flow.io/module/payment/resource/authorizations#get-organization-authorizations
|
|
67
|
+
def flow_get_authorization order_number:
|
|
68
|
+
response = flow_instance.authorizations.get @flow_organization, order_number: order_number
|
|
69
|
+
response.last
|
|
70
|
+
rescue => exception
|
|
71
|
+
error_response exception
|
|
74
72
|
end
|
|
75
73
|
|
|
76
74
|
# https://docs.flow.io/module/payment/resource/captures#post-organization-captures
|
|
77
|
-
def capture
|
|
78
|
-
|
|
75
|
+
def capture amount, authorization_key, options={}
|
|
76
|
+
return error_response('Currency is a required option') unless options[:currency]
|
|
77
|
+
|
|
78
|
+
body = {
|
|
79
|
+
authorization_id: authorization_key,
|
|
80
|
+
amount: amount,
|
|
81
|
+
currency: options[:currency]
|
|
82
|
+
}
|
|
79
83
|
|
|
80
84
|
begin
|
|
81
|
-
capture_form = ::Io::Flow::V0::Models::CaptureForm.new
|
|
85
|
+
capture_form = ::Io::Flow::V0::Models::CaptureForm.new body
|
|
82
86
|
response = flow_instance.captures.post @flow_organization, capture_form
|
|
83
87
|
rescue => exception
|
|
84
88
|
error_response exception
|
|
85
89
|
end
|
|
86
90
|
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
if response.id
|
|
90
|
-
Response.new true, 'Flow capture - Success', options
|
|
91
|
+
if response.try(:id)
|
|
92
|
+
Response.new true, 'Flow capture - Success', { response: response }
|
|
91
93
|
else
|
|
92
|
-
Response.new false, 'Flow capture - Error',
|
|
94
|
+
Response.new false, 'Flow capture - Error', { response: response }
|
|
93
95
|
end
|
|
96
|
+
rescue Io::Flow::V0::HttpClient::ServerError => exception
|
|
97
|
+
error_response exception
|
|
94
98
|
end
|
|
95
99
|
|
|
96
|
-
def purchase
|
|
97
|
-
response = authorize
|
|
98
|
-
capture
|
|
100
|
+
def purchase credit_card, order_number, options={}
|
|
101
|
+
response = authorize credit_card, order_number, options
|
|
102
|
+
capture options[:amount], response.authorization, options
|
|
99
103
|
end
|
|
100
104
|
|
|
101
|
-
# https://docs.flow.io/module/payment/resource/
|
|
102
|
-
|
|
103
|
-
|
|
105
|
+
# https://docs.flow.io/module/payment/resource/reversals#post-organization-reversals
|
|
106
|
+
# if amount is not provided, reverse the full or remaining amount
|
|
107
|
+
def void amount, authorization_id, options={}
|
|
108
|
+
options[:authorization_id] = authorization_id
|
|
109
|
+
|
|
110
|
+
if amount
|
|
111
|
+
options[:amount] = assert_currency options[:currency], amount
|
|
112
|
+
end
|
|
113
|
+
|
|
114
|
+
response = flow_instance.reversals.post @flow_organization, options
|
|
115
|
+
|
|
104
116
|
Response.new true, 'void success', { response: response }
|
|
105
117
|
rescue Io::Flow::V0::HttpClient::ServerError => exception
|
|
106
|
-
error_response
|
|
118
|
+
error_response exception
|
|
107
119
|
end
|
|
108
120
|
|
|
109
121
|
# https://docs.flow.io/module/payment/resource/refunds
|
|
110
122
|
# authorization_id - The Id of the authorization against which to issue the refund. If specified, we will look at all captures for this authorization, selecting 1 or more captures against which to issue the refund of the requested amount.
|
|
111
123
|
# capture_id - The Id of the capture against which to issue the refund. If specified, we will only consider this capture.
|
|
112
124
|
# order_number - The order number if specified during authorization. If specified, we will lookup all authorizations made against this order number, and then selecting 1 or more authorizations against which to issue the refund of the requested amount.
|
|
113
|
-
# key - Your unique identifier for this transaction, which if provided is used to implement idempotency. If not provided, we will assign.
|
|
114
125
|
# amount - The amount to refund, in the currency of the associated capture. Defaults to the value of the capture minus any prior refunds.
|
|
115
126
|
# currency - The ISO 4217-3 code for the currency. Required if amount is specified. Case insensitive. Note you will get an error if the currency does not match the related authrization's currency. See https://api.flow.io/reference/currencies
|
|
116
127
|
# rma_key - The RMA key, if available. If specified, this will udpate the RMA status as refunded.
|
|
117
128
|
def refund amount, capture_id, options={}
|
|
118
|
-
|
|
119
|
-
refund_form[:amount] = amount if amount
|
|
120
|
-
refund_form[:capture_id] = capture_id if capture_id
|
|
129
|
+
options[:capture_id] = capture_id if capture_id
|
|
121
130
|
|
|
122
|
-
|
|
123
|
-
|
|
131
|
+
if amount
|
|
132
|
+
options[:amount] = assert_currency options[:currency], amount
|
|
124
133
|
end
|
|
125
134
|
|
|
126
|
-
|
|
127
|
-
raise ArgumentError, 'Currency is required if amount is provided' unless refund_form[:currency]
|
|
128
|
-
refund_form[:amount] = assert_currency refund_form[:currency], refund_form[:amount]
|
|
129
|
-
end
|
|
135
|
+
response = flow_instance.refunds.post @flow_organization, options
|
|
130
136
|
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
def store credit_card, options={}
|
|
137
|
-
response = get_flow_cc_token credit_card
|
|
138
|
-
Response.new true, 'Credit card stored', { response: response, token: response.token }
|
|
137
|
+
if response.try(:id)
|
|
138
|
+
Response.new true, 'Flow refund - Success', { response: response }
|
|
139
|
+
else
|
|
140
|
+
Response.new false, 'Flow refund - Error', { response: response }
|
|
141
|
+
end
|
|
139
142
|
rescue Io::Flow::V0::HttpClient::ServerError => exception
|
|
140
143
|
error_response exception
|
|
141
144
|
end
|
|
142
145
|
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
146
|
+
# stores credit card and returns credit card Flow token String id
|
|
147
|
+
def store input
|
|
148
|
+
credit_card =
|
|
149
|
+
case input
|
|
150
|
+
when Hash
|
|
151
|
+
ActiveMerchant::Billing::CreditCard.new input
|
|
152
|
+
when ActiveMerchant::Billing::CreditCard
|
|
153
|
+
input
|
|
154
|
+
when String
|
|
155
|
+
return input
|
|
156
|
+
else
|
|
157
|
+
raise 'Unsuported store method input type [%s]' % input.class
|
|
158
|
+
end
|
|
148
159
|
|
|
149
|
-
def get_flow_cc_token credit_card
|
|
150
160
|
data = { number: credit_card.number,
|
|
151
161
|
name: '%s %s' % [credit_card.first_name, credit_card.last_name],
|
|
152
162
|
cvv: credit_card.verification_value,
|
|
153
163
|
expiration_year: credit_card.year.to_i,
|
|
154
164
|
expiration_month: credit_card.month.to_i
|
|
165
|
+
address: credit_card.address
|
|
155
166
|
}
|
|
156
167
|
|
|
157
|
-
|
|
158
|
-
|
|
168
|
+
response = flow_instance.cards.post @flow_organization, data
|
|
169
|
+
|
|
170
|
+
if response.respond_to?(:token)
|
|
171
|
+
Response.new true, 'Flow refund - Success', { response: response }
|
|
172
|
+
else
|
|
173
|
+
Response.new false, 'Flow POST /:organization/cards - Failure', { response: response }
|
|
174
|
+
end
|
|
175
|
+
rescue Io::Flow::V0::HttpClient::ServerError => exception
|
|
176
|
+
error_response exception
|
|
177
|
+
end
|
|
178
|
+
|
|
179
|
+
# Creates and order
|
|
180
|
+
# https://docs.flow.io/module/localization/resource/orders#post-organization-orders
|
|
181
|
+
def flow_create_order body, query_string={}
|
|
182
|
+
flow_instance.orders.post @flow_organization, body, query_string
|
|
183
|
+
rescue => exception
|
|
184
|
+
error_response exception
|
|
185
|
+
end
|
|
186
|
+
|
|
187
|
+
# Submits an order and
|
|
188
|
+
# pushes all subsequent authorizations from status "review" to "authorized"
|
|
189
|
+
# takes ~ 60 seconds
|
|
190
|
+
def flow_submission_by_number order_number
|
|
191
|
+
flow_instance.orders.put_submissions_by_number @flow_organization, order_number
|
|
192
|
+
rescue => exception
|
|
193
|
+
error_response exception
|
|
194
|
+
end
|
|
195
|
+
|
|
196
|
+
private
|
|
197
|
+
|
|
198
|
+
def flow_instance
|
|
199
|
+
FlowCommerce.instance token: @flow_api_key
|
|
159
200
|
end
|
|
160
201
|
|
|
161
202
|
def error_response exception_object
|
|
162
|
-
message =
|
|
203
|
+
message =
|
|
204
|
+
if exception_object.is_a?(String)
|
|
205
|
+
exception_object
|
|
206
|
+
elsif exception_object.respond_to?(:body) && exception_object.body.length > 0
|
|
163
207
|
description = JSON.load(exception_object.body)['messages'].to_sentence
|
|
164
208
|
'%s: %s (%s)' % [exception_object.details, description, exception_object.code]
|
|
165
|
-
|
|
209
|
+
elsif exception_object.respond_to?(:message)
|
|
166
210
|
exception_object.message
|
|
211
|
+
else
|
|
212
|
+
raise ArgumentError.new('Unsuported exception_object [%s]' % exception_object.class)
|
|
167
213
|
end
|
|
168
214
|
|
|
215
|
+
msg = 'ERROR: %s' % message
|
|
216
|
+
msg = msg.yellow if msg.respond_to?(:yellow)
|
|
217
|
+
|
|
218
|
+
puts msg
|
|
219
|
+
|
|
169
220
|
Response.new false, message, exception: exception_object
|
|
170
221
|
end
|
|
171
222
|
|
|
172
223
|
def assert_currency currency, amount
|
|
173
|
-
raise ArgumentError, 'currency not provided' unless currency
|
|
174
224
|
FlowCommerce::Reference::Currencies.find! currency
|
|
175
225
|
amount.to_f
|
|
176
226
|
end
|
metadata
CHANGED
|
@@ -1,14 +1,14 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: flowcommerce-activemerchant
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 0.1.
|
|
4
|
+
version: 0.1.4
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Dino Reic
|
|
8
8
|
autorequire:
|
|
9
9
|
bindir: bin
|
|
10
10
|
cert_chain: []
|
|
11
|
-
date: 2018-
|
|
11
|
+
date: 2018-11-14 00:00:00.000000000 Z
|
|
12
12
|
dependencies:
|
|
13
13
|
- !ruby/object:Gem::Dependency
|
|
14
14
|
name: activemerchant
|
|
@@ -59,6 +59,8 @@ executables: []
|
|
|
59
59
|
extensions: []
|
|
60
60
|
extra_rdoc_files: []
|
|
61
61
|
files:
|
|
62
|
+
- "./.version"
|
|
63
|
+
- "./LICENSE"
|
|
62
64
|
- "./lib/active_merchant/billing/gateways/flow.rb"
|
|
63
65
|
- "./lib/flowcommerce-activemerchant.rb"
|
|
64
66
|
homepage: https://www.flow.io
|