veritrans 2.0.0 → 2.0.2

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 7e5610cd76eb75ec441c3163cc61628015281b1f
4
- data.tar.gz: 30699bb305825a89ed1c458692f1d6b847ddb874
3
+ metadata.gz: 931d9054ff90cd1ba889f74542f676b54d6fd46b
4
+ data.tar.gz: df6815a8f4c46a28feb241a7ddc0c335aeecdcf9
5
5
  SHA512:
6
- metadata.gz: 37686f3294e0373f26f475fa80ac34ad1239f5d953323e0e819c4491907797836f54fc68e8de3ad429c05c796633ee10d6381c973bf80a0092f4f843361ecabd
7
- data.tar.gz: cc509a41393b64ee5356b9e70b324fc13355df3fe1470b24dd7bb248111853890ebdc3a35b0028fd0ac8dc5ce7cff94a7ea420c320dac2a61f4587898bc4fc87
6
+ metadata.gz: db0a441e12e6a7c4ccf3a89481503007337ef5577c520413dca0f4ed327b55269f86becaa80a32c33578471aabfa24174537e804cbdac88473287b9aa5b2efa2
7
+ data.tar.gz: 179e13bdcaae50bfc3b8e1723ba87fe347033d84eedb8ab6d505e5cbae336df28c515004e2fbc888a3d4c4660f9d11e43f555d4028d8cf6fc52c3286673949ce
data/.gitignore CHANGED
@@ -1,4 +1,5 @@
1
1
  coverage
2
2
  rails_example*
3
3
  .DS_Store
4
-
4
+ tmp
5
+ doc/
data/.travis.yml ADDED
@@ -0,0 +1,5 @@
1
+ script: "bundle exec rspec"
2
+ rvm:
3
+ - 2.0.0
4
+ - 2.1.5
5
+ - 2.2.0
data/CHANGELOG.md ADDED
@@ -0,0 +1,14 @@
1
+ ### Version 2.0.2 (date: 20 Feb 2014)
2
+
3
+ * Add feature to add default http options, via Veritrans.config.http_options
4
+ * Start writing documentation in RDoc format
5
+
6
+ ### Version 2.0.1 (date: 20 Jan 2014)
7
+
8
+ * Fix confusing json format, we don't have it anymore.
9
+ * Add testing for rails generator
10
+ * Disable logging in sample form generated by plugin
11
+
12
+ ### Version 2.0.0 (date: 12 Dec 2014)
13
+
14
+ * Complete rewrite from version 1.* to support new API version
data/Gemfile CHANGED
@@ -1,5 +1,3 @@
1
1
  source "https://rubygems.org"
2
2
 
3
3
  gemspec
4
-
5
- gem 'vcr'
data/Gemfile.lock CHANGED
@@ -1,92 +1,139 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- veritrans (2.0.0beta)
4
+ veritrans (2.0.2)
5
5
  excon (~> 0.20)
6
6
 
7
7
  GEM
8
8
  remote: https://rubygems.org/
9
9
  specs:
10
- actionmailer (4.1.6)
11
- actionpack (= 4.1.6)
12
- actionview (= 4.1.6)
10
+ actionmailer (4.2.0)
11
+ actionpack (= 4.2.0)
12
+ actionview (= 4.2.0)
13
+ activejob (= 4.2.0)
13
14
  mail (~> 2.5, >= 2.5.4)
14
- actionpack (4.1.6)
15
- actionview (= 4.1.6)
16
- activesupport (= 4.1.6)
17
- rack (~> 1.5.2)
15
+ rails-dom-testing (~> 1.0, >= 1.0.5)
16
+ actionpack (4.2.0)
17
+ actionview (= 4.2.0)
18
+ activesupport (= 4.2.0)
19
+ rack (~> 1.6.0)
18
20
  rack-test (~> 0.6.2)
19
- actionview (4.1.6)
20
- activesupport (= 4.1.6)
21
+ rails-dom-testing (~> 1.0, >= 1.0.5)
22
+ rails-html-sanitizer (~> 1.0, >= 1.0.1)
23
+ actionview (4.2.0)
24
+ activesupport (= 4.2.0)
21
25
  builder (~> 3.1)
22
26
  erubis (~> 2.7.0)
23
- activemodel (4.1.6)
24
- activesupport (= 4.1.6)
27
+ rails-dom-testing (~> 1.0, >= 1.0.5)
28
+ rails-html-sanitizer (~> 1.0, >= 1.0.1)
29
+ activejob (4.2.0)
30
+ activesupport (= 4.2.0)
31
+ globalid (>= 0.3.0)
32
+ activemodel (4.2.0)
33
+ activesupport (= 4.2.0)
25
34
  builder (~> 3.1)
26
- activerecord (4.1.6)
27
- activemodel (= 4.1.6)
28
- activesupport (= 4.1.6)
29
- arel (~> 5.0.0)
30
- activesupport (4.1.6)
31
- i18n (~> 0.6, >= 0.6.9)
35
+ activerecord (4.2.0)
36
+ activemodel (= 4.2.0)
37
+ activesupport (= 4.2.0)
38
+ arel (~> 6.0)
39
+ activesupport (4.2.0)
40
+ i18n (~> 0.7)
32
41
  json (~> 1.7, >= 1.7.7)
33
42
  minitest (~> 5.1)
34
- thread_safe (~> 0.1)
43
+ thread_safe (~> 0.3, >= 0.3.4)
35
44
  tzinfo (~> 1.1)
36
- addressable (2.3.6)
37
- arel (5.0.1.20140414130214)
45
+ addressable (2.3.7)
46
+ arel (6.0.0)
38
47
  builder (3.2.2)
48
+ capybara (2.4.4)
49
+ mime-types (>= 1.16)
50
+ nokogiri (>= 1.3.3)
51
+ rack (>= 1.0.0)
52
+ rack-test (>= 0.5.4)
53
+ xpath (~> 2.0)
54
+ cliver (0.3.2)
39
55
  crack (0.4.2)
40
56
  safe_yaml (~> 1.0.0)
