payment 0.9 → 1.0.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/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
+