alpha_card 0.2.6 → 0.3.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (41) hide show
  1. checksums.yaml +4 -4
  2. data/.gitignore +5 -0
  3. data/.travis.yml +1 -5
  4. data/CHANGELOG.md +54 -0
  5. data/Gemfile.lock +25 -37
  6. data/LICENSE +1 -1
  7. data/README.md +207 -67
  8. data/ROADMAP.md +12 -0
  9. data/alpha_card.gemspec +5 -4
  10. data/lib/alpha_card.rb +11 -6
  11. data/lib/alpha_card/alpha_card_object.rb +59 -3
  12. data/lib/alpha_card/alpha_card_response.rb +99 -16
  13. data/lib/alpha_card/data/avs_responses.yml +20 -0
  14. data/lib/alpha_card/data/credit_card_codes.yml +1 -1
  15. data/lib/alpha_card/data/cvv_responses.yml +5 -0
  16. data/lib/alpha_card/data/response_messages.yml +33 -0
  17. data/lib/alpha_card/errors/alpha_card_error.rb +1 -1
  18. data/lib/alpha_card/errors/invalid_object_error.rb +8 -0
  19. data/lib/alpha_card/objects/account.rb +1 -1
  20. data/lib/alpha_card/objects/billing.rb +15 -4
  21. data/lib/alpha_card/objects/capture.rb +51 -0
  22. data/lib/alpha_card/objects/order.rb +41 -4
  23. data/lib/alpha_card/objects/refund.rb +20 -0
  24. data/lib/alpha_card/objects/sale.rb +32 -22
  25. data/lib/alpha_card/objects/shipping.rb +15 -4
  26. data/lib/alpha_card/objects/update.rb +54 -0
  27. data/lib/alpha_card/objects/void.rb +45 -0
  28. data/lib/alpha_card/version.rb +18 -2
  29. data/spec/alpha_card/objects/account_spec.rb +20 -0
  30. data/spec/alpha_card/objects/capture_spec.rb +51 -0
  31. data/spec/alpha_card/objects/deprecated_methods_spec.rb +32 -0
  32. data/spec/alpha_card/objects/refund_spec.rb +35 -0
  33. data/spec/alpha_card/objects/sale_spec.rb +143 -0
  34. data/spec/alpha_card/objects/update_spec.rb +36 -0
  35. data/spec/alpha_card/objects/void_spec.rb +48 -0
  36. data/spec/alpha_card/response_spec.rb +111 -0
  37. data/spec/spec_helper.rb +7 -2
  38. metadata +44 -9
  39. data/spec/alpha_card/alpha_card_account_spec.rb +0 -18
  40. data/spec/alpha_card/alpha_card_response_spec.rb +0 -63
  41. data/spec/alpha_card/alpha_card_spec.rb +0 -123
@@ -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
@@ -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::VERSION
8
- gem.date = '2015-04-27'
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 = '>= 1.9.3'
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
@@ -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
- fail AlphaCardError, 'You must set credentials to create the sale!' unless account.filled?
91
+ raise AlphaCardError, 'You must set credentials to create the sale!' unless account.filled?
87
92
 
88
93
  begin
89
- response = http_request(@api_base, params.merge(account.attributes))
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 [Exception]
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
- fail APIConnectionError, "#{message}\n\n(Network error: #{error.message})"
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 http_request(url, params)
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
- include Virtus.model
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({orderid: '1', tax: nil, ponumber: 'PO123'})
60
+ # order = AlphaCard::Order.new(id: '1', tax: nil, po_number: 'PO123')
17
61
  # order.filled_attributes
18
62
  #
19
- # #=> {orderid: '1', ponumber: 'PO123'}
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
- # The text of the Alpha Card Gateway response.
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
- # r = AlphaCardResponse.new("response=1&responsetext=Test")
42
- # r.text
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
- # The ID of the transaction. Can be used to process
51
- # refund operation.
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
- # r = AlphaCardResponse.new("response=1&transactionid=123")
58
- # r.transaction_id
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 code of the Alpha Card Gateway response.
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
- # r = AlphaCardResponse.new("response=1&response_code=100")
73
- # r.code
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
- # r = AlphaCardResponse.new("response=1")
90
- # r.success?
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
- # r = AlphaCardResponse.new("response=2")
107
- # r.declined?
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
- # r = AlphaCardResponse.new("response=3")
124
- # r.error?
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,5 @@
1
+ "M": 'CVV2/CVC2 match'
2
+ "N": 'CVV2/CVC2 no match'
3
+ "P": 'Not processed'
4
+ "S": 'Merchant has indicated that CVV2/CVC2 is not present on card'
5
+ "U": 'Issuer is not certified and/or has not provided Visa encryption keys'
@@ -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'
@@ -12,7 +12,7 @@ module AlphaCard
12
12
  ##
13
13
  # <code>AlphaCard::AlphaCardError</code> constructor.
14
14
  #
15
- # @param [String] response
15
+ # @param [String] message
16
16
  # Error message
17
17
  # @param [AlphaCard::AlphaCardResponse] response
18
18
  # AlphaCard Gateway response
@@ -0,0 +1,8 @@
1
+ module AlphaCard
2
+ ##
3
+ # Exception class for invalid Alpha Card objects.
4
+ # Raises when some of the object doesn't have all
5
+ # the necessary attributes.
6
+ class InvalidObjectError < StandardError
7
+ end
8
+ end