rack-payment 0.1.0 → 0.1.1

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.
data/lib/rack-payment.rb CHANGED
@@ -2,6 +2,7 @@ $LOAD_PATH.unshift File.dirname(__FILE__)
2
2
 
3
3
  %w( active_merchant rack bigdecimal forwardable ostruct erb ).each {|lib| require lib }
4
4
 
5
+ require 'rack-payment/callable_hash'
5
6
  require 'rack-payment/payment'
6
7
  require 'rack-payment/request'
7
8
  require 'rack-payment/response'
@@ -33,6 +33,9 @@ module Rack #:nodoc:
33
33
  def address() address1 end
34
34
  def address=(value) self.address1=(value) end
35
35
 
36
+ def full_name() name end
37
+ def full_name=(value) self.name=(value) end
38
+
36
39
  # Returns a hash that can be passed to a Gateway#authorize call
37
40
  def active_merchant_hash
38
41
  {
@@ -0,0 +1,41 @@
1
+ # A Hash that you can call, like an OpenStruct, but you can still
2
+ # call [] on it.
3
+ #
4
+ # >> hash = CallableHash.new :foo => 'bar'
5
+ #
6
+ # >> hash.foo
7
+ # => 'bar'
8
+ #
9
+ # >> hash[:foo]
10
+ # => 'bar'
11
+ class CallableHash < Hash
12
+
13
+ def initialize hash
14
+ hash.each {|key, value| self[key] = value }
15
+ end
16
+
17
+ def method_missing name, *args
18
+ if self[name]
19
+ self[name]
20
+ else
21
+ super
22
+ end
23
+ end
24
+
25
+ # Override type so, if there's a :type or 'type' key in this Hash, we
26
+ # return that value. Else we return the actual object type.
27
+ def type
28
+ return self[:type] if self[:type]
29
+ return self['type'] if self['type']
30
+ super
31
+ end
32
+
33
+ # Override zip so, if there's a :zip or 'zip' key in this Hash, we
34
+ # return that value. Else we return the actual object zip.
35
+ def zip
36
+ return self[:zip] if self[:zip]
37
+ return self['zip'] if self['zip']
38
+ super
39
+ end
40
+
41
+ end
@@ -175,7 +175,11 @@ module Rack #:nodoc:
175
175
  # By default, the form will POST to the current URL (action='')
176
176
  #
177
177
  # You can pass a different URL for the form action
178
- def form post_to = '', options = nil
178
+ def form options = nil
179
+ options ||= {}
180
+ post_to = (options[:post_to] ||= '') # the url/path to post to
181
+ auth_token = options[:auth_token] # if not nil, we include the authenticity_token in the form
182
+
179
183
  view = ::File.dirname(__FILE__) + '/views/credit-card-and-billing-info-form.html.erb'
180
184
  erb = ::File.read view
181
185
  html = ''
@@ -218,6 +222,74 @@ module Rack #:nodoc:
218
222
  end
219
223
  }.join
220
224
  end
