veritrans 2.0.4 → 2.1.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (44) hide show
  1. checksums.yaml +4 -4
  2. data/.gitignore +2 -1
  3. data/.travis.yml +11 -3
  4. data/CHANGELOG.md +15 -0
  5. data/Gemfile +10 -0
  6. data/Gemfile.lock +136 -97
  7. data/Procfile +1 -0
  8. data/README.md +12 -5
  9. data/Rakefile +7 -5
  10. data/api_reference.md +21 -1
  11. data/example/README.md +8 -0
  12. data/example/config.ru +6 -0
  13. data/example/index.erb +104 -9
  14. data/example/localization.erb +248 -0
  15. data/example/points.erb +187 -0
  16. data/example/recurring.erb +201 -0
  17. data/example/response.erb +10 -1
  18. data/example/sinatra.rb +120 -8
  19. data/example/style.css +83 -2
  20. data/example/veritrans.yml +0 -1
  21. data/example/widget.erb +52 -0
  22. data/lib/generators/templates/assets/credit_card_form.js +3 -2
  23. data/lib/generators/templates/payments_controller.rb +5 -0
  24. data/lib/generators/templates/veritrans.rb +20 -17
  25. data/lib/generators/veritrans/install_generator.rb +1 -1
  26. data/lib/generators/veritrans/payment_form_generator.rb +1 -1
  27. data/lib/veritrans.rb +73 -44
  28. data/lib/veritrans/api.rb +39 -5
  29. data/lib/veritrans/cli.rb +1 -1
  30. data/lib/veritrans/client.rb +15 -10
  31. data/lib/veritrans/config.rb +11 -4
  32. data/lib/veritrans/events.rb +4 -4
  33. data/lib/veritrans/result.rb +28 -7
  34. data/lib/veritrans/version.rb +2 -2
  35. data/spec/cli_spec.rb +1 -0
  36. data/spec/rails_plugin_spec.rb +72 -27
  37. data/spec/spec_helper.rb +1 -0
  38. data/spec/veritrans_client_spec.rb +57 -3
  39. data/spec/veritrans_config_spec.rb +1 -1
  40. data/spec/veritrans_events_spec.rb +2 -0
  41. data/spec/veritrans_snap_spec.rb +39 -0
  42. data/testing_webhooks.md +0 -2
  43. data/veritrans.gemspec +5 -5
  44. metadata +29 -15
