spook_and_pay 0.2.6.alpha → 0.2.7.alpha

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: 5b1ff796137c7a459d6b8757e56e8c9ea52b76e3
4
- data.tar.gz: 8b3dc5f18685220533a8718177c945f0ba7eaa76
3
+ metadata.gz: 0bd84aa5f8a08e720cb7eb6140911be472d923ee
4
+ data.tar.gz: c9345a68d16c46d723812c9934f561c3ce5513ec
5
5
  SHA512:
6
- metadata.gz: 168c68ae8c2a3fe771938fe39dc87d06134d83494ec9e863a0a2e0f91d795b2f6d3f15f57833c3277df9f2b1e7705a1182b7bf22b3858c94611def2482f33c8c
7
- data.tar.gz: bdf338598dcc6f21327bad76f9c87b91e6b28dd9c7e288ae5ddaca8dfe8133580177935b0265b4fdf55b5d6abf34b0657142b748c681c5dcff6296b5774c4c46
6
+ metadata.gz: 045d465056dce7c1025c4c04b7dca6e4f504b2203c86f3ea52b86f40ede6b919db556c312fe25b5477e47304846eb48e294ee94c9e3edaecec46354ea0d48106
7
+ data.tar.gz: 7b9e0f4368ce879baf32b3a20f4b41ba1d1f3164ae3a44f69d83ffb7c0b6ab4a8835281da3aa67c9a80171a8f8a70dc7144a7d0473baf327c851b2286c3ac5c1
@@ -6,6 +6,14 @@ 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
10
+ # invalid details or has expired.
11
+ class InvalidCardError < StandardError
12
+ def to_s
13
+ "The action cannot be performed, this card is invalid or expired."
14
+ end
15
+ end
16
+
9
17
  # The basic attributes of the credit card.
10
18
  attr_reader :provider, :id, :raw
11
19
 
@@ -60,12 +68,58 @@ module SpookAndPay
60
68
  end
61
69
  end
62
70
 
71
+ # Checks to see if funds can be credited to a card. Depends on the
72
+ # gateway/provider supporting crediting and having a valid card.
73
+ #
74
+ # @return [true, false]
75
+ def can_credit?
76
+ provider.supports_credit? and valid? and !expired?
77
+ end
78
+
79
+ # Checks to see if this card can be authorized against the specified
80
+ # gateway.
81
+ #
82
+ # @return [true, false]
83
+ def can_authorize?
84
+ provider.supports_authorize? and valid? and !expired?
85
+ end
86
+
87
+ # Checks to see if this card can be used for a purchase against the
88
+ # underlying gateway.
89
+ #
90
+ # @return [true, false]
91
+ def can_purchase?
92
+ provider.supports_purchase? and valid? and !expired?
93
+ end
94
+
95
+ # Checks to see if the provider/gateway supports the deletion of credit
96
+ # card details.
97
+ #
98
+ # @return [true, false]
99
+ def can_delete?
100
+ provider.supports_delete?
101
+ end
102
+
103
+ # Credits the specified amount to the card.
104
+ #
105
+ # @param [String, Numeric] amount
106
+ # @return SpookAndPay::Result
107
+ # @raises SpookAndPay::Providers::Base::NotSupportedError
108
+ # @raises SpookAndPay::CreditCard::InvalidCardError
109
+ def credit!(amount)
110
+ verify_action
111
+ provider.credit_via_credit_card(self, amount)
112
+ end
113
+
63
114
  # Authorizes a payment of the specified amount. This generates a new
64
115
  # transaction that must be later settled.
65
116
  #
66
117
  # @param [String, Numeric] amount
67
118
  # @return SpookAndPay::Result
119
+ # @raises SpookAndPay::Providers::Base::NotSupportedError
120
+ # @raises SpookAndPay::CreditCard::InvalidCardError
68
121
  def authorize!(amount)
122
+ verify_action
69
123
  provider.authorize_via_credit_card(self, amount)
70
124
  end
71
125
 
@@ -73,13 +127,17 @@ module SpookAndPay
73
127
  #
74
128
  # @param [String, Numeric] amount
75
129
  # @return SpookAndPay::Result
