alpha_card 0.2.6 → 0.3.0
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/.gitignore +5 -0
- data/.travis.yml +1 -5
- data/CHANGELOG.md +54 -0
- data/Gemfile.lock +25 -37
- data/LICENSE +1 -1
- data/README.md +207 -67
- data/ROADMAP.md +12 -0
- data/alpha_card.gemspec +5 -4
- data/lib/alpha_card.rb +11 -6
- data/lib/alpha_card/alpha_card_object.rb +59 -3
- data/lib/alpha_card/alpha_card_response.rb +99 -16
- data/lib/alpha_card/data/avs_responses.yml +20 -0
- data/lib/alpha_card/data/credit_card_codes.yml +1 -1
- data/lib/alpha_card/data/cvv_responses.yml +5 -0
- data/lib/alpha_card/data/response_messages.yml +33 -0
- data/lib/alpha_card/errors/alpha_card_error.rb +1 -1
- data/lib/alpha_card/errors/invalid_object_error.rb +8 -0
- data/lib/alpha_card/objects/account.rb +1 -1
- data/lib/alpha_card/objects/billing.rb +15 -4
- data/lib/alpha_card/objects/capture.rb +51 -0
- data/lib/alpha_card/objects/order.rb +41 -4
- data/lib/alpha_card/objects/refund.rb +20 -0
- data/lib/alpha_card/objects/sale.rb +32 -22
- data/lib/alpha_card/objects/shipping.rb +15 -4
- data/lib/alpha_card/objects/update.rb +54 -0
- data/lib/alpha_card/objects/void.rb +45 -0
- data/lib/alpha_card/version.rb +18 -2
- data/spec/alpha_card/objects/account_spec.rb +20 -0
- data/spec/alpha_card/objects/capture_spec.rb +51 -0
- data/spec/alpha_card/objects/deprecated_methods_spec.rb +32 -0
- data/spec/alpha_card/objects/refund_spec.rb +35 -0
- data/spec/alpha_card/objects/sale_spec.rb +143 -0
- data/spec/alpha_card/objects/update_spec.rb +36 -0
- data/spec/alpha_card/objects/void_spec.rb +48 -0
- data/spec/alpha_card/response_spec.rb +111 -0
- data/spec/spec_helper.rb +7 -2
- metadata +44 -9
- data/spec/alpha_card/alpha_card_account_spec.rb +0 -18
- data/spec/alpha_card/alpha_card_response_spec.rb +0 -63
- data/spec/alpha_card/alpha_card_spec.rb +0 -123
data/ROADMAP.md
ADDED
@@ -0,0 +1,12 @@
|
|
1
|
+
# TODO
|
2
|
+
|
3
|
+
* Own `Attribute` class with validations and etc:
|
4
|
+
- default value
|
5
|
+
- writable: `true` / `false`
|
6
|
+
- presence: `true` / `false`
|
7
|
+
- values: `['1', '2']`
|
8
|
+
- coerce ?
|
9
|
+
* Configuration with `Account` setup
|
10
|
+
- all objects can use global or local account
|
11
|
+
* Add new transactions:
|
12
|
+
- Authorization/Credit/Validate/Offline
|
data/alpha_card.gemspec
CHANGED
@@ -4,8 +4,8 @@ require 'alpha_card/version'
|
|
4
4
|
|
5
5
|
Gem::Specification.new do |gem|
|
6
6
|
gem.name = 'alpha_card'
|
7
|
-
gem.version = AlphaCard
|
8
|
-
gem.date = '
|
7
|
+
gem.version = AlphaCard.gem_version
|
8
|
+
gem.date = '2016-09-22'
|
9
9
|
gem.summary = 'Alpha Card Services API for Ruby'
|
10
10
|
gem.description = 'Gem for creating sales with Alpha Card Services'
|
11
11
|
gem.authors = ['Nikita Bulaj']
|
@@ -14,9 +14,10 @@ Gem::Specification.new do |gem|
|
|
14
14
|
gem.files = `git ls-files`.split($RS)
|
15
15
|
gem.homepage = 'http://github.com/nbulaj/alpha_card'
|
16
16
|
gem.license = 'MIT'
|
17
|
-
gem.required_ruby_version = '>=
|
17
|
+
gem.required_ruby_version = '>= 2.0.0'
|
18
18
|
|
19
19
|
gem.add_runtime_dependency 'virtus', '~> 1.0', '>= 1.0.5'
|
20
|
+
gem.add_runtime_dependency 'rack', '~> 1.2', '>= 1.2'
|
20
21
|
|
21
|
-
gem.add_development_dependency 'rspec', '~> 3'
|
22
|
+
gem.add_development_dependency 'rspec', '~> 3.5'
|
22
23
|
end
|
data/lib/alpha_card.rb
CHANGED
@@ -14,13 +14,18 @@ require 'alpha_card/alpha_card_response'
|
|
14
14
|
# Errors
|
15
15
|
require 'alpha_card/errors/alpha_card_error'
|
16
16
|
require 'alpha_card/errors/api_connection_error'
|
17
|
+
require 'alpha_card/errors/invalid_object_error'
|
17
18
|
|
18
19
|
# Alpha Card Resources
|
19
20
|
require 'alpha_card/objects/account'
|
20
|
-
require 'alpha_card/objects/shipping'
|
21
21
|
require 'alpha_card/objects/billing'
|
22
|
+
require 'alpha_card/objects/capture'
|
23
|
+
require 'alpha_card/objects/shipping'
|
22
24
|
require 'alpha_card/objects/order'
|
25
|
+
require 'alpha_card/objects/void'
|
26
|
+
require 'alpha_card/objects/refund'
|
23
27
|
require 'alpha_card/objects/sale'
|
28
|
+
require 'alpha_card/objects/update'
|
24
29
|
|
25
30
|
##
|
26
31
|
# AlphaCard is a library for processing payments with Alpha Card Services, Inc.
|
@@ -83,10 +88,10 @@ module AlphaCard
|
|
83
88
|
#
|
84
89
|
# #=> AlphaCard::AlphaCardError: AlphaCard::AlphaCardError
|
85
90
|
def request(account, params = {})
|
86
|
-
|
91
|
+
raise AlphaCardError, 'You must set credentials to create the sale!' unless account.filled?
|
87
92
|
|
88
93
|
begin
|
89
|
-
response =
|
94
|
+
response = http_post_request(@api_base, params.merge(account.attributes))
|
90
95
|
rescue => e
|
91
96
|
handle_connection_errors(e)
|
92
97
|
end
|
@@ -121,7 +126,7 @@ module AlphaCard
|
|
121
126
|
# Raises an exception if a network error occurs. It
|
122
127
|
# could be request timeout, socket error or anything else.
|
123
128
|
#
|
124
|
-
# @param [
|
129
|
+
# @param [StandardError]
|
125
130
|
# Exception object.
|
126
131
|
#
|
127
132
|
# @raise [AlphaCard::AlphaCardError]
|
@@ -141,7 +146,7 @@ module AlphaCard
|
|
141
146
|
message = 'Unexpected error communicating with Alpha Card Gateway.'
|
142
147
|
end
|
143
148
|
|
144
|
-
|
149
|
+
raise APIConnectionError, "#{message}\n\n(Network error: #{error.message})"
|
145
150
|
end
|
146
151
|
|
147
152
|
##
|
@@ -155,7 +160,7 @@ module AlphaCard
|
|
155
160
|
#
|
156
161
|
# @return [HTTPResponse]
|
157
162
|
# Response of the request as HTTPResponse object
|
158
|
-
def
|
163
|
+
def http_post_request(url, params)
|
159
164
|
uri = URI.parse(url)
|
160
165
|
|
161
166
|
http = Net::HTTP.new(uri.host, uri.port)
|
@@ -3,7 +3,51 @@ module AlphaCard
|
|
3
3
|
# Parent class for each Alpha Card Gateway object, such as
|
4
4
|
# Order, Billing, Sale and others.
|
5
5
|
class AlphaCardObject
|
6
|
-
|
6
|
+
# Attributes DSL
|
7
|
+
include Virtus.model(nullify_blank: true)
|
8
|
+
|
9
|
+
##
|
10
|
+
# Original AlphaCard transaction variables names
|
11
|
+
ORIGIN_TRANSACTION_VARIABLES = {}.freeze
|
12
|
+
|
13
|
+
##
|
14
|
+
# Returns only filled attributes with the original Alpha Card Services
|
15
|
+
# transaction variables names.
|
16
|
+
#
|
17
|
+
# @param [Hash] attrs
|
18
|
+
# Attributes that must be converted to AlphaCard request params/
|
19
|
+
# Default value is <code>filled_attributes</code>.
|
20
|
+
#
|
21
|
+
# @example
|
22
|
+
# order = AlphaCard::Order.new(id: '1', tax: nil, po_number: 'PO123')
|
23
|
+
# order.send(:attributes_for_request)
|
24
|
+
#
|
25
|
+
# #=> { orderid: '1', ponumber: 'PO123' }
|
26
|
+
def attributes_for_request(attrs = filled_attributes)
|
27
|
+
return attrs if self.class::ORIGIN_TRANSACTION_VARIABLES.empty?
|
28
|
+
|
29
|
+
attrs.each_with_object({}) do |(attr, value), request_attrs|
|
30
|
+
request_attrs[self.class::ORIGIN_TRANSACTION_VARIABLES.fetch(attr, attr)] = value
|
31
|
+
end
|
32
|
+
end
|
33
|
+
|
34
|
+
##
|
35
|
+
# Deprecate old transaction variables names.
|
36
|
+
def self.deprecate_old_variables!
|
37
|
+
self::ORIGIN_TRANSACTION_VARIABLES.each do |new_attr, old_attr|
|
38
|
+
define_method "#{old_attr}=" do |value|
|
39
|
+
warn "[DEPRECATION] #{old_attr}= is deprecated! Please, use #{new_attr}= instead"
|
40
|
+
self[new_attr] = value
|
41
|
+
end
|
42
|
+
|
43
|
+
define_method old_attr do
|
44
|
+
warn "[DEPRECATION] #{old_attr} is deprecated! Please, use #{new_attr} instead"
|
45
|
+
self[new_attr]
|
46
|
+
end
|
47
|
+
end
|
48
|
+
end
|
49
|
+
|
50
|
+
protected
|
7
51
|
|
8
52
|
##
|
9
53
|
# Returns the <code>Hash</code> with only filled attributes
|
@@ -13,12 +57,24 @@ module AlphaCard
|
|
13
57
|
# Filled attributes of the <code>AlphaCard::AlphaCardObject</code>.
|
14
58
|
#
|
15
59
|
# @example
|
16
|
-
# order = AlphaCard::Order.new(
|
60
|
+
# order = AlphaCard::Order.new(id: '1', tax: nil, po_number: 'PO123')
|
17
61
|
# order.filled_attributes
|
18
62
|
#
|
19
|
-
# #=> {
|
63
|
+
# #=> { id: '1', po_number: 'PO123' }
|
20
64
|
def filled_attributes
|
21
65
|
attributes.select { |_, value| !value.nil? }
|
22
66
|
end
|
67
|
+
|
68
|
+
##
|
69
|
+
# Validate passed attributes for presence. Raises an exception
|
70
|
+
# if one of the attribute is not specified.
|
71
|
+
#
|
72
|
+
# @param [Array] attributes
|
73
|
+
# array of attributes to check
|
74
|
+
def abort_if_attributes_blank!(*attributes)
|
75
|
+
attributes.each do |attr|
|
76
|
+
raise InvalidObjectError, "#{attr} must be present!" if self[attr].nil? || self[attr].empty?
|
77
|
+
end
|
78
|
+
end
|
23
79
|
end
|
24
80
|
end
|
@@ -15,6 +15,15 @@ module AlphaCard
|
|
15
15
|
# Error response code
|
16
16
|
ERROR = '3'.freeze
|
17
17
|
|
18
|
+
# Messages for CVV response codes
|
19
|
+
CVV_RESPONSES = YAML.load_file(File.expand_path('../data/cvv_responses.yml', __FILE__)).freeze
|
20
|
+
|
21
|
+
# Messages for AVS response codes
|
22
|
+
AVS_RESPONSES = YAML.load_file(File.expand_path('../data/avs_responses.yml', __FILE__)).freeze
|
23
|
+
|
24
|
+
# AlphaCard response messages
|
25
|
+
RESPONSE_MESSAGES = YAML.load_file(File.expand_path('../data/response_messages.yml', __FILE__)).freeze
|
26
|
+
|
18
27
|
##
|
19
28
|
# AlphaCardResponse constructor.
|
20
29
|
#
|
@@ -32,14 +41,14 @@ module AlphaCard
|
|
32
41
|
end
|
33
42
|
|
34
43
|
##
|
35
|
-
#
|
44
|
+
# Textual response of the Alpha Card Gateway.
|
36
45
|
#
|
37
46
|
# @return [String] text of the response
|
38
47
|
#
|
39
48
|
# @example
|
40
49
|
#
|
41
|
-
#
|
42
|
-
#
|
50
|
+
# response = AlphaCardResponse.new("response=1&responsetext=Test")
|
51
|
+
# response.text
|
43
52
|
#
|
44
53
|
# #=> 'Test'
|
45
54
|
def text
|
@@ -47,15 +56,29 @@ module AlphaCard
|
|
47
56
|
end
|
48
57
|
|
49
58
|
##
|
50
|
-
#
|
51
|
-
#
|
59
|
+
# Response message by response code.
|
60
|
+
#
|
61
|
+
# @return [String] response message
|
62
|
+
#
|
63
|
+
# @example
|
64
|
+
#
|
65
|
+
# response = AlphaCardResponse.new("response_code=>300")
|
66
|
+
# response.message
|
67
|
+
#
|
68
|
+
# #=> 'Transaction was rejected by gateway'
|
69
|
+
def message
|
70
|
+
RESPONSE_MESSAGES[code]
|
71
|
+
end
|
72
|
+
|
73
|
+
##
|
74
|
+
# Payment gateway transaction ID.
|
52
75
|
#
|
53
76
|
# @return [String] transaction ID
|
54
77
|
#
|
55
78
|
# @example
|
56
79
|
#
|
57
|
-
#
|
58
|
-
#
|
80
|
+
# response = AlphaCardResponse.new("response=1&transactionid=123")
|
81
|
+
# response.transaction_id
|
59
82
|
#
|
60
83
|
# #=> '123'
|
61
84
|
def transaction_id
|
@@ -63,20 +86,50 @@ module AlphaCard
|
|
63
86
|
end
|
64
87
|
|
65
88
|
##
|
66
|
-
# The
|
89
|
+
# The original order id passed in the transaction request.
|
90
|
+
#
|
91
|
+
# @return [String] Order ID
|
92
|
+
#
|
93
|
+
# @example
|
94
|
+
#
|
95
|
+
# response = AlphaCardResponse.new("response=1&orderid=123")
|
96
|
+
# response.order_id
|
97
|
+
#
|
98
|
+
# #=> '123'
|
99
|
+
def order_id
|
100
|
+
@data['orderid']
|
101
|
+
end
|
102
|
+
|
103
|
+
##
|
104
|
+
# Numeric mapping of processor responses.
|
67
105
|
#
|
68
106
|
# @return [String] code of the response
|
69
107
|
#
|
70
108
|
# @example
|
71
109
|
#
|
72
|
-
#
|
73
|
-
#
|
110
|
+
# response = AlphaCardResponse.new("response=1&response_code=100")
|
111
|
+
# response.code
|
74
112
|
#
|
75
113
|
# #=> '100'
|
76
114
|
def code
|
77
115
|
@data['response_code']
|
78
116
|
end
|
79
117
|
|
118
|
+
##
|
119
|
+
# Transaction authorization code.
|
120
|
+
#
|
121
|
+
# @return [String] auth code
|
122
|
+
#
|
123
|
+
# @example
|
124
|
+
#
|
125
|
+
# response = AlphaCardResponse.new("response=1&authcode=083319")
|
126
|
+
# response.code
|
127
|
+
#
|
128
|
+
# #=> '083319'
|
129
|
+
def auth_code
|
130
|
+
@data['authcode']
|
131
|
+
end
|
132
|
+
|
80
133
|
##
|
81
134
|
# Indicate the state of the request to the
|
82
135
|
# Alpha Card Gateway. Returns <i>true</i> if
|
@@ -86,8 +139,8 @@ module AlphaCard
|
|
86
139
|
#
|
87
140
|
# @example
|
88
141
|
#
|
89
|
-
#
|
90
|
-
#
|
142
|
+
# response = AlphaCardResponse.new("response=1")
|
143
|
+
# response.success?
|
91
144
|
#
|
92
145
|
# #=> true
|
93
146
|
def success?
|
@@ -103,8 +156,8 @@ module AlphaCard
|
|
103
156
|
#
|
104
157
|
# @example
|
105
158
|
#
|
106
|
-
#
|
107
|
-
#
|
159
|
+
# response = AlphaCardResponse.new("response=2")
|
160
|
+
# response.declined?
|
108
161
|
#
|
109
162
|
# #=> true
|
110
163
|
def declined?
|
@@ -120,12 +173,42 @@ module AlphaCard
|
|
120
173
|
#
|
121
174
|
# @example
|
122
175
|
#
|
123
|
-
#
|
124
|
-
#
|
176
|
+
# response = AlphaCardResponse.new("response=3")
|
177
|
+
# response.error?
|
125
178
|
#
|
126
179
|
# #=> true
|
127
180
|
def error?
|
128
181
|
@data['response'] == ERROR
|
129
182
|
end
|
183
|
+
|
184
|
+
##
|
185
|
+
# CVV response message.
|
186
|
+
#
|
187
|
+
# @return [String] CVV response message
|
188
|
+
#
|
189
|
+
# @example
|
190
|
+
#
|
191
|
+
# response = AlphaCardResponse.new("cvvresponse=M")
|
192
|
+
# response.cvv_response
|
193
|
+
#
|
194
|
+
# #=> 'CVV2/CVC2 match'
|
195
|
+
def cvv_response
|
196
|
+
CVV_RESPONSES[@data['cvvresponse']]
|
197
|
+
end
|
198
|
+
|
199
|
+
##
|
200
|
+
# AVS response message.
|
201
|
+
#
|
202
|
+
# @return [String] AVS response message
|
203
|
+
#
|
204
|
+
# @example
|
205
|
+
#
|
206
|
+
# response = AlphaCardResponse.new("avsresponse=A")
|
207
|
+
# response.avs_response
|
208
|
+
#
|
209
|
+
# #=> 'Address match only'
|
210
|
+
def avs_response
|
211
|
+
AVS_RESPONSES[@data['avsresponse']]
|
212
|
+
end
|
130
213
|
end
|
131
214
|
end
|
@@ -0,0 +1,20 @@
|
|
1
|
+
"X": 'Exact match, 9-character numeric ZIP'
|
2
|
+
"Y": 'Exact match, 5-character numeric ZIP'
|
3
|
+
"D": 'Exact match, 5-character numeric ZIP'
|
4
|
+
"M": 'Exact match, 5-character numeric ZIP'
|
5
|
+
"A": 'Address match only'
|
6
|
+
"B": 'Address match only'
|
7
|
+
"W": '9-character numeric ZIP match only'
|
8
|
+
"Z": '5-character ZIP match only'
|
9
|
+
"P": '5-character ZIP match only'
|
10
|
+
"L": '5-character ZIP match only'
|
11
|
+
"N": 'No address or ZIP match only'
|
12
|
+
"C": 'No address or ZIP match only'
|
13
|
+
"U": 'Address unavailable'
|
14
|
+
"G": 'Non-U.S. issuer does not participate'
|
15
|
+
"I": 'Non-U.S. issuer does not participate'
|
16
|
+
"R": 'Issuer system unavailable'
|
17
|
+
"E": 'Not a mail/phone order'
|
18
|
+
"S": 'Service not supported'
|
19
|
+
"O": 'AVS not available'
|
20
|
+
"B": 'AVS not available'
|
@@ -59,4 +59,4 @@
|
|
59
59
|
"DB UNAVAIL 01": 'Problem at NDC routing transaction.'
|
60
60
|
"SCAN UNAVAILABLE": 'SCAN application is down, try later.'
|
61
61
|
"EXCEEDS MAX AMT": 'Exceeds withdrawal amount limit.'
|
62
|
-
"EXCEEDS MAX USES": 'Exceeds withdrawal frequency limit'
|
62
|
+
"EXCEEDS MAX USES": 'Exceeds withdrawal frequency limit'
|
@@ -0,0 +1,33 @@
|
|
1
|
+
"100": 'Transaction was approved'
|
2
|
+
"200": 'Transaction was declined by processor'
|
3
|
+
"201": 'Do not honor'
|
4
|
+
"202": 'Insufficient funds'
|
5
|
+
"203": 'Over limit'
|
6
|
+
"204": 'Transaction not allowed'
|
7
|
+
"220": 'Incorrect payment information'
|
8
|
+
"221": 'No such card issuer'
|
9
|
+
"222": 'No card number on file with issuer'
|
10
|
+
"223": 'Expired card'
|
11
|
+
"224": 'Invalid expiration date'
|
12
|
+
"225": 'Invalid card security code'
|
13
|
+
"240": 'Call issuer for further information'
|
14
|
+
"250": 'Pick up card'
|
15
|
+
"251": 'Lost card'
|
16
|
+
"252": 'Stolen card'
|
17
|
+
"253": 'Fraudulent card'
|
18
|
+
"260": 'Declined with further instructions available'
|
19
|
+
"261": 'Declined-Stop all recurring payments'
|
20
|
+
"262": 'Declined-Stop this recurring program'
|
21
|
+
"263": 'Declined-Update cardholder data available'
|
22
|
+
"264": 'Declined-Retry in a few days'
|
23
|
+
"300": 'Transaction was rejected by gateway'
|
24
|
+
"400": 'Transaction error returned by processor'
|
25
|
+
"410": 'Invalid merchant configuration'
|
26
|
+
"411": 'Merchant account is inactive'
|
27
|
+
"420": 'Communication error'
|
28
|
+
"421": 'Communication error with issuer'
|
29
|
+
"430": 'Duplicate transaction at processor'
|
30
|
+
"440": 'Processor format error'
|
31
|
+
"441": 'Invalid transaction information'
|
32
|
+
"460": 'Processor feature not available'
|
33
|
+
"461": 'Unsupported card type'
|