veritrans 1.2.6 → 2.0.0beta
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.
- checksums.yaml +13 -5
- data/.gitignore +4 -0
- data/.rspec +2 -0
- data/Gemfile +5 -0
- data/Gemfile.lock +111 -0
- data/README.md +258 -0
- data/Rakefile +7 -0
- data/api_reference.md +219 -0
- data/bin/veritrans +59 -48
- data/example/index.erb +118 -0
- data/example/response.erb +28 -0
- data/example/sinatra.rb +76 -0
- data/example/style.css +45 -0
- data/example/veritrans.yml +12 -0
- data/lib/generators/templates/assets/credit_card_form.js +50 -0
- data/lib/generators/templates/payments_controller.rb +81 -0
- data/lib/generators/templates/veritrans.rb +43 -0
- data/lib/generators/templates/veritrans.yml +13 -0
- data/lib/generators/templates/views/_credit_card_form.erb +42 -0
- data/lib/generators/templates/views/_veritrans_include.erb +10 -0
- data/lib/generators/templates/views/payments/create.erb +15 -0
- data/lib/generators/templates/views/payments/new.erb +6 -0
- data/lib/generators/veritrans/install_generator.rb +32 -0
- data/lib/generators/veritrans/payment_form_generator.rb +45 -0
- data/lib/veritrans/api.rb +90 -0
- data/lib/veritrans/cli.rb +166 -0
- data/lib/veritrans/client.rb +77 -209
- data/lib/veritrans/config.rb +48 -62
- data/lib/veritrans/events.rb +125 -0
- data/lib/veritrans/result.rb +81 -0
- data/lib/veritrans/version.rb +1 -41
- data/lib/veritrans.rb +79 -15
- data/license.txt +202 -0
- data/spec/cli_spec.rb +86 -0
- data/spec/configs/veritrans.yml +7 -0
- data/spec/configs/veritrans_flat.yml +2 -0
- data/spec/fixtures/approve_failed.yml +48 -0
- data/spec/fixtures/cancel_failed.yml +48 -0
- data/spec/fixtures/cancel_success.yml +106 -0
- data/spec/fixtures/capture_failed.yml +48 -0
- data/spec/fixtures/charge.yml +50 -0
- data/spec/fixtures/charge_direct.yml +56 -0
- data/spec/fixtures/charge_vtweb.yml +50 -0
- data/spec/fixtures/cli_test_1111-not-exists.yml +45 -0
- data/spec/fixtures/cli_test_not_exists.yml +45 -0
- data/spec/fixtures/cli_test_real_txn.yml +55 -0
- data/spec/fixtures/cli_test_unauthorized.yml +47 -0
- data/spec/fixtures/events_test_real_txn.yml +55 -0
- data/spec/fixtures/status_fail.yml +46 -0
- data/spec/fixtures/status_success.yml +109 -0
- data/spec/spec_helper.rb +29 -0
- data/spec/veritrans_client_spec.rb +83 -0
- data/spec/veritrans_config_spec.rb +48 -0
- data/spec/veritrans_events_spec.rb +70 -0
- data/spec/veritrans_logger_spec.rb +46 -0
- data/testing_webhooks.md +80 -0
- data/veritrans.gemspec +23 -0
- metadata +82 -31
- data/config/veritrans.yml +0 -24
- data/lib/generators/install_generator.rb +0 -78
- data/lib/generators/templates/app/controllers/vtlink/merchant_controller.rb +0 -7
- data/lib/generators/templates/app/controllers/vtlink/veritrans_controller.rb +0 -112
- data/lib/generators/templates/app/views/layouts/layout_auto_post.html.erb +0 -15
- data/lib/generators/templates/app/views/vtlink/merchant/checkout.html.erb +0 -43
- data/lib/generators/templates/app/views/vtlink/veritrans/cancel.html.erb +0 -2
- data/lib/generators/templates/app/views/vtlink/veritrans/confirm.html.erb +0 -13
- data/lib/generators/templates/app/views/vtlink/veritrans/error.html.erb +0 -2
- data/lib/generators/templates/app/views/vtlink/veritrans/finish.html.erb +0 -2
- data/lib/generators/templates/app/views/vtlink/veritrans/pay.html.erb +0 -2
- data/lib/generators/templates/config/veritrans.yml +0 -13
- data/lib/veritrans/hash_generator.rb +0 -19
- data/lib/veritrans/post_data.rb +0 -163
- data/lib/veritrans/v_t_direct.rb +0 -145
@@ -0,0 +1,32 @@
|
|
1
|
+
module Veritrans
|
2
|
+
class InstallGenerator < ::Rails::Generators::Base
|
3
|
+
source_root File.expand_path("../../templates", __FILE__)
|
4
|
+
|
5
|
+
desc %{
|
6
|
+
Description:
|
7
|
+
Copies Veritrans configuration file to your application's initializer directory.
|
8
|
+
}
|
9
|
+
|
10
|
+
desc "copy veritrans.yml"
|
11
|
+
def copy_config_file
|
12
|
+
copy_file "veritrans.yml", "config/veritrans.yml"
|
13
|
+
end
|
14
|
+
|
15
|
+
desc "copy initializer veritrans.rb"
|
16
|
+
def copy_initializer_file
|
17
|
+
copy_file "./veritrans.rb", "config/initializers/veritrans.rb"
|
18
|
+
|
19
|
+
say_status "", %{
|
20
|
+
|
21
|
+
We copy configs in your rails application
|
22
|
+
Please edit:
|
23
|
+
|
24
|
+
config/veritrans.yml
|
25
|
+
|
26
|
+
}
|
27
|
+
|
28
|
+
|
29
|
+
end
|
30
|
+
|
31
|
+
end
|
32
|
+
end
|
@@ -0,0 +1,45 @@
|
|
1
|
+
module Veritrans
|
2
|
+
class PaymentFormGenerator < ::Rails::Generators::Base
|
3
|
+
source_root File.expand_path("../../templates", __FILE__)
|
4
|
+
|
5
|
+
desc %{
|
6
|
+
Description:
|
7
|
+
Copies Veritrans payment form example to your rails application.
|
8
|
+
}
|
9
|
+
|
10
|
+
def copy_shared_views
|
11
|
+
copy_file "views/_veritrans_include.erb", "app/views/shared/_veritrans_include.erb"
|
12
|
+
copy_file "views/_credit_card_form.erb", "app/views/shared/_credit_card_form.erb"
|
13
|
+
end
|
14
|
+
|
15
|
+
def copy_controller
|
16
|
+
copy_file "payments_controller.rb", "app/controllers/payments_controller.rb"
|
17
|
+
|
18
|
+
route "resources :payments do\n" +
|
19
|
+
" collection do\n" +
|
20
|
+
" post :receive_webhook\n" +
|
21
|
+
" end\n" +
|
22
|
+
" end"
|
23
|
+
|
24
|
+
copy_file "views/payments/new.erb", "app/views/payments/new.erb"
|
25
|
+
copy_file "views/payments/create.erb", "app/views/payments/create.erb"
|
26
|
+
end
|
27
|
+
|
28
|
+
def append_javascript_file
|
29
|
+
copy_file "assets/credit_card_form.js", "app/assets/javascripts/credit_card_form.js"
|
30
|
+
insert_into_file "app/assets/javascripts/application.js", :after => %r{//= require +['"]?jquery['"]?$} do
|
31
|
+
"\n//= require credit_card_form"
|
32
|
+
end
|
33
|
+
|
34
|
+
say_status "", %{
|
35
|
+
|
36
|
+
Sample form installed in you app!
|
37
|
+
It contains example for VT-Web and VT-Direct
|
38
|
+
|
39
|
+
Now open http://localhost:3000/payments/new
|
40
|
+
|
41
|
+
}
|
42
|
+
|
43
|
+
end
|
44
|
+
end
|
45
|
+
end
|
@@ -0,0 +1,90 @@
|
|
1
|
+
# Veritrans API methods
|
2
|
+
|
3
|
+
require 'uri'
|
4
|
+
|
5
|
+
module Veritrans
|
6
|
+
module Api
|
7
|
+
|
8
|
+
# POST /v2/charge { payment_type: "vtlink" }
|
9
|
+
# Docs http://docs.veritrans.co.id/vtdirect/integration_cc.html#step2
|
10
|
+
# Docs http://docs.veritrans.co.id/sandbox/charge.html
|
11
|
+
#
|
12
|
+
# Example:
|
13
|
+
# Veritrans.charge(
|
14
|
+
# payment_type: "credit_card",
|
15
|
+
# credit_card: { token_id: "<token from client>" },
|
16
|
+
# transaction_details: {
|
17
|
+
# order_id: "order_123",
|
18
|
+
# gross_amount: 100_000
|
19
|
+
# }
|
20
|
+
# )
|
21
|
+
def charge(payment_type, data = nil)
|
22
|
+
if payment_type.kind_of?(Hash) && data.nil?
|
23
|
+
data = payment_type
|
24
|
+
payment_type = nil
|
25
|
+
end
|
26
|
+
|
27
|
+
data = data.deep_symbolize_keys if data.respond_to?(:deep_symbolize_keys)
|
28
|
+
|
29
|
+
data[:payment_type] = payment_type if payment_type
|
30
|
+
|
31
|
+
if data.has_key?(:payment_options)
|
32
|
+
data[ payment_type.to_sym ] = data.delete(:payment_options)
|
33
|
+
end
|
34
|
+
|
35
|
+
# Rename keys:
|
36
|
+
# payment -> transaction_details
|
37
|
+
# transaction -> transaction_details
|
38
|
+
# items -> item_details
|
39
|
+
# customer -> customer_details
|
40
|
+
|
41
|
+
data[:transaction_details] = data.delete(:payment) if data[:payment]
|
42
|
+
data[:transaction_details] = data.delete(:transaction) if data[:transaction]
|
43
|
+
data[:item_details] = data.delete(:items) if data[:items]
|
44
|
+
data[:customer_details] = data.delete(:customer) if data[:customer]
|
45
|
+
|
46
|
+
request_with_logging(:post, config.api_host + "/v2/charge", data)
|
47
|
+
end
|
48
|
+
|
49
|
+
# POST /v2/{id}/cancel
|
50
|
+
# Docs http://docs.veritrans.co.id/sandbox/other_commands.html
|
51
|
+
def cancel(payment_id, options = {})
|
52
|
+
request_with_logging(:post, config.api_host + "/v2/#{URI.escape(payment_id)}/cancel", options)
|
53
|
+
end
|
54
|
+
|
55
|
+
# POST /v2/{id}/approve
|
56
|
+
# Docs http://docs.veritrans.co.id/sandbox/other_commands.html
|
57
|
+
def approve(payment_id, options = {})
|
58
|
+
request_with_logging(:post, config.api_host + "/v2/#{URI.escape(payment_id)}/approve", options)
|
59
|
+
end
|
60
|
+
|
61
|
+
# GET /v2/{id}/status
|
62
|
+
# Docs http://docs.veritrans.co.id/sandbox/other_commands.html
|
63
|
+
def status(payment_id)
|
64
|
+
if !payment_id || payment_id == ""
|
65
|
+
raise ArgumentError, "parameter payment_id can not be bank"
|
66
|
+
end
|
67
|
+
|
68
|
+
get(config.api_host + "/v2/#{URI.escape(payment_id)}/status")
|
69
|
+
end
|
70
|
+
|
71
|
+
# POST /v2/capture
|
72
|
+
# Docs http://docs.veritrans.co.id/sandbox/other_features.html
|
73
|
+
def capture(payment_id, gross_amount, options = {})
|
74
|
+
post(config.api_host + "/v2/capture", options.merge(transaction_id: payment_id, gross_amount: gross_amount))
|
75
|
+
end
|
76
|
+
|
77
|
+
# POST /v2/charge { payment_type: "vtlink" }
|
78
|
+
def create_vtlink(data)
|
79
|
+
data = data.dup
|
80
|
+
data[:payment_type] = "vtlink"
|
81
|
+
request_with_logging(:post, config.api_host + "/v2/charge", data)
|
82
|
+
end
|
83
|
+
|
84
|
+
# DELETE /v2/vtlink/{id}
|
85
|
+
def delete_vtlink(id, options)
|
86
|
+
request_with_logging(:delete, config.api_host + "/v2/vtlink/#{URI.escape(id)}", options)
|
87
|
+
end
|
88
|
+
|
89
|
+
end
|
90
|
+
end
|
@@ -0,0 +1,166 @@
|
|
1
|
+
require 'json'
|
2
|
+
require 'securerandom'
|
3
|
+
require 'logger'
|
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
|
+
module Veritrans
|
17
|
+
module CLI
|
18
|
+
# can't find order
|
19
|
+
class OrderNotFound < Exception; end
|
20
|
+
class AuthenticationError < Exception; end
|
21
|
+
|
22
|
+
extend self
|
23
|
+
|
24
|
+
def test_webhook(args)
|
25
|
+
url = args.shift
|
26
|
+
raise ArgumentError, "missing required parameter URL" unless url && url != ""
|
27
|
+
|
28
|
+
options = {
|
29
|
+
body: json_data,
|
30
|
+
headers: {
|
31
|
+
:Accept => "application/json",
|
32
|
+
:"Content-Type" => "application/json",
|
33
|
+
:"User-Agent" => "Veritrans gem #{Veritrans::VERSION} - webhook tester"
|
34
|
+
},
|
35
|
+
read_timeout: 10,
|
36
|
+
write_timeout: 10,
|
37
|
+
connect_timeout: 10
|
38
|
+
}
|
39
|
+
|
40
|
+
puts "Sending #{options[:body].length} bytes to:"
|
41
|
+
puts " => #{cyan(url)}"
|
42
|
+
# Print body if it's custom
|
43
|
+
puts options[:body] + "\n\n" if CONFIG[:order]
|
44
|
+
|
45
|
+
s_time = Time.now
|
46
|
+
response = Excon.post(url, options)
|
47
|
+
response.body = response.body.to_s.encode('UTF-8', {:invalid => :replace, :undef => :replace, :replace => '?'})
|
48
|
+
|
49
|
+
puts "Got response: (#{((Time.now - s_time) * 1000).round}ms)"
|
50
|
+
puts " status: #{response.status}"
|
51
|
+
puts " body: #{response.body}"
|
52
|
+
|
53
|
+
if response.status >= 200 && response.status < 300
|
54
|
+
puts green("Success!")
|
55
|
+
else
|
56
|
+
puts red("Failed!")
|
57
|
+
puts "Response status is #{response.status} not 200"
|
58
|
+
end
|
59
|
+
#rescue Object => error
|
60
|
+
# puts red("Failed!")
|
61
|
+
# puts error.message
|
62
|
+
end
|
63
|
+
|
64
|
+
def load_local_config!
|
65
|
+
if CONFIG[:config_path]
|
66
|
+
if File.exists?(CONFIG[:config_path])
|
67
|
+
config_file = CONFIG[:config_path]
|
68
|
+
else
|
69
|
+
raise ArgumentError, "Can not find config at #{CONFIG[:config_path]}" unless config_file
|
70
|
+
end
|
71
|
+
end
|
72
|
+
|
73
|
+
|
74
|
+
if File.exists?("./veritrans.yml")
|
75
|
+
config_file = "./veritrans.yml"
|
76
|
+
end
|
77
|
+
if File.exists?("./config/veritrans.yml")
|
78
|
+
config_file = "./config/veritrans.yml"
|
79
|
+
end
|
80
|
+
|
81
|
+
raise ArgumentError, "Can not find config at ./config/veritrans.yml or ./veritrans.yml" unless config_file
|
82
|
+
|
83
|
+
puts "#{green('*')} Load config #{config_file}"
|
84
|
+
ENV['RAILS_ENV'] ||= 'development'
|
85
|
+
Veritrans.setup.load_yml("#{config_file}##{ENV['RAILS_ENV']}")
|
86
|
+
|
87
|
+
if !Veritrans.config.client_key || Veritrans.config.client_key == ""
|
88
|
+
puts red("Error")
|
89
|
+
raise ArgumentError, "Can not find client_key in #{config_file}"
|
90
|
+
end
|
91
|
+
|
92
|
+
if !Veritrans.config.server_key || Veritrans.config.server_key == ""
|
93
|
+
puts red("Error")
|
94
|
+
raise ArgumentError, "Can not find server_key in #{config_file}"
|
95
|
+
end
|
96
|
+
|
97
|
+
end
|
98
|
+
|
99
|
+
def get_order_info(order_id)
|
100
|
+
puts "#{green('*')} Getting order #{order_id}"
|
101
|
+
Veritrans.logger = Logger.new("/dev/null")
|
102
|
+
response = Veritrans.status(order_id)
|
103
|
+
if response.success?
|
104
|
+
return response
|
105
|
+
else
|
106
|
+
puts red("Error")
|
107
|
+
|
108
|
+
if response.status_code == 401
|
109
|
+
raise AuthenticationError, "Can not find order with id=#{order_id} (#{response.status_message})"
|
110
|
+
else
|
111
|
+
raise OrderNotFound, "Can not find order with id=#{order_id} (#{response.status_message})"
|
112
|
+
end
|
113
|
+
end
|
114
|
+
end
|
115
|
+
|
116
|
+
def json_data
|
117
|
+
data = {
|
118
|
+
status_code: "200",
|
119
|
+
status_message: "Veritrans payment notification",
|
120
|
+
transaction_id: SecureRandom.uuid,
|
121
|
+
order_id: "cli-testin-#{rand}",
|
122
|
+
payment_type: "credit_card",
|
123
|
+
transaction_time: Time.now.strftime("%Y-%m-%d %H:%M:%S"),
|
124
|
+
transaction_status: "capture",
|
125
|
+
fraud_status: "accept",
|
126
|
+
masked_card: "411111-1111",
|
127
|
+
gross_amount: "50000.0"
|
128
|
+
}
|
129
|
+
|
130
|
+
if CONFIG[:order]
|
131
|
+
load_local_config!
|
132
|
+
order_info = get_order_info(CONFIG[:order])
|
133
|
+
order_data = order_info.data.except(:status_message, :signature_key)
|
134
|
+
data = data.except(:fraud_status, :masked_card).merge(order_data)
|
135
|
+
end
|
136
|
+
|
137
|
+
JSON.dump(JSON.pretty_generate(data))
|
138
|
+
end
|
139
|
+
|
140
|
+
def colorize(str, color_code)
|
141
|
+
"\e[#{color_code}m#{str}\e[0m"
|
142
|
+
end
|
143
|
+
|
144
|
+
def red(str)
|
145
|
+
colorize(str, 31)
|
146
|
+
end
|
147
|
+
|
148
|
+
def green(str)
|
149
|
+
colorize(str, 32)
|
150
|
+
end
|
151
|
+
|
152
|
+
def yellow(str)
|
153
|
+
colorize(str, 33)
|
154
|
+
end
|
155
|
+
|
156
|
+
def blue(str)
|
157
|
+
colorize(str, 34)
|
158
|
+
end
|
159
|
+
|
160
|
+
def pink(str)
|
161
|
+
colorize(str, 35)
|
162
|
+
end
|
163
|
+
def cyan(str); colorize(str, 36) end
|
164
|
+
|
165
|
+
end
|
166
|
+
end
|
data/lib/veritrans/client.rb
CHANGED
@@ -1,240 +1,108 @@
|
|
1
|
-
#
|
2
|
-
module Veritrans
|
3
|
-
|
4
|
-
# :nodoc:
|
5
|
-
class Client
|
6
|
-
include Config
|
7
|
-
|
8
|
-
# constructor to create instance of Veritrans::Client
|
9
|
-
def initialize(&block)
|
10
|
-
class <<self
|
11
|
-
self
|
12
|
-
end.class_eval do
|
13
|
-
attr_accessor(:commodity, *PostData::PostParam)
|
14
|
-
end
|
15
|
-
|
16
|
-
# return-back to merchant-web
|
17
|
-
self.customer_specification_flag = Config::CUSTOMER_SPECIFICATION_FLAG
|
18
|
-
self.settlement_type = Config::SETTLEMENT_TYPE_CARD
|
19
|
-
|
20
|
-
# if block_given?
|
21
|
-
# yield(self) #self.instance_eval(&block)
|
22
|
-
# return self.get_keys
|
23
|
-
# end
|
24
|
-
end
|
25
|
-
|
26
|
-
#
|
27
|
-
# Example:
|
28
|
-
#
|
29
|
-
# client = Veritrans::Client.new
|
30
|
-
# client.order_id = "dummy#{(0...12).map{65.+(rand(25))}.join}"
|
31
|
-
# client.session_id = "session#{(0...12).map{65.+(rand(25))}.join}"
|
32
|
-
# client.gross_amount = "10"
|
33
|
-
# client.commodity = [{
|
34
|
-
# "COMMODITY_ID" => "IDxx1",
|
35
|
-
# "COMMODITY_UNIT" => "10",
|
36
|
-
# "COMMODITY_NUM" => "1",
|
37
|
-
# "COMMODITY_NAME1" => "Waterbotle",
|
38
|
-
# "COMMODITY_NAME2" => "Waterbottle in Indonesian"}]
|
39
|
-
# client.get_keys
|
40
|
-
#
|
41
|
-
def get_keys
|
42
|
-
init_instance
|
43
|
-
|
44
|
-
if customer_specification_flag == "0" && shipping_flag == "0"
|
45
|
-
raise "required_shipping_address must be '1'"
|
46
|
-
end
|
47
|
-
|
48
|
-
params = prepare_params(PostData::ServerParam,PostData::PostParam)
|
49
|
-
|
50
|
-
if !params[:promo_bins].blank?
|
51
|
-
params.merge!({ "promo_bins[]" => params[:promo_bins]})
|
52
|
-
params.delete :promo_bins
|
53
|
-
end
|
54
|
-
|
55
|
-
if !params[:point_banks].blank?
|
56
|
-
params.merge!({ "point_banks[]" => params[:point_banks]})
|
57
|
-
params.delete :point_banks
|
58
|
-
end
|
1
|
+
# Veritrans HTTP Client
|
59
2
|
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
end
|
3
|
+
require "base64"
|
4
|
+
require 'uri'
|
5
|
+
require 'excon'
|
64
6
|
|
65
|
-
|
66
|
-
|
67
|
-
|
68
|
-
end
|
69
|
-
|
70
|
-
if !params[:payment_methods].blank?
|
71
|
-
params.merge!({ "payment_methods[]" => params[:payment_methods]})
|
72
|
-
params.delete :payment_methods
|
73
|
-
end
|
74
|
-
|
75
|
-
commodity = @commodity.collect do |data|
|
76
|
-
data.keys.map do |key|
|
77
|
-
if key.downcase == "commodity_id"
|
78
|
-
data["item_id[]"] = data[key]
|
79
|
-
end
|
80
|
-
|
81
|
-
if key.downcase == "commodity_unit"
|
82
|
-
data["price[]"] = data[key]
|
83
|
-
end
|
84
|
-
|
85
|
-
if key.downcase == "commodity_num"
|
86
|
-
data["quantity[]"] = data[key]
|
87
|
-
end
|
88
|
-
|
89
|
-
if key.downcase == "commodity_name1"
|
90
|
-
data["item_name1[]"] = data[key]
|
91
|
-
end
|
92
|
-
|
93
|
-
if key.downcase == "commodity_name2"
|
94
|
-
data["item_name2[]"] = data[key]
|
95
|
-
end
|
96
|
-
|
97
|
-
data.delete key
|
98
|
-
end
|
99
|
-
|
100
|
-
# construct commodity
|
101
|
-
orders_uri = Addressable::URI.new
|
102
|
-
orders_uri.query_values = data
|
103
|
-
# return list of commodity as query string format
|
104
|
-
orders_uri.query
|
105
|
-
end
|
7
|
+
module Veritrans
|
8
|
+
module Client
|
9
|
+
extend self
|
106
10
|
|
107
|
-
|
108
|
-
|
109
|
-
|
110
|
-
|
111
|
-
|
112
|
-
|
113
|
-
|
114
|
-
req.body = query_string
|
115
|
-
end.env
|
116
|
-
|
117
|
-
delete_keys
|
118
|
-
@resp[:url] = @resp[:url].to_s
|
119
|
-
|
120
|
-
if version.to_i == 1
|
121
|
-
@token = JSON.parse(@resp[:body])
|
122
|
-
else
|
123
|
-
@token = parse_body(@resp[:body])
|
11
|
+
# Failback for activesupport
|
12
|
+
def _json_encode(params)
|
13
|
+
if defined?(ActiveSupport) && defined?(ActiveSupport::JSON)
|
14
|
+
ActiveSupport::JSON.encode(params)
|
15
|
+
else
|
16
|
+
require 'json' unless defined?(JSON)
|
17
|
+
JSON.generate(params)
|
124
18
|
end
|
125
19
|
end
|
126
20
|
|
127
|
-
|
128
|
-
|
129
|
-
|
130
|
-
|
131
|
-
|
132
|
-
|
133
|
-
|
134
|
-
end
|
135
|
-
|
136
|
-
# :nodoc:
|
137
|
-
def merchant_id
|
138
|
-
return Client.config["merchant_id"]
|
21
|
+
def _json_decode(params)
|
22
|
+
if defined?(ActiveSupport) && defined?(ActiveSupport::JSON)
|
23
|
+
ActiveSupport::JSON.decode(params)
|
24
|
+
else
|
25
|
+
require 'json' unless defined?(JSON)
|
26
|
+
JSON.parse(params)
|
27
|
+
end
|
139
28
|
end
|
140
29
|
|
141
|
-
#
|
142
|
-
def
|
143
|
-
|
144
|
-
|
30
|
+
# This is proxy method for make_request to save request and response to logfile
|
31
|
+
def request_with_logging(method, url, params)
|
32
|
+
short_url = url.sub(config.api_host, '')
|
33
|
+
file_logger.info("Perform #{short_url} \nSending: " + _json_encode(params))
|
145
34
|
|
146
|
-
|
147
|
-
def merchant_hash_key
|
148
|
-
return Client.config["merchant_hash_key"]
|
149
|
-
end
|
35
|
+
result = make_request(method, url, params)
|
150
36
|
|
151
|
-
|
152
|
-
|
153
|
-
|
154
|
-
|
37
|
+
if result.status_code < 300
|
38
|
+
file_logger.info("Success #{short_url} \nGot: " + _json_encode(result.data) + "\n")
|
39
|
+
else
|
40
|
+
file_logger.warn("Failed #{short_url} \nGot: " + _json_encode(result.data) + "\n")
|
41
|
+
end
|
155
42
|
|
156
|
-
|
157
|
-
def error_payment_return_url
|
158
|
-
return Client.config["error_payment_return_url"]
|
43
|
+
result
|
159
44
|
end
|
160
45
|
|
161
|
-
|
162
|
-
def finish_payment_return_url
|
163
|
-
return Client.config["finish_payment_return_url"]
|
164
|
-
end
|
46
|
+
private
|
165
47
|
|
166
|
-
|
167
|
-
|
168
|
-
|
48
|
+
def basic_auth_header(server_key = SERVER_KEY)
|
49
|
+
key = Base64.strict_encode64(server_key + ":")
|
50
|
+
"Basic #{key}"
|
169
51
|
end
|
170
52
|
|
171
|
-
|
172
|
-
|
173
|
-
return @token
|
53
|
+
def get(url, params = {})
|
54
|
+
make_request(:get, url, params)
|
174
55
|
end
|
175
56
|
|
176
|
-
|
177
|
-
|
178
|
-
@customer_specification_flag
|
57
|
+
def delete(url, params)
|
58
|
+
make_request(:delete, url, params)
|
179
59
|
end
|
180
60
|
|
181
|
-
|
182
|
-
|
183
|
-
@customer_specification_flag = customer_specification_flag
|
61
|
+
def post(url, params)
|
62
|
+
make_request(:post, url, params)
|
184
63
|
end
|
185
64
|
|
186
|
-
|
187
|
-
|
188
|
-
|
189
|
-
|
65
|
+
def make_request(method, url, params, auth_header = nil)
|
66
|
+
if !config.server_key || config.server_key == ''
|
67
|
+
raise "Please add server_key to config/veritrans.yml"
|
68
|
+
end
|
190
69
|
|
191
|
-
|
192
|
-
|
193
|
-
|
194
|
-
|
70
|
+
method = method.to_s.upcase
|
71
|
+
logger.info "Veritrans: #{method} #{url} #{_json_encode(params)}"
|
72
|
+
|
73
|
+
# Add authentication and content type
|
74
|
+
# Docs http://docs.veritrans.co.id/sandbox/introduction.html
|
75
|
+
options = {
|
76
|
+
:body => _json_encode(params),
|
77
|
+
:headers => {
|
78
|
+
:Authorization => auth_header || basic_auth_header(config.server_key),
|
79
|
+
:Accept => "application/json",
|
80
|
+
:"Content-Type" => "application/json",
|
81
|
+
:"User-Agent" => "Veritrans ruby gem #{Veritrans::VERSION}"
|
82
|
+
}
|
83
|
+
}
|
84
|
+
|
85
|
+
if method == "GET"
|
86
|
+
options.delete(:body)
|
87
|
+
options[:query] = URI.encode_www_form(params)
|
88
|
+
end
|
195
89
|
|
196
|
-
|
197
|
-
|
198
|
-
end
|
90
|
+
s_time = Time.now
|
91
|
+
request = Excon.new(url, read_timeout: 40, write_timeout: 40, connect_timeout: 40)
|
199
92
|
|
200
|
-
|
201
|
-
# Generate merchant hash code
|
202
|
-
def merchanthash
|
203
|
-
if version.to_i == 1
|
204
|
-
return HashGenerator::generate(merchant_hash_key, merchant_id, order_id);
|
205
|
-
else
|
206
|
-
return Digest::SHA512.hexdigest("#{merchant_hash_key},#{merchant_id},01,#{order_id},#{gross_amount}")
|
207
|
-
end
|
208
|
-
end
|
93
|
+
response = request.send(method.downcase.to_sym, options.merge(path: URI.parse(url).path))
|
209
94
|
|
210
|
-
|
211
|
-
def parse_body(body)
|
212
|
-
arrs = body.split("\r\n")
|
213
|
-
arrs = arrs[-2,2] if arrs.length > 1
|
214
|
-
return Hash[arrs.collect{|x|x.split("=")}]
|
215
|
-
end
|
216
|
-
|
217
|
-
def init_instance
|
218
|
-
@token = nil
|
219
|
-
end
|
95
|
+
logger.info "Veritrans: got #{(Time.now - s_time).round(3)} sec #{response.status} #{response.body}"
|
220
96
|
|
221
|
-
|
222
|
-
params = {}
|
223
|
-
# extract keys from post data
|
224
|
-
arg.flatten.each do |key|
|
225
|
-
# retrieve value from client configuration
|
226
|
-
value = self.send(key)
|
227
|
-
params[key.downcase] = value if value
|
228
|
-
end
|
229
|
-
return params
|
230
|
-
end
|
97
|
+
Result.new(response, url, options, Time.now - s_time)
|
231
98
|
|
232
|
-
|
233
|
-
|
234
|
-
|
235
|
-
|
236
|
-
|
237
|
-
|
99
|
+
rescue Excon::Errors::SocketError => error
|
100
|
+
logger.info "PAPI: socket error, can not connect"
|
101
|
+
error_response = Excon::Response.new(
|
102
|
+
body: '{"status_code": "500", "status_message": "Internal server error, no response from backend. Try again later"}',
|
103
|
+
status: '500'
|
104
|
+
)
|
105
|
+
Veritrans::Result.new(error_response, url, options, Time.now - s_time)
|
238
106
|
end
|
239
107
|
|
240
108
|
end
|