spook_and_pay 0.3.1.alpha → 1.0.0

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: b13e26bc3175899e0bc06a254cf58c8af8c20257
4
- data.tar.gz: a19c29f21df4f66dbeba4d1143428d105be2ff23
3
+ metadata.gz: fb962e2e5cb48aa5da0423021039c2e37f0d54cf
4
+ data.tar.gz: e247fc0540cd4656aab4f18edc31d9c4c853d349
5
5
  SHA512:
6
- metadata.gz: 7d0ddc7e8b5335a418d08c79dd9d8e66b3bf308fd85fdc0f5721f0890e856509d4edc0dd02a8179c7d817eb401cfddb1e31a48ebe47216f49a6cf5ce2ef50021
7
- data.tar.gz: f1033687ba256d2a6aa30e5411d868d263139c132ff0c03a20aaa5825fd056348979aeee583fb7fbe6ac1cb7099b92539b119d357cf4dc0d82e5cfd1821a4313
6
+ metadata.gz: 25de0492cbc31f34355c366cf2b55f4196ec0fa4914beea0b78f5a5d85d203026ebf6680cfc991b241b01f44760c8facdc2f3d838c7db05d18ed0af18e151b0e
7
+ data.tar.gz: 9a6240d5ad254c9fb48db134967f7d47e716f2b14f9784d3ad512946ff9ad78c408478d08c16d7b66be2fc9915e272978c21306ea9192a58f321b87f865f744e
@@ -6,7 +6,7 @@ module SpookAndPay
6
6
  # This module adds the ::attr_erroring_reader to this class
7
7
  extend SpookAndPay::ErroringReader
8
8
 
9
- # An error raised when trying to perform an action on a card that has
9
+ # An error raised when trying to perform an action on a card that has
10
10
  # invalid details or has expired.
11
11
  class InvalidCardError < StandardError
12
12
  def to_s
@@ -48,8 +48,8 @@ module SpookAndPay
48
48
  FIELDS.each {|f| instance_variable_set(:"@#{f}", vals[f]) if vals.has_key?(f)}
49
49
  end
50
50
 
51
- # A getter which takes the card number stored and generates a nice masked
52
- # version. It also handles the case where the number isn't available and
51
+ # A getter which takes the card number stored and generates a nice masked
52
+ # version. It also handles the case where the number isn't available and
53
53
  # just returns nil instead.
54
54
  #
55
55
  # @return String
@@ -68,7 +68,7 @@ module SpookAndPay
68
68
  end
69
69
  end
70
70
 
71
- # Checks to see if funds can be credited to a card. Depends on the
71
+ # Checks to see if funds can be credited to a card. Depends on the
72
72
  # gateway/provider supporting crediting and having a valid card.
73
73
  #
74
74
  # @return [true, false]
@@ -84,7 +84,7 @@ module SpookAndPay
84
84
  provider.supports_authorize? and valid? and !expired?
85
85
  end
86
86
 
87
- # Checks to see if this card can be used for a purchase against the
87
+ # Checks to see if this card can be used for a purchase against the
88
88
  # underlying gateway.
89
89
  #
90
90
  # @return [true, false]
@@ -157,6 +157,14 @@ module SpookAndPay
157
157
  expired
158
158
  end
159
159
 
160
+ # Retains the credit card within the payment provider's vault.
161
+ #
162
+ # @return SpookAndPay::Result
163
+ # @raises SpookAndPay::Providers::Base::NotSupportedError
164
+ def retain!
165
+ provider.retain_credit_card(self)
166
+ end
167
+
160
168
  private
161
169
 
162
170
 
@@ -1,13 +1,13 @@
1
1
  module SpookAndPay
2
2
  module Providers
3
3
  # The abstract class from which other Provider classes should inherit. This
4
- # class is intended to behave more as a template than anything else. It
4
+ # class is intended to behave more as a template than anything else. It
5
5
  # provides very little in the way of actual implementation.
6
6
  #
7
- # To implement a provider all of the public methods of this class —
7
+ # To implement a provider all of the public methods of this class —
8
8
  # excluding #initialize — must be implemented.
9
9
  #
10
- # Some features may not be supported by a provider, in which case the
10
+ # Some features may not be supported by a provider, in which case the
11
11
  # `NotSupportedError` should be raised in lieu of a real implementation.
12
12
  class Base
13
13
  # A hash which maps between the fields for a credit card and the actual
@@ -17,8 +17,8 @@ module SpookAndPay
17
17
  FORM_FIELD_NAMES = {}.freeze