225
+
226
+ def credit_card_values
227
+ %w( first_name last_name number cvv type expiration_month expiration_year ).inject({}) do |all, attribute|
228
+ all[attribute.to_sym] = credit_card[attribute.to_sym]
229
+ all
230
+ end
231
+ end
232
+
233
+ def billing_address_values
234
+ %w( name address1 city state zip country ).inject({}) do |all, attribute|
235
+ all[attribute.to_sym] = billing_address[attribute.to_sym]
236
+ all
237
+ end
238
+ end
239
+
240
+ # @return Hash of HTML fields with their values set
241
+ def fields values = nil
242
+ values ||= {}
243
+ values[:credit_card] = credit_card_values.merge( values[:credit_card] || {} )
244
+ values[:billing_address] = billing_address_values.merge( values[:billing_address] || {} )
245
+
246
+ CallableHash.new({
247
+ :credit_card => CallableHash.new({
248
+ :first_name => input_tag( :credit_card, :first_name, values[:credit_card][:first_name], :autofocus => true),
249
+ :last_name => input_tag( :credit_card, :last_name, values[:credit_card][:last_name]),
250
+ :number => input_tag( :credit_card, :number, values[:credit_card][:number], :autocomplete => 'off'),
251
+ :cvv => input_tag( :credit_card, :cvv, values[:credit_card][:cvv], :autocomplete => 'off'),
252
+ :type => select_tag( :credit_card, :type, values[:credit_card][:type]),
253
+ :expiration_month => select_tag( :credit_card, :expiration_month, values[:credit_card][:expiration_month]),
254
+ :expiration_year => select_tag( :credit_card, :expiration_year, values[:credit_card][:expiration_year])
255
+ }),
256
+
257
+ :billing_address => CallableHash.new({
258
+ :name => input_tag(:billing_address, :name, values[:billing_address][:name]),
259
+ :address1 => input_tag(:billing_address, :address1, values[:billing_address][:address1]),
260
+ :city => input_tag(:billing_address, :city, values[:billing_address][:city]),
261
+ :state => input_tag(:billing_address, :state, values[:billing_address][:state]),
262
+ :zip => input_tag(:billing_address, :zip, values[:billing_address][:zip]),
263
+ :country => input_tag(:billing_address, :country, values[:billing_address][:country])
264
+ })
265
+ })
266
+ end
267
+
268
+ def select_tag object, property, value = nil, options = nil
269
+ attributes = { :type => 'text', :id => "#{object}_#{property}", :name => "#{object}[#{property}]" }
270
+ attributes.merge!(options) if options
271
+
272
+ case property
273
+ when :type
274
+ options = options_for_credit_card_type(value)
275
+ when :expiration_month
276
+ options = options_for_expiration_month(value)
277
+ when :expiration_year
278
+ options = options_for_expiration_year(value)
279
+ end
280
+
281
+ "<select #{ attributes.map {|name, value| "#{name}='#{value}'" }.join(' ') }>#{ options }</select>"
282
+ end
283
+
284
+ # Returns the HTML for an <input /> element
285
+ # @return String
286
+ def input_tag object, property, value = nil, options = nil
287
+ attributes = { :type => 'text', :id => "#{object}_#{property}", :name => "#{object}[#{property}]" }
288
+ attributes[:value] = value if value.present?
289
+ attributes.merge!(options) if options
290
+
291
+ "<input #{ attributes.map {|name, value| "#{name}='#{value}'" }.join(' ') } />"
292
+ end
221
293
  end
222
294
 
223
295
  end
@@ -183,8 +183,20 @@ module Rack #:nodoc:
183
183
  payment.errors = errors
184
184
  new_env = env.clone
185
185
  new_env['REQUEST_METHOD'] = 'GET'
186
+
187
+ # Rails keeps track of its own Request/Response.
188
+ #
189
+ # If we're using Rails, we need to delete these variables
190
+ # to trick Rails into thinking that this is a new request.
191
+ #
192
+ # Kind of icky!
193
+ new_env.delete 'action_controller.rescue.request'
194
+ new_env.delete 'action_controller.rescue.response'
195
+
186
196
  new_env['PATH_INFO'] = on_success if request.path_info == express_ok_path # if express, we render on_success
187
- app.call(new_env)
197
+ resp = app.call(new_env)
198
+ puts resp.inspect
199
+ resp
188
200
  end
189
201
  end
190
202
 
@@ -203,7 +215,7 @@ module Rack #:nodoc:
203
215
 
204
216
  def credit_card_and_billing_info_response
205
217
  css_file = ::File.dirname(__FILE__) + '/views/credit-card-and-billing-info-form.css'
206
- form_html = payment.form built_in_form_path, :inline_css => ::File.read(css_file)
218
+ form_html = payment.form :post_to => built_in_form_path, :inline_css => ::File.read(css_file)
207
219
  layout = ::File.dirname(__FILE__) + '/views/layout.html'
208
220
  html = ::File.read(layout)
209
221
  html = html.sub 'CONTENT', form_html
@@ -1,6 +1,5 @@
1
1
  <%
2
- # TODO use helper for select options for credit card type
3
- # TODO use helper for select options for expiration
2
+ @fields = fields # so we don't recreate the fields abunchof times
4
3
  %>
5
4
 
6
5
  <div class='rack-payment'>
@@ -16,37 +15,33 @@
16
15
  <% end %>
17
16
 
18
17
  <form action='<%= post_to %>' method='post'>
19
-
18
+ <% if auth_token %>
19
+ <input name='authenticity_token' type='hidden' value='<%= auth_token %>' />
20
+ <% end %>
20
21
  <fieldset>
