flowcommerce-activemerchant 0.1.3 → 0.1.4

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 3cf3aa9eacfd0f8e012d25a368434cfdeeadcaba
4
- data.tar.gz: 274d8b6630325f87041bc7f3e5d7064fabb3b5f5
3
+ metadata.gz: fd3cd7c71165eb856d2df8a62f381c4a345216c2
4
+ data.tar.gz: 2da46342bd287ac1400862e00ab21d61d43b62e7
5
5
  SHA512:
6
- metadata.gz: d0c0387ad80950fce612a269ae46430f1aa11397e06c96875caac884c307e1d7b2c624979ec8813fb0fc29c866e93af5b710e4888da787b82a44d834231e21be
7
- data.tar.gz: 0d5d2f2168cbd65124df94c6aa3378df21364b2ce2ba5a6cf5fbc020c29107684ed189016f6d5b07e45f0f00100ed4fb90e8f4faf383ea53f386a72b1121c3bc
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
- VERSION = '0.1.3' unless defined?(::ActiveMerchant::Billing::FlowGateway::VERSION)
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 amount, payment_method, options={}
29
- amount = assert_currency options[:currency], amount
30
-
31
- response = get_flow_cc_token payment_method
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
- begin
47
- authorization_form = if options[:order_id]
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
- options = { response: response }
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
- if ['review', 'authorized'].include?(response.result.status.value)
63
- store = {
64
- key: response.key,
65
- amount: response.amount,
66
- currency: response.currency,
67
- authorization_id: response.id
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
- Response.new true, 'Flow authorize - Success', options, { authorization: store }
71
- else
72
- Response.new false, 'Flow authorize - Error', options
73
- end
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 _money, authorization, options={}
78
- raise ArgumentError, 'No Authorization authorization, please authorize first' unless authorization
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 authorization
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
- options = { response: response }
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', options
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 money, credit_card, options={}
97
- response = authorize money, credit_card, options
98
- capture money, response.authorization
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/authorizations#delete-organization-authorizations-key
102
- def void money, authorization_key, options={}
103
- response = flow_instance.authorizations.delete_by_key @flow_organization, authorization_key
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(exception)
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
- refund_form = {}
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
- [:authorization_id, :currency, :order_number, :key, :rma_key].each do |key|
123
- refund_form[key] = options[key] if options[key]
131
+ if amount
132
+ options[:amount] = assert_currency options[:currency], amount
124
133
  end
125
134
 
126
- if refund_form[:amount]
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
- refund_form = ::Io::Flow::V0::Models::RefundForm.new refund_form
132
- flow_instance.refunds.post @flow_organization, refund_form
133
- end
134
-
135
- # store credit card with flow and get reference token
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
- private
144
-
145
- def flow_instance
146
- FlowCommerce.instance token: @flow_api_key
147
- end
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
- card_form = ::Io::Flow::V0::Models::CardForm.new data
158
- flow_instance.cards.post @flow_organization, card_form
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 = if exception_object.respond_to?(:body) && exception_object.body.length > 0
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
- else
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.3
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-09-07 00:00:00.000000000 Z
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