lolita-first-data 1.0.0

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/.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