18
18
 
19
19
  # An error used when validating the contents of an options hash. Since
20
- # many of the methods on the provider classes take additional arguments
21
- # as a Hash, it's important to make sure we give good errors when they
20
+ # many of the methods on the provider classes take additional arguments
21
+ # as a Hash, it's important to make sure we give good errors when they
22
22
  # are missing.
23
23
  class InvalidOptionsError < StandardError
24
24
  def initialize(errors)
@@ -80,14 +80,14 @@ module SpookAndPay
80
80
  raise NotImplementedError
81
81
  end
82
82
 
83
- # Returns a hash containing the details necessary for making a
84
- # submission. If you know what you're doing, you can use this directly,
83
+ # Returns a hash containing the details necessary for making a
84
+ # submission. If you know what you're doing, you can use this directly,
85
85
  # but otherwise you should be using the form helpers.
86
86
  #
87
87
  # The details generated by this method are for submitting card details to
88
88
  # the provider for storage. Billing etc has to be handled via a separate
89
89
  # step after submission.
90
- #
90
+ #
91
91
  # The arguments for this are specific to each provider implementation,
92
92
  # but they all return a Hash with the same keys, like so:
93
93
  # {
@@ -95,9 +95,9 @@ module SpookAndPay
95
95
  # :hidden_fields => {...},
96
96
  # :field_names => {...}
97
97
  # }
98
- #
99
- # Where :url is the target URL, :hidden_fields should be embedded in a
100
- # form as they are and :field_names provide the mapping between known
98
+ #
99
+ # Where :url is the target URL, :hidden_fields should be embedded in a
100
+ # form as they are and :field_names provide the mapping between known
101
101
  # keys like :number and :cvv to the input names required by the provider.
102
102
  def prepare_payment_submission(*args)
103
103
  raise NotImplementedError
@@ -132,70 +132,90 @@ module SpookAndPay
132
132
  check_support('refund')
133
133
  end
134
134
 
135
- # Checks to see if purchasing is supported. This is dependent on the payment
136
- # provider. The default implementation simply returns true. Specific
135
+ # Partially refunds the amount of money captured in a transaction.
136
+ #
137
+ # This should not be called directly. Instead, use the #partial_refund! method
138
+ # provided by a Transaction instance.
139
+ #
140
+ # @param [SpookAndPay::Transaction, String] id
141
+ # @return SpookAndPay::Result
142
+ def partially_refund_transaction(id)
143
+ check_support('partial_refund')
144
+ end
145
+
146
+ # Checks to see if purchasing is supported. This is dependent on the payment
147
+ # provider. The default implementation simply returns true. Specific
137
148
  # implementations should over-ride this method.
138
- #
149
+ #
139
150
  # @return [true, false]
140
151
  def supports_purchase?
141
152
  true
142
153
  end
143
154
 
144
- # Checks to see if voiding is supported. This is dependent on the payment
145
- # provider. The default implementation simply returns true. Specific
155
+ # Checks to see if voiding is supported. This is dependent on the payment
156
+ # provider. The default implementation simply returns true. Specific
146
157
  # implementations should over-ride this method.
147
- #
158
+ #
148
159
  # @return [true, false]
149
160
  def supports_void?
150
161
  true
151
162
  end
152
163
 
153
- # Checks to see if crediting is supported. This is dependent on the payment
154
- # provider. The default implementation simply returns true. Specific
164
+ # Checks to see if crediting is supported. This is dependent on the payment
165
+ # provider. The default implementation simply returns true. Specific
155
166
  # implementations should over-ride this method.
156
- #
167
+ #
157
168
  # @return [true, false]
158
169
  def supports_credit?
159
170
  true
160
171
  end
161
172
 
162
- # Checks to see if refunding is supported. This is dependent on the payment
163
- # provider. The default implementation simply returns true. Specific
173
+ # Checks to see if refunding is supported. This is dependent on the payment
174
+ # provider. The default implementation simply returns true. Specific
164
175
  # implementations should over-ride this method.
165
- #
176
+ #
166
177
  # @return [true, false]
167
178
  def supports_refund?
168
179
  true
169
180
  end
170
181
 
171
- # Checks to see if capturing is supported. This is dependent on the payment
172
- # provider. The default implementation simply returns true. Specific
182
+ # Checks to see if partial refunding is supported. This is dependent on
183
+ # the payment provider. The default implementation simply returns true.
184
+ # Specific implementations should over-ride this method.
185
+ #
186
+ # @return [true, false]
187
+ def supports_partial_refund?
188
+ true
189
+ end
190
+
191
+ # Checks to see if capturing is supported. This is dependent on the payment
192
+ # provider. The default implementation simply returns true. Specific
173
193
  # implementations should over-ride this method.