57
+ cucumber (1.3.19)
58
+ builder (>= 2.1.2)
59
+ diff-lcs (>= 1.1.3)
60
+ gherkin (~> 2.12)
61
+ multi_json (>= 1.7.5, < 2.0)
62
+ multi_test (>= 0.1.2)
41
63
  diff-lcs (1.2.5)
42
64
  erubis (2.7.0)
43
- excon (0.40.0)
65
+ excon (0.44.2)
66
+ gherkin (2.12.2)
67
+ multi_json (~> 1.3)
68
+ globalid (0.3.3)
69
+ activesupport (>= 4.1.0)
44
70
  hike (1.2.3)
45
- i18n (0.6.11)
46
- json (1.8.1)
47
- mail (2.6.1)
71
+ i18n (0.7.0)
72
+ json (1.8.2)
73
+ loofah (2.0.1)
74
+ nokogiri (>= 1.5.9)
75
+ mail (2.6.3)
48
76
  mime-types (>= 1.16, < 3)
49
77
  mime-types (2.4.3)
50
- minitest (5.4.2)
78
+ mini_portile (0.6.2)
79
+ minitest (5.5.1)
51
80
  multi_json (1.10.1)
52
- rack (1.5.2)
53
- rack-test (0.6.2)
81
+ multi_test (0.1.2)
82
+ nokogiri (1.6.6.2)
83
+ mini_portile (~> 0.6.0)
84
+ poltergeist (1.6.0)
85
+ capybara (~> 2.1)
86
+ cliver (~> 0.3.1)
87
+ multi_json (~> 1.0)
88
+ websocket-driver (>= 0.2.0)
89
+ rack (1.6.0)
90
+ rack-test (0.6.3)
54
91
  rack (>= 1.0)
55
- rails (4.1.6)
56
- actionmailer (= 4.1.6)
57
- actionpack (= 4.1.6)
58
- actionview (= 4.1.6)
59
- activemodel (= 4.1.6)
60
- activerecord (= 4.1.6)
61
- activesupport (= 4.1.6)
92
+ rails (4.2.0)
93
+ actionmailer (= 4.2.0)
94
+ actionpack (= 4.2.0)
95
+ actionview (= 4.2.0)
96
+ activejob (= 4.2.0)
97
+ activemodel (= 4.2.0)
98
+ activerecord (= 4.2.0)
99
+ activesupport (= 4.2.0)
62
100
  bundler (>= 1.3.0, < 2.0)
63
- railties (= 4.1.6)
64
- sprockets-rails (~> 2.0)
65
- railties (4.1.6)
66
- actionpack (= 4.1.6)
67
- activesupport (= 4.1.6)
101
+ railties (= 4.2.0)
102
+ sprockets-rails
103
+ rails-deprecated_sanitizer (1.0.3)
104
+ activesupport (>= 4.2.0.alpha)
105
+ rails-dom-testing (1.0.5)
106
+ activesupport (>= 4.2.0.beta, < 5.0)
107
+ nokogiri (~> 1.6.0)
108
+ rails-deprecated_sanitizer (>= 1.0.1)
109
+ rails-html-sanitizer (1.0.1)
110
+ loofah (~> 2.0)
111
+ railties (4.2.0)
112
+ actionpack (= 4.2.0)
113
+ activesupport (= 4.2.0)
68
114
  rake (>= 0.8.7)
69
115
  thor (>= 0.18.1, < 2.0)
70
- rake (10.3.2)
71
- rspec (3.1.0)
72
- rspec-core (~> 3.1.0)
73
- rspec-expectations (~> 3.1.0)
74
- rspec-mocks (~> 3.1.0)
75
- rspec-core (3.1.7)
76
- rspec-support (~> 3.1.0)
77
- rspec-expectations (3.1.2)
116
+ rake (10.4.2)
117
+ rspec (3.2.0)
118
+ rspec-core (~> 3.2.0)
119
+ rspec-expectations (~> 3.2.0)
120
+ rspec-mocks (~> 3.2.0)
121
+ rspec-core (3.2.0)
122
+ rspec-support (~> 3.2.0)
123
+ rspec-expectations (3.2.0)
124
+ diff-lcs (>= 1.2.0, < 2.0)
125
+ rspec-support (~> 3.2.0)
126
+ rspec-mocks (3.2.0)
78
127
  diff-lcs (>= 1.2.0, < 2.0)
79
- rspec-support (~> 3.1.0)
80
- rspec-mocks (3.1.3)
81
- rspec-support (~> 3.1.0)
82
- rspec-support (3.1.2)
128
+ rspec-support (~> 3.2.0)
129
+ rspec-support (3.2.1)
83
130
  safe_yaml (1.0.4)
84
- sprockets (2.11.3)
131
+ sprockets (2.12.3)
85
132
  hike (~> 1.2)
86
133
  multi_json (~> 1.0)
87
134
  rack (~> 1.0)
88
135
  tilt (~> 1.1, != 1.3.0)
89
- sprockets-rails (2.2.0)
136
+ sprockets-rails (2.2.4)
90
137
  actionpack (>= 3.0)
91
138
  activesupport (>= 3.0)
92
139
  sprockets (>= 2.8, < 4.0)
@@ -96,14 +143,21 @@ GEM
96
143
  tzinfo (1.2.2)
97
144
  thread_safe (~> 0.1)
98
145
  vcr (2.9.3)
99
- webmock (1.20.2)
146
+ webmock (1.20.4)
100
147
  addressable (>= 2.3.6)
101
148
  crack (>= 0.3.2)
149
+ websocket-driver (0.5.2)
150
+ websocket-extensions (>= 0.1.0)
151
+ websocket-extensions (0.1.2)
152
+ xpath (2.0.0)
153
+ nokogiri (~> 1.3)
102
154
 
103
155
  PLATFORMS
104
156
  ruby
105
157
 
106
158
  DEPENDENCIES
159
+ cucumber
160
+ poltergeist
107
161
  rails
108
162
  rspec (>= 2.9.0)
109
163
  vcr
