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.
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