130
+ # @raises SpookAndPay::Providers::Base::NotSupportedError
131
+ # @raises SpookAndPay::CreditCard::InvalidCardError
76
132
  def purchase!(amount)
133
+ verify_action
77
134
  provider.purchase_via_credit_card(self, amount)
78
135
  end
79
136
 
80
137
  # Deletes the credit card from the provider's vault.
81
138
  #
82
- # @return [true, false]
139
+ # @return SpookAndPay::Result
140
+ # @raises SpookAndPay::Providers::Base::NotSupportedError
83
141
  def delete!
84
142
  provider.delete_credit_card(self)
85
143
  end
@@ -98,5 +156,17 @@ module SpookAndPay
98
156
  def expired?
99
157
  expired
100
158
  end
159
+
160
+ private
161
+
162
+
163
+ # A helper method which validates any actions — authorize, credit etc. —
164
+ # and where the card is expired or has invalid details, raises an error.
165
+ #
166
+ # @return nil
167
+ # @raises SpookAndPay::CreditCard::InvalidCardError
168
+ def verify_action
169
+ raise InvalidCardError if expired? or !valid?
170
+ end
101
171
  end
102
172
  end
@@ -118,7 +118,7 @@ module SpookAndPay
118
118
  # @param [SpookAndPay::Transaction, String] id
119
119
  # @return SpookAndPay::Result
120
120
  def capture_transaction(id)
121
- raise NotImplementedError
121
+ check_support('capture')
122
122
  end
123
123
 
124
124
  # Refunds the amount of money captured in a transaction.
@@ -129,7 +129,16 @@ module SpookAndPay
129
129
  # @param [SpookAndPay::Transaction, String] id
130
130
  # @return SpookAndPay::Result
131
131
  def refund_transaction(id)
132
- raise NotImplementedError
132
+ check_support('refund')
133
+ end
134
+
135
+ # Checks to see if purchasing is supported. This is dependent on the payment
136
+ # provider. The default implementation simply returns true. Specific
137
+ # implementations should over-ride this method.
138
+ #
139
+ # @return [true, false]
140
+ def supports_purchase?
141
+ true
133
142
  end
134
143
 
135
144
  # Checks to see if voiding is supported. This is dependent on the payment
@@ -141,6 +150,51 @@ module SpookAndPay
141
150
  true
142
151
  end
143
152
 
153
+ # Checks to see if crediting is supported. This is dependent on the payment
154
+ # provider. The default implementation simply returns true. Specific
155
+ # implementations should over-ride this method.
156
+ #
157
+ # @return [true, false]
158
+ def supports_credit?
159
+ true
160
+ end
161
+
162
+ # Checks to see if refunding is supported. This is dependent on the payment
163
+ # provider. The default implementation simply returns true. Specific
164
+ # implementations should over-ride this method.
165
+ #
166
+ # @return [true, false]
167
+ def supports_refund?
168
+ true
169
+ end
170
+
171
+ # Checks to see if capturing is supported. This is dependent on the payment
172
+ # provider. The default implementation simply returns true. Specific
173
+ # implementations should over-ride this method.
174
+ #
175
+ # @return [true, false]
176
+ def supports_capture?
177
+ true
178
+ end
179
+
180
+ # Checks to see if authorizing is supported. This is dependent on the payment
181
+ # provider. The default implementation simply returns true. Specific
182
+ # implementations should over-ride this method.
183
+ #
184
+ # @return [true, false]
185
+ def supports_authorize?
186
+ true
187
+ end
188
+
189
+ # Checks to see if the deletion of payment details is supported. This is
190
+ # dependent on the payment provider. The default implementation simply
191
+ # returns true. Specific implementations should over-ride this method.
192
+ #
193
+ # @return [true, false]
194
+ def supports_delete?
195
+ true
196
+ end
197
+
144
198
  # Voids an authorization.
145
199
  #
146
200
  # This should not be called directly. Instead, use the #void! method
@@ -151,7 +205,7 @@ module SpookAndPay
151
205
  # @api private
152
206
  # @abstract Subclass to implement
153
207
  def void_transaction(id)
