ljoseppi-paypal 3.0.0pre6

Sign up to get free protection for your applications and to get access to all the features.
data/.document ADDED
@@ -0,0 +1,5 @@
1
+ README.rdoc
2
+ lib/**/*.rb
3
+ bin/*
4
+ features/**/*.feature
5
+ LICENSE
data/.gitignore ADDED
@@ -0,0 +1,11 @@
1
+ *.sw?
2
+ .DS_Store
3
+ coverage
4
+ rdoc
5
+ pkg
6
+ ._*
7
+ *.orig
8
+ Thumbs.db
9
+ doc
10
+ .yardoc
11
+ .bundle
data/CHANGELOG.md ADDED
@@ -0,0 +1,75 @@
1
+ = 3.0.0 (git)
2
+
3
+ Update spec task to use the new RSpec module name
4
+ Remove constant/class variable usage and use Thread specific configurations
5
+ Start spec on Paypal::Helpers::Common.paypal_setup
6
+ Fix specs for Paypal::Config
7
+ Upgrade dev dependencies to use Rspec >= 2.0.0.a
8
+ Introduce a Paypal::Config module to handle ipn/certificates (Jonathan Tron)
9
+ Allow access to params as method (via method_missing) (Jonathan Tron)
10
+ Rework Paypal::Notification :
11
+ Remove methods to get params informations (CAUTION !!! THIS BREAK OLD API) (Jonathan Tron)
12
+ Add methods for all possible statuses and rename #complete? as completed? to follow Paypal naming (Jonathan Tron)
13
+ Use Rack::Utils#parse_query in Paypal::Notification for query parsing (Jonathan Tron)
14
+ Add Spec for notification (Jonathan Tron)
15
+ Add paypal/rails.rb to trigger helper inclusion in view (Jonathan Tron)
16
+ Separate actual helpers in two files (paypal/helpers/common.rb and paypal/helpers/rails.rb) (Jonathan Tron)
17
+ Move files around (Jonathan Tron)
18
+ Update the README and switch to MarkDown (Jonathan Tron)
19
+ Add a CHANGELOG file and switch to new format (Jonathan Tron)
20
+ Remove init.rb (Jonathan Tron)
21
+ Configure gem generation with jelewer (Jonathan Tron)
22
+
23
+ = 2008-10-16 -- 2.0.2
24
+
25
+ NEW: Added block style support for paypal_form_tag (paypal_form_tag do blah.. blah... end)
26
+ DEL: Removed patch for 2.0.0, no longer seems suitable.
27
+ NEW: Added testing for the paypal_form_tag block style.
28
+ NEW: Added a sample (actual from paypal sandbox) PayPal server response for IPN, to aid in testing.
29
+
30
+ = 2008-10-15 -- 2.0.1
31
+
32
+ CHG: Modified README.
33
+ FIX: Moved patch to own directory, was being caught by git-hub as gem's README
34
+ NEW: Added patch for currently installed paypal-2.0.0 gem to apply directly on gems directory.
35
+ NEW: Added relevant test statements.
36
+ FIX: removed duplicate 'invoice' method in lib/notification.rb
37
+ NEW: added correct 'custom' method to lib/notification.rb
38
+ NEW: added pending_reason, reason_code, memo, payment_type, exchange_rate methods to lib/notification.rb
39
+
40
+ = 2006-04-20 -- 2.0.0
41
+
42
+ Uses paypal extended syntax. The plugin can now submit shipping and billing addresses using the paypal_address helper.
43
+
44
+ = 2006-04-20 -- 1.7.0
45
+
46
+ Now a rails plugin
47
+
48
+ = 2006-02-10 -- 1.5.1
49
+
50
+ added complete list of valid paypal options (Paul Hart)
51
+
52
+ = 2006-02-02 -- 1.5.0
53
+
54
+ Now report an error when invalid option is passed to paypal_setup
55
+ Had to rename parameters cancel_url to cancel_return and return_url to return, please update your app
56
+ Improved the test coverage strategy for helper tests
57
+ Added support for encrypted form data (Paul Hart)
58
+
59
+ = 2005-09-16 -- 0.9.6
60
+
61
+ Added readme note about the openssl requirement
62
+
63
+ = 2005-07-26 -- 0.9.5
64
+
65
+ Added tax to the helper parameters
66
+ fixed bug when money class was used to pass in amount. Cents were always 00 (doh!)
67
+ Added invoice and custom optional parameters
68
+ Added charset = utf-8 to all paypal posts
69
+ Wrongly used undefined_quanitity parameter in 0.9.1, this caused users to be prompted for the quanitity on the paypal checkout page... fixed
70
+
71
+ = 2005-07-22 -- 0.9.1
72
+
73
+ support for cancel_url as well as notify_url. This means you can now set the IPN callback address from the paypal_setup method and
74
+ you don't have to do that in the paypal admin interface!
75
+ Removed the actual form tag from the paypal_setup generated code to conform better with docs
data/Gemfile ADDED
@@ -0,0 +1,3 @@
1
+ source "http://rubygems.org"
2
+
3
+ gemspec
data/Gemfile.lock ADDED
@@ -0,0 +1,36 @@
1
+ PATH
2
+ remote: .
3
+ specs:
4
+ jonathantron-paypal (3.0.0pre4)
5
+ rack (>= 1.0.0)
6
+
7
+ GEM
8
+ remote: http://rubygems.org/
9
+ specs:
10
+ bluecloth (2.1.0)
11
+ diff-lcs (1.1.2)
12
+ fakeweb (1.3.0)
13
+ nokogiri (1.5.0)
14
+ rack (1.3.1)
15
+ rcov (0.9.9)
16
+ rspec (2.6.0)
17
+ rspec-core (~> 2.6.0)
18
+ rspec-expectations (~> 2.6.0)
19
+ rspec-mocks (~> 2.6.0)
20
+ rspec-core (2.6.4)
21
+ rspec-expectations (2.6.0)
22
+ diff-lcs (~> 1.1.2)
23
+ rspec-mocks (2.6.0)
24
+ yard (0.7.2)
25
+
26
+ PLATFORMS
27
+ ruby
28
+
29
+ DEPENDENCIES
30
+ bluecloth
31
+ fakeweb
32
+ jonathantron-paypal!
33
+ nokogiri
34
+ rcov (>= 0.9.8)
35
+ rspec (~> 2.6.0)
36
+ yard
data/LICENSE ADDED
@@ -0,0 +1,23 @@
1
+ #--
2
+ # Copyright (c) 2005 Tobias Luetke
3
+ # Copyright (c) 2009 Tron Jonathan
4
+ #
5
+ # Permission is hereby granted, free of charge, to any person obtaining
6
+ # a copy of this software and associated documentation files (the
7
+ # "Software"), to deal in the Software without restriction, including
8
+ # without limitation the rights to use, copy, modify, merge, publish,
9
+ # distribute, sublicense, and/or sell copies of the Software, and to
10
+ # permit persons to whom the Software is furnished to do so, subject to
11
+ # the following conditions:
12
+ #
13
+ # The above copyright notice and this permission notice shall be
14
+ # included in all copies or substantial portions of the Software.
15
+ #
16
+ # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
17
+ # EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
18
+ # MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
19
+ # NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
20
+ # LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
21
+ # OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
22
+ # WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
23
+ #++
data/README.md ADDED
@@ -0,0 +1,117 @@
1
+ # Welcome to Paypal ruby library
2
+
3
+ This library is here to aid with integrating Paypal payments into ruby on rails
4
+ applications or similar. To set this up you will need to log into your paypal
5
+ business account and tell paypal where to send the IPN ( Instant payment notifications ).
6
+
7
+ # Download
8
+
9
+ * Preferred method of installation is using rubygems. gem install JonathanTron-paypal
10
+ * Alternatively you can get the source code at http://github.com/JonathanTron/paypal
11
+
12
+ # Requirements
13
+
14
+ * Ruby 1.8.2 (may work with previous versions) With OpenSSL support compiled in.
15
+ * Valid paypal business account.
16
+ * (optional) The money library from http://dist.leetsoft.com/api/money
17
+
18
+ # Installation
19
+
20
+ 1. sudo gem install JonathanTron-paypal --source=http://gems.github.com
21
+
22
+ 2. Require the library
23
+
24
+ require "paypal"
25
+
26
+ 2.1. If you're using Rails add :
27
+
28
+ require "paypal/rails"
29
+
30
+ 3. Create a paypal_ipn ( or similar ) action like the one in the "Example action" appendix.
31
+
32
+
33
+ ## -- - TODO : REWRITE BELOW THIS POINT - --
34
+
35
+ Within the new payment controller you can now create pages from which users can be sent to paypal. You always have to sent users to paypal using a HTTP Post so a standard link won't work (well OK but you need some javascript for that). The +Paypal::Helper+ namespace has some examples of how such a forward page may look.
36
+
37
+ # Testing the integration
38
+
39
+ Under https://developer.paypal.com/ you can signup for a paypal developer account.
40
+ This allows you to set up "sandboxed" accounts which work and act like real accounts
41
+ with the difference that no money is exchanged. Its a good idea to sign up for a
42
+ sandbox account to use while the application is running in development mode.
43
+
44
+
45
+ # Example rails controller
46
+
47
+ class BackendController < ApplicationController
48
+
49
+ # Simplification, please write better code then this...
50
+ def paypal_ipn
51
+ notify # Paypal::Notification.new(request.raw_post)
52
+
53
+ if notify.acknowledge
54
+ order # Order.find(notify.item_id)
55
+ order.success # (notify.complete? and order.total # notify.amount) ? 'success' : 'failure'
56
+ order.save
57
+ end
58
+
59
+ render :nothing #> true
60
+ end
61
+ end
62
+
63
+ # Example paypal forward page
64
+
65
+ <%# paypal_form_tag %>
66
+ <%# paypal_setup "Item 500", Money.us_dollar(50000), "bob@bigbusiness.com", :notify_url #> url_for(:only_path #> false, :action #> 'paypal_ipn') %>
67
+
68
+ Please press here to pay $500US using paypal. <br/>
69
+ <%# submit_tag "Go to paypal >>" %>
70
+
71
+ </form>
72
+
73
+ or, with the same results, the block version:
74
+
75
+ <% paypal_form_tag do %>
76
+ <%# paypal_setup "Item 500", Money.us_dollar(50000), "bob@bigbusiness.com", :notify_url #> url_for(:only_path #> false, :action #> 'paypal_ipn') %>
77
+
78
+ Please press here to pay $500US using paypal. <br/>
79
+ <%# submit_tag "Go to paypal >>" %>
80
+
81
+ <% end %>
82
+
83
+ # Using encrypted form data
84
+
85
+ Paypal supports encrypted form data to prevent tampering by third parties.
86
+ You must have a verified paypal account to use this functionality.
87
+
88
+ 1) Create a private key for yourself
89
+
90
+ openssl genrsa -out business_key.pem 1024
91
+
92
+ 2) Create a public certificate to share with Paypal
93
+
94
+ openssl req -new -key business_key.pem -x509 -days 3650 -out business_cert.pem
95
+
96
+ 3) Upload the public certificate to Paypal (under Profile -> Encrypted Payment Settings -> Your Public Certificates -> Add),
97
+ and note the "Cert ID" that Paypal shows for the certificate.
98
+
99
+ 4) Update your controller to include the details for your key and certificate.
100
+
101
+ @business_key # File::read("business_key.pem")
102
+ @business_cert # File::read("business_cert.pem")
103
+ @business_certid # "certid from paypal"
104
+
105
+ 5) Update your views to populate the :business_key, :business_cert and :business_certid options in 'paypal_setup' - the rest of the signature is the same.
106
+
107
+ 6) When you're ready to go live, download the production Paypal certificate and override the default certificate.
108
+
109
+ Paypal::Notification.paypal_cert # File::read("paypal_cert.pem")
110
+
111
+ 7) Finally, add the following line to your environment.rb or inside an initializer:
112
+
113
+ Paypal::Notification.ipn_url # "https://www.paypal.com/cgi-bin/webscr"
114
+
115
+ # Troubleshooting
116
+
117
+ uninitalized constant Paypal - Make sure your ruby has openssl support
data/Rakefile ADDED
@@ -0,0 +1,21 @@
1
+ require "rubygems"
2
+
3
+ $:.unshift "./lib"
4
+ require "paypal"
5
+
6
+ require "rspec/core/rake_task"
7
+ ::RSpec::Core::RakeTask.new(:spec)
8
+ ::RSpec::Core::RakeTask.new(:rcov) do |spec|
9
+ spec.rcov = true
10
+ spec.rcov_opts = "--exclude spec/"
11
+ end
12
+ task :default => :spec
13
+
14
+ begin
15
+ require "yard"
16
+ YARD::Rake::YardocTask.new
17
+ rescue LoadError
18
+ task :yardoc do
19
+ abort "YARD is not available. In order to run yardoc, you must: sudo gem install yard"
20
+ end
21
+ end
@@ -0,0 +1,22 @@
1
+ -----BEGIN CERTIFICATE-----
2
+ MIIDoTCCAwqgAwIBAgIBADANBgkqhkiG9w0BAQUFADCBmDELMAkGA1UEBhMCVVMx
3
+ EzARBgNVBAgTCkNhbGlmb3JuaWExETAPBgNVBAcTCFNhbiBKb3NlMRUwEwYDVQQK
4
+ EwxQYXlQYWwsIEluYy4xFjAUBgNVBAsUDXNhbmRib3hfY2VydHMxFDASBgNVBAMU
5
+ C3NhbmRib3hfYXBpMRwwGgYJKoZIhvcNAQkBFg1yZUBwYXlwYWwuY29tMB4XDTA0
6
+ MDQxOTA3MDI1NFoXDTM1MDQxOTA3MDI1NFowgZgxCzAJBgNVBAYTAlVTMRMwEQYD
7
+ VQQIEwpDYWxpZm9ybmlhMREwDwYDVQQHEwhTYW4gSm9zZTEVMBMGA1UEChMMUGF5
8
+ UGFsLCBJbmMuMRYwFAYDVQQLFA1zYW5kYm94X2NlcnRzMRQwEgYDVQQDFAtzYW5k
9
+ Ym94X2FwaTEcMBoGCSqGSIb3DQEJARYNcmVAcGF5cGFsLmNvbTCBnzANBgkqhkiG
10
+ 9w0BAQEFAAOBjQAwgYkCgYEAt5bjv/0N0qN3TiBL+1+L/EjpO1jeqPaJC1fDi+cC
11
+ 6t6tTbQ55Od4poT8xjSzNH5S48iHdZh0C7EqfE1MPCc2coJqCSpDqxmOrO+9QXsj
12
+ HWAnx6sb6foHHpsPm7WgQyUmDsNwTWT3OGR398ERmBzzcoL5owf3zBSpRP0NlTWo
13
+ nPMCAwEAAaOB+DCB9TAdBgNVHQ4EFgQUgy4i2asqiC1rp5Ms81Dx8nfVqdIwgcUG
14
+ A1UdIwSBvTCBuoAUgy4i2asqiC1rp5Ms81Dx8nfVqdKhgZ6kgZswgZgxCzAJBgNV
15
+ BAYTAlVTMRMwEQYDVQQIEwpDYWxpZm9ybmlhMREwDwYDVQQHEwhTYW4gSm9zZTEV
16
+ MBMGA1UEChMMUGF5UGFsLCBJbmMuMRYwFAYDVQQLFA1zYW5kYm94X2NlcnRzMRQw
17
+ EgYDVQQDFAtzYW5kYm94X2FwaTEcMBoGCSqGSIb3DQEJARYNcmVAcGF5cGFsLmNv
18
+ bYIBADAMBgNVHRMEBTADAQH/MA0GCSqGSIb3DQEBBQUAA4GBAFc288DYGX+GX2+W
19
+ P/dwdXwficf+rlG+0V9GBPJZYKZJQ069W/ZRkUuWFQ+Opd2yhPpneGezmw3aU222
20
+ CGrdKhOrBJRRcpoO3FjHHmXWkqgbQqDWdG7S+/l8n1QfDPp+jpULOrcnGEUY41Im
21
+ jZJTylbJQ1b5PBBjGiP0PpK48cdF
22
+ -----END CERTIFICATE-----
@@ -0,0 +1,49 @@
1
+ module Paypal
2
+ module Config
3
+
4
+ class << self
5
+ attr_accessor :ipn_urls, :mode, :paypal_sandbox_cert, :paypal_production_cert, :business_cert, :business_key, :business_cert_id
6
+
7
+ def ipn_urls
8
+ @ipn_urls ||= {
9
+ :sandbox => "https://www.sandbox.paypal.com/cgi-bin/webscr",
10
+ :production => "https://www.paypal.com/cgi-bin/webscr"
11
+ }
12
+ end
13
+
14
+ def mode=(new_mode)
15
+ raise ArgumentError.new("Paypal::Config.mode should be either :sandbox or :production (you tried to set it as : #{new_mode})") unless [:sandbox, :production].include?(new_mode.to_sym)
16
+ @mode = new_mode.to_sym
17
+ end
18
+ def mode
19
+ @mode ||= :sandbox
20
+ end
21
+
22
+ def ipn_url
23
+ ipn_urls[mode]
24
+ end
25
+
26
+ def ipn_validation_path
27
+ URI.parse(ipn_url).path + "?cmd=_notify-validate"
28
+ end
29
+
30
+ def ipn_validation_url
31
+ "#{ipn_url}?cmd=_notify-validate"
32
+ end
33
+
34
+ def paypal_sandbox_cert
35
+ @paypal_sandbox_cert ||= File.read(File.join(File.dirname(__FILE__), 'certs', 'paypal_sandbox.pem'))
36
+ end
37
+
38
+ def paypal_cert
39
+ case mode
40
+ when :sandbox
41
+ paypal_sandbox_cert
42
+ when :production
43
+ raise StandardError.new("You should set Paypal::Config.paypal_production_cert with your paypal production certificate") unless paypal_production_cert
44
+ paypal_production_cert
45
+ end
46
+ end
47
+ end
48
+ end
49
+ end
@@ -0,0 +1,304 @@
1
+ module Paypal
2
+ # This is a collection of helpers which aid in the creation of paypal buttons
3
+ #
4
+ # Example:
5
+ #
6
+ # <%= form_tag Paypal::Config.ipn_url %>
7
+ #
8
+ # <%= paypal_setup "Item 500", Money.us_dollar(50000), "bob@bigbusiness.com" %>
9
+ # Please press here to pay $500US using paypal. <%= submit_tag %>
10
+ #
11
+ # <% end_form_tag %>
12
+ #
13
+ # For this to work you have to include these methods as helpers in your rails application.
14
+ # One way is to add "include Paypal::Helpers" in your application_helper.rb
15
+ # See Paypal::Notification for information on how to catch payment events.
16
+ module Helpers
17
+ module Common
18
+ # This helper creates the hidden form data which is needed for a paypal purchase.
19
+ #
20
+ # * <tt>item_number</tt> -- The first parameter is the item number. This is for your personal organization and can
21
+ # be arbitrary. Paypal will sent the item number back with the IPN so its a great place to
22
+ # store a user ID or a order ID or something like this.
23
+ #
24
+ # * <tt>amount</tt> -- should be a parameter of type Money ( see http://leetsoft.com/api/money ) but can also
25
+ # be a string of type "50.00" for 50$. If you use the string syntax make sure you set the current
26
+ # currency as part of the options hash. The default is USD
27
+ #
28
+ # * <tt>business</tt> -- This is your paypal account name ( an email ). This needs to be a valid paypal business account.
29
+ #
30
+ # The last parameter is a options hash. You can set or override any Paypal-recognized parameter, including:
31
+ #
32
+ # * <tt>:cmd</tt> -- default is '_xclick' or '_xclick-subscriptions' when you use :subscription.
33
+ # * <tt>:quantity</tt> -- default is '1'.
34
+ # * <tt>:no_note</tt> -- default is '1'.
35
+ # * <tt>:item_name</tt> -- default is 'Store purchase'. This is the name of the purchase which will be displayed
36
+ # on the paypal page.
37
+ # * <tt>:no_shipping</tt> -- default is '1'. By default we tell paypal that no shipping is required. Usually
38
+ # the shipping address should be collected in our application, not by paypal.
39
+ # * <tt>:currency</tt> -- default is 'USD'. If you provide a Money object, that will automatically override
40
+ # the value.
41
+ # * <tt>:charset</tt> -- default is 'utf-8'.
42
+ # * <tt>:notify_url</tt> -- If provided paypal will send its IPN notification once a
43
+ # purchase is made, canceled or any other status changes occur.
44
+ # * <tt>:return</tt> -- If provided paypal will redirect a user back to this url after a
45
+ # successful purchase. Useful for a kind of thankyou page.
46
+ # * <tt>:cancel_return</tt> -- If provided paypal will redirect a user back to this url when
47
+ # the user cancels the purchase.
48
+ # * <tt>:tax</tt> -- the tax for the store purchase. Same format as the amount parameter but optional
49
+ # * <tt>:invoice</tt> -- Unique invoice number. User will never see this. optional
50
+ # * <tt>:custom</tt> -- Custom field. User will never see this. optional
51
+ #
52
+ # Dealing with subscriptions
53
+ #
54
+ # * <tt>:subscription</tt> -- Hash containing the subscription options. optional
55
+ # * <tt>:period</tt> -- One of :monthly, :yearly, :weekly or :daily
56
+ # * <tt>:length</tt> -- How often, based on :period. E.g. 6 :monthly?
57
+ # * <tt>:retry</tt> -- Default is false. Boolean for if paypal should retry failed payments.
58
+ # * <tt>:recurring</tt> -- Default is false. Boolean for if paypal should recur payment and end of period.
59
+ #
60
+ # Generating encrypted form data
61
+ #
62
+ # The helper also supports the generation of encrypted button data. Please see the README for more information
63
+ # on the setup and prerequisite steps for using encrypted forms.
64
+ #
65
+ # The following options must all be provided (as strings) to encrypt the data:
66
+ #
67
+ # * <tt>:business_key</tt> -- The private key you have generated
68
+ # * <tt>:business_cert</tt> -- The public certificate you have also uploaded to Paypal
69
+ # * <tt>:business_certid</tt> -- The certificate ID that Paypal has assigned to your certificate.
70
+ #
71
+ # Examples:
72
+ #
73
+ # <%= paypal_setup @order.id, Money.us_dollar(50000), "bob@bigbusiness.com" %>
74
+ # <%= paypal_setup @order.id, '50.00', "bob@bigbusiness.com", :currency => 'USD' %>
75
+ # <%= paypal_setup @order.id, '50.00', "bob@bigbusiness.com", :currency => 'USD', :notify_url => url_for(:only_path => false, :action => 'paypal_ipn') %>
76
+ # <%= paypal_setup @order.id, Money.ca_dollar(50000), "bob@bigbusiness.com", :item_name => 'Snowdevil shop purchase', :return_url => paypal_return_url, :cancel_url => paypal_cancel_url, :notify_url => paypal_ipn_url %>
77
+ # <%= paypal_setup @order.id, Money.ca_dollar(50000), "bob@bigbusiness.com", :item_name => 'Snowdevil shop purchase', :return_url => paypal_return_url, :cancel_url => paypal_cancel_url, :business_key => @business_key, :business_cert => @business_cert, :business_certid => @business_certid %>
78
+ #
79
+ def paypal_setup(item_number, amount, business, options = {})
80
+
81
+ subscription = options.delete(:subscription)
82
+
83
+ misses = (options.keys - valid_setup_options)
84
+ raise ArgumentError, "Unknown option #{misses.inspect}" unless misses.empty?
85
+
86
+ params = {
87
+ :cmd => subscription ? '_ext-enter' : '_xclick',
88
+ :redirect_cmd => subscription ? '_xclick-subscriptions' : nil,
89
+ :quantity => 1,
90
+ :business => business,
91
+ :item_number => item_number,
92
+ :item_name => 'Store purchase',
93
+ :no_shipping => '1',
94
+ :no_note => '1',
95
+ :charset => 'utf-8',
96
+ :page_style => 'PayPal'
97
+ }.reject{|k,v| v.nil?}.merge(options)
98
+
99
+ params[:currency_code] = amount.currency if amount.respond_to?(:currency)
100
+ params[:currency_code] = params.delete(:currency) if params[:currency]
101
+ params[:currency_code] ||= 'USD'
102
+
103
+ # We accept both strings and money objects as amount
104
+ amount = amount.cents.to_f / 100.0 if amount.respond_to?(:cents)
105
+ amount = sprintf('%.2f', amount)
106
+
107
+ if subscription.nil?
108
+ params[:amount] = amount
109
+ else
110
+ params[:a3] = amount
111
+ params[:p3] = subscription[:length]
112
+ params[:sra] = subscription[:retry] == true ? 1 : 0
113
+ params[:src] = subscription[:recurring] == true ? 1 : 0
114
+ params[:t3] = case subscription[:period]
115
+ when :monthly; 'M'
116
+ when :yearly; 'Y'
117
+ when :weekly; 'W'
118
+ when :daily; 'D'
119
+ end
120
+ end
121
+
122
+ # same for tax
123
+ tax = params[:tax]
124
+ unless tax.nil?
125
+ tax = tax.cents.to_f / 100.0 if tax.respond_to?(:cents)
126
+ params[:tax] = sprintf("%.2f", tax)
127
+ end
128
+
129
+ # look for encryption parameters, save them outsite the parameter hash.
130
+ if params.delete(:enable_encryption)
131
+ business_key = Paypal::Config.business_key
132
+ business_cert = Paypal::Config.business_cert
133
+ business_certid = Paypal::Config.business_cert_id
134
+ unless business_key && business_cert && business_certid
135
+ raise ArgumentError, "Paypal::Config.business_key, Paypal::Config.business_cert and Paypal::Config.business_cert_id should be set if you use :enable_encryption"
136
+ end
137
+ end
138
+
139
+ # Build the form
140
+ buttons = []
141
+ # Only attempt an encrypted form if we have all the required fields.
142
+ if business_key and business_cert and business_certid
143
+ require 'openssl'
144
+
145
+ # Convert the key and certificates into OpenSSL-friendly objects.
146
+ paypal_cert = OpenSSL::X509::Certificate.new(Paypal::Config.paypal_cert)
147
+ business_key = OpenSSL::PKey::RSA.new(business_key)
148
+ business_cert = OpenSSL::X509::Certificate.new(business_cert)
149
+ # Put the certificate ID back into the parameter hash the way Paypal wants it.
150
+ params[:cert_id] = business_certid
151
+
152
+ # Prepare a string of data for encryption
153
+ data = ""
154
+ params.each_pair {|k,v| data << "#{k}=#{v}\n"}
155
+
156
+ # Sign the data with our key/certificate pair
157
+ signed = OpenSSL::PKCS7::sign(business_cert, business_key, data, [], OpenSSL::PKCS7::BINARY)
158
+ # Encrypt the signed data with Paypal's public certificate.
159
+ encrypted = OpenSSL::PKCS7::encrypt([paypal_cert], signed.to_der, OpenSSL::Cipher::Cipher::new("DES3"), OpenSSL::PKCS7::BINARY).to_s.gsub("\n", "")
160
+
161
+ # The command for encrypted forms is always '_s-xclick'; the real command is in the encrypted data.
162
+ buttons << %Q{<input type="hidden" name="cmd" value="_s-xclick" />}
163
+ buttons << %Q{<input type="hidden" name="encrypted" value="#{encrypted}" />}
164
+ else
165
+ # Just emit all the parameters that we have as hidden fields.
166
+ # Note that the sorting isn't really needed, but it makes testing a lot easier for now.
167
+ params.each do |key, value|
168
+ buttons << %Q{<input type="hidden" name="#{key}" value="#{value}" />} unless value.nil?
169
+ end
170
+ end
171
+ buttons.join("\n")
172
+ end
173
+
174
+ # Pass an address to paypal so that all signup forms can be prefilled
175
+ #
176
+ # * <tt>email</tt> -- Customer's email address
177
+ # * <tt>first_name</tt> -- Customer's first name. Must be alpha-numeric, with a 32 character limit
178
+ # * <tt>last_name</tt> -- Customer's last name. Must be alpha-numeric, with a 64 character limit
179
+ # * <tt>address1</tt> -- First line of customer's address. Must be alpha-numeric, with a 100 character limit
180
+ # * <tt>address2</tt> -- Second line of customer's address. Must be alpha-numeric, with a 100 character limit
181
+ # * <tt>city</tt> -- City of customer's address. Must be alpha-numeric, with a 100 character limit
182
+ # * <tt>state</tt> -- State of customer's address. Must be official 2 letter abbreviation
183
+ # * <tt>zip</tt> -- Zip code of customer's address
184
+ # * <tt>night_phone_a</tt> -- Area code of customer's night telephone number
185
+ # * <tt>night_phone_b</tt> -- First three digits of customer's night telephone number
186
+ # * <tt>day_phone_a</tt> -- Area code of customer's daytime telephone number
187
+ # * <tt>day_phone_b</tt> -- First three digits of customer's daytime telephon
188
+ def paypal_address(options = {})
189
+ options.collect do |key, value|
190
+ %Q{<input type="hidden" name="#{key}" value="#{value}" />}
191
+ end.join("\n")
192
+ end
193
+
194
+ private
195
+
196
+ # See https://www.paypal.com/IntegrationCenter/ic_std-variable-reference.html for details on the following options.
197
+ def valid_setup_options
198
+ [
199
+ # Generic Options
200
+ :cmd,
201
+ # IPN Support
202
+ :notify_url,
203
+ # Item Information
204
+ :item_name,
205
+ :quantity,
206
+ :undefined_quantity,
207
+ :on0,
208
+ :os0,
209
+ :on1,
210
+ :os1,
211
+ # Display Information
212
+ :add,
213
+ :cancel_return,
214
+ :cbt,
215
+ :cn,
216
+ :cpp_header_image,
217
+ :cpp_headerback_color,
218
+ :cpp_headerborder_color,
219
+ :cpp_payflow_color,
220
+ :cs,
221
+ :display,
222
+ :image_url,
223
+ :no_note,
224
+ :no_shipping,
225
+ :page_style,
226
+ :return,
227
+ :rm,
228
+ # Transaction Information
229
+ :address_override,
230
+ :currency,
231
+ :currency_code,
232
+ :custom,
233
+ :handling,
234
+ :invoice,
235
+ :redirect_cmd,
236
+ :shipping,
237
+ :tax,
238
+ :tax_cart,
239
+ # Shopping Cart Options
240
+ :amount,
241
+ :business,
242
+ :handling_cart,
243
+ :paymentaction,
244
+ :rupload,
245
+ :charset,
246
+ :upload,
247
+ # Prepopulating PayPal FORMs or Address Overriding
248
+ :address1,
249
+ :address2,
250
+ :city,
251
+ :country,
252
+ :email,
253
+ :first_name,
254
+ :last_name,
255
+ :lc,
256
+ :night_phone_a,
257
+ :night_phone_b,
258
+ :night_phone_c,
259
+ :state,
260
+ :zip,
261
+ # Prepopulating Business Account Sign-up
262
+ :business_address1,
263
+ :business_address2,
264
+ :business_city,
265
+ :business_state,
266
+ :business_country,
267
+ :business_cs_email,
268
+ :business_cs_phone_a,
269
+ :business_cs_phone_b,
270
+ :business_cs_phone_c,
271
+ :business_url,
272
+ :business_night_phone_a,
273
+ :business_night_phone_b,
274
+ :business_night_phone_c,
275
+ # End of list from https://www.paypal.com/IntegrationCenter/ic_std-variable-reference.html
276
+ # The following items are known to exist but are not yet on the above page.
277
+ :business_zip,
278
+ :day_phone_a,
279
+ :day_phone_b,
280
+ :day_phone_c,
281
+ # Subscription Options
282
+ :a1, # Trial Amount 1
283
+ :p1, # Trial Period 1
284
+ :t1, # Trial Period 1 Units (D=days, W=weeks, M=months, Y=years)
285
+ :a2, # Trial Amount 2
286
+ :p2, # Trial Period 2
287
+ :t2, # Trial Period 2 Units
288
+ :a3, # Regular Subscription Amount
289
+ :p3, # Regular Subscription Period
290
+ :t3, # Regular Subscription Period Units
291
+ :src, # Recurring Payments? (1=yes, default=0)
292
+ :sra, # Reattempt Transaction on Failure? (1=yes, default=0)
293
+ :srt, # Recurring Times (number of renewals before auto-cancel, default=forever)
294
+ :usr_manage, # Username and Password Generator? (1=yes, default=0)
295
+ :modify, # Modification Behaviour (0=new subs only, 1=new or modify, 2=modify existing only, default=0)
296
+ # Encryption Options - used internally only.
297
+ :enable_encryption, # Use business_cert, business_key and business_cert_id from Paypal::Config
298
+ # Other
299
+ :bn
300
+ ]
301
+ end
302
+ end
303
+ end
304
+ end