174
- #
194
+ #
175
195
  # @return [true, false]
176
196
  def supports_capture?
177
197
  true
178
198
  end
179
199
 
180
- # Checks to see if authorizing is supported. This is dependent on the payment
181
- # provider. The default implementation simply returns true. Specific
200
+ # Checks to see if authorizing is supported. This is dependent on the payment
201
+ # provider. The default implementation simply returns true. Specific
182
202
  # implementations should over-ride this method.
183
- #
203
+ #
184
204
  # @return [true, false]
185
205
  def supports_authorize?
186
206
  true
187
207
  end
188
208
 
189
209
  # Checks to see if the deletion of payment details is supported. This is
190
- # dependent on the payment provider. The default implementation simply
210
+ # dependent on the payment provider. The default implementation simply
191
211
  # returns true. Specific implementations should over-ride this method.
192
- #
212
+ #
193
213
  # @return [true, false]
194
214
  def supports_delete?
195
215
  true
196
216
  end
197
217
 
198
- # Voids an authorization.
218
+ # Voids an authorization.
199
219
  #
200
220
  # This should not be called directly. Instead, use the #void! method
201
221
  # provided by a Transaction instance.
@@ -263,13 +283,26 @@ module SpookAndPay
263
283
  check_support('delete')
264
284
  end
265
285
 
286
+ # Retains a credit card within the provider's vault.
287
+ #
288
+ # This should not be called directly. Instead, use the #retain! method
289
+ # provided by a CreditCard instance.
290
+ #
291
+ # @param [SpookAndPay::CreditCard, String] id
292
+ # @return SpookAndPay::Result
293
+ # @api private
294
+ # @abstract Subclass to implement
295
+ def retain_credit_card(id)
296
+ check_support('retain')
297
+ end
298
+
266
299
  private
267
300
 
268
- # Checks to see if a particular action is defined as being supported and
301
+ # Checks to see if a particular action is defined as being supported and
269
302
  # raises the appropriate error.
270
303
  #
271
304
  # The basic semantics is this; if someone implementing a provider says an
272
- # action is supported via a #supports_*? predicate, this method should
305
+ # action is supported via a #supports_*? predicate, this method should
273
306
  # never be called, so we raise NotImplementedError. Otherwise they are
274
307
  # saying it's not supported and the appropriate response is to raise a
275
308
  # NotSupportedError.
@@ -11,7 +11,7 @@ module SpookAndPay
11
11
  :cvv => "credit_card[verification_value]"
12
12
  }.freeze
13
13
 
14
- # The which refers to a specific gateway.
14
+ # The which refers to a specific gateway.
15
15
  #
16
16
  # @attr_reader String
17
17
  attr_reader :gateway_token
@@ -37,7 +37,7 @@ module SpookAndPay
37
37
  @gateway_token = config[:gateway_token]
38
38
  @currency_code = config[:currency_code] || 'AUD'
39
39
  @spreedly = ::Spreedly::Environment.new(
40
- config[:environment_key],
40
+ config[:environment_key],
41
41
  config[:access_secret],
42
42
  :currency_code => currency_code
43
43
  )
@@ -77,7 +77,7 @@ module SpookAndPay
77
77
  case opts[:execute]
78
78
  when :authorize then card.authorize!(opts[:amount])
79
79
  when :purchase then card.purchase!(opts[:amount])
80
- when :store then SpookAndPay::Result.new(true, nil, :credit_card => card)
80
+ else SpookAndPay::Result.new(true, nil, :credit_card => card)
81
81
  end
82
82
  else
83
83
  SpookAndPay::Result.new(false, nil, :credit_card => card, :errors => extract_card_errors(card.raw))
@@ -109,12 +109,17 @@ module SpookAndPay
109
109
  coerce_result(result)
110
110
  end
111
111
 
112
+ def partially_refund_transaction(id, amount)
113
+ result = spreedly.refund_transaction(transaction_id(id), :amount => (amount.to_f * 100).to_i)
114
+ coerce_result(result)
115
+ end
116
+
112
117
  def void_transaction(id)
113
118
  result = spreedly.void_transaction(transaction_id(id))
114
119
  coerce_result(result)
115
120
  end
116
121
 
117
- # This is a nasty little trick that makes the spreedly gateway class
122
+ # This is a nasty little trick that makes the spreedly gateway class
118
123
  # store the characteristics XML fragment from the server.