@@ -0,0 +1,201 @@
1
+ <!doctype html>
2
+ <html>
3
+ <head>
4
+ <title>veritrans-ruby demo</title>
5
+ <link rel="icon" type="image/x-icon" href="https://account.veritrans.co.id/favicon.ico" />
6
+ <link rel="stylesheet" href="/style.css">
7
+ </head>
8
+ <body>
9
+
10
+ <header>
11
+ <h3>
12
+ <a href="/">Veritrans sinatra app</a>
13
+ <link rel="icon" type="image/x-icon" href="https://account.veritrans.co.id/favicon.ico" />
14
+ </h3>
15
+ </header>
16
+
17
+ <section class="recurring-page">
18
+ <h4>Recurring / One Click</h4>
19
+
20
+ <section class="cards">
21
+ Saved cards:
22
+ <ul>
23
+
24
+ </ul>
25
+ </section>
26
+
27
+ <form id="add_card_form">
28
+ <input type="hidden" name="token_id" id="card_token">
29
+ <fieldset>
30
+ <legend>Credit Card Recurring</legend>
31
+ <p>
32
+ <label for="card_number">Card number</label>
33
+ <input type="text" id="card_number" style="width: 150px" value="4811 1111 1111 1114">
34
+ <br>
35
+ <small style="margin-left: 100px" class="card-numbers">
36
+ <a onclick="$('#card_number').val('4811 1111 1111 1114')">success Visa 1</a>
37
+ <a onclick="$('#card_number').val('4411 1111 1111 1118')">success Visa 2</a>
38
+ <a onclick="$('#card_number').val('5810 1111 1111 1112')">success MasterCard 1</a>
39
+ <a onclick="$('#card_number').val('5410 1111 1111 1116')">success MasterCard 2</a>
40
+ <a href="http://docs.veritrans.co.id/en/api/test_credentials.html" target="_blank">documentation</a>
41
+ </small>
42
+ </p>
43
+
44
+ <p>
45
+ <label for="card_cvc">Security Code</label>
46
+ <input type="text" id="card_cvc" style="width: 30px" placeholder="cvc" value="123">
47
+ </p>
48
+
49
+ <p>
50
+ <label for="card_exp">Expiration date</label>
51
+ <input type="text" id="card_exp" placeholder="MM / YY" value="12 / 16">
52
+ </p>
53
+
54
+ </fieldset>
55
+
56
+ <input id="add_card_btn" type="submit" value="Add Card">
57
+ </form>
58
+
59
+ <script src="//api.sandbox.veritrans.co.id/v2/assets/veritrans.js"></script>
60
+ <script src="//ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
61
+ <script src="//cdnjs.cloudflare.com/ajax/libs/jquery.payment/1.0.2/jquery.payment.js"></script>
62
+ <script src="//cdnjs.cloudflare.com/ajax/libs/magnific-popup.js/1.0.1/jquery.magnific-popup.js"></script>
63
+ <link rel="stylesheet" href="//cdnjs.cloudflare.com/ajax/libs/magnific-popup.js/0.9.9/magnific-popup.css">
64
+
65
+ <script type="text/javascript">
66
+ Veritrans.client_key = "<%= Veritrans.config.client_key %>";
67
+
68
+ // Here is a difference, for
69
+ Veritrans.url = "<%= Veritrans.config.api_host %>/v2/card/register";
70
+
71
+
72
+ function createTokenData() {
73
+ return {
74
+ card_number: $('#card_number').val().replace(/\s/g, ''),
75
+ card_cvv: $('#card_cvc').val(),
76
+ card_exp_month: $('#card_exp').val().match(/(\d+) \//)[1],
77
+ card_exp_year: '20' + $('#card_exp').val().match(/\/ (\d+)/)[1]
78
+ };
79
+ }
80
+
81
+ $(document).ready(function () {
82
+ $('#card_number').payment('formatCardNumber');
83
+ $('#card_cvc').payment('formatCardCVC');
84
+ $('#card_exp').payment('formatCardExpiry');
85
+
86
+ renderCards();
87
+
88
+ $('#add_card_form').on('submit', function (event) {
89
+ var form = this;
90
+ $('#submit_btn').attr('disabled', true).val("Processing ...");
91
+ event.preventDefault();
92
+
93
+ Veritrans.token(createTokenData, function (data) {
94
+ console.log('Token data:', data);
95
+ // if we get url then it's 3d-secure transaction
96
+ // so we need to open that page
97
+ // this callback function will be called again after user confirm 3d-secure
98
+ // you can also redirect on server side
99
+ if (data.redirect_url) {
100
+ $.magnificPopup.open({
101
+ items: { type: 'iframe', src: data.redirect_url }
102
+ });
103
+ $.magnificPopup.instance.content.find('iframe').height(590);
104
+ // if no redirect_url and we have token_id then just make charge request
105
+ } else if (data.saved_token_id) {
106
+ $('#card_token').val(data.saved_token_id);
107
+ //form.submit();
108
+ $.magnificPopup.close();
109
+ saveCard(data, createTokenData());
110
+ renderCards();
111
+ // if no redirect_url and no token_id, then it should be error
112
+ } else {
113
+ alert(data.validation_messages ? data.validation_messages.join("\n") : data.status_message);
114
+ $('#submit_btn').removeAttr('disabled').removeAttr("value");
115
+ }
116
+ });
117
+ });
118
+ });
119
+
120
+ function loadCards () {
121
+ return localStorage.recurring ? JSON.parse(localStorage.recurring) : [];
122
+ }
123
+
124
+ function saveCard (tokenInfo, cardInfo) {
125
+ var data = loadCards();
126
+
127
+ var row = {
128
+ token_id: tokenInfo.saved_token_id,
129
+ card_number: tokenInfo.masked_card,
130
+ card_expiry: cardInfo.card_exp_month + " / " + cardInfo.card_exp_year
131
+ };
132
+ data.push(row);
133
+
134
+ localStorage.recurring = JSON.stringify(data);
135
+ }
136
+
137
+ function renderCards () {
138
+ var cards = loadCards();
139
+
140
+ var container = $('section.cards ul');
141
+ container.empty();
142
+ cards.forEach(function (card) {
143
+ var el = $('<li>').html(
144
+ "Card Number: <code>" + card.card_number + "</code> " +
145
+ "Expiry: <i>" + card.card_expiry + "</i> "
146
+ );
147
+ el.attr('data-id', card.id);
148
+ el.attr('token-id', card.token_id);
149
+ $('<a>').text('Charge card').bind('click', chargeSavedCard).attr('href', '#').appendTo(el);
150
+ $('<a>').text('Remove').bind('click', removeSavedCard).attr('href', '#').appendTo(el);
151
+ $('<small>').text('Token ' + card.token_id).appendTo(el);
152
+ el.appendTo(container);
153
+ })
154
+ }
155
+
156
+ function chargeSavedCard (e) {
157
+ e.preventDefault();
158
+ var token = $(e.target).closest('li').attr('token-id');
159
+ var amount = prompt("Please enter amount (Rp.)", 15000);
160
+
161
+ if (amount === "" || amount === null || parseInt(amount, 10) <= 0) {
162
+ console.log("Canceled");
163
+ return;
164
+ }
165
+
166
+ // Create iFrame and submit form in it
167
+ var html = '<form action="' + window.location.protocol + '//' + window.location.host + '/charge_vtdirect" method="post">' +
168
+ '<input type=hidden name=recurring value=1>' +
169
+ '<input type=hidden name=token_id value="' + token + '">' +
170
+ '<input type=hidden name=gross_amount value="' + parseInt(amount, 10) + '">' +
171
+ '<input type=submit style="display: none">' +
172
+ '</form>' + "<script>console.log(document.forms[0]); document.forms[0].submit()<\/script>";
173
+
174
+ var content = 'data:text/html;charset=utf-8,' + encodeURI(html);
175
+ $.magnificPopup.open({
176
+ items: { type: 'iframe', src: content}
177
+ });
178
+ }
179
+
180
+ function removeSavedCard (e) {
181
+ e.preventDefault();
182
+ var tokenId = $(e.target).closest('li').attr('token-id');
183
+ var cards = loadCards();
184
+
185
+ cards.forEach(function (card, index) {
186
+ if (card.token_id == tokenId) {
187
+ if (confirm("Remove card " + card.card_number + "?")) {
188
+ cards.splice(index, 1);
189
+ console.log(cards);
190
+ }
191
+ }
192
+ });
193
+
194
+ localStorage.recurring = JSON.stringify(cards);
195
+ renderCards();
196
+ }
197
+
198
+ </script>
199
+
200
+ </body>
201
+ </html>
@@ -6,7 +6,7 @@
6
6
 
7
7
  <% if @result.redirect_url %>
8
8
  <section>
9
- <p>Here's redirect url <a href='<%= @result.redirect_url %>'><%= @result.redirect_url %></a> </p>
9
+ <p>Here's redirect url <a href='<%= @vtweb_url %>'><%= @vtweb_url %></a> </p>
10
10
  </section>
11
11
  <% end %>
12
12
 
@@ -24,5 +24,14 @@
24
24
  </pre>
25
25
  </code>
26
26
 
27
+ <% if @cahrge_params %>
28
+ <strong>Request Body</strong>
29
+ <code>
30
+ <pre>
31
+ <%= JSON.pretty_generate(@cahrge_params) %>
32
+ </pre>
33
+ </code>
34
+ <% end %>
35
+
27
36
  <a href="/">Go back</a>
28
37
  </section>
@@ -5,6 +5,12 @@ require 'json'
5
5
  require 'veritrans'
6
6
  require 'sinatra'
7
7
 
8
+ begin
9
+ require 'tilt/erubis'
10
+ rescue LoadError => error
11
+ puts "Warning: Can not load 'tilt', continue"
12
+ end
13
+
8
14
  Veritrans.setup do
9
15
  config.load_yml "./veritrans.yml#development"
10
16
 
@@ -20,6 +26,8 @@ end
20
26
  set :public_folder, "."
21
27
  set :views, "."
22
28
 
29
+ set :run, $0 == __FILE__
30
+
23
31
  def generate_order_id
24
32
  "testing-#{rand.round(4)}-#{Time.now.to_i}"
25
33
  end
@@ -28,31 +36,135 @@ get "/" do
28
36
  erb :index
29
37
  end
30
38
 
31
- post "/charge_vtdirect" do
32
- @result = Veritrans.charge(
33
- payment_type: "credit_card",
34
- credit_card: { token_id: params[:token_id] },
39
+ get "/recurring" do
40
+ erb :recurring
41
+ end
42
+
43
+ get "/localization" do
44
+ erb :localization
45
+ end
46
+
47
+ get "/points" do
48
+ erb :points
49
+ end
50
+
51
+ get "/widget" do
52
+ response = Veritrans.create_widget_token(
35
53
  transaction_details: {
36
54
  order_id: generate_order_id,
37
- gross_amount: params[:gross_amount]
55
+ gross_amount: 30_000
38
56
  }
39
57
  )
58
+ @token_id = response.data[:token_id]
59
+ erb :widget
60
+ end
40
61
 
62
+ get "/widget/confirm/:transaction_id" do
63
+ @result = Veritrans.status(params[:transaction_id])
41
64
  erb :response
42
65
  end
43
66
 
67
+ post "/charge_vtdirect" do
68
+ @charge_params = {
69
+ payment_type: "credit_card",
70
+ credit_card: {
71
+ token_id: params[:token_id]
72
+ },
73
+ transaction_details: {
74
+ order_id: generate_order_id,
75
+ gross_amount: params[:gross_amount].to_f,
76
+ }
77
+ }
78
+
79
+ if params[:recurring] == "1"
80
+ @charge_params[:credit_card][:recurring] = true
81
+ end
82
+
83
+ if params[:points_amount]
84
+ @charge_params[:credit_card][:point_redeem_amount] = params[:points_amount]
85
+ @charge_params[:credit_card][:bank] = "bni"
86
+ end
87
+
88
+ @result = Veritrans.charge(@charge_params)
89
+
90
+ if params[:format] == "json"
91
+ content_type :json
92
+ @result.response.body
93
+ else
94
+ erb :response
95
+ end
96
+ end
97
+
44
98
  get "/charge_vtweb" do
45
- @result = Veritrans.charge(
99
+ vtweb_options = {}
100
+
101
+ if params[:enabled_payments] && params[:enabled_payments].size > 0
102
+ vtweb_options[:enabled_payments] = params[:enabled_payments]
103
+ end
104
+
105
+ if params[:credit_card_3d_secure] && params[:credit_card_3d_secure] != ""
106
+ vtweb_options[:credit_card_3d_secure] = params[:credit_card_3d_secure] == "true"
107
+ end
108
+
109
+ if params[:bin_promo] && params[:bin_promo] != ""
110
+ vtweb_options[:credit_card_bins] = params[:bin_promo]
111
+ end
112
+
113
+ if params[:installment]
114
+ vtweb_options[:payment_options] = {
115
+ installment: {
116
+ required: true,
117
+ installment_terms: {}
118
+ }
119
+ }
120
+
121
+ if params[:installment]['bni']
122
+ vtweb_options[:payment_options][:installment][:installment_terms][:bni] = [3, 6, 12]
123
+ end
124
+
125
+ if params[:installment][:mandiri]
126
+ vtweb_options[:payment_options][:installment][:installment_terms][:mandiri] = [3, 6, 12]
127
+ end
128
+
129
+ if params[:installment]['bca']
130
+ vtweb_options[:payment_options][:installment][:installment_terms][:bca] = [3, 6, 12]
131
+ end
132
+ end
133
+
134
+ if request.env["HTTP_REFERER"]
135
+ vtweb_options[:finish_redirect_url] = request.env["HTTP_REFERER"]
136
+ vtweb_options[:unfinish_redirect_url] = request.env["HTTP_REFERER"]
137
+ vtweb_options[:error_redirect_url] = request.env["HTTP_REFERER"]
138
+ end
139
+
140
+ @cahrge_params = {
46
141
  payment_type: "VTWEB",
142
+ vtweb: vtweb_options,
47
143
  transaction_details: {
48
144
  order_id: generate_order_id,
49
145
  gross_amount: 100_000
50
146
  }
51
- )
147
+ }
148
+
149
+ @result = Veritrans.charge(@cahrge_params)
150
+
151
+ if @result.redirect_url
152
+ if params[:locale].to_s != ""
153
+ @vtweb_url = "#{@result.redirect_url}?locale=#{params[:locale]}"
154
+ else
155
+ @vtweb_url = @result.redirect_url
156
+ end
157
+ end
52
158
 
53
159
  erb :response
54
160
  end
55
161
 
162
+ get "/check_points/:token_id" do
163
+ @result = Veritrans.inquiry_points(params[:token_id])
164
+ content_type :json
165
+ @result.response.body
166
+ end
167
+
56
168
  post "/webhook" do
57
169
  post_body = request.body.read
58
170
  request_data = Veritrans.decode_notification_json(post_body)
@@ -73,4 +185,4 @@ post "/webhook" do
73
185
  end
74
186
 
75
187
  return "ok"
76
- end
188
+ end
@@ -1,6 +1,8 @@
1
1
  body {
2
2
  max-width: 900px;
3
3
  margin: 0 auto;
4
+ font-size: 16px;
5
+ background: white;
4
6
  }
5
7
  a {
6
8
  color: #00E;
@@ -24,7 +26,9 @@ section + section {
24
26
  }
25
27
 
26
28
  label {
27
- display: inline-block; min-width: 100px;
29
+ display: inline-block;
30
+ min-width: 100px;
31
+ vertical-align: top;
28
32
  }
29
33
  .card-numbers {
30
34
  margin-left: 100px;
@@ -42,4 +46,81 @@ label {
42
46
 
43
47
  fieldset {
44
48
  margin: 25px 0 12px;
45
- }
49
+ }
50
+
51
+ .white-popup {
52
+ position: relative;
53
+ background: #FFF;
54
+ padding: 20px;
55
+ width: auto;
56
+ max-width: 600px;
57
+ margin: 20px auto;
58
+ }
59
+
60
+ .white-popup pre code {
61
+ white-space: pre-wrap;
62
+ }
63
+
64
+ #vtweb_form label {
65
+ min-width: 180px;
66
+ }
67
+
68
+ #vtweb_form ul {
69
+ display: inline-block;
70
+ vertical-align: top;
71
+ margin-top: 0;
72
+ padding-left: 0px;
73
+ }
74
+
75
+ #vtweb_form ul li {
76
+ list-style-type: none;
77
+ margin-bottom: 1px;
78
+ font-size: 15px;
79
+ }
80
+
81
+ #vtweb_form small {
82
+ margin-left: 184px;
83
+ }
84
+
85
+ .recurring-page .cards {
86
+ border: 1px dashed #acf;
87
+ padding: 10px;
88
+ }
89
+
90
+ .recurring-page .cards ul {
91
+ padding-left: 0;
92
+ margin-bottom: 3px;
93
+ }
94
+
95
+ .recurring-page .cards ul li {
96
+ list-style-type: none;
97
+ display: block;
98
+ background: #f5f5f5;
99
+ padding: 7px 9px;
100
+ box-shadow: inset 0px 0px 2px rgba(0, 0, 64, 0.25);
101
+ }
102
+
103
+ .recurring-page .cards ul li + li {
104
+ margin-top: 10px;
105
+ }
106
+
107
+ .recurring-page .cards ul li code {
108
+ margin: 0 18px 0 4px;
109
+ }
110
+ .recurring-page .cards ul li i {
111
+ margin: 0 35px 0 4px;
112
+ font-style: normal;
113
+ }
114
+
115
+ .recurring-page .cards ul li a {
116
+ margin-right: 10px;
117
+ }
118
+
119
+ .recurring-page .cards ul li small {
120
+ display: block;
121
+ margin-top: 7px;
122
+ color: #666;
123
+ font-family: monospace;
124
+ font-size: 10px;
125
+ }
126
+