154
- raise NotImplementedError
208
+ check_support('void')
155
209
  end
156
210
 
157
211
  # Authorizes a payment against a credit card
@@ -165,7 +219,21 @@ module SpookAndPay
165
219
  # @api private
166
220
  # @abstract Subclass to implement
167
221
  def authorize_via_credit_card(id, amount)
168
- raise NotImplementedError
222
+ check_support('authorize')
223
+ end
224
+
225
+ # Credits funds to a credit card
226
+ #
227
+ # This should not be called directly. Instead, use the #authorize! method
228
+ # provided by a CreditCard instance.
229
+ #
230
+ # @param [SpookAndPay::CreditCard, String] id
231
+ # @param [String, Numeric] amount in dollars
232
+ # @return SpookAndPay::Result
233
+ # @api private
234
+ # @abstract Subclass to implement
235
+ def credit_via_credit_card(id, amount)
236
+ check_support('credit')
169
237
  end
170
238
 
171
239
  # Creates a purchase against a credit card.
@@ -179,7 +247,7 @@ module SpookAndPay
179
247
  # @api private
180
248
  # @abstract Subclass to implement
181
249
  def purchase_via_credit_card(id, amount)
182
- raise NotImplementedError
250
+ check_support('purchase')
183
251
  end
184
252
 
185
253
  # Removes payment details from the provider's vault.
@@ -192,11 +260,32 @@ module SpookAndPay
192
260
  # @api private
193
261
  # @abstract Subclass to implement
194
262
  def delete_credit_card(id)
195
- raise NotImplementedError
263
+ check_support('delete')
196
264
  end
197
265
 
198
266
  private
199
267
 
268
+ # Checks to see if a particular action is defined as being supported and
269
+ # raises the appropriate error.
270
+ #
271
+ # The basic semantics is this; if someone implementing a provider says an
272
+ # action is supported via a #supports_*? predicate, this method should
273
+ # never be called, so we raise NotImplementedError. Otherwise they are
274
+ # saying it's not supported and the appropriate response is to raise a
275
+ # NotSupportedError.
276
+ #
277
+ # @param String action
278
+ # @return nil
279
+ # @raises NotSupportedError
280
+ # @raises NotImplementedError
281
+ def check_support(action)
282
+ if send(:"supports_#{action}?")
283
+ raise NotImplementedError
284
+ else
285
+ raise NotSupportedError
286
+ end
287
+ end
288
+
200
289
  # Extracts the credit card id from it's argument. This is is to help with
201
290
  # methods that accept either a card instance of an id.
202
291
  #
@@ -49,11 +49,17 @@ module SpookAndPay
49
49
  # @param Hash opts
50
50
  # @return Hash
51
51
  def prepare_payment_submission(redirect_url, opts = {})