21
22
  <legend>Credit Card</legend>
22
23
 
23
24
  <div class='group'>
24
25
  <label for='credit_card_first_name'>First Name</label>
25
- <input type='text' id='credit_card_first_name' name='credit_card[first_name]' value='<%= credit_card.first_name %>' autofocus='true' />
26
+ <%= @fields.credit_card.first_name %>
26
27
 
27
28
  <label for='credit_card_last_name'>Last Name</label>
28
- <input type='text' id='credit_card_last_name' name='credit_card[last_name]' value='<%= credit_card.last_name %>' />
29
+ <%= @fields.credit_card.last_name %>
29
30
 
30
31
  <label for='credit_card_number'>Card Number</label>
31
- <input type='text' id='credit_card_number' name='credit_card[number]' value='<%= credit_card.number %>' autocomplete='off' />
32
+ <%= @fields.credit_card.number %>
32
33
  </div>
33
34
 
34
35
  <div class='group'>
35
36
  <label for='credit_card_type'>Card Type</label>
36
- <select id='credit_card_type' name='credit_card[type]' />
37
- <%= options_for_credit_card_type credit_card.type %>
38
- </select>
37
+ <%= @fields.credit_card.type %>
39
38
 
40
39
  <label for='credit_card_cvv'>CVV</label>
41
- <input type='text' id='credit_card_cvv' name='credit_card[cvv]' value='<%= credit_card.cvv %>' autocomplete='off' />
40
+ <%= @fields.credit_card.cvv %>
42
41
 
43
42
  <label for='credit_card_expiration_month'>Expiration</label>
44
- <select id='credit_card_expiration_month' name='credit_card[expiration_month]'>
45
- <%= options_for_expiration_month credit_card.month %>
46
- </select>
47
- <select id='credit_card_expiration_year' name='credit_card[expiration_year]'>
48
- <%= options_for_expiration_year credit_card.year %>
49
- </select>
43
+ <%= @fields.credit_card.expiration_month %>
44
+ <%= @fields.credit_card.expiration_year %>
50
45
 
51
46
  </div>
52
47
  </fieldset>
@@ -56,24 +51,24 @@
56
51
 
57
52
  <div class='group'>
58
53
  <label for='billing_address_name'>Full Name</label>
59
- <input type='text' id='billing_address_name' name='billing_address[name]' value='<%= billing_address.name %>' />
54
+ <%= @fields.billing_address.name %>
60
55
 
61
56
  <label for='billing_address_address1'>Address</label>
62
- <input type='text' id='billing_address_address1' name='billing_address[address1]' value='<%= billing_address.address1 %>' />
57
+ <%= @fields.billing_address.address1 %>
63
58
 
64
59
  <label for='billing_address_city'>City</label>
65
- <input type='text' id='billing_address_city' name='billing_address[city]' value='<%= billing_address.city %>' />
60
+ <%= @fields.billing_address.city %>
66
61
  </div>
67
62
 
68
63
  <div class='group'>
69
64
  <label for='billing_address_state'>State</label>
70
- <input type='text' id='billing_address_state' name='billing_address[state]' value='<%= billing_address.state %>' />
65
+ <%= @fields.billing_address.state %>
71
66
 
72
67
  <label for='billing_address_country'>Country</label>
73
- <input type='text' id='billing_address_country' name='billing_address[country]' value='<%= billing_address.country %>' />
68
+ <%= @fields.billing_address.country %>
74
69
 
75
70
  <label for='billing_address_zip'>Zip</label>
76
- <input type='text' id='billing_address_zip' name='billing_address[zip]' value='<%= billing_address.zip %>' />
71
+ <%= @fields.billing_address.zip %>
77
72
  </div>
78
73
  </fieldset>
79
74
 
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: rack-payment
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.0
4
+ version: 0.1.1
5
5
  platform: ruby
6
6
  authors:
7
7
  - remi
@@ -36,6 +36,7 @@ files:
36
36
  - lib/rack-payment/test.rb
37
37
  - lib/rack-payment/payment.rb
38
38
  - lib/rack-payment/response.rb
39
+ - lib/rack-payment/callable_hash.rb
39
40
  - lib/rack-payment/helper.rb
40
41
  - lib/rack-payment/billing_address.rb
41
42
  - lib/rack-payment/methods.rb