rack-payment 0.1.0 → 0.1.1

Sign up to get free protection for your applications and to get access to all the features.
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