data/README.md CHANGED
@@ -1,12 +1,11 @@
1
1
  # Veritrans ruby library
2
2
 
3
- ## Installation
4
-
5
- $ gem install veritrans
3
+ [![Gem Version](https://badge.fury.io/rb/veritrans.svg)](http://badge.fury.io/rb/veritrans)
4
+ [![Build Status](https://travis-ci.org/veritrans/veritrans-ruby.svg?branch=master)](https://travis-ci.org/veritrans/veritrans-ruby)
6
5
 
7
6
  ## How to use (Rails)
8
7
 
9
- ### Add veritrans to Gemfile
8
+ ### Add gem veritrans to Gemfile
10
9
 
11
10
  ```ruby
12
11
  gem 'veritrans'
@@ -69,6 +68,7 @@ File: "app/views/shared/_veritrans_include.erb"
69
68
  ```
70
69
 
71
70
  Payment form:
71
+
72
72
  ```html
73
73
  <form action="/charge_vtdirect" method="post" id="card_form">
74
74
  <input type="hidden" name="token_id" id="card_token">
@@ -177,7 +177,7 @@ For every transaction success and failed we will send you HTTP POST notification
177
177
 
178
178
  First you should set callback url in our dashboard https://my.sandbox.veritrans.co.id/settings/vtweb_configuration
179
179
 
180
- In development mode please read our [Testing webhooks tutorial](https://github.com/Paxa/veritrans-ruby/blob/new_api/testing_webhooks.md)
180
+ For testing in development phase please read our [Testing webhooks tutorial](https://github.com/Paxa/veritrans-ruby/blob/new_api/testing_webhooks.md) and [command line tool](#command-line-tool)
181
181
 
182
182
 
183
183
  For rails:
@@ -188,7 +188,10 @@ match "/payments/receive_webhook" => "payments#receive_webhook", via: [:post]
188
188
 
189
189
  # app/controllers/payments_controller.rb
190
190
  def receive_webhook
191
- verified_data = Veritrans.status(params[:transaction_id])
191
+ post_body = request.body.read
192
+ callback_params = Veritrans.decode_notification_json(post_body)
193
+
194
+ verified_data = Veritrans.status(callback_params['transaction_id'])
192
195
 
193
196
  if verified_data.status_code != 404
194
197
  puts "--- Transaction callback ---"
@@ -206,6 +209,8 @@ def receive_webhook
206
209
  end
207
210
  ```
208
211
 
212
+ ----
213
+
209
214
  #### Veritrans::Events
210
215
 
211
216
  Other option to handle callbacks is our rack-based handler
@@ -231,12 +236,12 @@ end
231
236
 
232
237
  #### Logging
233
238
 
234
- By default gem veritrans will show information via rails' logger. And in addition save important information to `RAILS_APP/config/veritrans.log`
239
+ By default gem veritrans will show information via rails' logger. And in addition save important information to `RAILS_APP/log/veritrans.log`
235
240
 
236
241
  It's configurable.
237
242
 
238
243
  ```ruby
239
- Veritrans.logger = Logger.new("/my/logs/veritrans.log")
244
+ Veritrans.logger = Rails.logger
240
245
  Veritrans.file_logger = Logger.new("/my/important_logs/veritrans.log")
241
246
  ```
242
247
 
@@ -247,6 +252,22 @@ Veritrans.file_logger = Logger.new("/my/important_logs/veritrans.log")
247
252
  * Received http notifications
248
253
  * Errors and exception while processing http notifications
249
254
 
255
+ ----
256
+
257
+ #### Command line tool
258
+
259
+ **Installation**
260
+
261
+ $ gem install veritrans
262
+
263
+ **Usage**
264
+
265
+ Testing http notification:
266
+
267
+ $ veritrans testhook http://localhost:3000/vt_events
268
+ $ veritrans testhook -o my-order-1 -c ~/path/to/veritrans.yml http://localhost:3000/vt_events
269
+
270
+
250
271
 
251
272
  #### Get help
252
273
 
data/Rakefile CHANGED
@@ -5,3 +5,10 @@ task :default => :spec
5
5
  desc "Run Specs"
6
6
  require 'rspec/core/rake_task'
7
7
  RSpec::Core::RakeTask.new(:spec)
8
+
9
+ desc "Generate documentation with sdoc"
10
+ task :doc do
11
+ Bundler.with_clean_env do
12
+ exec %{sdoc -i ./*.md ./lib/*.rb ./lib/veritrans/*.rb -m "Veritrans Ruby Library"}
13
+ end
14
+ end
data/api_reference.md CHANGED
@@ -49,7 +49,9 @@ please use our [documentation](http://docs.veritrans.co.id/sandbox/introduction.
49
49
  </table>
50
50
 
51
51
 
52
- ### <a name="charge"></a> Charge
52
+ <a name="charge"></a>
53
+
54
+ ### Charge
53
55
 
54
56
  Actually make transaction. But for vt-web create a redirect url, and for vt-link creates payment page
55
57
 
@@ -134,7 +136,8 @@ q.success? # => true
134
136
  ```
135
137
 
136
138
 
137
- ### <a name="status"></a> Status
139
+ <a name="status"></a>
140
+ ### Status
138
141
 
139
142
  Return current status of transaction.
140
143
 
@@ -158,7 +161,8 @@ q.data == {
158
161
  ```
159
162
 
160
163
 
161
- ### <a name="cancel"></a> Cancel
164
+ <a name="cancel"></a>
165
+ ### Cancel
162
166
 
163
167
  Cancel transaction, before it was settled. For credit card payments you can cancel it before we trigger settlement in bank.
164
168
  Usually we do settlement next day after payment happen, about 4pm.
@@ -185,7 +189,8 @@ q.data == {
185
189
  ```
186
190
 
187
191
 
188
- ### <a name="approve"></a> Approve
192
+ <a name="approve"></a>
193
+ ### Approve
189
194
 
190
195
  Some transactions marked as challenge. If challenge you can approve it or cancel it. Usual way is to use our dashboard web interface,
191
196
  but you also can do it programatically, via API
@@ -208,8 +213,8 @@ q.data == {
208
213
  }
209
214
  ```
210
215
 
211
-
212
- ### <a name="capture"></a> Capture
216
+ <a name="capture"></a>
217
+ ### Capture
213
218
 
214
219
  This API method is only for merchants who have pre-authorise feature (can be requested) and have pre-authorise payments.
215
220
 
@@ -25,8 +25,8 @@ $(document).ready(function () {
25
25
  button.val("Processing ...");
26
26
 
27
27
  Veritrans.token(VT_createTokenData, function (data) {
28
- console.log('Get token response:');
29
- console.log(data);
28
+ // console.log('Get token response:');
29
+ // console.log(data);
30
30
 
31
31
  // if we get redirect_url then it's 3d-secure transaction
32
32
  // so we need to open that page
@@ -32,14 +32,13 @@ class PaymentsController < ApplicationController
32
32
 
33
33
  def receive_webhook
34
34
  post_body = request.body.read
35
- callback_params = Veritrans.decode_notification_json(post_body)
36
35
 
37
36
  Veritrans.file_logger.info("Callback for order: " +
38
- "#{callback_params[:order_id]} #{callback_params[:transaction_status]}\n" +
37
+ "#{params[:order_id]} #{params[:transaction_status]}\n" +
39
38
  post_body + "\n"
40
39
  )
41
40
 
42
- verified_data = Veritrans.status(callback_params["transaction_id"])
41
+ verified_data = Veritrans.status(params["transaction_id"])
43
42
 
44
43
  if verified_data.status_code != 404
45
44
  puts "--- Transaction callback ---"
@@ -53,7 +52,7 @@ class PaymentsController < ApplicationController
53
52
  render text: "ok"
54
53
  else
55
54
  Veritrans.file_logger.info("Callback verification failed for order: " +
56
- "#{callback_params[:order_id]} #{callback_params[:transaction_status]}}\n" +
55
+ "#{params[:order_id]} #{params[:transaction_status]}}\n" +
57
56
  verified_data.body + "\n"
58
57
  )
59
58
 
data/lib/veritrans.rb CHANGED
@@ -1,4 +1,5 @@
1
1
  require 'veritrans/version'
2
+ require 'veritrans/core_extensions'
2
3
  require 'veritrans/config'
3
4
  require 'veritrans/client'
4
5
  require 'veritrans/api'
@@ -66,17 +67,8 @@ module Veritrans
66
67
  Veritrans::Events if defined?(Veritrans::Events)
67
68
  end
68
69
 
69
- # Note: Veritrans sending notification data as json, encoded twice
70
- # so we should call JSON.parse twice
71
70
  def decode_notification_json(input)
72
- if input.start_with?('"{') && input.end_with?('}"')
73
- # ruby's JSON library can't excpect only hash or array. To decode string I wrap it in array.
74
- request_data = Veritrans::Client._json_decode('[' + input + ']').first
75
- return Veritrans::Client._json_decode(request_data)
76
- else
77
- # in case we will make it in expected way later
78
- return Veritrans::Client._json_decode(input)
79
- end
71
+ return Veritrans::Client._json_decode(input)
80
72
  end
81
73
 
82
74
  end
data/lib/veritrans/cli.rb CHANGED
@@ -2,17 +2,6 @@ require 'json'
2
2
  require 'securerandom'
3
3
  require 'logger'
4
4
 
5
- class Hash
6
- def except!(*keys)
7
- keys.each { |key| delete(key) }
8
- self
9
- end
10
-
11
- def except(*keys)
12
- dup.except!(*keys)
13
- end
14
- end
15
-
16
5
  module Veritrans
17
6
  module CLI
18
7
  # can't find order
@@ -134,7 +123,7 @@ module Veritrans
134
123
  data = data.except(:fraud_status, :masked_card).merge(order_data)
135
124
  end
136
125
 
137
- JSON.dump(JSON.pretty_generate(data))
126
+ JSON.pretty_generate(data)
138
127
  end
139
128
 
140
129
  def colorize(str, color_code)
@@ -70,10 +70,12 @@ module Veritrans
70
70
  method = method.to_s.upcase
71
71
  logger.info "Veritrans: #{method} #{url} #{_json_encode(params)}"
72
72
 
73
+ default_options = config.http_options || {}
74
+
73
75
  # Add authentication and content type
74
76
  # Docs http://docs.veritrans.co.id/sandbox/introduction.html
75
- options = {
76
- :body => _json_encode(params),
77
+ request_options = {
78
+ :path => URI.parse(url).path,
77
79
  :headers => {
78
80
  :Authorization => auth_header || basic_auth_header(config.server_key),
79
81
  :Accept => "application/json",
@@ -83,18 +85,25 @@ module Veritrans
83
85
  }
84
86
 
85
87
  if method == "GET"
86
- options.delete(:body)
87
- options[:query] = URI.encode_www_form(params)
88
+ request_options[:query] = URI.encode_www_form(params)
89
+ else
90
+ request_options[:body] = _json_encode(params)
88
91
  end
89
92
 
93
+ connection_options = {
94
+ read_timeout: 40,
95
+ write_timeout: 40,
96
+ connect_timeout: 40
97
+ }.deep_merge(default_options)
98
+
90
99
  s_time = Time.now
91
- request = Excon.new(url, read_timeout: 40, write_timeout: 40, connect_timeout: 40)
100
+ request = Excon.new(url, connection_options)
92
101
 
93
- response = request.send(method.downcase.to_sym, options.merge(path: URI.parse(url).path))
102
+ response = request.send(method.downcase.to_sym, request_options)
94
103
 
95
104
  logger.info "Veritrans: got #{(Time.now - s_time).round(3)} sec #{response.status} #{response.body}"
96
105
 
97
- Result.new(response, url, options, Time.now - s_time)
106
+ Result.new(response, url, request_options, Time.now - s_time)
98
107
 
99
108
  rescue Excon::Errors::SocketError => error
100
109
  logger.info "PAPI: socket error, can not connect"
@@ -1,4 +1,5 @@
1
1
  require 'yaml'
2
+ require 'excon'
2
3
 
3
4
  module Veritrans
4
5
 
@@ -7,30 +8,90 @@ module Veritrans
7
8
 
8
9
  @api_host = "https://api.sandbox.veritrans.co.id"
9
10
 
11
+ ##
12
+ # Merhcant's Client key, used to make getToken request. (only for VT-Direct)
13
+ #
14
+ # Can be found in merchant portal: Settings -> Access Keys
15
+ #
16
+ def client_key=(value)
17
+ @client_key = value
18
+ end
19
+
20
+
10
21
  def client_key
11
22
  @client_key
12
23
  end
13
24
 
14
- def client_key=(value)
15
- @client_key = value
25
+ ##
26
+ # Merhcant's Server key, used to sign every http API call.
27
+ #
28
+ # Can be found in merchant portal: Settings -> Access Keys
29
+ #
30
+ def server_key=(value)
31
+ @server_key = value
16
32
  end
17
33
 
18
34
  def server_key
19
35
  @server_key
20
36
  end
21
37
 
22
- def server_key=(value)
23
- @server_key = value
38
+ ##
39
+ # API Server hostname, this allow to switch between production and sandbox
40
+ #
41
+ # Should be "https://api.sandbox.veritrans.co.id" or "https://api.veritrans.co.id"
42
+ #
43
+ # Default is "https://api.sandbox.veritrans.co.id"
44
+ #
45
+ def api_host=(value)
46
+ @api_host = value
24
47
  end
25
48
 
26
49
  def api_host
27
50
  @api_host
28
51
  end
29
52
 
30
- def api_host=(value)
31
- @api_host = value
53
+ ##
54
+ # This will override http request settings for api calls.
55
+ # http_options should be hash, it will be merged with connection options for every request.
56
+ #
57
+ # Full list of options: https://github.com/excon/excon/blob/master/lib/excon/constants.rb
58
+ #
59
+ # For unsupported key it will raise ArgumentError
60
+ #
61
+ # Veritrans.config.http_options = {tcp_nodelay: true, ssl_version: 'TLSv1'}
62
+ #
63
+ def http_options=(options)
64
+ unless options.is_a?(Hash)
65
+ raise ArgumentError, "http_options should be a hash"
66
+ end
67
+
68
+ # Validate allowed keys
69
+ diff = options.keys.map(&:to_sym) - Excon::VALID_CONNECTION_KEYS
70
+ if diff.size > 0
71
+ raise ArgumentError,
72
+ "http_options contain unsupported keys: #{diff.inspect}\n" +
73
+ "Supported keys are: #{Excon::VALID_CONNECTION_KEYS.inspect}"
74
+ end
75
+
76
+ @http_options = options
77
+ end
78
+
79
+ def http_options
80
+ @http_options
32
81
  end
33
82
 
83
+ ##
84
+ # Loads YAML file and assign config values
85
+ #
86
+ # Supports #section in filename to choose one section.
87
+ # If you are using Rails, it will try to use Rails.env as a section name
88
+ #
89
+ # Available config keys: server_key, client_key, api_host, http_options
90
+ #
91
+ # Veritrans.setup do
92
+ # config.load_yml "#{Rails.root.to_s}/config/veritrans.yml#development"
93
+ # end
94
+ #
34
95
  def load_config(filename)
35
96
  yml_file, yml_section = filename.to_s.split('#')
36
97
  config_data = YAML.load(File.read(yml_file))
@@ -45,7 +106,11 @@ module Veritrans
45
106
  alias :load_yml :load_config
46
107
 
47
108
  def inspect
48
- "<Veritrans::Config @api_host=#{@api_host.inspect} @server_key=#{@server_key.inspect} @client_key=#{@client_key.inspect}>"
109
+ "<Veritrans::Config " +
110
+ "@api_host=#{@api_host.inspect} " +
111
+ "@server_key=#{@server_key.inspect} " +
112
+ "@client_key=#{@client_key.inspect} " +
113
+ "@http_options=#{@http_options.inspect}>"
49
114
  end
50
115
 
51
116
  private
@@ -0,0 +1,32 @@
1
+ # This is replacement for Hash#deep_merge in acive_support
2
+ # when acive_support not loaded
3
+
4
+ class Hash #:nodoc:
5
+
6
+ unless method_defined?(:deep_merge)
7
+ def deep_merge(second)
8
+ merger = proc { |key, v1, v2|
9
+ if Hash === v1 && Hash === v2
10
+ v1.merge(v2, &merger)
11
+ else
12
+ [:undefined, nil, :nil].include?(v2) ? v1 : v2
13
+ end
14
+ }
15
+ self.merge(second, &merger)
16
+ end
17
+ end
18
+
19
+ unless method_defined?(:except!)
20
+ def except!(*keys)
21
+ keys.each { |key| delete(key) }
22
+ self
23
+ end
24
+ end
25
+
26
+ unless method_defined?(:except)
27
+ def except(*keys)
28
+ dup.except!(*keys)
29
+ end
30
+ end
31
+
32
+ end
@@ -1,3 +1,3 @@
1
1
  module Veritrans
2
- VERSION = "2.0.0"
2
+ VERSION = "2.0.2"
3
3
  end
data/license.txt CHANGED
File without changes
data/spec/cli_spec.rb CHANGED
@@ -15,8 +15,6 @@ describe Veritrans do
15
15
  end
16
16
 
17
17
  data = ActiveSupport::JSON.decode(@request.body)
18
- data.class.should == String
19
- data = ActiveSupport::JSON.decode(data)
20
18
 
21
19
  data["status_code"].should == "200"
22
20
  data["status_message"].should == "Veritrans payment notification"
@@ -74,8 +72,6 @@ describe Veritrans do
74
72
  end
75
73
 
76
74
  data = ActiveSupport::JSON.decode(@request.body)
77
- data.class.should == String
78
- data = ActiveSupport::JSON.decode(data)
79
75
 
80
76
  data["status_code"].should == "200"
81
77
  data["status_message"].should == "Veritrans payment notification"
@@ -0,0 +1,212 @@
1
+ require 'fileutils'
2
+ require 'open3'
3
+ require 'shellwords'
4
+ require 'socket'
5
+
6
+ describe "Rails plugin", vcr: false do
7
+ include Capybara::DSL
8
+
9
+ RAILS_VER = "4.1.9"
10
+ APP_DIR = "plugin_test"
11
+ PLUGIN_DIR = File.expand_path("..", File.dirname(__FILE__))
12
+
13
+ before :all do
14
+ FileUtils.mkdir_p("#{PLUGIN_DIR}/tmp")
15
+ #Capybara::Screenshot.instance_variable_set(:@capybara_root, "#{PLUGIN_DIR}/tmp")
16
+ end
17
+
18
+ def capture_stdout(&block)
19
+ original_stdout = $stdout
20
+ $stdout = fake = StringIO.new
21
+ begin
22
+ yield
23
+ ensure
24
+ $stdout = original_stdout
25
+ end
26
+ fake.string
27
+ end
28
+
29
+ def run_cmd(cmd, cli_args = [])
30
+ full_cmd = ([cmd] + cli_args).join.strip
31
+
32
+ stdout_str, stderr_str, status = Open3.capture3(full_cmd)
33
+
34
+ if status != 0
35
+ puts "CMD: #{full_cmd}"
36
+ puts "FAILED"
37
+ puts stderr_str
38
+
39
+ exit 1
40
+ end
41
+
42
+ #puts stdout_str
43
+
44
+ return stdout_str
45
+ end
46
+
47
+ def install_rails_in_tmp
48
+ @rails_dir = Dir.mktmpdir()
49
+ @app_abs_path = "#{@rails_dir}/#{APP_DIR}"
50
+
51
+ Dir.chdir(@rails_dir) do
52
+ Bundler.with_clean_env do
53
+ ENV["RAILS_ENV"] = "development"
54
+ find_or_install_rails
55
+ generate_rails_app
56
+ generate_plugin_things
57
+ end
58
+ end
59
+ end
60
+
61
+ def find_or_install_rails
62
+ response = run_cmd('gem list \^rails\$ -q')
63
+ if response =~ /[^\d]#{RAILS_VER}[^\d]/
64
+ return true
65
+ else
66
+ run_cmd("gem install rails -v #{RAILS_VER} --no-ri --no-rdoc")
67
+ end
68
+ end
69
+
70
+ def generate_rails_app
71
+ gen = "rails _#{RAILS_VER}_ new #{APP_DIR} -B -G --skip-spring -d sqlite3 --skip-turbolinks --skip-test-unit --no-rc"
72
+ run_cmd(gen)
73
+
74
+ gemfile_content = "
75
+ source 'https://rubygems.org'
76
+
77
+ gem 'rails', '#{RAILS_VER}'
78
+ gem 'sqlite3'
79
+ gem 'turbolinks'
80
+ gem 'jquery-rails'
81
+ gem 'veritrans', path: '#{PLUGIN_DIR}'
82
+ ".gsub(/^\s+/, '')
83
+
84
+ File.open("#{@app_abs_path}/Gemfile", "w") {|f| f.write(gemfile_content) }
85
+
86
+ Dir.chdir(@app_abs_path) do
87
+ run_cmd("bundle")
88
+ end
89
+ end
90
+
91
+ def generate_plugin_things
92
+ Dir.chdir(@app_abs_path) do
93
+ run_cmd("rails g veritrans:install")
94
+ run_cmd("rails g veritrans:payment_form")
95
+ end
96
+
97
+ config_content = "
98
+ development:
99
+ client_key: VT-client-NArmatJZqzsmTmzR
100
+ server_key: VT-server-9Htb-RxXkg7-7hznSCCjxvoY
101
+ api_host: https://api.sandbox.veritrans.co.id
102
+ "
103
+
104
+ File.open("#{@app_abs_path}/config/veritrans.yml", "w") {|f| f.write(config_content) }
105
+ end
106
+
107
+ def run_rails_app
108
+ @rails_port = find_open_port
109
+
110
+ Bundler.with_clean_env do
111
+ ENV["RAILS_ENV"] = "development"
112
+ Dir.chdir(@app_abs_path) do
113
+ run_cmd("./bin/rails server -d -p #{@rails_port} --bind 127.0.0.1")
114
+ end
115
+ end
116
+
117
+ Capybara.app_host = "http://localhost:#{@rails_port}"
118
+
119
+ #puts "RAILS_DIR: #{@app_abs_path}"
120
+
121
+ while true
122
+ begin
123
+ run_cmd("curl #{Capybara.app_host}/payments/new > /dev/null")
124
+ break
125
+ rescue Object => error
126
+ p error
127
+ puts "Retry"
128
+ end
129
+ end
130
+ end
131
+
132
+ def stop_rails_app
133
+ Dir.chdir(@app_abs_path) do
134
+ if File.exist?("./tmp/pids/server.pid")
135
+ run_cmd("kill `cat tmp/pids/server.pid`")
136
+ end
137
+ end
138
+ end
139
+
140
+ def find_open_port
141
+ socket = Socket.new(:INET, :STREAM, 0)
142
+ socket.bind(Addrinfo.tcp("127.0.0.1", 0))
143
+ return socket.local_address.ip_port
144
+ ensure
145
+ socket.close
146
+ end
147
+
148
+ after do
149
+ stop_rails_app
150
+ FileUtils.remove_entry_secure(@rails_dir) if @rails_dir
151
+ end
152
+
153
+ it "should tests plugin" do
154
+ # PREPARE APP
155
+ install_rails_in_tmp
156
+ run_rails_app
157
+
158
+ # CREATE PAYMENT 1
159
+ visit "/payments/new"
160
+
161
+ click_button "Pay via VT-Direct"
162
+
163
+ # Waiting for get token request in javascript...
164
+ Timeout.timeout(30.seconds) do
165
+ loop do
166
+ break if current_path != "/payments/new"
167
+ sleep 0.1
168
+ end
169
+ end
170
+
171
+ Timeout.timeout(10.seconds) do
172
+ loop do
173
+ break if page.body =~ /<body>/
174
+ sleep 0.1
175
+ end
176
+ end
177
+
178
+ if page.body =~ /too many transactions/
179
+ page.should have_content("Merchant has sent too many transactions to the same card number")
180
+ else
181
+ page.should have_content("Success, Credit Card transaction is successful")
182
+ end
183
+
184
+ created_order_id = ActiveSupport::JSON.decode(find("pre").text)["order_id"]
185
+ #Capybara::Screenshot.screenshot_and_open_image
186
+
187
+ # CREATE PAYMENT 2
188
+ visit "/payments/new"
189
+ click_link "Pay via VT-Web"
190
+
191
+ page.should have_content("Payment is securely processed by Veritrans")
192
+ #Capybara::Screenshot.screenshot_and_open_image
193
+
194
+ # TEST CALLBACK FOR WRONG DATA
195
+ stub_const("CONFIG", {})
196
+ result1 = capture_stdout do
197
+ Veritrans::CLI.test_webhook(["#{Capybara.app_host}/payments/receive_webhook"])
198
+ end
199
+
200
+ result1.should =~ /status: 404/
201
+
202
+ # TEST CALLBACK FOR CORRECT DATA
203
+ stub_const("CONFIG", {order: created_order_id, config_path: "#{@app_abs_path}/config/veritrans.yml"})
204
+ result2 = capture_stdout do
205
+ Veritrans::CLI.test_webhook(["#{Capybara.app_host}/payments/receive_webhook"])
206
+ end
207
+
208
+ result2.should =~ /status: 200/
209
+ result2.should =~ /body: ok/
210
+ end
211
+
212
+ end
data/spec/spec_helper.rb CHANGED
@@ -10,6 +10,19 @@ require 'rails'
10
10
  require 'webmock/rspec'
11
11
  require 'vcr'
12
12
 
13
+ require 'capybara/rspec'
14
+ require 'capybara/poltergeist'
15
+
16
+ Capybara.configure do |config|
17
+ config.javascript_driver = :poltergeist
18
+ config.default_driver = :poltergeist
19
+ config.app_host = ""
20
+ config.run_server = false
21
+ end
22
+
23
+ GEM_ROOT = File.expand_path("../..", __FILE__)
24
+ ENV['RAILS_ENV'] = 'development'
25
+
13
26
  VCR.configure do |c|
14
27
  c.cassette_library_dir = 'spec/fixtures'
15
28
  c.hook_into :webmock # or :fakeweb
@@ -26,4 +39,14 @@ RSpec.configure do |config|
26
39
  config.mock_with :rspec do |c|
27
40
  c.syntax = [:should, :expect]
28
41
  end
42
+
43
+ config.around(:each) do |example|
44
+ if example.metadata[:vcr] === false
45
+ WebMock.allow_net_connect!
46
+ VCR.turned_off { example.run }
47
+ WebMock.disable_net_connect!
48
+ else
49
+ example.run
50
+ end
51
+ end
29
52
  end
@@ -8,6 +8,38 @@ describe Veritrans do
8
8
  end
9
9
  end
10
10
 
11
+ it "should use Veritrans.http_options", vcr: false do
12
+ Veritrans::Config.stub(:http_options) do
13
+ { omit_default_port: true }
14
+ end
15
+
16
+ api_request = nil
17
+ stub_request(:any, /.*/).to_return(lambda { |request|
18
+ api_request = request
19
+ {body: request.body}
20
+ })
21
+
22
+ result = Veritrans.request_with_logging(:get, Veritrans.config.api_host + "/ping", {})
23
+
24
+ api_request.headers["Host"].should == "api.sandbox.veritrans.co.id"
25
+ end
26
+
27
+ it "should use Veritrans.http_options to attach hedaers", vcr: false do
28
+ Veritrans::Config.stub(:http_options) do
29
+ { headers: { "X-Rspec" => "ok" } }
30
+ end
31
+
32
+ api_request = nil
33
+ stub_request(:any, /.*/).to_return(lambda { |request|
34
+ api_request = request
35
+ {body: request.body}
36
+ })
37
+
38
+ result = Veritrans.request_with_logging(:get, Veritrans.config.api_host + "/ping", {})
39
+
40
+ api_request.headers["X-Rspec"].should == "ok"
41
+ end
42
+
11
43
  it "should send charge vt-web request" do
12
44
  VCR.use_cassette('charge_vtweb') do
13
45
  result = Veritrans.charge('vtweb', transaction: { order_id: Time.now.to_s, gross_amount: 100_000 } )
@@ -45,4 +45,15 @@ describe Veritrans::Config do
45
45
  data.should == {"client_key" => "test_client_key", "server_key" => "test_server_key"}
46
46
  end
47
47
 
48
- end
48
+ it "should validate http_params type" do
49
+ expect {
50
+ Veritrans.config.http_options = nil
51
+ }.to raise_error(ArgumentError, "http_options should be a hash")
52
+ end
53
+
54
+ it "should validate http_params type" do
55
+ expect {
56
+ Veritrans.config.http_options = {foo: "bar", tcp_nodelay: true}
57
+ }.to raise_error(ArgumentError, /http_options contain unsupported keys: \[:foo\]/)
58
+ end
59
+ end
data/veritrans.gemspec CHANGED
@@ -20,4 +20,7 @@ Gem::Specification.new do |s|
20
20
  s.add_development_dependency "rspec", ">= 2.9.0"
21
21
  s.add_development_dependency "rails"
22
22
  s.add_development_dependency 'webmock'
23
+ s.add_development_dependency 'vcr'
24
+ s.add_development_dependency 'cucumber'
25
+ s.add_development_dependency "poltergeist"
23
26
  end
metadata CHANGED
@@ -1,69 +1,111 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: veritrans
3
3
  version: !ruby/object:Gem::Version
4
- version: 2.0.0
4
+ version: 2.0.2
5
5
  platform: ruby
6
6
  authors:
7
7
  - Veritrans Dev Team
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2014-12-12 00:00:00.000000000 Z
11
+ date: 2015-02-20 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: excon
15
15
  requirement: !ruby/object:Gem::Requirement
16
16
  requirements:
17
- - - ~>
17
+ - - "~>"
18
18
  - !ruby/object:Gem::Version
19
19
  version: '0.20'
20
20
  type: :runtime
21
21
  prerelease: false
22
22
  version_requirements: !ruby/object:Gem::Requirement
23
23
  requirements:
24
- - - ~>
24
+ - - "~>"
25
25
  - !ruby/object:Gem::Version
26
26
  version: '0.20'
27
27
  - !ruby/object:Gem::Dependency
28
28
  name: rspec
29
29
  requirement: !ruby/object:Gem::Requirement
30
30
  requirements:
31
- - - '>='
31
+ - - ">="
32
32
  - !ruby/object:Gem::Version
33
33
  version: 2.9.0
34
34
  type: :development
35
35
  prerelease: false
36
36
  version_requirements: !ruby/object:Gem::Requirement
37
37
  requirements:
38
- - - '>='
38
+ - - ">="
39
39
  - !ruby/object:Gem::Version
40
40
  version: 2.9.0
41
41
  - !ruby/object:Gem::Dependency
42
42
  name: rails
43
43
  requirement: !ruby/object:Gem::Requirement
44
44
  requirements:
45
- - - '>='
45
+ - - ">="
46
46
  - !ruby/object:Gem::Version
47
47
  version: '0'
48
48
  type: :development
49
49
  prerelease: false
50
50
  version_requirements: !ruby/object:Gem::Requirement
51
51
  requirements:
52
- - - '>='
52
+ - - ">="
53
53
  - !ruby/object:Gem::Version
54
54
  version: '0'
55
55
  - !ruby/object:Gem::Dependency
56
56
  name: webmock
57
57
  requirement: !ruby/object:Gem::Requirement
58
58
  requirements:
59
- - - '>='
59
+ - - ">="
60
60
  - !ruby/object:Gem::Version
61
61
  version: '0'
62
62
  type: :development
63
63
  prerelease: false
64
64
  version_requirements: !ruby/object:Gem::Requirement
65
65
  requirements:
66
- - - '>='
66
+ - - ">="
67
+ - !ruby/object:Gem::Version
68
+ version: '0'
69
+ - !ruby/object:Gem::Dependency
70
+ name: vcr
71
+ requirement: !ruby/object:Gem::Requirement
72
+ requirements:
73
+ - - ">="
74
+ - !ruby/object:Gem::Version
75
+ version: '0'
76
+ type: :development
77
+ prerelease: false
78
+ version_requirements: !ruby/object:Gem::Requirement
79
+ requirements:
80
+ - - ">="
81
+ - !ruby/object:Gem::Version
82
+ version: '0'
83
+ - !ruby/object:Gem::Dependency
84
+ name: cucumber
85
+ requirement: !ruby/object:Gem::Requirement
86
+ requirements:
87
+ - - ">="
88
+ - !ruby/object:Gem::Version
89
+ version: '0'
90
+ type: :development
91
+ prerelease: false
92
+ version_requirements: !ruby/object:Gem::Requirement
93
+ requirements:
94
+ - - ">="
95
+ - !ruby/object:Gem::Version
96
+ version: '0'
97
+ - !ruby/object:Gem::Dependency
98
+ name: poltergeist
99
+ requirement: !ruby/object:Gem::Requirement
100
+ requirements:
101
+ - - ">="
102
+ - !ruby/object:Gem::Version
103
+ version: '0'
104
+ type: :development
105
+ prerelease: false
106
+ version_requirements: !ruby/object:Gem::Requirement
107
+ requirements:
108
+ - - ">="
67
109
  - !ruby/object:Gem::Version
68
110
  version: '0'
69
111
  description:
@@ -74,8 +116,10 @@ executables:
74
116
  extensions: []
75
117
  extra_rdoc_files: []
76
118
  files:
77
- - .gitignore
78
- - .rspec
119
+ - ".gitignore"
120
+ - ".rspec"
121
+ - ".travis.yml"
122
+ - CHANGELOG.md
79
123
  - Gemfile
80
124
  - Gemfile.lock
81
125
  - README.md
@@ -102,6 +146,7 @@ files:
102
146
  - lib/veritrans/cli.rb
103
147
  - lib/veritrans/client.rb
104
148
  - lib/veritrans/config.rb
149
+ - lib/veritrans/core_extensions.rb
105
150
  - lib/veritrans/events.rb
106
151
  - lib/veritrans/result.rb
107
152
  - lib/veritrans/version.rb
@@ -123,6 +168,7 @@ files:
123
168
  - spec/fixtures/events_test_real_txn.yml
124
169
  - spec/fixtures/status_fail.yml
125
170
  - spec/fixtures/status_success.yml
171
+ - spec/rails_plugin_spec.rb
126
172
  - spec/spec_helper.rb
127
173
  - spec/veritrans_client_spec.rb
128
174
  - spec/veritrans_config_spec.rb
@@ -139,18 +185,19 @@ require_paths:
139
185
  - lib
140
186
  required_ruby_version: !ruby/object:Gem::Requirement
141
187
  requirements:
142
- - - '>='
188
+ - - ">="
143
189
  - !ruby/object:Gem::Version
144
190
  version: '0'
145
191
  required_rubygems_version: !ruby/object:Gem::Requirement
146
192
  requirements:
147
- - - '>='
193
+ - - ">="
148
194
  - !ruby/object:Gem::Version
149
195
  version: '0'
150
196
  requirements: []
151
197
  rubyforge_project:
152
- rubygems_version: 2.0.14
198
+ rubygems_version: 2.4.4
153
199
  signing_key:
154
200
  specification_version: 4
155
201
  summary: Veritrans ruby library
156
202
  test_files: []
203
+ has_rdoc: