spree_vpago 2.2.2.pre.pre19 → 2.2.2.pre.pre21
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 +4 -4
- data/.env.example +0 -4
- data/Gemfile.lock +4 -4
- data/README.md +0 -8
- data/app/assets/javascripts/vpago/vpago_payments/check_transaction_periodically.js +59 -0
- data/app/controllers/spree/vpago_payments_controller.rb +22 -15
- data/app/helpers/vpago/vpago_payments_helper.rb +0 -11
- data/app/models/spree/gateway/payway_v2.rb +0 -12
- data/app/models/spree/gateway/true_money.rb +0 -2
- data/app/models/spree/gateway/vattanac.rb +0 -2
- data/app/models/vpago/payment_decorator.rb +2 -2
- data/app/models/vpago/payment_method_decorator.rb +3 -4
- data/app/services/vpago/payment_url_constructor.rb +1 -1
- data/app/views/layouts/vpago_payments.html.erb +1 -1
- data/app/views/spree/vpago_payments/_transaction_checker.html.erb +7 -37
- data/app/views/spree/vpago_payments/checkout.html.erb +13 -7
- data/app/views/spree/vpago_payments/forms/spree/gateway/_payway_v2.html.erb +28 -19
- data/app/views/spree/vpago_payments/forms/spree/gateway/_true_money.html.erb +14 -17
- data/app/views/spree/vpago_payments/forms/spree/gateway/_vattanac.html.erb +17 -3
- data/app/views/spree/vpago_payments/forms/spree/gateway/_vattanac_mini_app.html.erb +15 -17
- data/app/views/spree/vpago_payments/processing.html.erb +20 -0
- data/config/routes.rb +1 -1
- data/lib/spree_vpago/version.rb +1 -1
- data/lib/vpago/payway_v2/checkout.rb +1 -1
- data/lib/vpago/payway_v2/pre_auth_canceler.rb +1 -1
- data/lib/vpago/payway_v2/pre_auth_completer.rb +1 -1
- data/lib/vpago/payway_v2/transaction_status.rb +2 -2
- metadata +3 -3
- data/app/assets/javascripts/vpago/vpago_payments/payment_processing_listener.js +0 -95
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: '05536639cc3731496d0e01bd7ecccb56062d2b412ca795b7a924deac49c9c9a5'
|
|
4
|
+
data.tar.gz: f2dbe115e30add8edc1188b3c8a8ae855235d88197d45683615cb5dbe4b17445
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 43688b89eab0f758808875722761c47b35d460c2c76501b3ff0218ea25b60d2b7859183cf4733a66704ae0f10b72b4f7bc9a75a6b1e97a1139f893c08b5cf008
|
|
7
|
+
data.tar.gz: 5642262ac80774489724678f53fb027e09c2257dbed79ae9fa32c3cf9f806baee60315120053f97feb272779d8fda1b3497c4cdf7e0941e1c9c9dbffbd838012
|
data/.env.example
CHANGED
data/Gemfile.lock
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
PATH
|
|
2
2
|
remote: .
|
|
3
3
|
specs:
|
|
4
|
-
spree_vpago (2.2.2.pre.
|
|
4
|
+
spree_vpago (2.2.2.pre.pre21)
|
|
5
5
|
faraday
|
|
6
6
|
google-cloud-firestore
|
|
7
7
|
spree_api (>= 4.5)
|
|
@@ -188,7 +188,7 @@ GEM
|
|
|
188
188
|
faraday-http-cache (2.5.0)
|
|
189
189
|
faraday (>= 0.8)
|
|
190
190
|
faraday-net_http (3.0.2)
|
|
191
|
-
faraday-retry (2.
|
|
191
|
+
faraday-retry (2.3.2)
|
|
192
192
|
faraday (~> 2.0)
|
|
193
193
|
ffaker (2.21.0)
|
|
194
194
|
ffi (1.15.5)
|
|
@@ -242,7 +242,7 @@ GEM
|
|
|
242
242
|
gapic-common (~> 1.2)
|
|
243
243
|
google-cloud-errors (~> 1.0)
|
|
244
244
|
google-logging-utils (0.2.0)
|
|
245
|
-
google-protobuf (4.33.
|
|
245
|
+
google-protobuf (4.33.4)
|
|
246
246
|
bigdecimal
|
|
247
247
|
rake (>= 13)
|
|
248
248
|
googleapis-common-protos (1.9.0)
|
|
@@ -259,7 +259,7 @@ GEM
|
|
|
259
259
|
multi_json (~> 1.11)
|
|
260
260
|
os (>= 0.9, < 2.0)
|
|
261
261
|
signet (>= 0.16, < 2.a)
|
|
262
|
-
grpc (1.
|
|
262
|
+
grpc (1.76.0)
|
|
263
263
|
google-protobuf (>= 3.25, < 5.0)
|
|
264
264
|
googleapis-common-protos-types (~> 1.0)
|
|
265
265
|
hashdiff (1.1.0)
|
data/README.md
CHANGED
|
@@ -95,14 +95,6 @@ ENV configuration:
|
|
|
95
95
|
|
|
96
96
|
```ruby
|
|
97
97
|
ENV['PAYWAY_MERCHANT_PROFILE_CONTENT_TYPE'] # html, json
|
|
98
|
-
ENV['PAYWAY_CHECKOUT_PATH']
|
|
99
|
-
ENV['PAYWAY_CHECK_TRANSACTION_PATH']
|
|
100
|
-
ENV['PAYWAY_RETURN_CALLBACK_URL']
|
|
101
|
-
ENV['PAYWAY_CONTINUE_SUCCESS_CALLBACK_URL']
|
|
102
|
-
|
|
103
|
-
#pre-auth
|
|
104
|
-
ENV['PAYWAY_V2_PRE_AUTH_COMPLETE_PATH']
|
|
105
|
-
ENV['PAYWAY_V2_PRE_AUTH_CANCEL_PATH']
|
|
106
98
|
```
|
|
107
99
|
|
|
108
100
|
Payment method configuration:
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Polls the transaction status endpoint until the payment succeeds, fails, or
|
|
3
|
+
* the maximum polling duration is reached.
|
|
4
|
+
*
|
|
5
|
+
* @param {Object} options
|
|
6
|
+
* @param {string} options.checkTransactionUrl
|
|
7
|
+
* @param {Function} options.onSuccess
|
|
8
|
+
* @param {Function} options.onFailure
|
|
9
|
+
*/
|
|
10
|
+
async function checkTransactionPeriodically({
|
|
11
|
+
checkTransactionUrl,
|
|
12
|
+
onSuccess,
|
|
13
|
+
onFailure,
|
|
14
|
+
}) {
|
|
15
|
+
var pollIntervalMs = 5000;
|
|
16
|
+
var maxDurationMs = 10 * 60 * 1000;
|
|
17
|
+
var shouldPoll = true;
|
|
18
|
+
var intervalId;
|
|
19
|
+
var startTime = Date.now();
|
|
20
|
+
|
|
21
|
+
var pollStatus = function () {
|
|
22
|
+
if (shouldPoll) return;
|
|
23
|
+
|
|
24
|
+
if (Date.now() - startTime >= maxDurationMs) {
|
|
25
|
+
if (intervalId) clearInterval(intervalId);
|
|
26
|
+
return;
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
fetch(checkTransactionUrl, {
|
|
30
|
+
method: "GET",
|
|
31
|
+
headers: { Accept: "application/json" },
|
|
32
|
+
credentials: "same-origin",
|
|
33
|
+
})
|
|
34
|
+
.then(function (response) {
|
|
35
|
+
return response.json().then(function (body) {
|
|
36
|
+
return { ok: response.ok, body: body };
|
|
37
|
+
});
|
|
38
|
+
})
|
|
39
|
+
.then(function (result) {
|
|
40
|
+
var status =
|
|
41
|
+
result.body && result.body.status
|
|
42
|
+
? String(result.body.status)
|
|
43
|
+
: "pending";
|
|
44
|
+
|
|
45
|
+
if (status === "success" || status === "failed") {
|
|
46
|
+
shouldPoll = false;
|
|
47
|
+
if (intervalId) clearInterval(intervalId);
|
|
48
|
+
|
|
49
|
+
if (status === "success") onSuccess(status);
|
|
50
|
+
if (status === "failed") onFailure(status);
|
|
51
|
+
}
|
|
52
|
+
})
|
|
53
|
+
.catch(function () {});
|
|
54
|
+
};
|
|
55
|
+
|
|
56
|
+
intervalId = window.setInterval(pollStatus, pollIntervalMs);
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
window.checkTransactionPeriodically = checkTransactionPeriodically;
|
|
@@ -19,36 +19,43 @@ module Spree
|
|
|
19
19
|
end
|
|
20
20
|
|
|
21
21
|
# GET
|
|
22
|
-
def
|
|
22
|
+
def processing
|
|
23
23
|
@payment = Vpago::PaymentFinder.new(params.permit!.to_h).find_and_verify
|
|
24
24
|
raise ActiveRecord::RecordNotFound unless @payment.present?
|
|
25
25
|
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
if checker.success?
|
|
29
|
-
render json: { status: :success }, status: :ok
|
|
30
|
-
elsif checker.failed?
|
|
31
|
-
render json: { status: :failed }, status: :payment_required
|
|
32
|
-
else
|
|
33
|
-
render json: { status: :pending }, status: :accepted
|
|
34
|
-
end
|
|
26
|
+
@order = @payment.order
|
|
35
27
|
end
|
|
36
28
|
|
|
37
29
|
# GET
|
|
38
|
-
def
|
|
30
|
+
def success
|
|
39
31
|
@payment = Vpago::PaymentFinder.new(params.permit!.to_h).find_and_verify
|
|
40
32
|
raise ActiveRecord::RecordNotFound unless @payment.present?
|
|
41
33
|
|
|
42
34
|
@order = @payment.order
|
|
35
|
+
raise CanCan::AccessDenied unless @order.completed?
|
|
43
36
|
end
|
|
44
37
|
|
|
45
38
|
# GET
|
|
46
|
-
def
|
|
39
|
+
def check_transaction
|
|
47
40
|
@payment = Vpago::PaymentFinder.new(params.permit!.to_h).find_and_verify
|
|
48
41
|
raise ActiveRecord::RecordNotFound unless @payment.present?
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
42
|
+
|
|
43
|
+
return render json: { status: :success }, status: :ok if @payment.completed?
|
|
44
|
+
return render json: { status: :failed }, status: :ok if @payment.failed?
|
|
45
|
+
|
|
46
|
+
if @payment.payment_method.support_check_transaction_api?
|
|
47
|
+
checker = @payment.payment_method.check_transaction(@payment)
|
|
48
|
+
|
|
49
|
+
if checker.success?
|
|
50
|
+
render json: { status: :success }, status: :ok
|
|
51
|
+
elsif checker.try(:failed?) == true
|
|
52
|
+
render json: { status: :failed }, status: :ok
|
|
53
|
+
else
|
|
54
|
+
render json: { status: :pending }, status: :ok
|
|
55
|
+
end
|
|
56
|
+
else
|
|
57
|
+
render json: { status: :pending }, status: :ok
|
|
58
|
+
end
|
|
52
59
|
end
|
|
53
60
|
|
|
54
61
|
# POST
|
|
@@ -4,17 +4,6 @@ module Vpago
|
|
|
4
4
|
'firebase'
|
|
5
5
|
end
|
|
6
6
|
|
|
7
|
-
# eg. forms/spree/gateway/payway_v2
|
|
8
|
-
def render_form
|
|
9
|
-
render partial: "spree/vpago_payments/forms/#{@payment.payment_method.class.to_s.underscore}"
|
|
10
|
-
end
|
|
11
|
-
|
|
12
|
-
def render_transaction_checker
|
|
13
|
-
if @payment.payment_method.support_check_transaction_api?
|
|
14
|
-
render partial: 'spree/vpago_payments/transaction_checker'
|
|
15
|
-
end
|
|
16
|
-
end
|
|
17
|
-
|
|
18
7
|
# when return nil, each payment method should use their default URL.
|
|
19
8
|
# eg. PayWayV2 will use the continue_success_url as deeplink back URL.
|
|
20
9
|
def custom_return_deeplink_url
|
|
@@ -33,11 +33,6 @@ module Spree
|
|
|
33
33
|
preferred_abapay_khqr_deeplink_option.in?(%w[open_both open_checkout_url_only])
|
|
34
34
|
end
|
|
35
35
|
|
|
36
|
-
# override
|
|
37
|
-
def support_check_transaction_api?
|
|
38
|
-
true
|
|
39
|
-
end
|
|
40
|
-
|
|
41
36
|
# override
|
|
42
37
|
def default_payout_profile
|
|
43
38
|
Spree::PayoutProfiles::PaywayV2.default
|
|
@@ -72,12 +67,6 @@ module Spree
|
|
|
72
67
|
!enable_pre_auth?
|
|
73
68
|
end
|
|
74
69
|
|
|
75
|
-
# override
|
|
76
|
-
def check_status(payment)
|
|
77
|
-
checker = check_transaction(payment)
|
|
78
|
-
checker.success?
|
|
79
|
-
end
|
|
80
|
-
|
|
81
70
|
# override
|
|
82
71
|
# authorize is used when pre auth enabled
|
|
83
72
|
def authorize(_amount, _source, gateway_options = {})
|
|
@@ -159,7 +148,6 @@ module Spree
|
|
|
159
148
|
ActiveMerchant::Billing::Response.new(true, 'Payway Gateway: Payment has been canceled.')
|
|
160
149
|
end
|
|
161
150
|
|
|
162
|
-
# override
|
|
163
151
|
def check_transaction(payment)
|
|
164
152
|
checker = Vpago::PaywayV2::TransactionStatus.new(payment)
|
|
165
153
|
checker.call
|
|
@@ -20,11 +20,11 @@ module Vpago
|
|
|
20
20
|
|
|
21
21
|
base.delegate :checkout_url,
|
|
22
22
|
:web_checkout_url,
|
|
23
|
-
:check_transaction_url,
|
|
24
23
|
:processing_url,
|
|
25
24
|
:success_url,
|
|
26
|
-
:process_payment_url,
|
|
27
25
|
:success_deeplink_url,
|
|
26
|
+
:check_transaction_url,
|
|
27
|
+
:process_payment_url,
|
|
28
28
|
to: :url_constructor
|
|
29
29
|
|
|
30
30
|
# Add state machine event for payment retry
|
|
@@ -35,11 +35,10 @@ module Vpago
|
|
|
35
35
|
def support_payout? = false
|
|
36
36
|
def support_pre_auth? = false
|
|
37
37
|
|
|
38
|
-
#
|
|
39
|
-
#
|
|
40
|
-
# must provide: success?, failed?, pending?.
|
|
38
|
+
# The payment method must implement `check_transaction(payment)`.
|
|
39
|
+
# The returned object should respond to `.success?`, and optionally `.failed?` and `.pending?`.
|
|
41
40
|
def support_check_transaction_api?
|
|
42
|
-
|
|
41
|
+
respond_to?(:check_transaction)
|
|
43
42
|
end
|
|
44
43
|
|
|
45
44
|
# TODO: we have already implement purchase for payway_v2.
|
|
@@ -12,12 +12,12 @@ module Vpago
|
|
|
12
12
|
def checkout_url = "#{base_url}/vpago_payments/checkout?#{query}&platform=app"
|
|
13
13
|
def web_checkout_url = "#{base_url}/vpago_payments/checkout?#{query}&platform=web"
|
|
14
14
|
|
|
15
|
-
def check_transaction_url = "#{base_url}/vpago_payments/check_transaction?#{query}"
|
|
16
15
|
def processing_url = "#{base_url}/vpago_payments/processing?#{query}"
|
|
17
16
|
|
|
18
17
|
def success_url = "#{base_url}/vpago_payments/success?#{query}"
|
|
19
18
|
def success_deeplink_url = "#{app_scheme}://#{URI(base_url).host}/book/payment?number=#{order.number}&tk=#{order.token}"
|
|
20
19
|
|
|
20
|
+
def check_transaction_url = "#{base_url}/vpago_payments/check_transaction?#{query}"
|
|
21
21
|
def process_payment_url = "#{base_url}/vpago_payments/process_payment?#{query}"
|
|
22
22
|
|
|
23
23
|
def query
|
|
@@ -8,7 +8,7 @@
|
|
|
8
8
|
<%= csrf_meta_tags %>
|
|
9
9
|
<%= csp_meta_tag %>
|
|
10
10
|
|
|
11
|
-
<%= javascript_include_tag "vpago/vpago_payments/
|
|
11
|
+
<%= javascript_include_tag "vpago/vpago_payments/check_transaction_periodically", 'data-turbo-track': 'reload' %>
|
|
12
12
|
<%= javascript_include_tag "vpago/vpago_payments/request_process_payment", 'data-turbo-track': 'reload' %>
|
|
13
13
|
<%= javascript_include_tag "vpago/vpago_payments/user_informers/#{user_informer}", 'data-turbo-track': 'reload' %>
|
|
14
14
|
</head>
|
|
@@ -1,40 +1,10 @@
|
|
|
1
|
-
<%# This partial listens to payment status changes from bank and does not process the payment. %>
|
|
2
|
-
<%# When it detects a status change, it automatically redirects to the processing URL for actual processing. %>
|
|
3
|
-
<%# Designed to be used in checkout.html.erb %>
|
|
4
|
-
|
|
5
1
|
<script>
|
|
6
2
|
document.addEventListener("DOMContentLoaded", function() {
|
|
7
|
-
var
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
var pollStatus = function() {
|
|
14
|
-
if (hasRedirected) return;
|
|
15
|
-
|
|
16
|
-
fetch(checkTransactionUrl, {
|
|
17
|
-
method: "GET",
|
|
18
|
-
headers: { "Accept": "application/json" },
|
|
19
|
-
credentials: "same-origin"
|
|
20
|
-
})
|
|
21
|
-
.then(function(response) {
|
|
22
|
-
return response.json().then(function(body) {
|
|
23
|
-
return { ok: response.ok, body: body };
|
|
24
|
-
});
|
|
25
|
-
})
|
|
26
|
-
.then(function(result) {
|
|
27
|
-
var status = result.body && result.body.status ? String(result.body.status) : "pending";
|
|
28
|
-
|
|
29
|
-
if (status === "success" || status === "failed") {
|
|
30
|
-
hasRedirected = true;
|
|
31
|
-
if (intervalId) clearInterval(intervalId);
|
|
32
|
-
window.location.replace(processingUrl);
|
|
33
|
-
}
|
|
34
|
-
})
|
|
35
|
-
.catch(function() {});
|
|
36
|
-
};
|
|
37
|
-
|
|
38
|
-
intervalId = window.setInterval(pollStatus, pollIntervalMs);
|
|
3
|
+
var processingUrl = "<%= raw @payment.processing_url %>";
|
|
4
|
+
window.checkTransactionPeriodically({
|
|
5
|
+
checkTransactionUrl: "<%= raw @payment.check_transaction_url %>",
|
|
6
|
+
onFailure: () => window.location.replace(processingUrl),
|
|
7
|
+
onSuccess: () => window.location.replace(processingUrl),
|
|
8
|
+
});
|
|
39
9
|
});
|
|
40
|
-
</script>
|
|
10
|
+
</script>
|
|
@@ -1,9 +1,15 @@
|
|
|
1
|
-
<
|
|
1
|
+
<div id="vpago_loading_container">
|
|
2
|
+
Loading...
|
|
3
|
+
</div>
|
|
2
4
|
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
<button id="vpago_primary_button" style="display: none;"></button>
|
|
5
|
+
<div id="vpago_redirect_container" style="display: none;">
|
|
6
|
+
<h1>We're redirecting you to your bank</h1>
|
|
7
|
+
<p>You'll be returned here after confirming your <strong><%= @payment.display_amount %></strong> payment.</p>
|
|
7
8
|
|
|
8
|
-
|
|
9
|
-
|
|
9
|
+
<button id="vpago_redirect_button">
|
|
10
|
+
<!-- Use JS to modify button label and callback -->
|
|
11
|
+
</button>
|
|
12
|
+
</div>
|
|
13
|
+
|
|
14
|
+
<%= render partial: "spree/vpago_payments/forms/#{@payment.payment_method.class.to_s.underscore}" %>
|
|
15
|
+
<%= render partial: 'spree/vpago_payments/transaction_checker' %>
|
|
@@ -11,38 +11,40 @@
|
|
|
11
11
|
const isTelegram = <%= telegram_user_agent? %>;
|
|
12
12
|
const isMobile = <%= mobile_user_agent? %>;
|
|
13
13
|
|
|
14
|
-
const abapayKhqrDeeplink =
|
|
14
|
+
const abapayKhqrDeeplink = <%= @payment.payment_method.abapay_khqr_deeplink? %>;
|
|
15
15
|
const shouldOpenAbaPayDeeplink = isMobile && <%= @payment.payment_method.open_abapay_deeplink? %>;
|
|
16
16
|
const shouldOpenCheckoutUrl = <%= @payment.payment_method.open_checkout_url? %>;
|
|
17
17
|
|
|
18
|
-
function
|
|
18
|
+
function openDeeplinkUrl(deeplinkUrl) {
|
|
19
19
|
if(isTelegram){
|
|
20
|
-
window.open(
|
|
20
|
+
window.open(deeplinkUrl, '_blank');
|
|
21
21
|
} else {
|
|
22
|
-
window.location.href =
|
|
22
|
+
window.location.href = deeplinkUrl;
|
|
23
23
|
}
|
|
24
24
|
}
|
|
25
25
|
|
|
26
|
-
function
|
|
27
|
-
document.getElementById("vpago_primary_button").style.display = "block";
|
|
28
|
-
document.getElementById("vpago_primary_button").innerText = "Open ABA Pay";
|
|
29
|
-
document.getElementById("vpago_primary_button").addEventListener("click", function() {
|
|
30
|
-
openDeeplink(abapay_deeplink)
|
|
31
|
-
});
|
|
32
|
-
|
|
33
|
-
openDeeplink(abapay_deeplink)
|
|
34
|
-
}
|
|
35
|
-
|
|
36
|
-
function openCheckoutUrl(checkout_qr_url, delay = 0) {
|
|
26
|
+
function openUrl(url, delay = 0) {
|
|
37
27
|
if(delay > 0) {
|
|
38
28
|
setTimeout(function() {
|
|
39
|
-
window.location.href =
|
|
29
|
+
window.location.href = url;
|
|
40
30
|
}, delay);
|
|
41
31
|
} else {
|
|
42
|
-
window.location.href =
|
|
32
|
+
window.location.href = url;
|
|
43
33
|
}
|
|
44
34
|
}
|
|
45
35
|
|
|
36
|
+
function showRedirectContainer(buttonLabel, onClick) {
|
|
37
|
+
const loadingContainer = document.getElementById('vpago_loading_container');
|
|
38
|
+
const redirectContainer = document.getElementById('vpago_redirect_container');
|
|
39
|
+
const redirectButton = document.getElementById('vpago_redirect_button');
|
|
40
|
+
|
|
41
|
+
redirectButton.textContent = buttonLabel;
|
|
42
|
+
redirectButton.addEventListener('click', onClick);
|
|
43
|
+
|
|
44
|
+
loadingContainer.style.display = 'none';
|
|
45
|
+
redirectContainer.style.removeProperty('display');
|
|
46
|
+
}
|
|
47
|
+
|
|
46
48
|
document.addEventListener("DOMContentLoaded", function () {
|
|
47
49
|
if (abapayKhqrDeeplink) {
|
|
48
50
|
var formData = new FormData(document.getElementById("aba_merchant_request"));
|
|
@@ -57,14 +59,21 @@
|
|
|
57
59
|
})
|
|
58
60
|
.then(function(data) {
|
|
59
61
|
var shouldDelayBeforeOpenCheckoutUrl = false;
|
|
62
|
+
var shouldShowRedirectContainer = false;
|
|
60
63
|
|
|
61
64
|
if (data.abapay_deeplink && shouldOpenAbaPayDeeplink) {
|
|
62
|
-
|
|
65
|
+
openDeeplinkUrl(data.abapay_deeplink);
|
|
63
66
|
shouldDelayBeforeOpenCheckoutUrl = true;
|
|
67
|
+
shouldShowRedirectContainer = true;
|
|
64
68
|
}
|
|
65
69
|
|
|
66
70
|
if (data.checkout_qr_url && shouldOpenCheckoutUrl) {
|
|
67
|
-
|
|
71
|
+
openUrl(data.checkout_qr_url, shouldDelayBeforeOpenCheckoutUrl ? 500 : 0);
|
|
72
|
+
shouldShowRedirectContainer = false;
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
if(shouldShowRedirectContainer){
|
|
76
|
+
showRedirectContainer("Open ABA Mobile", () => openDeeplinkUrl(data.abapay_deeplink));
|
|
68
77
|
}
|
|
69
78
|
})
|
|
70
79
|
.catch(function(error) {
|
|
@@ -1,15 +1,22 @@
|
|
|
1
1
|
<% @checkout = ::Vpago::TrueMoney::Checkout.new(@payment) %>
|
|
2
2
|
<% redirect_urls = @checkout.generate_payment_urls(params[:platform]) %>
|
|
3
|
-
<% @payment.user_informer.payment_is_processing(processing: true) %>
|
|
4
3
|
|
|
5
4
|
<script>
|
|
5
|
+
function showRedirectContainer(buttonLabel, onClick) {
|
|
6
|
+
const loadingContainer = document.getElementById('vpago_loading_container');
|
|
7
|
+
const redirectContainer = document.getElementById('vpago_redirect_container');
|
|
8
|
+
const redirectButton = document.getElementById('vpago_redirect_button');
|
|
9
|
+
|
|
10
|
+
redirectButton.textContent = buttonLabel;
|
|
11
|
+
redirectButton.addEventListener('click', onClick);
|
|
12
|
+
|
|
13
|
+
loadingContainer.style.display = 'none';
|
|
14
|
+
redirectContainer.style.removeProperty('display');
|
|
15
|
+
}
|
|
16
|
+
|
|
6
17
|
document.addEventListener("DOMContentLoaded", () => {
|
|
7
18
|
const platform = "<%= params[:platform] %>";
|
|
8
19
|
const redirectUrls = <%= redirect_urls.to_json.html_safe %>;
|
|
9
|
-
const confirmButton = document.getElementById("confirm-payment-button");
|
|
10
|
-
const firebaseConfigs = <%= Rails.application.credentials.firebase_web_config.to_json.html_safe %>;
|
|
11
|
-
const docRefPath = "<%= @payment.user_informer.document_reference_path %>";
|
|
12
|
-
const successUrl = "<%= @payment.success_url %>";
|
|
13
20
|
|
|
14
21
|
function setupConfirmPaymentButton() {
|
|
15
22
|
if (platform === "app") {
|
|
@@ -17,21 +24,11 @@
|
|
|
17
24
|
setTimeout(() => {
|
|
18
25
|
window.location.href = redirectUrls.webview;
|
|
19
26
|
}, 1500);
|
|
20
|
-
} else if (confirmButton) {
|
|
21
|
-
confirmButton.addEventListener("click", () => {
|
|
22
|
-
window.open(redirectUrls.webview, '_blank');
|
|
23
|
-
});
|
|
24
|
-
}
|
|
25
|
-
}
|
|
26
|
-
|
|
27
|
-
function setupPaymentProcessingListener() {
|
|
28
|
-
if (window.initPaymentProcessingListener) {
|
|
29
|
-
window.initPaymentProcessingListener(firebaseConfigs, docRefPath, successUrl);
|
|
30
27
|
} else {
|
|
31
|
-
|
|
28
|
+
window.open(redirectUrls.webview, '_blank');
|
|
32
29
|
}
|
|
33
30
|
}
|
|
31
|
+
|
|
34
32
|
setupConfirmPaymentButton();
|
|
35
|
-
setupPaymentProcessingListener();
|
|
36
33
|
});
|
|
37
34
|
</script>
|
|
@@ -11,6 +11,18 @@ end
|
|
|
11
11
|
%>
|
|
12
12
|
|
|
13
13
|
<script>
|
|
14
|
+
function showRedirectContainer(buttonLabel, onClick) {
|
|
15
|
+
const loadingContainer = document.getElementById('vpago_loading_container');
|
|
16
|
+
const redirectContainer = document.getElementById('vpago_redirect_container');
|
|
17
|
+
const redirectButton = document.getElementById('vpago_redirect_button');
|
|
18
|
+
|
|
19
|
+
redirectButton.textContent = buttonLabel;
|
|
20
|
+
redirectButton.addEventListener('click', onClick);
|
|
21
|
+
|
|
22
|
+
loadingContainer.style.display = 'none';
|
|
23
|
+
redirectContainer.style.removeProperty('display');
|
|
24
|
+
}
|
|
25
|
+
|
|
14
26
|
const platform = "<%= params[:platform] %>";
|
|
15
27
|
const deeplinkUrl = "<%= raw(result[:deeplink_url]) %>";
|
|
16
28
|
const webUrl = "<%= raw(result[:web_url]) %>";
|
|
@@ -25,12 +37,14 @@ end
|
|
|
25
37
|
|
|
26
38
|
case "deeplink":
|
|
27
39
|
redirectTo(deeplinkUrl);
|
|
40
|
+
showRedirectContainer("Continue", () => redirectTo(deeplinkUrl));
|
|
28
41
|
break;
|
|
29
42
|
|
|
30
43
|
case "all":
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
44
|
+
redirectTo(deeplinkUrl);
|
|
45
|
+
setTimeout(() => {
|
|
46
|
+
redirectTo(webUrl);
|
|
47
|
+
}, 1500);
|
|
34
48
|
break;
|
|
35
49
|
|
|
36
50
|
default:
|
|
@@ -1,13 +1,23 @@
|
|
|
1
1
|
<% @checkout = ::Vpago::VattanacMiniApp::Checkout.new(@payment) %>
|
|
2
|
-
<% @payment.user_informer.payment_is_processing(processing: true) %>
|
|
3
2
|
|
|
4
3
|
<p id="unsupported-message"
|
|
5
4
|
style="margin-top: 10px; font-weight: bold; color: red; display: none;">
|
|
6
5
|
</p>
|
|
7
6
|
|
|
8
7
|
<script>
|
|
9
|
-
|
|
8
|
+
function showRedirectContainer(buttonLabel, onClick) {
|
|
9
|
+
const loadingContainer = document.getElementById('vpago_loading_container');
|
|
10
|
+
const redirectContainer = document.getElementById('vpago_redirect_container');
|
|
11
|
+
const redirectButton = document.getElementById('vpago_redirect_button');
|
|
12
|
+
|
|
13
|
+
redirectButton.textContent = buttonLabel;
|
|
14
|
+
redirectButton.addEventListener('click', onClick);
|
|
10
15
|
|
|
16
|
+
loadingContainer.style.display = 'none';
|
|
17
|
+
redirectContainer.style.removeProperty('display');
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
document.addEventListener("DOMContentLoaded", () => {
|
|
11
21
|
const setupMiniAppPayment = () => {
|
|
12
22
|
const detectMobileOS = () => {
|
|
13
23
|
const ua = navigator.userAgent || navigator.vendor || window.opera;
|
|
@@ -24,8 +34,10 @@
|
|
|
24
34
|
|
|
25
35
|
if (os === 'iOS' && window.webkit?.messageHandlers?.startPayment) {
|
|
26
36
|
window.webkit.messageHandlers.startPayment.postMessage(JSON.stringify(payload));
|
|
37
|
+
showRedirectContainer("Continue", () => window.webkit.messageHandlers.startPayment.postMessage(JSON.stringify(payload)));
|
|
27
38
|
} else if (os === 'Android' && window.AndroidInterface?.startPayment) {
|
|
28
39
|
window.AndroidInterface.startPayment(JSON.stringify(payload));
|
|
40
|
+
showRedirectContainer("Continue", () => window.AndroidInterface.startPayment(JSON.stringify(payload)));
|
|
29
41
|
} else {
|
|
30
42
|
const unsupported = document.getElementById('unsupported-message');
|
|
31
43
|
unsupported.style.display = 'block';
|
|
@@ -33,20 +45,6 @@
|
|
|
33
45
|
}
|
|
34
46
|
};
|
|
35
47
|
|
|
36
|
-
|
|
37
|
-
const firebaseConfigs = <%= Rails.application.credentials.firebase_web_config.to_json.html_safe %>;
|
|
38
|
-
const documentReferencePath = "<%= @payment.user_informer.document_reference_path %>";
|
|
39
|
-
const successUrl = "<%= @payment.success_url %>";
|
|
40
|
-
|
|
41
|
-
if (window.initPaymentProcessingListener) {
|
|
42
|
-
window.initPaymentProcessingListener(firebaseConfigs, documentReferencePath, successUrl);
|
|
43
|
-
} else {
|
|
44
|
-
console.log("initPaymentProcessingListener is not defined");
|
|
45
|
-
}
|
|
46
|
-
};
|
|
47
|
-
|
|
48
|
-
setupMiniAppPayment();
|
|
49
|
-
setupPaymentProcessingListener();
|
|
50
|
-
|
|
48
|
+
setupMiniAppPayment();
|
|
51
49
|
});
|
|
52
50
|
</script>
|
|
@@ -14,6 +14,26 @@
|
|
|
14
14
|
retryDelayMs: 1000,
|
|
15
15
|
})
|
|
16
16
|
|
|
17
|
+
// This block in /processing is purely JUST for review/audit purposes (ABA requirement).
|
|
18
|
+
// It checks the bank transaction status periodically without actually
|
|
19
|
+
// triggering payment processing again. By the time the user lands
|
|
20
|
+
// on this page, the transaction is normally complete or failed.
|
|
21
|
+
//
|
|
22
|
+
// What it does:
|
|
23
|
+
// 1. Logs or updates the UI with transaction status for review.
|
|
24
|
+
// 2. Provides reassurance that the bank transaction was confirmed.
|
|
25
|
+
// 3. Optionally, could allow a manual retry button if needed.
|
|
26
|
+
//
|
|
27
|
+
// What it does NOT do:
|
|
28
|
+
// - It does NOT call requestProcessPayment again (payment job is
|
|
29
|
+
// already unique and idempotent elsewhere).
|
|
30
|
+
// - It does NOT retry processing unnecessarily.
|
|
31
|
+
window.checkTransactionPeriodically({
|
|
32
|
+
checkTransactionUrl: "<%= raw @payment.check_transaction_url %>",
|
|
33
|
+
onFailure: () => console.log("Bank transaction failed"),
|
|
34
|
+
onSuccess: () => console.log("Bank transaction confirmed"),
|
|
35
|
+
})
|
|
36
|
+
|
|
17
37
|
window.listenToProcessingState({
|
|
18
38
|
firebaseConfigs: firebaseConfigs,
|
|
19
39
|
documentReferencePath: "<%= payment.user_informer.document_reference_path %>",
|
data/config/routes.rb
CHANGED
|
@@ -20,10 +20,10 @@ Spree::Core::Engine.add_routes do
|
|
|
20
20
|
resource :vpago_payments do
|
|
21
21
|
collection do
|
|
22
22
|
get :checkout
|
|
23
|
-
get :check_transaction
|
|
24
23
|
get :processing
|
|
25
24
|
get :success
|
|
26
25
|
|
|
26
|
+
match :check_transaction, via: %i[get]
|
|
27
27
|
match :process_payment, via: %i[get post]
|
|
28
28
|
match :true_money_process_payment, via: %i[get post]
|
|
29
29
|
end
|
data/lib/spree_vpago/version.rb
CHANGED
|
@@ -76,9 +76,9 @@ module Vpago
|
|
|
76
76
|
# somehow php counter part are not able to decode if the \n present.
|
|
77
77
|
hash.delete("\n")
|
|
78
78
|
end
|
|
79
|
-
|
|
79
|
+
|
|
80
80
|
def check_transaction_url
|
|
81
|
-
"#{host}
|
|
81
|
+
"#{host}/api/payment-gateway/v1/payments/check-transaction-2"
|
|
82
82
|
end
|
|
83
83
|
end
|
|
84
84
|
end
|
metadata
CHANGED
|
@@ -1,14 +1,14 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: spree_vpago
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 2.2.2.pre.
|
|
4
|
+
version: 2.2.2.pre.pre21
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- You
|
|
8
8
|
autorequire:
|
|
9
9
|
bindir: bin
|
|
10
10
|
cert_chain: []
|
|
11
|
-
date: 2026-
|
|
11
|
+
date: 2026-03-19 00:00:00.000000000 Z
|
|
12
12
|
dependencies:
|
|
13
13
|
- !ruby/object:Gem::Dependency
|
|
14
14
|
name: faraday
|
|
@@ -146,7 +146,7 @@ files:
|
|
|
146
146
|
- app/assets/images/payment_logos/wingpay.png
|
|
147
147
|
- app/assets/images/vpago/payway/abapay.png
|
|
148
148
|
- app/assets/images/vpago/payway/cards.png
|
|
149
|
-
- app/assets/javascripts/vpago/vpago_payments/
|
|
149
|
+
- app/assets/javascripts/vpago/vpago_payments/check_transaction_periodically.js
|
|
150
150
|
- app/assets/javascripts/vpago/vpago_payments/request_process_payment.js
|
|
151
151
|
- app/assets/javascripts/vpago/vpago_payments/user_informers/firebase.js
|
|
152
152
|
- app/controllers/.gitkeep
|
|
@@ -1,95 +0,0 @@
|
|
|
1
|
-
window.initPaymentProcessingListener = async function (
|
|
2
|
-
firebaseConfigs,
|
|
3
|
-
documentReferencePath,
|
|
4
|
-
successUrl
|
|
5
|
-
) {
|
|
6
|
-
function log(status, processing, reasonCode, reasonMessage) {
|
|
7
|
-
console.log(`Status: ${status}`);
|
|
8
|
-
console.log(`Reason Code: ${reasonCode}`);
|
|
9
|
-
console.log(
|
|
10
|
-
`Processing: ${processing ? "Processing..." : "No more process."}`
|
|
11
|
-
);
|
|
12
|
-
console.log(`Reason Message: ${reasonMessage}`);
|
|
13
|
-
}
|
|
14
|
-
|
|
15
|
-
window.listenToProcessingState({
|
|
16
|
-
firebaseConfigs,
|
|
17
|
-
documentReferencePath,
|
|
18
|
-
|
|
19
|
-
onPaymentIsProcessing(
|
|
20
|
-
orderState,
|
|
21
|
-
paymentState,
|
|
22
|
-
processing,
|
|
23
|
-
reasonCode,
|
|
24
|
-
reasonMessage
|
|
25
|
-
) {
|
|
26
|
-
log("Payment is processing", processing, reasonCode, reasonMessage);
|
|
27
|
-
},
|
|
28
|
-
|
|
29
|
-
onPaymentIsRetrying(
|
|
30
|
-
orderState,
|
|
31
|
-
paymentState,
|
|
32
|
-
processing,
|
|
33
|
-
reasonCode,
|
|
34
|
-
reasonMessage
|
|
35
|
-
) {
|
|
36
|
-
log("Payment is retrying", processing, reasonCode, reasonMessage);
|
|
37
|
-
},
|
|
38
|
-
|
|
39
|
-
onOrderIsProcessing(
|
|
40
|
-
orderState,
|
|
41
|
-
paymentState,
|
|
42
|
-
processing,
|
|
43
|
-
reasonCode,
|
|
44
|
-
reasonMessage
|
|
45
|
-
) {
|
|
46
|
-
log("Order is processing", processing, reasonCode, reasonMessage);
|
|
47
|
-
},
|
|
48
|
-
|
|
49
|
-
onOrderIsCompleted(
|
|
50
|
-
orderState,
|
|
51
|
-
paymentState,
|
|
52
|
-
processing,
|
|
53
|
-
reasonCode,
|
|
54
|
-
reasonMessage
|
|
55
|
-
) {
|
|
56
|
-
log("Order is completed", processing, reasonCode, reasonMessage);
|
|
57
|
-
},
|
|
58
|
-
|
|
59
|
-
onOrderProcessFailed(
|
|
60
|
-
orderState,
|
|
61
|
-
paymentState,
|
|
62
|
-
processing,
|
|
63
|
-
reasonCode,
|
|
64
|
-
reasonMessage
|
|
65
|
-
) {
|
|
66
|
-
log("Order process failed", processing, reasonCode, reasonMessage);
|
|
67
|
-
},
|
|
68
|
-
|
|
69
|
-
onPaymentProcessFailed(
|
|
70
|
-
orderState,
|
|
71
|
-
paymentState,
|
|
72
|
-
processing,
|
|
73
|
-
reasonCode,
|
|
74
|
-
reasonMessage
|
|
75
|
-
) {
|
|
76
|
-
log("Payment process failed", processing, reasonCode, reasonMessage);
|
|
77
|
-
},
|
|
78
|
-
|
|
79
|
-
onCompleted(
|
|
80
|
-
orderState,
|
|
81
|
-
paymentState,
|
|
82
|
-
processing,
|
|
83
|
-
reasonCode,
|
|
84
|
-
reasonMessage
|
|
85
|
-
) {
|
|
86
|
-
log(
|
|
87
|
-
"Completed — redirecting to success URL",
|
|
88
|
-
processing,
|
|
89
|
-
reasonCode,
|
|
90
|
-
reasonMessage
|
|
91
|
-
);
|
|
92
|
-
window.location.href = successUrl;
|
|
93
|
-
},
|
|
94
|
-
});
|
|
95
|
-
};
|