119
124
  #
120
125
  # @todo In later versions this might not be necessary. When updating the
@@ -162,9 +167,19 @@ module SpookAndPay
162
167
  coerce_result(result)
163
168
  end
164
169
 
170
+ # Calls the retain action on the provider's vault.
171
+ #
172
+ # @param [SpookAndPay::CreditCard, Integer, String] id
173
+ # @return SpookAndPay::Result
174
+ # @api private
175
+ def retain_credit_card(id)
176
+ result = spreedly.retain_payment_method(credit_card_id(id))
177
+ coerce_result(result)
178
+ end
179
+
165
180
  private
166
181
 
167
- # Retrieves the gateway from Spreedly and then inspects the response to
182
+ # Retrieves the gateway from Spreedly and then inspects the response to
168
183
  # see what features it supports. This is a helper for the #supports_*?
169
184
  # predicates.
170
185
  #
@@ -197,7 +212,7 @@ module SpookAndPay
197
212
  # A mapping from the names used by Spreedly to the names SpookAndPay uses
198
213
  # internally.
199
214
  CARD_FIELDS = {
200
- "full_name" => :name,
215
+ "full_name" => :name,
201
216
  "number" => :number,
202
217
  "year" => :expiration_year,
203
218
  "month" => :expiration_month,
@@ -216,12 +231,12 @@ module SpookAndPay
216
231
  #
217
232
  # @param Spreedly::CreditCard result
218
233
  # @return Array<SpookAndPay::SubmissionError>
219
- # @todo If the Spreedly API behaves later, the check for first/last
234
+ # @todo If the Spreedly API behaves later, the check for first/last
220
235
  # name might not be needed anymore.
221
236
  def extract_card_errors(result)
222
- # This gnarly bit of code transforms errors on the first_name or
237
+ # This gnarly bit of code transforms errors on the first_name or
223
238
  # last_name attributes into an error on full_name. This is because
224
- # Spreedly accepts input for full_name, but propogates errors to the
239
+ # Spreedly accepts input for full_name, but propogates errors to the
225
240
  # separate attributes.
226
241
  errors = result.errors.map do |e|
227
242
  case e[:attribute]
@@ -243,7 +258,7 @@ module SpookAndPay
243
258
  end
244
259
  end
245
260
 
246
- # Extracts/coerces errors from a Spreedly transaction into
261
+ # Extracts/coerces errors from a Spreedly transaction into
247
262
  # SubmissionError instances.
248
263
  #
249
264
  # @param Spreedly::Transaction result
@@ -288,11 +303,12 @@ module SpookAndPay
288
303
  fields = {}
289
304
 
290
305
  fields[:type], status = case transaction
291
- when ::Spreedly::Authorization then [:authorize, :authorized]
292
- when ::Spreedly::Purchase then [:purchase, :settled]
293
- when ::Spreedly::Capture then [:capture, :settled]
294
- when ::Spreedly::Refund then [:credit, :refunded]
295
- when ::Spreedly::Void then [:void, :voided]
306
+ when ::Spreedly::Authorization then [:authorize, :authorized]
307
+ when ::Spreedly::Purchase then [:purchase, :settled]
308
+ when ::Spreedly::Capture then [:capture, :settled]
309
+ when ::Spreedly::Refund then [:credit, :refunded]
310
+ when ::Spreedly::Void then [:void, :voided]
311
+ when ::Spreedly::RetainPaymentMethod then [:retain, :retained]
296
312
  end
297
313
 
298
314
  if transaction.respond_to?(:amount)
@@ -1,12 +1,12 @@
1
1
  module SpookAndPay
2
- # A simple class representing an interaction with a provider. Each
3
- # interaction has an ID, a type and may be successful or not. It is
2
+ # A simple class representing an interaction with a provider. Each
3
+ # interaction has an ID, a type and may be successful or not. It is
4
4
  # read-only.
5
5
  class Transaction
6
6
  # Basic attributes
7
7
  attr_reader :provider, :id, :status, :raw
8
8
 
9
- # Extra set of fields which may or may not be present depending on the
9
+ # Extra set of fields which may or may not be present depending on the
10
10
  # provider.
11
11
  FIELDS = [:created_at, :updated_at, :amount, :credit_card, :type].freeze
12
12
  attr_reader *FIELDS
@@ -37,7 +37,7 @@ module SpookAndPay
37
37
  end
38
38
  end
39
39
 
40
- # As a bare minimum the transaction captures the transaction ID, it's
40
+ # As a bare minimum the transaction captures the transaction ID, it's
41
41
  # status and the raw response from the provider. Optionally, it can receive
42
42
  # other fields via the opts hash.
43
43
  #
@@ -60,7 +60,7 @@ module SpookAndPay
60
60
  FIELDS.each {|f| instance_variable_set(:"@#{f}", opts[f]) if opts.has_key?(f)}
61
61
  end
62
62
 
63
- # Implements value comparison i.e. if class and ID match, they are the
63
+ # Implements value comparison i.e. if class and ID match, they are the
64
64
  # same.
65
65
  #
66
66
  # @param Class other
@@ -127,7 +127,20 @@ module SpookAndPay
127
127
  provider.refund_transaction(self)
128
128
  end
129
129
 
130
- # Captures an authorized transaction. Will only capture the amount
130
+ # Refunds the transaction. The related credit card will be credited for
131
+ # the amount specified. It will only succeed for purchases or captured
132
+ # authorizations.
133
+ #
134
+ # @param Numeric amount
135
+ # @return SpookAndPay::Result
136
+ # @raises SpookAndPay::Transaction::InvalidActionError
137
+ # @raises SpookAndPay::Providers::Base::NotSupportedError
138
+ def partial_refund!(amount)
139
+ raise InvalidActionError.new(id, :partial_refund, status) unless settled?
140
+ provider.partially_refund_transaction(self, amount)
141
+ end
142
+
143
+ # Captures an authorized transaction. Will only capture the amount
131
144
  # authorized and will fail if the transaction is already captured.
132
145
  #
133
146
  # @return SpookAndPay::Result
@@ -138,7 +151,7 @@ module SpookAndPay
138
151
  provider.capture_transaction(self)
139
152
  end
140
153
 
141
- # Voids a transaction. Can only be done when the transaction is in the
154
+ # Voids a transaction. Can only be done when the transaction is in the
142
155
  # authorized status. Otherwise it must be refunded.
143
156
  #
144
157
  # @return SpookAndPay::Result
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: spook_and_pay
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.3.1.alpha
4
+ version: 1.0.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Luke Sutton
@@ -9,7 +9,7 @@ authors:
9
9
  autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
- date: 2014-09-23 00:00:00.000000000 Z
12
+ date: 2015-11-03 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: braintree
@@ -43,14 +43,14 @@ dependencies:
43
43
  name: rack
44
44
  requirement: !ruby/object:Gem::Requirement
45
45
  requirements:
46
- - - '>='
46
+ - - ">="
47
47
  - !ruby/object:Gem::Version
48
48
  version: 1.4.0
49
49
  type: :runtime
50
50
  prerelease: false
51
51
  version_requirements: !ruby/object:Gem::Requirement
52
52
  requirements:
53
- - - '>='
53
+ - - ">="
54
54
  - !ruby/object:Gem::Version
55
55
  version: 1.4.0
56
56
  - !ruby/object:Gem::Dependency
@@ -81,20 +81,6 @@ dependencies:
81
81
  - - '='
82
82
  - !ruby/object:Gem::Version
83
83
  version: 0.11.0
84
- - !ruby/object:Gem::Dependency
85
- name: debugger
86
- requirement: !ruby/object:Gem::Requirement
87
- requirements:
88
- - - '='
89
- - !ruby/object:Gem::Version
90
- version: 1.6.1
91
- type: :development
92
- prerelease: false
93
- version_requirements: !ruby/object:Gem::Requirement
94
- requirements:
95
- - - '='
96
- - !ruby/object:Gem::Version
97
- version: 1.6.1
98
84
  description:
99
85
  email:
100
86
  - lukeandben@spookandpuff.com
@@ -126,17 +112,17 @@ require_paths:
126
112
  - lib
127
113
  required_ruby_version: !ruby/object:Gem::Requirement
128
114
  requirements:
129
- - - '>='
115
+ - - ">="
130
116
  - !ruby/object:Gem::Version
131
117
  version: '0'
132
118
  required_rubygems_version: !ruby/object:Gem::Requirement
133
119
  requirements:
134
- - - '>'
120
+ - - ">="
135
121
  - !ruby/object:Gem::Version
136
- version: 1.3.1
122
+ version: '0'
137
123
  requirements: []
138
124
  rubyforge_project:
139
- rubygems_version: 2.2.2
125
+ rubygems_version: 2.4.8
140
126
  signing_key:
141
127
  specification_version: 4
142
128
  summary: A library for handling online payments using services providing transparent