veritrans 2.0.4 → 2.1.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.
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
+