payment 0.9 → 1.0.1

Sign up to get free protection for your applications and to get access to all the features.
data/README ADDED
@@ -0,0 +1,71 @@
1
+ == Welcome to Payment
2
+
3
+ Payment is used to process credit cards and electronic cash through merchant accounts.
4
+
5
+ To choose a gateway, require 'payment/gateway_name'. For example, if you want to use Authorize.net, do a require 'payment/authorize_net'. If you would like to use multiple gateways in the same code, simply do a require 'payment' and it will grab each gateway's code for you.
6
+
7
+ Payment was inspired by and has borrowed much of its infrastructure from the Business::OnlinePayment Perl module (http://search.cpan.org/~jasonk/Business-OnlinePayment-2.01/OnlinePayment.pm).
8
+
9
+ If you would like to loosely check the validity of a credit card without using a merchant account, look at the CreditCard module (http://rubyforge.org/projects/creditcard/).
10
+
11
+ == Example
12
+
13
+ require 'payment/authorize_net'
14
+
15
+ transaction = Payment::AuthorizeNet.new (
16
+ :login => 'username',
17
+ :password => 'password',
18
+ :amount => '49.95',
19
+ :card_number => '4012888818888',
20
+ :expiration => '03/10',
21
+ :first_name => 'John',
22
+ :last_name => 'Doe'
23
+ )
24
+ begin
25
+ transaction.submit
26
+ puts "Card processed successfully: #{transaction.authorization}"
27
+ rescue
28
+ puts "Card was rejected: #{transaction.error_message}"
29
+ end
30
+
31
+ To set default values, setup a file called .payment.yml in the home directory of the user who will be using this library. An example file would be:
32
+
33
+ username: my_account
34
+ transaction_key: my_trans_key
35
+
36
+ That way there is no need to keep sensitive information in your application's code itself. To specify an alternative configuration file, add a :prefs => '/path/to/file.yml' to the initialization parameters.
37
+
38
+ == Currently Supported Gateways
39
+
40
+ * Authorize.Net (authorize_net) - http://www.authorize.net
41
+
42
+ == Upcoming Gateways
43
+
44
+ * Moneris - http://www.moneris.com
45
+ * Skipjack - http://www.skipjack.com
46
+
47
+ == Planned Support for the Following Gateways
48
+
49
+ * Trust Commerce - http://www.trustcommerce.com
50
+ * Verisign Payflow Pro - http://www.verisign.com
51
+ * Cardstream - http://www.cardstream.com
52
+ * Beanstream - http://www.beanstream.com
53
+ * Vital - http://www.vitalps.com
54
+ * Merchant Commerce - http://www.innuity.com
55
+ * iAuthorizer - http://www.iauthorizer.com
56
+ * Electronic Clearing House, Inc. - http://www.echo-inc.com
57
+ * Bank of America eStores - http://www.bankofamerica.com
58
+ * Network1Financial - http://www.eftsecure.com
59
+ * eSec - http://www.esecpayments.com.au
60
+ * Ingenico OCV - http://www.ingenico.com.au
61
+ * St.George IPG - https://www.ipg.stgeorge.com.au
62
+ * Jettis - http://www.jettis.com
63
+ * PaymentsGateway.Net - http://www.paymentsgateway.net
64
+ * PayConnect - http://www.paymentone.com
65
+ * Secure Hosting UPG - http://www.securehosting.com
66
+
67
+ == About
68
+
69
+ Author:: Lucas Carlson (mailto:lucas@rufy.com)
70
+ Copyright:: Copyright (c) 2005 Lucas Carlson
71
+ License:: Distributes under the same terms as Ruby
@@ -0,0 +1,95 @@
1
+ require 'rubygems'
2
+ require 'rake'
3
+ require 'rake/testtask'
4
+ require 'rake/rdoctask'
5
+ require 'rake/gempackagetask'
6
+ require 'rake/contrib/rubyforgepublisher'
7
+
8
+ PKG_VERSION = "1.0.1"
9
+
10
+ PKG_FILES = FileList[
11
+ "lib/**/*", "bin/*", "test/**/*", "[A-Z]*", "Rakefile", "doc/**/*"
12
+ ]
13
+
14
+ desc "Default Task"
15
+ task :default => [ :test ]
16
+
17
+ # Run the unit tests
18
+ desc "Run all unit tests"
19
+ Rake::TestTask.new("test") { |t|
20
+ t.libs << "lib"
21
+ t.pattern = 'test/*/*_test.rb'
22
+ t.verbose = true
23
+ }
24
+
25
+ # Make a console, useful when working on tests
26
+ desc "Generate a test console"
27
+ task :console do
28
+ verbose( false ) { sh "irb -I lib/ -r 'payment'" }
29
+ end
30
+
31
+ # Genereate the RDoc documentation
32
+ desc "Create documentation"
33
+ Rake::RDocTask.new("doc") { |rdoc|
34
+ rdoc.title = "Ruby Merchant Payment - Authorize.Net and others"
35
+ rdoc.rdoc_dir = 'doc'
36
+ rdoc.rdoc_files.include('README')
37
+ rdoc.rdoc_files.include('lib/**/*.rb')
38
+ }
39
+
40
+ # Genereate the package
41
+ spec = Gem::Specification.new do |s|
42
+
43
+ #### Basic information.
44
+
45
+ s.name = 'payment'
46
+ s.version = PKG_VERSION
47
+ s.summary = <<-EOF
48
+ Payment is used to process credit cards and electronic cash through merchant accounts.
49
+ EOF
50
+ s.description = <<-EOF
51
+ These functions tell you whether a credit card number is
52
+ self-consistent using known algorithms for credit card numbers.
53
+ All non-integer values are removed from the string before parsing
54
+ so that you don't have to worry about the format of the string.
55
+ EOF
56
+
57
+ #### Which files are to be included in this gem? Everything! (Except SVN directories.)
58
+
59
+ s.files = PKG_FILES
60
+
61
+ #### Load-time details: library and application (you will need one or both).
62
+
63
+ s.require_path = 'lib'
64
+ s.autorequire = 'payment'
65
+
66
+ #### Documentation and testing.
67
+
68
+ s.has_rdoc = true
69
+
70
+ #### Author and project details.
71
+
72
+ s.author = "Lucas Carlson"
73
+ s.email = "lucas@rufy.com"
74
+ s.homepage = "http://payment.rufy.com/"
75
+ end
76
+
77
+ Rake::GemPackageTask.new(spec) do |pkg|
78
+ pkg.need_zip = true
79
+ pkg.need_tar = true
80
+ end
81
+
82
+ desc "Report code statistics (KLOCs, etc) from the application"
83
+ task :stats do
84
+ require 'code_statistics'
85
+ CodeStatistics.new(
86
+ ["Library", "lib"],
87
+ ["Units", "test"]
88
+ ).to_s
89
+ end
90
+
91
+ desc "Publish new documentation"
92
+ task :publish do
93
+ `ssh rufy update-payment-doc`
94
+ Rake::RubyForgePublisher.new('payment', 'cardmagic').upload
95
+ end
@@ -20,62 +20,13 @@
20
20
  # OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
21
21
  # WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
22
22
  #++
23
+ #
24
+ # See Payment documentation.
23
25
 
24
- # == Welcome to Payment
25
- #
26
- # Payment is used to process credit cards and electronic cash through merchant accounts.
27
- #
28
- # To choose a gateway, require 'payment/gateway_name'. For example, if you want to use Authorize.net, do a require 'payment/authorize_net'. If you would like to use multiple gateways in the same code, simply do a require 'payment' and it will grab each gateway's code for you.
29
- #
30
- # Payment was inspired by and has borrowed much of its infrastructure from the Business::OnlinePayment Perl module (http://search.cpan.org/~jasonk/Business-OnlinePayment-2.01/OnlinePayment.pm).
31
- #
32
- # If you would like to loosely check the validity of a credit card without using a merchant account, look at the CreditCard module (http://rubyforge.org/projects/creditcard/).
33
- #
34
- # == Example
35
- #
36
- # require 'payment/authorize_net'
37
- #
38
- # transaction = Payment::AuthorizeNet.new (
39
- # :login => 'username',
40
- # :password => 'password',
41
- # :amount => '49.95',
42
- # :card_number => '1234123412341238',
43
- # :expiration => '03/05',
44
- # :first_name => 'John',
45
- # :last_name => 'Doe'
46
- # )
47
- # transaction.submit
48
- #
49
- # if transaction.success?
50
- # puts "Card processed successfully: #{transaction.authorization}";
51
- # else
52
- # puts "Card was rejected: #{transaction.error_message}";
53
- # end
54
- #
55
- # == Currently Supported Gateways
56
- #
57
- # * Authorize.Net (authorize_net) - http://www.authorize.net/
58
- #
59
- # == Planned Support for the Following Gateways
60
- #
61
- # * Trust Commerce - http://www.trustcommerce.com/
62
- # * Verisign Payflow Pro - http://www.verisign.com/
63
- # * Moneris - http://www.moneris.com/
64
- # * Cardstream - http://www.cardstream.com/
65
- # * Beanstream - http://www.beanstream.com/
66
- # * Vital - http://www.vitalps.com/
67
- # * Merchant Commerce - http://www.innuity.com/
68
- # * iAuthorizer - http://www.iauthorizer.com/
69
- # * Electronic Clearing House, Inc. - http://www.echo-inc.com/
70
- # * Bank of America eStores - http://www.bankofamerica.com/
71
- # * Network1Financial - http://www.eftsecure.com/
72
- # * eSec - http://www.esecpayments.com.au/
73
- # * Ingenico OCV - http://www.ingenico.com.au/
74
- # * St.George IPG - https://www.ipg.stgeorge.com.au/
75
- # * Jettis - http://www.jettis.com/
76
- # * PaymentsGateway.Net - http://www.paymentsgateway.net/
77
- # * PayConnect - http://www.paymentone.com/
78
- # * Secure Hosting UPG - http://www.securehosting.com/
26
+ require 'yaml'
27
+ require 'rexml/document'
28
+ require 'net/http'
29
+ require 'net/https'
79
30
 
80
31
  require 'payment/base'
81
32
  require 'payment/authorize_net'
@@ -2,206 +2,210 @@
2
2
  # Copyright:: Copyright (c) 2005 Lucas Carlson
3
3
  # License:: Distributes under the same terms as Ruby
4
4
 
5
- require 'payment/base'
6
5
  require 'cgi'
7
6
  require 'csv'
8
7
 
8
+ require 'payment/base'
9
+
9
10
  module Payment
10
11
 
11
12
  class AuthorizeNet < Base
12
13
  attr_reader :server_response, :avs_code, :order_number, :md5, :cvv2_response, :cavv_response
13
- attr_accessor :first_name, :last_name, :transaction_key
14
+ attr_accessor :first_name, :last_name, :transaction_key, :transaction_id, :invoice_num, :description
14
15
 
15
16
  # version of the gateway's API
16
17
  API_VERSION = '3.1'
17
18
 
18
- # map the instance variable names to the gateway's requested variable names
19
- FIELDS = {
20
- 'type' => 'x_Method',
21
- 'login' => 'x_Login',
22
- 'password' => 'x_Password',
23
- 'transaction_key' => 'x_Tran_Key',
24
- 'type' => 'x_Type',
25
- 'description' => 'x_Description',
26
- 'amount' => 'x_Amount',
27
- 'currency_code' => 'x_Currency_Code',
28
- 'invoice_num' => 'x_Invoice_Num',
29
- 'trans_id' => 'x_Trans_ID',
30
- 'auth_code' => 'x_Auth_Code',
31
- 'cust_id' => 'x_Cust_ID',
32
- 'customer_ip' => 'x_Customer_IP',
33
- 'last_name' => 'x_Last_Name',
34
- 'first_name' => 'x_First_Name',
35
- 'company' => 'x_Company',
36
- 'address' => 'x_Address',
37
- 'city' => 'x_City',
38
- 'state' => 'x_State',
39
- 'zip' => 'x_Zip',
40
- 'country' => 'x_Country',
41
- 'ship_to_last_name' => 'x_Ship_To_Last_Name',
42
- 'ship_to_first_name' => 'x_Ship_To_First_Name',
43
- 'ship_to_address' => 'x_Ship_To_Address',
44
- 'ship_to_city' => 'x_Ship_To_City',
45
- 'ship_to_state' => 'x_Ship_To_State',
46
- 'ship_to_zip' => 'x_Ship_To_Zip',
47
- 'ship_to_country' => 'x_Ship_To_Country',
48
- 'phone' => 'x_Phone',
49
- 'fax' => 'x_Fax',
50
- 'email' => 'x_Email',
51
- 'card_number' => 'x_Card_Num',
52
- 'expiration' => 'x_Exp_Date',
53
- 'card_code' => 'x_Card_Code',
54
- 'echeck_type' => 'x_Echeck_Type',
55
- 'account_name' => 'x_Bank_Acct_Name',
56
- 'account_number' => 'x_Bank_Acct_Num',
57
- 'account_type' => 'x_Bank_Acct_Type',
58
- 'bank_name' => 'x_Bank_Name',
59
- 'bank_aba_code' => 'x_Bank_ABA_Code',
60
- 'customer_org' => 'x_Customer_Organization_Type',
61
- 'customer_ssn' => 'x_Customer_Tax_ID',
62
- 'drivers_license_num' => 'x_Drivers_License_Num',
63
- 'drivers_license_state' => 'x_Drivers_License_State',
64
- 'drivers_license_dob' => 'x_Drivers_License_DOB',
65
- 'recurring_billing' => 'x_Recurring_Billing',
66
- 'test_request' => 'x_Test_Request',
67
- 'adc_delim_data' => 'x_ADC_Delim_Data',
68
- 'adc_url' => 'x_ADC_URL',
69
- 'version' => 'x_Version',
70
- }
71
-
72
- # map the actions to the merchant's action names
73
- ACTIONS = {
74
- 'normal authorization' => 'AUTH_CAPTURE',
75
- 'authorization only' => 'AUTH_ONLY',
76
- 'credit' => 'CREDIT',
77
- 'post authorization' => 'PRIOR_AUTH_CAPTURE',
78
- 'void' => 'VOID',
79
- }
80
-
19
+ # Set some sensible defaults for Authorize.Net
20
+ # transaction = Payment::AuthorizeNet.new (
21
+ # :login => 'username',
22
+ # :password => 'password',
23
+ # :amount => '49.95',
24
+ # :card_number => '4012888818888',
25
+ # :expiration => '03/10',
26
+ # :first_name => 'John',
27
+ # :last_name => 'Doe'
28
+ # )
29
+ #
81
30
  def initialize(options = {})
82
31
  # set some sensible defaults
83
32
  @url = 'https://secure.authorize.net/gateway/transact.dll'
84
- @adc_delim_data = 'TRUE'
85
- @adc_url = 'FALSE'
33
+ @delim_data = 'TRUE'
34
+ @relay_response = 'FALSE'
86
35
  @version = API_VERSION
87
36
 
88
37
  # include all provided data
89
38
  super options
90
39
  end
91
40
 
92
- def submit
93
- uri = URI.parse @url
94
- http = Net::HTTP.new uri.host, uri.port
95
-
96
- http.verify_mode = OpenSSL::SSL::VERIFY_NONE if @strict_ssl == false
97
- http.use_ssl = true
98
-
99
- begin
100
- response = http.post uri.path, post_data
101
- rescue
102
- @is_success = false
103
- @error_message = "Could not access #{@url}. Error code #{response.code}. #{response.message}"
104
- return
105
- end
106
-
107
- col = nil
108
- CSV::Reader.parse response.body do |row|
109
- col ||= row
110
- end
111
-
112
- if col
113
- @server_response = response.code
114
- @result_code = col[0].data
115
- @avs_code = col[5].data
116
- @order_number = col[6].data
117
- @md5 = col[37].data
118
- @cvv2_response = col[38].data
119
- @cavv_response = col[39].data
120
-
121
- if @result_code == "1" # Approved/Pending/Test
122
- @is_success = true
123
- @authorization = col[4].data
124
- else
125
- @is_success = false
126
- @error_code = col[2].data
127
- @error_message = col[3].data
128
- end
129
- else
130
- @is_success = false
131
- @error_message = "Could not interpret the result. #{response.body}"
132
- end
133
-
134
- return @is_success
41
+ # Submit the order to be processed. If it is not fulfilled for any reason
42
+ # this method will raise an exception.
43
+ def submit
44
+ set_post_data
45
+ get_response @url
46
+ parse_response
135
47
  end
136
48
 
137
- def post_data
138
- prepare_data
49
+ private
50
+
51
+ def set_post_data
52
+ prepare_data
139
53
 
140
- post_array = Array.new
141
- FIELDS.each do |loc_var, gate_var|
142
- if @@required.include?(loc_var) && eval("@#{loc_var}").nil?
143
- raise PaymentError, "The required variable '#{loc_var}' was left empty"
144
- else
145
- value = eval "CGI.escape(@#{loc_var}.to_s)"
146
- post_array << "#{gate_var}=#{value}"
147
- end
148
- end
54
+ post_array = Array.new
55
+ FIELDS.each do |loc_var, gate_var|
56
+ if @required.include?(loc_var) && eval("@#{loc_var}").nil?
57
+ raise PaymentError, "The required variable '#{loc_var}' was left empty"
58
+ else
59
+ value = eval "CGI.escape(@#{loc_var}.to_s)"
60
+ post_array << "#{gate_var}=#{value}" unless value.empty?
61
+ end
62
+ end
149
63
 
150
- return post_array.join("&")
151
- end
152
-
153
- def prepare_data
154
- # make sensible changes to data
155
- @card_number = @card_number.to_s.gsub(/[^\d]/, "") unless @card_number.nil?
156
-
157
- @test_request = @test_transaction == true ? "TRUE" : "FALSE"
64
+ @data = post_array.join('&')
65
+ end
158
66
 
159
- if @recurring_billing.class != String
160
- if @recurring_billing == true
161
- @recurring_billing = "YES"
162
- elsif @recurring_billing == false
163
- @recurring_billing = "NO"
164
- end
165
- end
166
-
167
- @expiration = @expiration.strftime "%m/%y" rescue nil # in case a date or time is passed
168
-
169
- @type = (@type.nil? && @card_number) ? 'CC' : @type.upcase
170
-
171
- # convert the action
172
- if ACTIONS.include?(@action)
173
- @action = ACTIONS[@action]
174
- elsif ! ACTIONS.has_value?(@action)
175
- raise PaymentError, "The action '#{@action}' is not valid"
176
- end
177
-
178
- # add some required fields specific to this payment gateway and the provided data
179
- @@required.concat %w(type action login test_request adc_delim_data adc_url)
67
+ def parse_response
68
+ data = @response.plain.split(',').unshift nil
69
+
70
+ @result_code = data[1].to_i
71
+ @result_reason_code = data[3]
72
+ @result_reason = data[4]
73
+ @authorization = data[5]
74
+ @avs_code = data[6]
75
+ @transaction_id = @order_number = data[7]
76
+ @md5 = data[38]
77
+ @cvv2_response = data[39]
78
+ @cavv_response = data[40]
79
+
80
+ if @result_code == 1 # Approved/Pending/Test
81
+ return @transaction_id
82
+ else
83
+ @error_code = data[3]
84
+ @error_message = data[4]
85
+ raise PaymentError, @error_message
86
+ end
87
+
88
+ end
89
+
90
+ # make sensible changes to data
91
+ def prepare_data
92
+ @card_number = @card_number.to_s.gsub(/[^\d]/, "") unless @card_number.nil?
93
+
94
+ @test_request = @test_transaction.to_s.downcase == 'true' ? 'TRUE' : 'FALSE'
95
+
96
+ if @recurring_billing.class != String
97
+ if @recurring_billing == true
98
+ @recurring_billing = "YES"
99
+ elsif @recurring_billing == false
100
+ @recurring_billing = "NO"
101
+ end
102
+ end
103
+
104
+ @expiration = @expiration.strftime "%m/%y" rescue nil # in case a date or time is passed
105
+
106
+ @method = (@method.nil? || @card_number) ? 'CC' : @method.upcase
107
+
108
+ # convert the action
109
+ if TYPES.include?(@type)
110
+ @type = TYPES[@type]
111
+ elsif ! TYPES.has_value?(@type)
112
+ raise PaymentError, "The type '#{@type}' is not valid"
113
+ end
114
+
115
+ # add some required fields specific to this payment gateway and the provided data
116
+ @required += %w(method type login test_request delim_data relay_response)
117
+
118
+ # If a transaction key is specified, use that instead
119
+ if @transaction_key.nil?
120
+ @transaction_key = nil
121
+ @required += %w(password)
122
+ else
123
+ @password = nil
124
+ @required += %w(transaction_key)
125
+ end
126
+
127
+ unless @method == 'VOID'
128
+ if @method == 'ECHECK'
129
+ @required += %w(amount routing_code account_number account_type bank_name account_name account_type)
130
+ @required += %w(customer_org customer_ssn) unless @customer_org.nil?
131
+ elsif @method == 'CC'
132
+ @required += %w(amount)
133
+ if @type == 'PRIOR_AUTH_CAPTURE'
134
+ @required += @order_number ? %w(order_number) : %w(card_number expiration)
135
+ else
136
+ @required += %w(card_number expiration)
137
+ end
138
+ else
139
+ raise PaymentError, "Can't handle transaction method: #{@method}"
140
+ end
141
+ end
142
+
143
+ @required.uniq!
144
+ end
145
+
146
+ # map the instance variable names to the gateway's requested variable names
147
+ FIELDS = {
148
+ 'method' => 'x_Method',
149
+ 'type' => 'x_Type',
150
+ 'login' => 'x_Login',
151
+ 'password' => 'x_Password',
152
+ 'transaction_key' => 'x_Tran_Key',
153
+ 'description' => 'x_Description',
154
+ 'amount' => 'x_Amount',
155
+ 'currency_code' => 'x_Currency_Code',
156
+ 'invoice_num' => 'x_Invoice_Num',
157
+ 'transaction_id' => 'x_Trans_ID',
158
+ 'auth_code' => 'x_Auth_Code',
159
+ 'cust_id' => 'x_Cust_ID',
160
+ 'customer_ip' => 'x_Customer_IP',
161
+ 'last_name' => 'x_Last_Name',
162
+ 'first_name' => 'x_First_Name',
163
+ 'company' => 'x_Company',
164
+ 'address' => 'x_Address',
165
+ 'city' => 'x_City',
166
+ 'state' => 'x_State',
167
+ 'zip' => 'x_Zip',
168
+ 'country' => 'x_Country',
169
+ 'ship_to_last_name' => 'x_Ship_To_Last_Name',
170
+ 'ship_to_first_name' => 'x_Ship_To_First_Name',
171
+ 'ship_to_address' => 'x_Ship_To_Address',
172
+ 'ship_to_city' => 'x_Ship_To_City',
173
+ 'ship_to_state' => 'x_Ship_To_State',
174
+ 'ship_to_zip' => 'x_Ship_To_Zip',
175
+ 'ship_to_country' => 'x_Ship_To_Country',
176
+ 'phone' => 'x_Phone',
177
+ 'fax' => 'x_Fax',
178
+ 'email' => 'x_Email',
179
+ 'card_number' => 'x_Card_Num',
180
+ 'expiration' => 'x_Exp_Date',
181
+ 'card_code' => 'x_Card_Code',
182
+ 'echeck_type' => 'x_Echeck_Type',
183
+ 'account_name' => 'x_Bank_Acct_Name',
184
+ 'account_number' => 'x_Bank_Acct_Num',
185
+ 'account_type' => 'x_Bank_Acct_Type',
186
+ 'bank_name' => 'x_Bank_Name',
187
+ 'bank_aba_code' => 'x_Bank_ABA_Code',
188
+ 'customer_org' => 'x_Customer_Organization_Type',
189
+ 'customer_ssn' => 'x_Customer_Tax_ID',
190
+ 'drivers_license_num' => 'x_Drivers_License_Num',
191
+ 'drivers_license_state' => 'x_Drivers_License_State',
192
+ 'drivers_license_dob' => 'x_Drivers_License_DOB',
193
+ 'recurring_billing' => 'x_Recurring_Billing',
194
+ 'test_request' => 'x_Test_Request',
195
+ 'delim_data' => 'x_Delim_Data',
196
+ 'relay_response' => 'x_Relay_Response',
197
+ 'version' => 'x_Version',
198
+ }
199
+
200
+ # map the types to the merchant's action names
201
+ TYPES = {
202
+ 'normal authorization' => 'AUTH_CAPTURE',
203
+ 'authorization only' => 'AUTH_ONLY',
204
+ 'credit' => 'CREDIT',
205
+ 'post authorization' => 'PRIOR_AUTH_CAPTURE',
206
+ 'void' => 'VOID',
207
+ }
180
208
 
181
- if @transaction_key.nil?
182
- @@required.concat %w(password)
183
- else
184
- @@required.concat %w(transaction_key)
185
- end
186
-
187
- unless @type == 'VOID'
188
- if @type == 'ECHECK'
189
- @@required.concat %w(amount routing_code account_number account_type bank_name account_name account_type)
190
- @@required.concat %w(customer_org customer_ssn) unless @customer_org.nil?
191
- elsif @type == 'CC'
192
- @@required.concat %w(amount)
193
- if @action == 'PRIOR_AUTH_CAPTURE'
194
- @@required.concat @order_number ? %w(order_number) : %w(card_number expiration)
195
- else
196
- @@required.concat %w(last_name first_name card_number expiration)
197
- end
198
- else
199
- raise PaymentError, "Can't handle transaction type: #{@type}"
200
- end
201
- end
202
-
203
- @@required.uniq!
204
- end
205
209
  end
206
210
 
207
211
  end
@@ -1,38 +1,61 @@
1
- # Author:: Lucas Carlson (mailto:lucas@rufy.com)
2
- # Copyright:: Copyright (c) 2005 Lucas Carlson
3
- # License:: Distributes under the same terms as Ruby
4
-
5
- require 'net/http'
6
- require 'net/https'
7
-
8
1
  module Payment
9
2
 
10
- class PaymentError < StandardError; end # :nodoc:
3
+ class PaymentError < StandardError#:nodoc:
4
+ end
11
5
 
12
6
  class Base
13
- attr_reader :error_message, :authorization, :transaction_type, :result_code
7
+ attr_reader :response, :error_code, :error_message, :authorization, :transaction_type, :result_code
14
8
  attr_accessor :url
15
- attr_accessor :require_avs, :test_transaction, :strict_ssl
16
- attr_accessor :type, :login, :password, :action, :description, :amount, :invoice_number, :customer_id, :name, :address, :city, :state, :zip, :country, :phone, :fax, :email, :card_number, :expiration, :account_number, :routing_code, :bank_name
9
+ attr_accessor :require_avs, :test_transaction
10
+ attr_accessor :method, :type, :login, :password, :action, :description, :amount, :invoice_number, :customer_id, :name, :address, :city, :state, :zip, :country, :phone, :fax, :email, :card_number, :expiration, :account_number, :routing_code, :bank_name
17
11
 
18
- @@required = []
19
-
20
- def initialize(options = {})
12
+ # Set the variables and get default variables from the :prefs file.
13
+ # This method will be overriden by each gateway to set sensible defaults
14
+ # for each gateway.
15
+ #
16
+ def initialize(options = {}) #:nodoc:
21
17
  # set some sensible defaults
22
- @strict_ssl = true
23
- @action = 'credit'
18
+ @type = 'normal authorization'
19
+
20
+ # get defaults from a preference file
21
+ prefs = File.expand_path(options[:prefs] || "~/.payment.yml")
22
+ YAML.load(File.open(prefs)).each {|pref, value| instance_variable_set("@#{pref}", value) } if File.exists?(prefs)
24
23
 
25
24
  # include all provided data
26
- options.each { |method, value| eval "@#{method} = '#{value}'" if methods.include? "#{method}=" }
25
+ options.each { |pref, value| instance_variable_set("@#{pref}", value) }
26
+
27
+ @required = Array.new
27
28
  end
28
29
 
29
- def submit
30
+ def submit #:nodoc:
30
31
  raise PaymentError, "No gateway specified"
31
32
  end
32
33
 
33
- def success?
34
- @is_success ? true : false
34
+ private
35
+
36
+ # Make sure that the required fields are not empty
37
+ def check_required
38
+ for var in @required
39
+ raise PaymentError, "The #{var} variable needs to be set" if eval("@#{var}").nil?
40
+ end
35
41
  end
42
+
43
+ # Goes out, posts the data, and sets the @response variable with the information
44
+ def get_response(url)
45
+ check_required
46
+ uri = URI.parse url
47
+ http = Net::HTTP.new uri.host, uri.port
48
+ if uri.port == 443
49
+ http.use_ssl = true
50
+ http.verify_mode = OpenSSL::SSL::VERIFY_NONE
51
+ end
52
+ @response_plain = http.post(uri.path, @data).body
53
+ @response = @response_plain.include?('<?xml') ? REXML::Document.new(@response_plain) : @response_plain
54
+
55
+ @response.instance_variable_set "@response_plain", @response_plain
56
+ def @response.plain; @response_plain; end
57
+ end
58
+
36
59
  end
37
60
 
38
61
  end
@@ -0,0 +1,51 @@
1
+ =begin
2
+ Test cards available:
3
+ 370000000000002 - American Express Test Card
4
+ 6011000000000012 - Discover Test Card
5
+ 5424000000000015 - MasterCard Test Card
6
+ 4007000000027 - Visa Test Card
7
+ 4012888818888 - Visa Test Card II
8
+ 3088000000000017 - JCB Test Card (Use expiration date 0905)
9
+ 38000000000006 - Diners Club/Carte Blanche Test (Use expiration date 0905)
10
+ =end
11
+
12
+ require File.dirname(__FILE__) + '/../test_helper'
13
+
14
+ class AuthorizeNetTest < Test::Unit::TestCase
15
+ CARD = '4012888818888'
16
+
17
+ # In order to test this code, create a .payment.yml file in the code
18
+ # home directory of the user that will test this that looks like this:
19
+ #
20
+ # username: my_uname
21
+ # transaction_key: my_key
22
+ #
23
+ def setup
24
+ @transaction = Payment::AuthorizeNet.new(
25
+ :amount => '49.95',
26
+ :expiration => '0310',
27
+ :first_name => 'John',
28
+ :last_name => 'Doe',
29
+ :card_number => '4012888818888',
30
+ :test_transaction => true
31
+ )
32
+ end
33
+
34
+ def test_submit_bad_card
35
+ @transaction.card_number = ''
36
+ assert_raise(Payment::PaymentError) { @transaction.submit }
37
+ end
38
+
39
+ def test_submit_good_card
40
+ @transaction.card_number = CARD
41
+ assert_nothing_raised { @transaction.submit }
42
+ end
43
+
44
+ def test_authorization
45
+ @transaction.card_number = CARD
46
+ @transaction.submit
47
+ assert_kind_of String, @transaction.authorization
48
+ assert_nil @transaction.error_message
49
+ end
50
+
51
+ end
@@ -0,0 +1,4 @@
1
+ $:.unshift(File.dirname(__FILE__) + '/../lib')
2
+
3
+ require 'test/unit'
4
+ require 'payment'
metadata CHANGED
@@ -1,40 +1,61 @@
1
1
  --- !ruby/object:Gem::Specification
2
- rubygems_version: 0.8.3
3
- specification_version: 1
4
2
  name: payment
5
3
  version: !ruby/object:Gem::Version
6
- version: "0.9"
7
- date: 2005-02-04
8
- summary: Payment is used to process credit cards and electronic cash through merchant accounts.
9
- require_paths:
10
- - lib
11
- email: lucas@rufy.com
12
- homepage: http://payment.rubyforge.org
13
- rubyforge_project: payment
14
- description: "These functions tell you whether a credit card number is self-consistent using known algorithms for credit card numbers. All non-integer values are removed from the string before parsing so that you don't have to worry about the format of the string."
15
- autorequire:
16
- default_executable:
17
- bindir: bin
18
- has_rdoc: true
19
- required_ruby_version: !ruby/object:Gem::Version::Requirement
20
- requirements:
21
- -
22
- - ">"
23
- - !ruby/object:Gem::Version
24
- version: 0.0.0
25
- version:
4
+ version: 1.0.1
26
5
  platform: ruby
27
6
  authors:
28
- - Lucas Carlson
29
- files:
30
- - lib/payment
31
- - lib/payment.rb
32
- - lib/payment/authorize_net.rb
33
- - lib/payment/base.rb
34
- test_files: []
35
- rdoc_options: []
36
- extra_rdoc_files: []
7
+ - Lucas Carlson
8
+ autorequire: payment
9
+ bindir: bin
10
+ cert_chain: []
11
+
12
+ date: 2009-10-10 00:00:00 -07:00
13
+ default_executable:
14
+ dependencies: []
15
+
16
+ description: " These functions tell you whether a credit card number is\n self-consistent using known algorithms for credit card numbers.\n All non-integer values are removed from the string before parsing\n so that you don't have to worry about the format of the string.\n"
17
+ email: lucas@rufy.com
37
18
  executables: []
19
+
38
20
  extensions: []
21
+
22
+ extra_rdoc_files: []
23
+
24
+ files:
25
+ - lib/payment/authorize_net.rb
26
+ - lib/payment/base.rb
27
+ - lib/payment.rb
28
+ - test/authorize_net/base_test.rb
29
+ - test/test_helper.rb
30
+ - Rakefile
31
+ - README
32
+ has_rdoc: true
33
+ homepage: http://payment.rufy.com/
34
+ licenses: []
35
+
36
+ post_install_message:
37
+ rdoc_options: []
38
+
39
+ require_paths:
40
+ - lib
41
+ required_ruby_version: !ruby/object:Gem::Requirement
42
+ requirements:
43
+ - - ">="
44
+ - !ruby/object:Gem::Version
45
+ version: "0"
46
+ version:
47
+ required_rubygems_version: !ruby/object:Gem::Requirement
48
+ requirements:
49
+ - - ">="
50
+ - !ruby/object:Gem::Version
51
+ version: "0"
52
+ version:
39
53
  requirements: []
40
- dependencies: []
54
+
55
+ rubyforge_project:
56
+ rubygems_version: 1.3.5
57
+ signing_key:
58
+ specification_version: 3
59
+ summary: Payment is used to process credit cards and electronic cash through merchant accounts.
60
+ test_files: []
61
+