52
- {
52
+ config = {
53
53
  :url => spreedly.transparent_redirect_form_action,
54
54
  :field_names => self.class::FORM_FIELD_NAMES,
55
55
  :hidden_fields => {:redirect_url => redirect_url, :environment_key => spreedly.key}
56
56
  }
57
+
58
+ if opts[:token]
59
+ config[:hidden_fields][:payment_method_token] = opts[:token]
60
+ end
61
+
62
+ config
57
63
  end
58
64
 
59
65
  # Confirms the submission of payment details to Spreedly Core.
@@ -115,10 +121,30 @@ module SpookAndPay
115
121
  # spreedly gem, check it.
116
122
  ::Spreedly::Gateway.send(:field, :characteristics)
117
123
 
124
+ def supports_purchase?
125
+ check_support_for('supports_purchase')
126
+ end
127
+
118
128
  def supports_void?
119
- gateway = spreedly.find_gateway(gateway_token)
120
- node = Nokogiri::XML::DocumentFragment.parse(gateway.characteristics)
121
- node.xpath(".//supports_void").inner_html.strip == 'true'
129
+ check_support_for('supports_void')
130
+ end
131
+
132
+ def supports_credit?
133
+ false
134
+ end
135
+
136
+ def supports_capture?
137
+ check_support_for('supports_capture')
138
+ end
139
+
140
+ def supports_authorize?
141
+ check_support_for('supports_authorize')
142
+ end
143
+
144
+ def supports_delete?
145
+ # This does not check the gateway, since the redaction is specific to
146
+ # Spreedly's store, not the gateway.
147
+ true
122
148
  end
123
149
 
124
150
  def authorize_via_credit_card(id, amount)
@@ -138,6 +164,18 @@ module SpookAndPay
138
164
 
139
165
  private
140
166
 
167
+ # Retrieves the gateway from Spreedly and then inspects the response to
168
+ # see what features it supports. This is a helper for the #supports_*?
169
+ # predicates.
170
+ #
171
+ # @param String path
172
+ # @return [true, false]
173
+ def check_support_for(path)
174
+ gateway = spreedly.find_gateway(gateway_token)
175
+ node = Nokogiri::XML::DocumentFragment.parse(gateway.characteristics)
176
+ node.xpath(".//#{path}").inner_html.strip == 'true'
177
+ end
178
+
141
179
  # Takes the result of running a transaction against a Spreedly gateway
142
180
  # and coerces it into a SpookAndPay::Result
143
181
  #
@@ -96,7 +96,7 @@ module SpookAndPay
96
96
  #
97
97
  # @return [true, false]
98
98
  def can_refund?
99
- status == :settled
99
+ settled? and provider.supports_refund?
100
100
  end
101
101
 
102
102
  # A predicate for checking if a transaction can be captured. Only true if
@@ -104,7 +104,7 @@ module SpookAndPay
104
104
  #
105
105
  # @return [true, false]
106
106
  def can_capture?
107
- status == :authorized
107
+ authorized? and provider.supports_capture?
108
108
  end
109
109
 
110
110
  # A predicate for checking if a transaction can be voided. Only true if
@@ -112,7 +112,7 @@ module SpookAndPay
112
112
  #
113
113
  # @return [true, false]
114
114
  def can_void?
115
- (status == :authorized or status == :settling) and provider.supports_void?
115
+ (authorized? or settling?) and provider.supports_void?
116
116
  end
117
117
 
118
118
  # Refunds the transaction. The related credit card will be credited for
@@ -120,9 +120,10 @@ module SpookAndPay
120
120
  # authorizations.
121
121
  #
122
122
  # @return SpookAndPay::Result
123
- # @raises InvalidActionError
123
+ # @raises SpookAndPay::Transaction::InvalidActionError
124
+ # @raises SpookAndPay::Providers::Base::NotSupportedError
124
125
  def refund!
125
- raise InvalidActionError.new(id, :refund, status) unless can_refund?
126
+ raise InvalidActionError.new(id, :refund, status) unless settled?
126
127
  provider.refund_transaction(self)
127
128
  end
128
129
 
@@ -130,9 +131,10 @@ module SpookAndPay
130
131
  # authorized and will fail if the transaction is already captured.
131
132
  #
132
133
  # @return SpookAndPay::Result
133
- # @raises InvalidActionError
134
+ # @raises SpookAndPay::Transaction::InvalidActionError
135
+ # @raises SpookAndPay::Providers::Base::NotSupportedError
134
136
  def capture!
135
- raise InvalidActionError.new(id, :capture, status) unless can_capture?
137
+ raise InvalidActionError.new(id, :capture, status) unless authorized?
136
138
  provider.capture_transaction(self)
137
139
  end
138
140
 
@@ -140,9 +142,10 @@ module SpookAndPay
140
142
  # authorized status. Otherwise it must be refunded.
141
143
  #
142
144
  # @return SpookAndPay::Result
143
- # @raises InvalidActionError
145
+ # @raises SpookAndPay::Transaction::InvalidActionError
146
+ # @raises SpookAndPay::Providers::Base::NotSupportedError
144
147
  def void!
145
- raise InvalidActionError.new(id, :void, status) unless can_void?
148
+ raise InvalidActionError.new(id, :void, status) unless authorized? or settling?
146
149
  provider.void_transaction(self)
147
150
  end
148
151
  end
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.2.6.alpha
4
+ version: 0.2.7.alpha
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: 2013-12-03 00:00:00.000000000 Z
12
+ date: 2014-01-13 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: braintree