spook_and_pay 0.3.1.alpha → 1.0.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 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