lolita-first-data 1.0.0

Sign up to get free protection for your applications and to get access to all the features.
data/.rspec ADDED
@@ -0,0 +1,2 @@
1
+ --color
2
+ --format d
data/Gemfile ADDED
@@ -0,0 +1,15 @@
1
+ source "http://rubygems.org"
2
+
3
+ gem 'rails', '>= 3.0.0'
4
+ gem "activemerchant", "~> 1.17.0"
5
+
6
+ group :development do
7
+ gem 'sqlite3', '~> 1.3.4'
8
+ gem 'rspec', '~> 2.6.0'
9
+ gem 'webmock', '~> 1.7.6'
10
+ gem 'ruby-debug19', '~> 0.11.6'
11
+ gem "bundler", "~> 1.0.0"
12
+ gem "jeweler", "~> 1.6.4"
13
+ gem "rcov", ">= 0"
14
+ gem 'fabrication', "~> 1.1.0"
15
+ end
@@ -0,0 +1,140 @@
1
+ GEM
2
+ remote: http://rubygems.org/
3
+ specs:
4
+ actionmailer (3.1.0)
5
+ actionpack (= 3.1.0)
6
+ mail (~> 2.3.0)
7
+ actionpack (3.1.0)
8
+ activemodel (= 3.1.0)
9
+ activesupport (= 3.1.0)
10
+ builder (~> 3.0.0)
11
+ erubis (~> 2.7.0)
12
+ i18n (~> 0.6)
13
+ rack (~> 1.3.2)
14
+ rack-cache (~> 1.0.3)
15
+ rack-mount (~> 0.8.2)
16
+ rack-test (~> 0.6.1)
17
+ sprockets (~> 2.0.0)
18
+ activemerchant (1.17.0)
19
+ activesupport (>= 2.3.11)
20
+ braintree (>= 2.0.0)
21
+ builder (>= 2.0.0)
22
+ json (>= 1.5.1)
23
+ activemodel (3.1.0)
24
+ activesupport (= 3.1.0)
25
+ bcrypt-ruby (~> 3.0.0)
26
+ builder (~> 3.0.0)
27
+ i18n (~> 0.6)
28
+ activerecord (3.1.0)
29
+ activemodel (= 3.1.0)
30
+ activesupport (= 3.1.0)
31
+ arel (~> 2.2.1)
32
+ tzinfo (~> 0.3.29)
33
+ activeresource (3.1.0)
34
+ activemodel (= 3.1.0)
35
+ activesupport (= 3.1.0)
36
+ activesupport (3.1.0)
37
+ multi_json (~> 1.0)
38
+ addressable (2.2.6)
39
+ archive-tar-minitar (0.5.2)
40
+ arel (2.2.1)
41
+ bcrypt-ruby (3.0.0)
42
+ braintree (2.11.0)
43
+ builder (>= 2.0.0)
44
+ builder (3.0.0)
45
+ columnize (0.3.4)
46
+ crack (0.1.8)
47
+ diff-lcs (1.1.3)
48
+ erubis (2.7.0)
49
+ fabrication (1.1.0)
50
+ git (1.2.5)
51
+ hike (1.2.1)
52
+ i18n (0.6.0)
53
+ jeweler (1.6.4)
54
+ bundler (~> 1.0)
55
+ git (>= 1.2.5)
56
+ rake
57
+ json (1.5.4)
58
+ linecache19 (0.5.12)
59
+ ruby_core_source (>= 0.1.4)
60
+ mail (2.3.0)
61
+ i18n (>= 0.4.0)
62
+ mime-types (~> 1.16)
63
+ treetop (~> 1.4.8)
64
+ mime-types (1.16)
65
+ multi_json (1.0.3)
66
+ polyglot (0.3.2)
67
+ rack (1.3.2)
68
+ rack-cache (1.0.3)
69
+ rack (>= 0.4)
70
+ rack-mount (0.8.3)
71
+ rack (>= 1.0.0)
72
+ rack-ssl (1.3.2)
73
+ rack
74
+ rack-test (0.6.1)
75
+ rack (>= 1.0)
76
+ rails (3.1.0)
77
+ actionmailer (= 3.1.0)
78
+ actionpack (= 3.1.0)
79
+ activerecord (= 3.1.0)
80
+ activeresource (= 3.1.0)
81
+ activesupport (= 3.1.0)
82
+ bundler (~> 1.0)
83
+ railties (= 3.1.0)
84
+ railties (3.1.0)
85
+ actionpack (= 3.1.0)
86
+ activesupport (= 3.1.0)
87
+ rack-ssl (~> 1.3.2)
88
+ rake (>= 0.8.7)
89
+ rdoc (~> 3.4)
90
+ thor (~> 0.14.6)
91
+ rake (0.9.2)
92
+ rcov (0.9.10)
93
+ rdoc (3.9.4)
94
+ rspec (2.6.0)
95
+ rspec-core (~> 2.6.0)
96
+ rspec-expectations (~> 2.6.0)
97
+ rspec-mocks (~> 2.6.0)
98
+ rspec-core (2.6.4)
99
+ rspec-expectations (2.6.0)
100
+ diff-lcs (~> 1.1.2)
101
+ rspec-mocks (2.6.0)
102
+ ruby-debug-base19 (0.11.25)
103
+ columnize (>= 0.3.1)
104
+ linecache19 (>= 0.5.11)
105
+ ruby_core_source (>= 0.1.4)
106
+ ruby-debug19 (0.11.6)
107
+ columnize (>= 0.3.1)
108
+ linecache19 (>= 0.5.11)
109
+ ruby-debug-base19 (>= 0.11.19)
110
+ ruby_core_source (0.1.5)
111
+ archive-tar-minitar (>= 0.5.2)
112
+ sprockets (2.0.0)
113
+ hike (~> 1.2)
114
+ rack (~> 1.0)
115
+ tilt (!= 1.3.0, ~> 1.1)
116
+ sqlite3 (1.3.4)
117
+ thor (0.14.6)
118
+ tilt (1.3.3)
119
+ treetop (1.4.10)
120
+ polyglot
121
+ polyglot (>= 0.3.1)
122
+ tzinfo (0.3.29)
123
+ webmock (1.7.6)
124
+ addressable (> 2.2.5, ~> 2.2)
125
+ crack (>= 0.1.7)
126
+
127
+ PLATFORMS
128
+ ruby
129
+
130
+ DEPENDENCIES
131
+ activemerchant (~> 1.17.0)
132
+ bundler (~> 1.0.0)
133
+ fabrication (~> 1.1.0)
134
+ jeweler (~> 1.6.4)
135
+ rails (>= 3.0.0)
136
+ rcov
137
+ rspec (~> 2.6.0)
138
+ ruby-debug19 (~> 0.11.6)
139
+ sqlite3 (~> 1.3.4)
140
+ webmock (~> 1.7.6)
@@ -0,0 +1,20 @@
1
+ Copyright (c) 2011 ITHouse and Gatis Tomsons
2
+
3
+ Permission is hereby granted, free of charge, to any person obtaining
4
+ a copy of this software and associated documentation files (the
5
+ "Software"), to deal in the Software without restriction, including
6
+ without limitation the rights to use, copy, modify, merge, publish,
7
+ distribute, sublicense, and/or sell copies of the Software, and to
8
+ permit persons to whom the Software is furnished to do so, subject to
9
+ the following conditions:
10
+
11
+ The above copyright notice and this permission notice shall be
12
+ included in all copies or substantial portions of the Software.
13
+
14
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
15
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
16
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
17
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
18
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
19
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
20
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
@@ -0,0 +1,89 @@
1
+ ### INSTALL
2
+
3
+ - `gem install lolita-first-data`
4
+ - `rails g lolita_first_data:install`
5
+
6
+ ### SETUP
7
+
8
+ For example create model *Payment* and then add these special methods and modify them to suit your needs:
9
+
10
+ include Lolita::Billing:FirstData
11
+
12
+ # Methods for #Lolita::Billing:FirstData
13
+ #---------------------------------------
14
+
15
+ # returns integer in cents
16
+ def price
17
+ self.total_price
18
+ end
19
+
20
+ # string up to 125 symbols
21
+ # this will included in payment description
22
+ def description
23
+ "Payment to INC Lolipop"
24
+ end
25
+
26
+ # returns 3 digit string according to http://en.wikipedia.org/wiki/ISO_4217
27
+ def currency
28
+ "840"
29
+ end
30
+
31
+ # triggered when FirstData transaction is saved
32
+ def fd_trx_saved trx
33
+ case trx.status
34
+ when 'processing'
35
+ # update_attribute(:status, 'processing')
36
+ when 'completed'
37
+ # update_attribute(:status, 'completed')
38
+ when 'rejected'
39
+ # update_attribute(:status, 'rejected')
40
+ end
41
+ end
42
+
43
+ # optional
44
+ # this is called when FirstData merchant is taking some actions
45
+ # there you can save the log message other than the default log file
46
+ def log severity, message
47
+ #self.logs.create(:severity => severity, :message => message)
48
+ end
49
+ #---------------------------------------
50
+
51
+ Generate certificates by running:
52
+
53
+ rake first_data:generate_certificate
54
+
55
+ Generate certificates for both environments - test/production and specify correct merchantId.
56
+
57
+ Use `Lolita::FirstData::TestController` to pass all tests by running server and executing:
58
+
59
+ http://localhost:3000/first_data_test/test?nr=1
60
+ http://localhost:3000/first_data_test/test?nr=2
61
+ http://localhost:3000/first_data_test/test?nr=3
62
+ ...
63
+
64
+ Configure your environments
65
+
66
+ # For development.rb and test.rb
67
+ #---------------------
68
+
69
+ FD_PEM = "#{Rails.root}/config/first-data/test.pem"
70
+ FD_PASS = "qwerty"
71
+
72
+ config.after_initialize do
73
+ ActiveMerchant::Billing::Base.mode = :test
74
+ end
75
+
76
+ When you are ready to pay your payment controller action should end like this:
77
+
78
+ @payment = Payment....
79
+ ....
80
+ ....
81
+ session[:first_data] ||= {}
82
+ session[:first_data][:billing_class] = @payment.class.to_s
83
+ session[:first_data][:billing_id] = @payment.id
84
+ session[:first_data][:finish_path] = done_payments_path
85
+ redirect_to checkout_first_data_path
86
+
87
+ ### TESTS
88
+
89
+ Get source and run `rspec spec`
@@ -0,0 +1,53 @@
1
+ # encoding: utf-8
2
+
3
+ require 'rubygems'
4
+ require 'bundler'
5
+ begin
6
+ Bundler.setup(:default, :development)
7
+ rescue Bundler::BundlerError => e
8
+ $stderr.puts e.message
9
+ $stderr.puts "Run `bundle install` to install missing gems"
10
+ exit e.status_code
11
+ end
12
+ require 'rake'
13
+
14
+ require 'jeweler'
15
+ Jeweler::Tasks.new do |gem|
16
+ # gem is a Gem::Specification... see http://docs.rubygems.org/read/chapter/20 for more options
17
+ gem.name = "lolita-first-data"
18
+ gem.homepage = "http://github.com/ithouse/lolita-first-data"
19
+ gem.license = "MIT"
20
+ gem.summary = %Q{FirstData Payment plugin for Lolita}
21
+ gem.description = %Q{FirstData Payment plugin for Lolita using ActiveMerchant}
22
+ gem.email = "gatis@ithouse.cc"
23
+ gem.authors = ["ITHouse, Gatis Tomsons"]
24
+ # dependencies defined in Gemfile
25
+ end
26
+ Jeweler::RubygemsDotOrgTasks.new
27
+
28
+ require 'rake/testtask'
29
+ Rake::TestTask.new(:test) do |test|
30
+ test.libs << 'lib' << 'test'
31
+ test.pattern = 'test/**/test_*.rb'
32
+ test.verbose = true
33
+ end
34
+
35
+ require 'rcov/rcovtask'
36
+ Rcov::RcovTask.new do |test|
37
+ test.libs << 'test'
38
+ test.pattern = 'test/**/test_*.rb'
39
+ test.verbose = true
40
+ test.rcov_opts << '--exclude "gems/*"'
41
+ end
42
+
43
+ task :default => :test
44
+
45
+ require 'rdoc/task'
46
+ RDoc::Task.new do |rdoc|
47
+ version = File.exist?('VERSION') ? File.read('VERSION') : ""
48
+
49
+ rdoc.rdoc_dir = 'rdoc'
50
+ rdoc.title = "lolita-first-data #{version}"
51
+ rdoc.rdoc_files.include('README*')
52
+ rdoc.rdoc_files.include('lib/**/*.rb')
53
+ end
data/VERSION ADDED
@@ -0,0 +1 @@
1
+ 1.0.0
@@ -0,0 +1,25 @@
1
+ module Lolita::FirstData
2
+ class CommonController < ApplicationController
3
+ include ActiveMerchant::Billing
4
+ before_filter :set_gateway
5
+ skip_before_filter :verify_authenticity_token
6
+
7
+ private
8
+
9
+ def set_gateway
10
+ @gateway ||= ActiveMerchant::Billing::FirstDataGateway.new(
11
+ :pem => File.open(FD_PEM).read,
12
+ :pem_password => FD_PASS,
13
+ :payment => set_active_payment
14
+ )
15
+ end
16
+
17
+ # returns current payment instance from session
18
+ def set_active_payment
19
+ if session && session[:first_data] && params[:controller] == 'Lolita::FirstData::Transaction'
20
+ @payment ||= session[:first_data][:billing_class].constantize.find(session[:first_data][:billing_id])
21
+ end
22
+ end
23
+
24
+ end
25
+ end
@@ -0,0 +1,78 @@
1
+ module Lolita::FirstData
2
+ class TestController < Lolita::FirstData::CommonController
3
+ before_filter :render_nothing
4
+
5
+ # renders nothing if not in development environment
6
+ def render_nothing
7
+ render :nothing => true unless Rails.env == 'development'
8
+ end
9
+
10
+ #FIXME: refactor
11
+ # There are all 12 FirstData tests
12
+ # you should pass them to get production certificates
13
+ # use: http://localhost:3000/first_data_test/test?nr=1
14
+ # then increment the "nr" until done
15
+ def test
16
+ ip = params[:nr] == '9' ? '192.168.1.2' : request.remote_ip
17
+ # REQUEST
18
+ case params[:nr]
19
+ when /^(1|2|5|6|7|8|10)$/
20
+ session[:first_data] = {}
21
+ session[:first_data][:test] = params[:nr]
22
+ rs = @gateway.purchase(100,428,ip,'tests')
23
+ if rs.success?
24
+ session[:first_data][:trans_id] = rs.params['TRANSACTION_ID']
25
+ return redirect_to(@gateway.go_out)
26
+ else
27
+ return render(:text => "<pre>#{rs.message}</pre>", :satus => 400)
28
+ end
29
+ when /^(3|4|9|11)$/
30
+ session[:first_data] = {}
31
+ session[:first_data][:test] = params[:nr]
32
+ rs = @gateway.authorize(100,428,ip,'tests')
33
+ if rs.success?
34
+ session[:first_data][:trans_id] = rs.params['TRANSACTION_ID']
35
+ return redirect_to(@gateway.go_out)
36
+ else
37
+ return render(:text => "<pre>#{rs.message}</pre>", :satus => 400)
38
+ end
39
+ when /^(12)$/
40
+ session[:first_data] = {}
41
+ session[:first_data][:test] = params[:nr]
42
+ rs = @gateway.close_day
43
+ return render(:text => "<pre>#{rs.message}</pre>")
44
+ end
45
+
46
+ # RESPONSE
47
+ case session[:first_data][:test]
48
+ when /^(1|2|5|6|7|8)$/
49
+ rs = @gateway.get_trans_result(ip,session[:first_data][:trans_id])
50
+ msg = %^
51
+ trans_id: #{session[:first_data][:trans_id]} <br />
52
+ <pre>#{rs.message}</pre>
53
+ ^
54
+ return render(:text => msg)
55
+ when /^3|4|9$/
56
+ rs = @gateway.complete(session[:first_data][:trans_id],100,428,ip,'tests')
57
+ msg = %^
58
+ trans_id: #{session[:first_data][:trans_id]} <br />
59
+ <pre>#{rs.message}</pre>
60
+ ^
61
+ return render(:text => msg)
62
+ when /^(10|11)$/
63
+ if session[:first_data][:test] == '11'
64
+ @gateway.complete(session[:first_data][:trans_id],100,428,ip,'tests')
65
+ @gateway.close_day
66
+ end
67
+ rs = @gateway.reverse(session[:first_data][:trans_id],100)
68
+ msg = %^
69
+ trans_id: #{session[:first_data][:trans_id]} <br />
70
+ <pre>#{rs.message}</pre>
71
+ ^
72
+ return render(:text => msg)
73
+ end if session[:first_data]
74
+ render :text => "WRONG REQUEST", :status => 400
75
+ end
76
+
77
+ end
78
+ end
@@ -0,0 +1,49 @@
1
+ module Lolita::FirstData
2
+ class TransactionController < Lolita::FirstData::CommonController
3
+ before_filter :is_ssl_required
4
+
5
+ # should exist
6
+ # session[:first_data][:billing_class]
7
+ # session[:first_data]:billing_id]
8
+ # Class should respond to these methods:
9
+ # => :price - cents
10
+ # => :currency - according to http://en.wikipedia.org/wiki/ISO_4217
11
+ # => :description - string that will show up in payment details
12
+ def checkout
13
+ if @payment && !@payment.paid?
14
+ rs = @gateway.purchase(@payment.price,@payment.currency,request.remote_ip,@payment.description)
15
+ if rs.success?
16
+ Lolita::FirstData::Transaction.add(@payment, request, rs)
17
+ redirect_to(@gateway.go_out)
18
+ else
19
+ if request.xhr? || !request.referer
20
+ render :text => I18n.t('fd.purchase_failed'), :status => 400
21
+ else
22
+ redirect_to :back
23
+ end
24
+ end
25
+ else
26
+ render :text => I18n.t('fd.wrong_request'), :status => 400
27
+ end
28
+ end
29
+
30
+ # there we land after returning from FirstData server
31
+ # then we get transactions result and redirect to your given "finish" path
32
+ def answer
33
+ if trx = Lolita::FirstData::Transaction.where(transaction_id: params[:trans_id]).first
34
+ rs = @gateway.get_trans_result(request.remote_ip,params[:trans_id])
35
+ trx.process_answer(rs, @gateway, request)
36
+ redirect_to "#{session[:first_data][:finish_path]}?merchant=fd&trans_id=#{CGI::escape(params[:trans_id])}"
37
+ else
38
+ render :text => "wrong transaction ID", :status => 400
39
+ end
40
+ end
41
+
42
+ private
43
+
44
+ # forces SSL in production mode if available
45
+ def is_ssl_required
46
+ ssl_required(:answer, :checkout) if defined?(ssl_required) && (Rails.env == 'production' || Rails.env == 'staging')
47
+ end
48
+ end
49
+ end