active_merchant_card_flex 0.0.1
Sign up to get free protection for your applications and to get access to all the features.
- data/.gitignore +4 -0
- data/Gemfile +4 -0
- data/MIT-LICENSE. +20 -0
- data/README.md +0 -0
- data/Rakefile +23 -0
- data/active_merchant_card_flex.gemspec +28 -0
- data/lib/active_merchant/billing/gateways/card_flex.rb +250 -0
- data/lib/active_merchant_card_flex.rb +2 -0
- data/lib/active_merchant_card_flex/version.rb +3 -0
- data/test/fixtures.yml +2 -0
- data/test/remote/gateways/remote_cardflex_test.rb +102 -0
- data/test/test_helper.rb +217 -0
- data/test/unit/gateways/card_flex_test.rb +305 -0
- metadata +126 -0
data/.gitignore
ADDED
data/Gemfile
ADDED
data/MIT-LICENSE.
ADDED
@@ -0,0 +1,20 @@
|
|
1
|
+
Copyright (c) 2005-2010 Tobias Luetke
|
2
|
+
|
3
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
4
|
+
a copy of this software and associated documentation files (the
|
5
|
+
"Software"), to deal in the Software without restriction, including
|
6
|
+
without limitation the rights to use, copy, modify, merge, publish,
|
7
|
+
distribute, sublicense, and/or sell copies of the Software, and to
|
8
|
+
permit persons to whom the Software is furnished to do so, subject to
|
9
|
+
the following conditions:
|
10
|
+
|
11
|
+
The above copyright notice and this permission notice shall be
|
12
|
+
included in all copies or substantial portions of the Software.
|
13
|
+
|
14
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
15
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
16
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
17
|
+
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
18
|
+
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
19
|
+
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
20
|
+
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/README.md
ADDED
File without changes
|
data/Rakefile
ADDED
@@ -0,0 +1,23 @@
|
|
1
|
+
require 'rake'
|
2
|
+
require 'rake/testtask'
|
3
|
+
require 'bundler'
|
4
|
+
Bundler::GemHelper.install_tasks
|
5
|
+
|
6
|
+
desc "Run the unit test suite"
|
7
|
+
task :default => 'test:units'
|
8
|
+
|
9
|
+
namespace :test do
|
10
|
+
Rake::TestTask.new(:units) do |t|
|
11
|
+
t.pattern = 'test/unit/**/*_test.rb'
|
12
|
+
t.ruby_opts << '-rubygems'
|
13
|
+
t.libs << 'test'
|
14
|
+
t.verbose = true
|
15
|
+
end
|
16
|
+
|
17
|
+
Rake::TestTask.new(:remote) do |t|
|
18
|
+
t.pattern = 'test/remote/**/*_test.rb'
|
19
|
+
t.ruby_opts << '-rubygems'
|
20
|
+
t.libs << 'test'
|
21
|
+
t.verbose = true
|
22
|
+
end
|
23
|
+
end
|
@@ -0,0 +1,28 @@
|
|
1
|
+
# -*- encoding: utf-8 -*-
|
2
|
+
$:.push File.expand_path("../lib", __FILE__)
|
3
|
+
require "active_merchant_card_flex/version"
|
4
|
+
|
5
|
+
Gem::Specification.new do |s|
|
6
|
+
s.name = "active_merchant_card_flex"
|
7
|
+
s.version = ActiveMerchantCardFlex::VERSION
|
8
|
+
s.platform = Gem::Platform::RUBY
|
9
|
+
s.authors = ["Stephen St. Martin"]
|
10
|
+
s.email = ["kuprishuz@gmail.com"]
|
11
|
+
s.homepage = ""
|
12
|
+
s.summary = %q{CardFlex support for ActiveMerchant}
|
13
|
+
s.description = %q{Provide support for CardFlex's standard integration and stored profile tokenization integrations.'}
|
14
|
+
|
15
|
+
s.rubyforge_project = "active_merchant_card_flex"
|
16
|
+
|
17
|
+
s.files = `git ls-files`.split("\n")
|
18
|
+
s.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
|
19
|
+
s.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) }
|
20
|
+
s.require_paths = ["lib"]
|
21
|
+
|
22
|
+
s.add_dependency 'activemerchant', '> 1.10.0'
|
23
|
+
s.add_dependency 'activesupport', '> 2.3.5'
|
24
|
+
s.add_dependency 'money'
|
25
|
+
|
26
|
+
s.add_development_dependency 'actionpack'
|
27
|
+
s.add_development_dependency 'mocha'
|
28
|
+
end
|
@@ -0,0 +1,250 @@
|
|
1
|
+
module ActiveMerchant
|
2
|
+
module Billing
|
3
|
+
class CardFlexGateway < Gateway
|
4
|
+
cattr_accessor :gateway_url
|
5
|
+
|
6
|
+
self.display_name = 'CardFlex Inc'
|
7
|
+
self.gateway_url = 'https://post.cfinc.com/cgi-bin/process.cgi'
|
8
|
+
self.homepage_url = 'http://www.cardflexnow.com/'
|
9
|
+
self.default_currency = 'USD'
|
10
|
+
self.money_format = :dollars
|
11
|
+
self.supported_cardtypes = [:visa, :master, :american_express, :discover]
|
12
|
+
self.supported_countries = ['US']
|
13
|
+
|
14
|
+
# Creates a new CardFlexGateway
|
15
|
+
#
|
16
|
+
# The gateway requires that a valid login and password be passed
|
17
|
+
# in the +options+ hash.
|
18
|
+
#
|
19
|
+
# ==== Options
|
20
|
+
#
|
21
|
+
# * <tt>:login</tt> -- The CardFlex Account ID (REQUIRED)
|
22
|
+
# * <tt>:password</tt> -- The CardFlex Merchant PIN. (REQUIRED)
|
23
|
+
# * <tt>:test</tt> -- +true+ or +false+. If true, perform transactions against the test server.
|
24
|
+
# Otherwise, perform transactions against the production server.
|
25
|
+
def initialize(options = {})
|
26
|
+
requires!(options, :login)
|
27
|
+
@options = options
|
28
|
+
super
|
29
|
+
end
|
30
|
+
|
31
|
+
# Performs an authorization, which reserves the funds on the customer's credit card, but does not
|
32
|
+
# charge the card.
|
33
|
+
#
|
34
|
+
# ==== Parameters
|
35
|
+
#
|
36
|
+
# * <tt>money</tt> -- The amount to be captured as a FLOAT value in dollars and cents. (REQUIRED)
|
37
|
+
# * <tt>creditcard_or_credit_card_id</tt> -- The CreditCard details for the transaction. (REQUIRED)
|
38
|
+
# * <tt>options</tt> -- A hash of optional parameters.
|
39
|
+
def authorize(money, creditcard_or_credit_card_id, options = {})
|
40
|
+
post = {}
|
41
|
+
post[:authonly] = 1
|
42
|
+
|
43
|
+
add_address(post, options)
|
44
|
+
add_invoice(post, options)
|
45
|
+
add_payment_source(post, creditcard_or_credit_card_id, options)
|
46
|
+
|
47
|
+
commit(post[:userprofileid] ? :profile_sale : :ns_quicksale_cc, money, post)
|
48
|
+
end
|
49
|
+
|
50
|
+
# Captures the funds from an authorized transaction.
|
51
|
+
#
|
52
|
+
# ==== Parameters
|
53
|
+
#
|
54
|
+
# * <tt>money</tt> -- The amount to be captured as a FLOAT value in dollars and cents. (REQUIRED)
|
55
|
+
# * <tt>authorization</tt> -- The authorization returned from the previous authorize request. (REQUIRED)
|
56
|
+
# * <tt>options</tt> -- A hash of optional parameters
|
57
|
+
def capture(money, authorization, options = {})
|
58
|
+
post = {}
|
59
|
+
|
60
|
+
# remove last 4 digits of cc number as they are not required here
|
61
|
+
post[:postonly] = authorization[0...-4]
|
62
|
+
|
63
|
+
commit(post[:userprofileid] ? :profile_sale : :ns_quicksale_cc, money, post)
|
64
|
+
end
|
65
|
+
|
66
|
+
# Credit a transaction.
|
67
|
+
#
|
68
|
+
# This transaction indicates to the gateway that
|
69
|
+
# money should flow from the merchant to the customer.
|
70
|
+
#
|
71
|
+
# ==== Parameters
|
72
|
+
#
|
73
|
+
# * <tt>:money</tt> -- The amount to be credited as a FLOAT value in dollars and cents (REQUIRED)
|
74
|
+
# * <tt>:creditcard_or_credit_card_id</tt> -- The creditcard or stored creditcard id the refund is being issued to. (REQUIRED)
|
75
|
+
# * <tt>options</tt> -- A hash of optional parameters
|
76
|
+
def credit(money, creditcard_or_credit_card_id, options = {})
|
77
|
+
post = {}
|
78
|
+
add_address(post, options)
|
79
|
+
add_invoice(post, options)
|
80
|
+
add_payment_source(post, creditcard_or_credit_card_id, options)
|
81
|
+
|
82
|
+
commit(post[:userprofileid] ? :profile_credit : :ns_credit, money, post)
|
83
|
+
end
|
84
|
+
|
85
|
+
# Perform a purchase, which is essentially an authorization and capture in a single operation.
|
86
|
+
#
|
87
|
+
# ==== Parameters
|
88
|
+
#
|
89
|
+
# * <tt>money</tt> -- The amount to be purchased as a FLOAT value in dollars and cents. (REQUIRED)
|
90
|
+
# * <tt>creditcard_or_credit_card_id</tt> -- The CreditCard details for the transaction or ID of a stored credit card. (REQUIRED)
|
91
|
+
# * <tt>options</tt> -- A hash of optional parameters.
|
92
|
+
def purchase(money, creditcard_or_credit_card_id, options = {})
|
93
|
+
post = {}
|
94
|
+
add_address(post, options)
|
95
|
+
add_invoice(post, options)
|
96
|
+
add_payment_source(post, creditcard_or_credit_card_id, options)
|
97
|
+
|
98
|
+
commit(post[:userprofileid] ? :profile_sale : :ns_quicksale_cc, money, post)
|
99
|
+
end
|
100
|
+
|
101
|
+
# Stores CreditCard details for later use.
|
102
|
+
#
|
103
|
+
# ==== Parameters
|
104
|
+
#
|
105
|
+
# * <tt>creditcard</tt> -- The CreditCard details to store. (REQUIRED)
|
106
|
+
# * <tt>options</tt> -- A hash of optional parameters
|
107
|
+
def store(creditcard, options = {})
|
108
|
+
post = {}
|
109
|
+
post[:accttype] = 1
|
110
|
+
add_address(post, options)
|
111
|
+
add_creditcard(post, creditcard)
|
112
|
+
|
113
|
+
commit(:profile_add, nil, post)
|
114
|
+
end
|
115
|
+
|
116
|
+
# Removes stored CreditCard details.
|
117
|
+
#
|
118
|
+
# ==== Parameters
|
119
|
+
#
|
120
|
+
# * <tt>creditcard_id</tt> -- The ID of the CreditCard details to remove. (REQUIRED)
|
121
|
+
# * <tt>options</tt> -- A hash of optional parameters
|
122
|
+
def unstore(creditcard_id, options = {})
|
123
|
+
commit(:profile_delete, nil, options.merge(:userprofileid => creditcard_id.to_s[0...-4].to_i, :last4digits => creditcard_id.to_s[-4..-1].to_i))
|
124
|
+
end
|
125
|
+
|
126
|
+
# Void a previous transaction
|
127
|
+
#
|
128
|
+
# ==== Parameters
|
129
|
+
#
|
130
|
+
# * <tt>authorization</tt> - The authorization returned from the previous authorize request. (REQUIRED)
|
131
|
+
# * <tt>options</tt> -- A hash of optional parameters
|
132
|
+
def void(authorization, options = {})
|
133
|
+
commit(:ns_void, nil, options.merge(:historykeyid => authorization[0...-4], :last4digits => authorization[-4..-1]))
|
134
|
+
end
|
135
|
+
|
136
|
+
private
|
137
|
+
# adds a billing or shipping address for the charge
|
138
|
+
def add_address(post, options)
|
139
|
+
if address = options[:billing_address] || options[:address]
|
140
|
+
post[:ci_billaddr1] = address[:address1]
|
141
|
+
post[:ci_billaddr2] = address[:address2] if address[:address2]
|
142
|
+
post[:ci_billcity] = address[:city]
|
143
|
+
post[:ci_billstate] = address[:state]
|
144
|
+
post[:ci_billzip] = address[:zip]
|
145
|
+
post[:ci_billcountry] = address[:country]
|
146
|
+
end
|
147
|
+
|
148
|
+
if address = options[:shipping_address]
|
149
|
+
post[:ci_shipaddr1] = address[:address1]
|
150
|
+
post[:ci_shipaddr2] = address[:address2] if address[:address2]
|
151
|
+
post[:ci_shipcity] = address[:city]
|
152
|
+
post[:ci_shipstate] = address[:state]
|
153
|
+
post[:ci_shipzip] = address[:zip]
|
154
|
+
post[:ci_shipcountry] = address[:country]
|
155
|
+
end
|
156
|
+
end
|
157
|
+
|
158
|
+
# add a new credit card to the transaction
|
159
|
+
def add_creditcard(post, creditcard)
|
160
|
+
post[:ccname] = "#{creditcard.first_name} #{creditcard.last_name}"
|
161
|
+
post[:ccnum] = creditcard.number
|
162
|
+
post[:cvv2] = creditcard.verification_value if creditcard.verification_value?
|
163
|
+
post[:expmon] = creditcard.month
|
164
|
+
post[:expyear] = creditcard.year
|
165
|
+
end
|
166
|
+
|
167
|
+
# add order id to charge
|
168
|
+
def add_invoice(post, options)
|
169
|
+
post[:merchantordernumber] = options[:order_id] if options.has_key?(:order_id)
|
170
|
+
end
|
171
|
+
|
172
|
+
# determine if we are using a new credit card or stored one
|
173
|
+
def add_payment_source(post, credit_card_or_card_id, options)
|
174
|
+
if credit_card_or_card_id.is_a?(ActiveMerchant::Billing::CreditCard)
|
175
|
+
add_creditcard(post, credit_card_or_card_id)
|
176
|
+
else
|
177
|
+
post[:userprofileid] = credit_card_or_card_id[0...-4]
|
178
|
+
post[:last4digits] = credit_card_or_card_id[-4..-1]
|
179
|
+
end
|
180
|
+
end
|
181
|
+
|
182
|
+
def commit(action, money, parameters)
|
183
|
+
parameters[:amount] = money unless money.nil?
|
184
|
+
response = parse(ssl_post(self.gateway_url, post_data(action, parameters)))
|
185
|
+
test_mode = @options[:test] || @options[:login] == "TEST0"
|
186
|
+
|
187
|
+
Response.new(response[:result] == "1", response[:message], response,
|
188
|
+
:avs_result => { :code => response[:avs_result] },
|
189
|
+
:authorization => response[:authorization],
|
190
|
+
:cvv_result => response[:cvv_result],
|
191
|
+
:test => test_mode
|
192
|
+
)
|
193
|
+
end
|
194
|
+
|
195
|
+
# parse response body into its components
|
196
|
+
def parse(body)
|
197
|
+
response = {}
|
198
|
+
|
199
|
+
# parse reponse body into a hash
|
200
|
+
body.gsub!("<html><body><plaintext>", "")
|
201
|
+
body.split("\r\n").each do |pair|
|
202
|
+
key,val = pair.split("=")
|
203
|
+
response[key.underscore.to_sym] = val if key && val
|
204
|
+
end
|
205
|
+
|
206
|
+
# split response from : delimited format
|
207
|
+
if response[:result] == "1"
|
208
|
+
approval_response = response[:accepted].split(":")
|
209
|
+
response[:message] = "Accepted"
|
210
|
+
response[:transaction_type] = approval_response[0]
|
211
|
+
response[:authorization_code] = approval_response[1]
|
212
|
+
response[:reference_number] = approval_response[2]
|
213
|
+
response[:batch_number] = approval_response[3]
|
214
|
+
response[:transaction_id] = approval_response[4]
|
215
|
+
response[:avs_result] = approval_response[5]
|
216
|
+
response[:auth_net_message] = approval_response[6]
|
217
|
+
response[:cvv_result] = approval_response[7]
|
218
|
+
response[:partial_auth] = approval_response[8]
|
219
|
+
|
220
|
+
# if a stored profile was added use its id for authorization otherwise
|
221
|
+
# use the historyid, and append the last4digits of the card number so
|
222
|
+
# that it does not have to be passed in, making it more compliant to
|
223
|
+
# ActiveMerchant
|
224
|
+
if response[:accountnumber]
|
225
|
+
response[:authorization] = "#{response[:transaction_type] == 'PROFILEADD' || response[:partial_auth] == 'DUPLICATE' ? response[:userprofileid] : response[:historyid]}#{response[:accountnumber][-4..-1]}"
|
226
|
+
end
|
227
|
+
else
|
228
|
+
decline_response = response[:reason].split(":")
|
229
|
+
response[:transaction_result] = decline_response[0]
|
230
|
+
response[:decline_code] = decline_response[1]
|
231
|
+
response[:message] = decline_response[2]
|
232
|
+
end
|
233
|
+
|
234
|
+
response
|
235
|
+
end
|
236
|
+
|
237
|
+
# format post data for transaction
|
238
|
+
def post_data(action, parameters = {})
|
239
|
+
post = {}
|
240
|
+
post[:action] = action
|
241
|
+
post[:usepost] = 1
|
242
|
+
post[:acctid] = @options[:test] ? 'TEST0' : @options[:login]
|
243
|
+
post[:merchantpin] = @options[:password] if @options[:password] && !@options[:test]
|
244
|
+
|
245
|
+
request = post.merge(parameters).map {|key,value| "#{key}=#{CGI.escape(value.to_s)}"}.join("&")
|
246
|
+
request
|
247
|
+
end
|
248
|
+
end
|
249
|
+
end
|
250
|
+
end
|
data/test/fixtures.yml
ADDED
@@ -0,0 +1,102 @@
|
|
1
|
+
require 'test_helper'
|
2
|
+
|
3
|
+
class RemoteCardFlexTest < Test::Unit::TestCase
|
4
|
+
|
5
|
+
def setup
|
6
|
+
@gateway = CardFlexGateway.new(fixtures(:card_flex))
|
7
|
+
@amount = 100
|
8
|
+
@credit_card = credit_card('5454545454545454')
|
9
|
+
@declined_card = credit_card('4111111111111112')
|
10
|
+
@options = {
|
11
|
+
:order_id => generate_unique_id,
|
12
|
+
:billing_address => address,
|
13
|
+
:description => 'Test purchase'
|
14
|
+
}
|
15
|
+
end
|
16
|
+
|
17
|
+
def test_sucessful_purchase
|
18
|
+
assert response = @gateway.purchase(@amount, @credit_card, @options)
|
19
|
+
assert_success response
|
20
|
+
assert response.test?
|
21
|
+
assert_equal 'Accepted', response.message
|
22
|
+
assert response.authorization
|
23
|
+
end
|
24
|
+
|
25
|
+
def test_unsuccessful_purchase
|
26
|
+
assert response = @gateway.purchase(@amount, @declined_card, @options)
|
27
|
+
assert_failure response
|
28
|
+
assert_equal 'Invalid account number', response.message
|
29
|
+
end
|
30
|
+
|
31
|
+
def test_successful_credit
|
32
|
+
assert response = @gateway.credit(@amount, @credit_card, @options)
|
33
|
+
assert_success response
|
34
|
+
assert response.test?
|
35
|
+
assert_equal 'Accepted', response.message
|
36
|
+
assert response.authorization
|
37
|
+
end
|
38
|
+
|
39
|
+
def test_authorize_and_capture
|
40
|
+
amount = @amount
|
41
|
+
assert auth = @gateway.authorize(amount, @credit_card, @options)
|
42
|
+
assert_success auth
|
43
|
+
assert_equal 'Accepted', auth.message
|
44
|
+
assert auth.authorization
|
45
|
+
|
46
|
+
assert capture = @gateway.capture(amount, auth.authorization)
|
47
|
+
assert_success capture
|
48
|
+
assert_equal 'Accepted', capture.message
|
49
|
+
end
|
50
|
+
|
51
|
+
def test_failed_capture
|
52
|
+
authorization = "12345678910"
|
53
|
+
assert response = @gateway.capture(@amount, '1234567890')
|
54
|
+
assert_failure response
|
55
|
+
assert_equal 'ProcessPostTrans... could not load order (123456,)', response.message
|
56
|
+
|
57
|
+
assert response = @gateway.capture(@amount, '')
|
58
|
+
assert_failure response
|
59
|
+
assert_equal 'Missing account number', response.message
|
60
|
+
end
|
61
|
+
|
62
|
+
def test_authorize_and_void
|
63
|
+
assert auth = @gateway.authorize(@amount, @credit_card, @options)
|
64
|
+
assert_success auth
|
65
|
+
assert_equal 'Accepted', auth.message
|
66
|
+
assert auth.authorization
|
67
|
+
|
68
|
+
assert void = @gateway.void(auth.authorization)
|
69
|
+
assert_success void
|
70
|
+
assert_equal 'Accepted', void.message
|
71
|
+
end
|
72
|
+
|
73
|
+
def test_unsuccessful_void
|
74
|
+
assert void = @gateway.void('')
|
75
|
+
assert_failure void
|
76
|
+
assert_equal 'Invalid acct type', void.message
|
77
|
+
end
|
78
|
+
|
79
|
+
def test_store_purchase_unstore
|
80
|
+
assert store = @gateway.store(@credit_card)
|
81
|
+
assert_success store
|
82
|
+
assert_equal 'Accepted', store.message
|
83
|
+
|
84
|
+
# wait a few seconds before charging a profile
|
85
|
+
sleep 10
|
86
|
+
assert purchase = @gateway.purchase(@amount, store.authorization, @options)
|
87
|
+
assert_success purchase
|
88
|
+
assert_equal 'Accepted', purchase.message
|
89
|
+
|
90
|
+
assert unstore = @gateway.unstore(store.authorization)
|
91
|
+
assert_success unstore
|
92
|
+
assert_equal 'Accepted', unstore.message
|
93
|
+
assert purchase_after_unstore = @gateway.purchase(@amount, store.authorization, @options)
|
94
|
+
assert_failure purchase_after_unstore
|
95
|
+
assert_equal 'Profile Not Found', purchase_after_unstore.message
|
96
|
+
end
|
97
|
+
|
98
|
+
def test_unsuccessful_unstore
|
99
|
+
assert unstore = @gateway.unstore('123456789')
|
100
|
+
assert_failure unstore
|
101
|
+
end
|
102
|
+
end
|
data/test/test_helper.rb
ADDED
@@ -0,0 +1,217 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
$:.unshift File.expand_path('../../lib', __FILE__)
|
3
|
+
|
4
|
+
begin
|
5
|
+
require 'rubygems'
|
6
|
+
require 'bundler'
|
7
|
+
Bundler.setup
|
8
|
+
rescue LoadError => e
|
9
|
+
puts "Error loading bundler (#{e.message}): \"gem install bundler\" for bundler support."
|
10
|
+
end
|
11
|
+
|
12
|
+
require 'test/unit'
|
13
|
+
require 'money'
|
14
|
+
require 'mocha'
|
15
|
+
require 'yaml'
|
16
|
+
require 'active_merchant'
|
17
|
+
|
18
|
+
require 'active_support/core_ext/integer/time'
|
19
|
+
require 'active_support/core_ext/numeric/time'
|
20
|
+
|
21
|
+
begin
|
22
|
+
require 'active_support/core_ext/time/acts_like'
|
23
|
+
rescue LoadError
|
24
|
+
end
|
25
|
+
|
26
|
+
begin
|
27
|
+
gem 'actionpack'
|
28
|
+
rescue LoadError
|
29
|
+
raise StandardError, "The view tests need ActionPack installed as gem to run"
|
30
|
+
end
|
31
|
+
|
32
|
+
require 'action_controller'
|
33
|
+
require "action_view/template"
|
34
|
+
begin
|
35
|
+
require 'active_support/core_ext/module/deprecation'
|
36
|
+
require 'action_dispatch/testing/test_process'
|
37
|
+
rescue LoadError
|
38
|
+
require 'action_controller/test_process'
|
39
|
+
end
|
40
|
+
require 'active_merchant/billing/integrations/action_view_helper'
|
41
|
+
require 'active_merchant_card_flex'
|
42
|
+
|
43
|
+
ActiveMerchant::Billing::Base.mode = :test
|
44
|
+
|
45
|
+
if ENV['DEBUG_ACTIVE_MERCHANT'] == 'true'
|
46
|
+
require 'logger'
|
47
|
+
ActiveMerchant::Billing::Gateway.logger = Logger.new(STDOUT)
|
48
|
+
ActiveMerchant::Billing::Gateway.wiredump_device = STDOUT
|
49
|
+
end
|
50
|
+
|
51
|
+
# Test gateways
|
52
|
+
class SimpleTestGateway < ActiveMerchant::Billing::Gateway
|
53
|
+
end
|
54
|
+
|
55
|
+
class SubclassGateway < SimpleTestGateway
|
56
|
+
end
|
57
|
+
|
58
|
+
|
59
|
+
module ActiveMerchant
|
60
|
+
module Assertions
|
61
|
+
AssertionClass = RUBY_VERSION > '1.9' ? MiniTest::Assertion : Test::Unit::AssertionFailedError
|
62
|
+
|
63
|
+
def assert_field(field, value)
|
64
|
+
clean_backtrace do
|
65
|
+
assert_equal value, @helper.fields[field]
|
66
|
+
end
|
67
|
+
end
|
68
|
+
|
69
|
+
# Allows the testing of you to check for negative assertions:
|
70
|
+
#
|
71
|
+
# # Instead of
|
72
|
+
# assert !something_that_is_false
|
73
|
+
#
|
74
|
+
# # Do this
|
75
|
+
# assert_false something_that_should_be_false
|
76
|
+
#
|
77
|
+
# An optional +msg+ parameter is available to help you debug.
|
78
|
+
def assert_false(boolean, message = nil)
|
79
|
+
message = build_message message, '<?> is not false or nil.', boolean
|
80
|
+
|
81
|
+
clean_backtrace do
|
82
|
+
assert_block message do
|
83
|
+
not boolean
|
84
|
+
end
|
85
|
+
end
|
86
|
+
end
|
87
|
+
|
88
|
+
# A handy little assertion to check for a successful response:
|
89
|
+
#
|
90
|
+
# # Instead of
|
91
|
+
# assert_success response
|
92
|
+
#
|
93
|
+
# # DRY that up with
|
94
|
+
# assert_success response
|
95
|
+
#
|
96
|
+
# A message will automatically show the inspection of the response
|
97
|
+
# object if things go afoul.
|
98
|
+
def assert_success(response)
|
99
|
+
clean_backtrace do
|
100
|
+
assert response.success?, "Response failed: #{response.inspect}"
|
101
|
+
end
|
102
|
+
end
|
103
|
+
|
104
|
+
# The negative of +assert_success+
|
105
|
+
def assert_failure(response)
|
106
|
+
clean_backtrace do
|
107
|
+
assert_false response.success?, "Response expected to fail: #{response.inspect}"
|
108
|
+
end
|
109
|
+
end
|
110
|
+
|
111
|
+
def assert_valid(validateable)
|
112
|
+
clean_backtrace do
|
113
|
+
assert validateable.valid?, "Expected to be valid"
|
114
|
+
end
|
115
|
+
end
|
116
|
+
|
117
|
+
def assert_not_valid(validateable)
|
118
|
+
clean_backtrace do
|
119
|
+
assert_false validateable.valid?, "Expected to not be valid"
|
120
|
+
end
|
121
|
+
end
|
122
|
+
|
123
|
+
def assert_deprecation_warning(message, target)
|
124
|
+
target.expects(:deprecated).with(message)
|
125
|
+
yield
|
126
|
+
end
|
127
|
+
|
128
|
+
private
|
129
|
+
def clean_backtrace(&block)
|
130
|
+
yield
|
131
|
+
rescue AssertionClass => e
|
132
|
+
path = File.expand_path(__FILE__)
|
133
|
+
raise AssertionClass, e.message, e.backtrace.reject { |line| File.expand_path(line) =~ /#{path}/ }
|
134
|
+
end
|
135
|
+
end
|
136
|
+
|
137
|
+
module Fixtures
|
138
|
+
HOME_DIR = RUBY_PLATFORM =~ /mswin32/ ? ENV['HOMEPATH'] : ENV['HOME'] unless defined?(HOME_DIR)
|
139
|
+
LOCAL_CREDENTIALS = File.join(HOME_DIR.to_s, '.active_merchant/fixtures.yml') unless defined?(LOCAL_CREDENTIALS)
|
140
|
+
DEFAULT_CREDENTIALS = File.join(File.dirname(__FILE__), 'fixtures.yml') unless defined?(DEFAULT_CREDENTIALS)
|
141
|
+
|
142
|
+
private
|
143
|
+
def credit_card(number = '4242424242424242', options = {})
|
144
|
+
defaults = {
|
145
|
+
:number => number,
|
146
|
+
:month => 9,
|
147
|
+
:year => Time.now.year + 1,
|
148
|
+
:first_name => 'Longbob',
|
149
|
+
:last_name => 'Longsen',
|
150
|
+
:verification_value => '123',
|
151
|
+
:type => 'visa'
|
152
|
+
}.update(options)
|
153
|
+
|
154
|
+
Billing::CreditCard.new(defaults)
|
155
|
+
end
|
156
|
+
|
157
|
+
def check(options = {})
|
158
|
+
defaults = {
|
159
|
+
:name => 'Jim Smith',
|
160
|
+
:routing_number => '244183602',
|
161
|
+
:account_number => '15378535',
|
162
|
+
:account_holder_type => 'personal',
|
163
|
+
:account_type => 'checking',
|
164
|
+
:number => '1'
|
165
|
+
}.update(options)
|
166
|
+
|
167
|
+
Billing::Check.new(defaults)
|
168
|
+
end
|
169
|
+
|
170
|
+
def address(options = {})
|
171
|
+
{
|
172
|
+
:name => 'Jim Smith',
|
173
|
+
:address1 => '1234 My Street',
|
174
|
+
:address2 => 'Apt 1',
|
175
|
+
:company => 'Widgets Inc',
|
176
|
+
:city => 'Ottawa',
|
177
|
+
:state => 'ON',
|
178
|
+
:zip => 'K1C2N6',
|
179
|
+
:country => 'CA',
|
180
|
+
:phone => '(555)555-5555',
|
181
|
+
:fax => '(555)555-6666'
|
182
|
+
}.update(options)
|
183
|
+
end
|
184
|
+
|
185
|
+
def all_fixtures
|
186
|
+
@@fixtures ||= load_fixtures
|
187
|
+
end
|
188
|
+
|
189
|
+
def fixtures(key)
|
190
|
+
data = all_fixtures[key] || raise(StandardError, "No fixture data was found for '#{key}'")
|
191
|
+
|
192
|
+
data.dup
|
193
|
+
end
|
194
|
+
|
195
|
+
def load_fixtures
|
196
|
+
file = File.exists?(LOCAL_CREDENTIALS) ? LOCAL_CREDENTIALS : DEFAULT_CREDENTIALS
|
197
|
+
yaml_data = YAML.load(File.read(file))
|
198
|
+
symbolize_keys(yaml_data)
|
199
|
+
|
200
|
+
yaml_data
|
201
|
+
end
|
202
|
+
|
203
|
+
def symbolize_keys(hash)
|
204
|
+
return unless hash.is_a?(Hash)
|
205
|
+
|
206
|
+
hash.symbolize_keys!
|
207
|
+
hash.each{|k,v| symbolize_keys(v)}
|
208
|
+
end
|
209
|
+
end
|
210
|
+
end
|
211
|
+
|
212
|
+
Test::Unit::TestCase.class_eval do
|
213
|
+
include ActiveMerchant::Billing
|
214
|
+
include ActiveMerchant::Assertions
|
215
|
+
include ActiveMerchant::Utils
|
216
|
+
include ActiveMerchant::Fixtures
|
217
|
+
end
|
@@ -0,0 +1,305 @@
|
|
1
|
+
require 'test_helper'
|
2
|
+
|
3
|
+
class CardFlexTest < Test::Unit::TestCase
|
4
|
+
def setup
|
5
|
+
@gateway = CardFlexGateway.new(fixtures(:card_flex))
|
6
|
+
@amount = 100
|
7
|
+
@credit_card = credit_card('5454545454545454')
|
8
|
+
@declined_card = credit_card('4111111111111112')
|
9
|
+
@options = {
|
10
|
+
:order_id => generate_unique_id,
|
11
|
+
:billing_address => address,
|
12
|
+
:description => 'Test purchase'
|
13
|
+
}
|
14
|
+
end
|
15
|
+
|
16
|
+
def test_successful_purchase
|
17
|
+
@gateway.expects(:ssl_post).returns(successful_purchase_response)
|
18
|
+
assert response = @gateway.purchase(@amount, @credit_card, @options)
|
19
|
+
assert_instance_of Response, response
|
20
|
+
assert_success response
|
21
|
+
assert_equal '1921788665454', response.authorization
|
22
|
+
assert response.test?
|
23
|
+
end
|
24
|
+
|
25
|
+
def test_unsuccessful_purchase
|
26
|
+
@gateway.expects(:ssl_post).returns(failed_purchase_response)
|
27
|
+
assert response = @gateway.purchase(@amount, @credit_card, @options)
|
28
|
+
assert_failure response
|
29
|
+
assert response.test?
|
30
|
+
end
|
31
|
+
|
32
|
+
def test_authorization
|
33
|
+
@gateway.expects(:ssl_post).returns(successful_authorization_response)
|
34
|
+
assert response = @gateway.authorize(@amount, @credit_card, @options)
|
35
|
+
assert response.success?
|
36
|
+
assert_equal '1921799375454', response.authorization
|
37
|
+
assert response.test?
|
38
|
+
end
|
39
|
+
|
40
|
+
def test_capture
|
41
|
+
@gateway.expects(:ssl_post).returns(successful_capture_response)
|
42
|
+
assert response = @gateway.capture(@amount, '1921799375454', @options)
|
43
|
+
assert response.success?
|
44
|
+
assert_equal '1921799405454', response.authorization
|
45
|
+
assert response.test?
|
46
|
+
end
|
47
|
+
|
48
|
+
def test_credit
|
49
|
+
@gateway.expects(:ssl_post).returns(successful_credit_response)
|
50
|
+
assert_success @gateway.credit(@amount, @credit_card, @options)
|
51
|
+
end
|
52
|
+
|
53
|
+
def test_void
|
54
|
+
@gateway.expects(:ssl_post).returns(successful_void_response)
|
55
|
+
assert response = @gateway.void('1921799375454')
|
56
|
+
assert response.success?
|
57
|
+
assert_equal '1921796055454', response.authorization
|
58
|
+
assert response.test?
|
59
|
+
end
|
60
|
+
|
61
|
+
def test_store
|
62
|
+
@gateway.expects(:ssl_post).returns(successful_store_response)
|
63
|
+
assert response = @gateway.store(@credit_card)
|
64
|
+
assert response.success?
|
65
|
+
assert_equal '65567155454', response.authorization
|
66
|
+
assert response.test?
|
67
|
+
end
|
68
|
+
|
69
|
+
def test_unstore
|
70
|
+
@gateway.expects(:ssl_post).returns(successful_unstore_response)
|
71
|
+
assert response = @gateway.unstore('65567155454')
|
72
|
+
assert response.success?
|
73
|
+
assert_equal nil, response.authorization
|
74
|
+
assert response.test?
|
75
|
+
end
|
76
|
+
|
77
|
+
def test_successful_avs_check
|
78
|
+
@gateway.expects(:ssl_post).returns(successful_purchase_response.gsub('192178866:N::U', '192178866:Y::U'))
|
79
|
+
assert response = @gateway.purchase(@amount, @credit_card, @options)
|
80
|
+
assert_equal response.avs_result['code'], "Y"
|
81
|
+
assert_equal response.avs_result['message'], "Street address and 5-digit postal code match."
|
82
|
+
assert_equal response.avs_result['street_match'], "Y"
|
83
|
+
assert_equal response.avs_result['postal_match'], "Y"
|
84
|
+
end
|
85
|
+
|
86
|
+
def test_unsuccessful_avs_check_with_bad_street_address
|
87
|
+
@gateway.expects(:ssl_post).returns(successful_purchase_response.gsub('192178866:N::U', '192178866:Z::U'))
|
88
|
+
assert response = @gateway.purchase(@amount, @credit_card, @options)
|
89
|
+
assert_equal response.avs_result['code'], "Z"
|
90
|
+
assert_equal response.avs_result['message'], "Street address does not match, but 5-digit postal code matches."
|
91
|
+
assert_equal response.avs_result['street_match'], "N"
|
92
|
+
assert_equal response.avs_result['postal_match'], "Y"
|
93
|
+
end
|
94
|
+
|
95
|
+
def test_unsuccessful_avs_check_with_bad_zip
|
96
|
+
@gateway.expects(:ssl_post).returns(successful_purchase_response.gsub('192178866:N::U', '192178866:A::U'))
|
97
|
+
assert response = @gateway.purchase(@amount, @credit_card, @options)
|
98
|
+
assert_equal response.avs_result['code'], "A"
|
99
|
+
assert_equal response.avs_result['message'], "Street address matches, but 5-digit and 9-digit postal code do not match."
|
100
|
+
assert_equal response.avs_result['street_match'], "Y"
|
101
|
+
assert_equal response.avs_result['postal_match'], "N"
|
102
|
+
end
|
103
|
+
|
104
|
+
def test_successful_cvv_check
|
105
|
+
@gateway.expects(:ssl_post).returns(successful_purchase_response.gsub('192178866:N::U', '192178866:N::M'))
|
106
|
+
assert response = @gateway.purchase(@amount, @credit_card, @options)
|
107
|
+
assert_equal response.cvv_result['code'], "M"
|
108
|
+
assert_equal response.cvv_result['message'], "Match"
|
109
|
+
end
|
110
|
+
|
111
|
+
def test_unsuccessful_cvv_check
|
112
|
+
@gateway.expects(:ssl_post).returns(successful_purchase_response.gsub('192178866:N::U', '192178866:N::N'))
|
113
|
+
assert response = @gateway.purchase(@amount, @credit_card, @options)
|
114
|
+
assert_equal response.cvv_result['code'], "N"
|
115
|
+
assert_equal response.cvv_result['message'], "No Match"
|
116
|
+
end
|
117
|
+
|
118
|
+
def test_supported_countries
|
119
|
+
assert_equal ['US'], CardFlexGateway.supported_countries
|
120
|
+
end
|
121
|
+
|
122
|
+
def test_supported_card_types
|
123
|
+
assert_equal [:visa, :master, :american_express, :discover], CardFlexGateway.supported_cardtypes
|
124
|
+
end
|
125
|
+
|
126
|
+
private
|
127
|
+
def successful_purchase_response
|
128
|
+
<<-eos.gsub(/^ {6}/, '').gsub("\n", "\r\n")
|
129
|
+
<html><body><plaintext>
|
130
|
+
Accepted=AVSAUTH:TEST:::192178866:N::U
|
131
|
+
historyid=192178866
|
132
|
+
orderid=141639490
|
133
|
+
Accepted=AVSAUTH:TEST:::192178866:N::U
|
134
|
+
ACCOUNTNUMBER=************5454
|
135
|
+
authcode=TEST
|
136
|
+
AuthNo=AVSAUTH:TEST:::192178866:N::U
|
137
|
+
ENTRYMETHOD=KEYED
|
138
|
+
historyid=192178866
|
139
|
+
MERCHANTORDERNUMBER=d86139833ae6f675c21931d1ca68a674
|
140
|
+
orderid=141639490
|
141
|
+
PAYTYPE=MasterCard
|
142
|
+
recurid=0
|
143
|
+
refcode=192178866-TEST
|
144
|
+
result=1
|
145
|
+
Status=Accepted
|
146
|
+
transid=0
|
147
|
+
eos
|
148
|
+
end
|
149
|
+
|
150
|
+
def successful_authorization_response
|
151
|
+
<<-eos.gsub(/^ {6}/, '').gsub("\n", "\r\n")
|
152
|
+
<html><body><plaintext>
|
153
|
+
Accepted=AVSAUTH:TEST:::192179937:N::U
|
154
|
+
historyid=192179937
|
155
|
+
orderid=141640360
|
156
|
+
Accepted=AVSAUTH:TEST:::192179937:N::U
|
157
|
+
ACCOUNTNUMBER=************5454
|
158
|
+
authcode=TEST
|
159
|
+
AuthNo=AVSAUTH:TEST:::192179937:N::U
|
160
|
+
ENTRYMETHOD=KEYED
|
161
|
+
historyid=192179937
|
162
|
+
MERCHANTORDERNUMBER=dd9d22bc626a793e039975bdc3f70eda
|
163
|
+
orderid=141640360
|
164
|
+
PAYTYPE=MasterCard
|
165
|
+
recurid=0
|
166
|
+
refcode=192179937-TEST
|
167
|
+
result=1
|
168
|
+
Status=Accepted
|
169
|
+
transid=0
|
170
|
+
eos
|
171
|
+
end
|
172
|
+
|
173
|
+
def successful_credit_response
|
174
|
+
<<-eos.gsub(/^ {6}/, '').gsub("\n", "\r\n")
|
175
|
+
<html><body><plaintext>
|
176
|
+
Accepted=CREDIT:TEST:::192180043:::
|
177
|
+
historyid=192180043
|
178
|
+
orderid=141640416
|
179
|
+
Accepted=CREDIT:TEST:::192180043:::
|
180
|
+
ACCOUNTNUMBER=************5454
|
181
|
+
authcode=TEST
|
182
|
+
AuthNo=CREDIT:TEST:::192180043:::
|
183
|
+
ENTRYMETHOD=KEYED
|
184
|
+
historyid=192180043
|
185
|
+
MERCHANTORDERNUMBER=1fe19bf710c5800dcef50fa9572b8962
|
186
|
+
orderid=141640416
|
187
|
+
PAYTYPE=MasterCard
|
188
|
+
recurid=0
|
189
|
+
refcode=192180043-TEST
|
190
|
+
result=1
|
191
|
+
Status=Accepted
|
192
|
+
transid=0
|
193
|
+
eos
|
194
|
+
end
|
195
|
+
|
196
|
+
def successful_void_response
|
197
|
+
<<-eos.gsub(/^ {6}/, '').gsub("\n", "\r\n")
|
198
|
+
<html><body><plaintext>
|
199
|
+
Accepted=VOID:TEST:::192179605:::
|
200
|
+
historyid=192179605
|
201
|
+
orderid=141640067
|
202
|
+
Accepted=VOID:TEST:::192179605:::
|
203
|
+
ACCOUNTNUMBER=************5454
|
204
|
+
authcode=TEST
|
205
|
+
AuthNo=VOID:TEST:::192179605:::
|
206
|
+
ENTRYMETHOD=KEYED
|
207
|
+
historyid=192179605
|
208
|
+
MERCHANTORDERNUMBER=42ecde63168c401ccb02a40171aa0042
|
209
|
+
orderid=141640067
|
210
|
+
PAYTYPE=MasterCard
|
211
|
+
recurid=0
|
212
|
+
refcode=192179605-TEST
|
213
|
+
result=1
|
214
|
+
Status=Accepted
|
215
|
+
transid=0
|
216
|
+
eos
|
217
|
+
end
|
218
|
+
|
219
|
+
def successful_capture_response
|
220
|
+
<<-eos.gsub(/^ {6}/, '').gsub("\n", "\r\n")
|
221
|
+
<html><body><plaintext>
|
222
|
+
Accepted=AVSPOST:TEST:::192179940:::
|
223
|
+
historyid=192179940
|
224
|
+
orderid=141640360
|
225
|
+
Accepted=AVSPOST:TEST:::192179940:::
|
226
|
+
ACCOUNTNUMBER=************5454
|
227
|
+
authcode=TEST
|
228
|
+
AuthNo=AVSPOST:TEST:::192179940:::
|
229
|
+
ENTRYMETHOD=KEYED
|
230
|
+
historyid=192179940
|
231
|
+
MERCHANTORDERNUMBER=dd9d22bc626a793e039975bdc3f70eda
|
232
|
+
orderid=141640360
|
233
|
+
PAYTYPE=MasterCard
|
234
|
+
recurid=0
|
235
|
+
refcode=192179940-TEST
|
236
|
+
result=1
|
237
|
+
Status=Accepted
|
238
|
+
transid=192179937
|
239
|
+
eos
|
240
|
+
end
|
241
|
+
|
242
|
+
def successful_store_response
|
243
|
+
<<-eos.gsub(/^ {6}/, '').gsub("\n", "\r\n")
|
244
|
+
<html><body><plaintext>
|
245
|
+
Accepted=AVSAUTH:TEST:::192179530:N::U:DUPLICATE
|
246
|
+
historyid=192179530
|
247
|
+
orderid=141640000
|
248
|
+
Accepted=AVSAUTH:TEST:::192179530:N::U:DUPLICATE
|
249
|
+
ACCOUNTNUMBER=************5454
|
250
|
+
authcode=TEST
|
251
|
+
AuthNo=AVSAUTH:TEST:::192179530:N::U:DUPLICATE
|
252
|
+
DUPLICATE=1
|
253
|
+
ENTRYMETHOD=KEYED
|
254
|
+
historyid=192179530
|
255
|
+
orderid=141640000
|
256
|
+
PAYTYPE=MasterCard
|
257
|
+
recurid=0
|
258
|
+
refcode=192179530-TEST
|
259
|
+
result=1
|
260
|
+
Status=Accepted
|
261
|
+
transid=0
|
262
|
+
USERPROFILEID=6556715
|
263
|
+
eos
|
264
|
+
end
|
265
|
+
|
266
|
+
def successful_unstore_response
|
267
|
+
<<-eos.gsub(/^ {6}/, '').gsub("\n", "\r\n")
|
268
|
+
<html><body><plaintext>
|
269
|
+
Accepted=PROFILEDELETE:Success:::0:::
|
270
|
+
historyid=0
|
271
|
+
orderid=
|
272
|
+
Accepted=PROFILEDELETE:Success:::0:::
|
273
|
+
authcode=Success
|
274
|
+
AuthNo=PROFILEDELETE:Success:::0:::
|
275
|
+
historyid=0
|
276
|
+
refcode=
|
277
|
+
result=1
|
278
|
+
Status=Accepted
|
279
|
+
transid=0
|
280
|
+
USERPROFILEID=6556715
|
281
|
+
eos
|
282
|
+
end
|
283
|
+
|
284
|
+
def failed_purchase_response
|
285
|
+
<<-eos.gsub(/^ {6}/, '').gsub("\n", "\r\n")
|
286
|
+
<html><body><plaintext>
|
287
|
+
Declined=DECLINED:1101610001:Invalid account number:
|
288
|
+
historyid=192179887
|
289
|
+
orderid=141640315
|
290
|
+
ACCOUNTNUMBER=************1112
|
291
|
+
Declined=DECLINED:1101610001:Invalid account number:
|
292
|
+
ENTRYMETHOD=KEYED
|
293
|
+
historyid=192179887
|
294
|
+
MERCHANTORDERNUMBER=5b42749552174e683282b5b0ddcd6459
|
295
|
+
orderid=141640315
|
296
|
+
PAYTYPE=Visa
|
297
|
+
rcode=1101610001
|
298
|
+
Reason=DECLINED:1101610001:Invalid account number:
|
299
|
+
recurid=0
|
300
|
+
result=0
|
301
|
+
Status=Declined
|
302
|
+
transid=0
|
303
|
+
eos
|
304
|
+
end
|
305
|
+
end
|
metadata
ADDED
@@ -0,0 +1,126 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: active_merchant_card_flex
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
prerelease:
|
5
|
+
version: 0.0.1
|
6
|
+
platform: ruby
|
7
|
+
authors:
|
8
|
+
- Stephen St. Martin
|
9
|
+
autorequire:
|
10
|
+
bindir: bin
|
11
|
+
cert_chain: []
|
12
|
+
|
13
|
+
date: 2011-06-16 00:00:00 -04:00
|
14
|
+
default_executable:
|
15
|
+
dependencies:
|
16
|
+
- !ruby/object:Gem::Dependency
|
17
|
+
name: activemerchant
|
18
|
+
prerelease: false
|
19
|
+
requirement: &id001 !ruby/object:Gem::Requirement
|
20
|
+
none: false
|
21
|
+
requirements:
|
22
|
+
- - ">"
|
23
|
+
- !ruby/object:Gem::Version
|
24
|
+
version: 1.10.0
|
25
|
+
type: :runtime
|
26
|
+
version_requirements: *id001
|
27
|
+
- !ruby/object:Gem::Dependency
|
28
|
+
name: activesupport
|
29
|
+
prerelease: false
|
30
|
+
requirement: &id002 !ruby/object:Gem::Requirement
|
31
|
+
none: false
|
32
|
+
requirements:
|
33
|
+
- - ">"
|
34
|
+
- !ruby/object:Gem::Version
|
35
|
+
version: 2.3.5
|
36
|
+
type: :runtime
|
37
|
+
version_requirements: *id002
|
38
|
+
- !ruby/object:Gem::Dependency
|
39
|
+
name: money
|
40
|
+
prerelease: false
|
41
|
+
requirement: &id003 !ruby/object:Gem::Requirement
|
42
|
+
none: false
|
43
|
+
requirements:
|
44
|
+
- - ">="
|
45
|
+
- !ruby/object:Gem::Version
|
46
|
+
version: "0"
|
47
|
+
type: :runtime
|
48
|
+
version_requirements: *id003
|
49
|
+
- !ruby/object:Gem::Dependency
|
50
|
+
name: actionpack
|
51
|
+
prerelease: false
|
52
|
+
requirement: &id004 !ruby/object:Gem::Requirement
|
53
|
+
none: false
|
54
|
+
requirements:
|
55
|
+
- - ">="
|
56
|
+
- !ruby/object:Gem::Version
|
57
|
+
version: "0"
|
58
|
+
type: :development
|
59
|
+
version_requirements: *id004
|
60
|
+
- !ruby/object:Gem::Dependency
|
61
|
+
name: mocha
|
62
|
+
prerelease: false
|
63
|
+
requirement: &id005 !ruby/object:Gem::Requirement
|
64
|
+
none: false
|
65
|
+
requirements:
|
66
|
+
- - ">="
|
67
|
+
- !ruby/object:Gem::Version
|
68
|
+
version: "0"
|
69
|
+
type: :development
|
70
|
+
version_requirements: *id005
|
71
|
+
description: Provide support for CardFlex's standard integration and stored profile tokenization integrations.'
|
72
|
+
email:
|
73
|
+
- kuprishuz@gmail.com
|
74
|
+
executables: []
|
75
|
+
|
76
|
+
extensions: []
|
77
|
+
|
78
|
+
extra_rdoc_files: []
|
79
|
+
|
80
|
+
files:
|
81
|
+
- .gitignore
|
82
|
+
- Gemfile
|
83
|
+
- MIT-LICENSE.
|
84
|
+
- README.md
|
85
|
+
- Rakefile
|
86
|
+
- active_merchant_card_flex.gemspec
|
87
|
+
- lib/active_merchant/billing/gateways/card_flex.rb
|
88
|
+
- lib/active_merchant_card_flex.rb
|
89
|
+
- lib/active_merchant_card_flex/version.rb
|
90
|
+
- test/fixtures.yml
|
91
|
+
- test/remote/gateways/remote_cardflex_test.rb
|
92
|
+
- test/test_helper.rb
|
93
|
+
- test/unit/gateways/card_flex_test.rb
|
94
|
+
has_rdoc: true
|
95
|
+
homepage: ""
|
96
|
+
licenses: []
|
97
|
+
|
98
|
+
post_install_message:
|
99
|
+
rdoc_options: []
|
100
|
+
|
101
|
+
require_paths:
|
102
|
+
- lib
|
103
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
104
|
+
none: false
|
105
|
+
requirements:
|
106
|
+
- - ">="
|
107
|
+
- !ruby/object:Gem::Version
|
108
|
+
version: "0"
|
109
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
110
|
+
none: false
|
111
|
+
requirements:
|
112
|
+
- - ">="
|
113
|
+
- !ruby/object:Gem::Version
|
114
|
+
version: "0"
|
115
|
+
requirements: []
|
116
|
+
|
117
|
+
rubyforge_project: active_merchant_card_flex
|
118
|
+
rubygems_version: 1.6.2
|
119
|
+
signing_key:
|
120
|
+
specification_version: 3
|
121
|
+
summary: CardFlex support for ActiveMerchant
|
122
|
+
test_files:
|
123
|
+
- test/fixtures.yml
|
124
|
+
- test/remote/gateways/remote_cardflex_test.rb
|
125
|
+
- test/test_helper.rb
|
126
|
+
- test/unit/gateways/card_flex_test.rb
|