spree_vpago 2.3.14.pre.pre1 → 2.4.0.pre.pre1
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/Gemfile.lock +1 -1
- data/app/assets/config/spree_vpago_manifest.js +0 -2
- data/app/controllers/spree/admin/payment_payway_queriers_controller.rb +0 -7
- data/app/controllers/spree/{mini_app → miniapp}/acledas_controller.rb +6 -12
- data/app/controllers/spree/vpago_payments_controller.rb +3 -15
- data/app/helpers/vpago/vpago_payments_helper.rb +0 -6
- data/app/models/spree/gateway/acleda_mini_app.rb +6 -4
- data/app/models/spree/payment_method/cash_on.rb +0 -7
- data/app/models/vpago/order_decorator.rb +1 -1
- data/app/models/vpago/payment_decorator.rb +0 -4
- data/app/models/vpago/payment_method_decorator.rb +0 -14
- data/app/serializers/spree/v2/storefront/payment_method_serializer_decorator.rb +0 -6
- data/app/services/vpago/acleda_mini_app/session/create.rb +23 -45
- data/app/services/vpago/payment_finder.rb +0 -11
- data/app/services/vpago/payment_redirect_handler.rb +6 -6
- data/app/views/spree/admin/payments/source_views/_acleda_v2.html.erb +2 -2
- data/app/views/spree/admin/payments/source_views/_vattanac.html.erb +3 -3
- data/app/views/spree/vpago_payments/forms/spree/gateway/_acleda_mini_app.html.erb +79 -80
- data/app/views/spree/vpago_payments/success.html.erb +0 -2
- data/config/locales/en.yml +0 -1
- data/config/locales/km.yml +0 -1
- data/config/routes.rb +4 -17
- data/lib/spree_vpago/engine.rb +0 -1
- data/lib/spree_vpago/version.rb +1 -1
- data/lib/vpago/acleda_mini_app/checkout.rb +9 -5
- data/lib/vpago/payway_v2/payment_request_updater.rb +0 -5
- data/lib/vpago/payway_v2/transaction_status.rb +0 -2
- data/lib/vpago/payway_v2/transaction_status_v2.rb +0 -2
- data/lib/vpago/true_money/base.rb +1 -1
- data/lib/vpago/true_money/transaction_status.rb +1 -1
- data/lib/vpago/vattanac/base.rb +2 -3
- data/lib/vpago/vattanac/transaction_status.rb +1 -17
- data/lib/vpago/wing_sdk/base.rb +1 -1
- metadata +3 -27
- data/app/assets/javascripts/vpago/wing_mini_app/login.js +0 -75
- data/app/assets/javascripts/vpago/wing_mini_app/web_jsbridge.bundle.js +0 -1507
- data/app/controllers/concerns/spree/mini_app_concern.rb +0 -25
- data/app/controllers/spree/admin/payment_acleda_v2_base_controller.rb +0 -21
- data/app/controllers/spree/admin/payment_acleda_v2_checkers_controller.rb +0 -26
- data/app/controllers/spree/admin/payment_acleda_v2_queriers_controller.rb +0 -38
- data/app/controllers/spree/admin/payment_vattanac_base_controller.rb +0 -21
- data/app/controllers/spree/admin/payment_vattanac_checkers_controller.rb +0 -26
- data/app/controllers/spree/admin/payment_vattanac_queriers_controller.rb +0 -38
- data/app/controllers/spree/mini_app/wings_controller.rb +0 -58
- data/app/models/spree/gateway/wing_mini_app.rb +0 -58
- data/app/services/vpago/wing_mini_app/session/create.rb +0 -55
- data/app/views/layouts/wing_mini_app.html.erb +0 -20
- data/app/views/spree/admin/payments/source_views/_wing_mini_app.html.erb +0 -6
- data/app/views/spree/mini_app/wings/show.html.erb +0 -44
- data/app/views/spree/vpago_payments/_success_script.html.erb +0 -7
- data/app/views/spree/vpago_payments/forms/spree/gateway/_wing_mini_app.html.erb +0 -88
- data/app/views/spree/vpago_payments/processing_scripts/spree/gateway/_wing_mini_app.html.erb +0 -15
- data/lib/vpago/acleda_mini_app/session_hash_validator.rb +0 -35
- data/lib/vpago/acleda_v2/payment_request_updater.rb +0 -54
- data/lib/vpago/http_timeouts.rb +0 -6
- data/lib/vpago/vattanac/payment_request_updater.rb +0 -54
- data/lib/vpago/wing_mini_app/checkout.rb +0 -60
- data/lib/vpago/wing_mini_app/webhook_verifier.rb +0 -78
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 2b281c3ae420620dbd3d1da80ed2bc713c9283292484c1812cd1e9c979e6bf52
|
|
4
|
+
data.tar.gz: 70b7603d37c2c5e8f434e1ab333e622619296fd1ced75642ea9c0512a7591eb1
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 718d7eb47ff0a91b7cbcd43d13bd28f4808e008bed9ebee489c913af2d18d5069b5bdc4f06cca8e57693559e96da51a7af8c6e8843e5e01952898c7853c919e1
|
|
7
|
+
data.tar.gz: dd5f68ec20858da961d36f88a488bd3906d0623baa9f88a3811bbe10957ebd93bf891d047df9b2b8123a549d6881ef8ef32e1c7674144e6dd7901c779e79ae8b
|
data/Gemfile.lock
CHANGED
|
@@ -2,5 +2,3 @@
|
|
|
2
2
|
//= link vpago/vpago_payments/check_transaction_periodically.js
|
|
3
3
|
//= link vpago/vpago_payments/request_process_payment.js
|
|
4
4
|
//= link vpago/vpago_payments/user_informers/firebase.js
|
|
5
|
-
//= link vpago/wing_mini_app/web_jsbridge.bundle.js
|
|
6
|
-
//= link vpago/wing_mini_app/login.js
|
|
@@ -16,13 +16,6 @@ module Spree
|
|
|
16
16
|
flash[:error] = Spree.t('vpago.payments.payment_not_found_with_error', error: tran_status.error_message)
|
|
17
17
|
end
|
|
18
18
|
|
|
19
|
-
redirect_to admin_order_payment_path(order_id: @payment.order.number, id: @payment.number)
|
|
20
|
-
rescue Faraday::TimeoutError, Faraday::ConnectionFailed => e
|
|
21
|
-
VpagoLogger.error(
|
|
22
|
-
label: 'Spree::Admin::PaymentPaywayQueriersController#show gateway_timeout',
|
|
23
|
-
data: { payment_number: @payment.number, error_class: e.class.name, error_message: e.message }
|
|
24
|
-
)
|
|
25
|
-
flash[:error] = Spree.t('vpago.payments.gateway_timeout')
|
|
26
19
|
redirect_to admin_order_payment_path(order_id: @payment.order.number, id: @payment.number)
|
|
27
20
|
end
|
|
28
21
|
|
|
@@ -1,27 +1,21 @@
|
|
|
1
1
|
module Spree
|
|
2
|
-
module
|
|
2
|
+
module Miniapp
|
|
3
3
|
# Partner Session Initialization API (ACLEDA Mini App Integration Spec, Step 01).
|
|
4
|
-
# ACLEDA POSTs { phone, first_name, last_name }
|
|
5
|
-
#
|
|
4
|
+
# ACLEDA (server-to-server) POSTs { phone, first_name, last_name }; we return a
|
|
5
|
+
# session-based miniAppUrl for ACLEDA to open in the WebView.
|
|
6
6
|
class AcledasController < Spree::Api::V2::BaseController
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
PROVIDER = 'acleda_bank'.freeze
|
|
10
|
-
|
|
11
|
-
# POST /mini_app/acleda
|
|
7
|
+
# POST /miniapp/acleda
|
|
12
8
|
def create
|
|
13
9
|
result = ::Vpago::AcledaMiniApp::Session::Create.call(
|
|
14
10
|
phone: session_params[:phone],
|
|
15
11
|
first_name: session_params[:first_name],
|
|
16
|
-
last_name: session_params[:last_name]
|
|
17
|
-
signature: request.headers['X-Acleda-Signature'],
|
|
18
|
-
gate: session_gate(PROVIDER)
|
|
12
|
+
last_name: session_params[:last_name]
|
|
19
13
|
)
|
|
20
14
|
|
|
21
15
|
if result.success?
|
|
22
16
|
render json: { message: 'SUCCESS', miniAppUrl: result.value[:mini_app_url] }
|
|
23
17
|
else
|
|
24
|
-
render json: { message: 'FAILED', error: result.error.to_s }, status:
|
|
18
|
+
render json: { message: 'FAILED', error: result.error.to_s }, status: :unprocessable_entity
|
|
25
19
|
end
|
|
26
20
|
end
|
|
27
21
|
|
|
@@ -24,12 +24,6 @@ module Spree
|
|
|
24
24
|
def processing
|
|
25
25
|
@order = @payment.order
|
|
26
26
|
|
|
27
|
-
# Common, not an edge case: the gateway callback or the checkout page's transaction
|
|
28
|
-
# checker often completes the order before the browser lands here. Skipping this page
|
|
29
|
-
# also skips its Firebase listener, so success must post order_is_completed itself
|
|
30
|
-
# (render_success_script) or an embedding iframe modal never closes.
|
|
31
|
-
return redirect_to @payment.success_url, allow_other_host: true if @order.completed?
|
|
32
|
-
|
|
33
27
|
VpagoLogger.log(label: 'Spree::VpagoPaymentsController#processing', data: vpago_log_context)
|
|
34
28
|
end
|
|
35
29
|
|
|
@@ -66,12 +60,6 @@ module Spree
|
|
|
66
60
|
else
|
|
67
61
|
render json: { status: :pending }, status: :ok
|
|
68
62
|
end
|
|
69
|
-
rescue Faraday::TimeoutError, Faraday::ConnectionFailed => e
|
|
70
|
-
VpagoLogger.error(
|
|
71
|
-
label: 'Spree::VpagoPaymentsController#check_transaction gateway_timeout',
|
|
72
|
-
data: vpago_log_context(error_class: e.class.name, error_message: e.message)
|
|
73
|
-
)
|
|
74
|
-
render json: { status: :pending }, status: :ok
|
|
75
63
|
end
|
|
76
64
|
|
|
77
65
|
# POST
|
|
@@ -158,9 +146,9 @@ module Spree
|
|
|
158
146
|
raise ActiveRecord::RecordNotFound unless @payment.present?
|
|
159
147
|
end
|
|
160
148
|
|
|
161
|
-
#
|
|
162
|
-
#
|
|
163
|
-
#
|
|
149
|
+
# frame-ancestors (set above) supersedes X-Frame-Options in modern
|
|
150
|
+
# browsers, but the default SAMEORIGIN header would still block legacy
|
|
151
|
+
# browsers from embedding these pages, so drop it for the iframe actions.
|
|
164
152
|
def allow_iframe_embedding
|
|
165
153
|
response.headers.delete('X-Frame-Options')
|
|
166
154
|
end
|
|
@@ -13,12 +13,6 @@ module Vpago
|
|
|
13
13
|
render partial: 'spree/vpago_payments/transaction_checker'
|
|
14
14
|
end
|
|
15
15
|
|
|
16
|
-
# Host apps override success.html.erb; call this from every override so an
|
|
17
|
-
# embedding iframe modal still learns the order completed.
|
|
18
|
-
def render_success_script
|
|
19
|
-
render partial: 'spree/vpago_payments/success_script'
|
|
20
|
-
end
|
|
21
|
-
|
|
22
16
|
# Each payment method may have their own additional processing script,
|
|
23
17
|
# so we will look for the partial based on the payment method class name.
|
|
24
18
|
#
|
|
@@ -1,16 +1,18 @@
|
|
|
1
1
|
module Spree
|
|
2
2
|
# ACLEDA Mini App payment method.
|
|
3
3
|
#
|
|
4
|
-
# Reuses the ACLEDA V2 integration in deeplink mode:
|
|
5
|
-
#
|
|
6
|
-
#
|
|
4
|
+
# Reuses the ACLEDA V2 integration in deeplink mode: the deeplink produced by
|
|
5
|
+
# ACLEDA's openSessionV2 API is handed to the ACLEDA super-app through the
|
|
6
|
+
# `acledaJSBridge` (startPayment) instead of redirecting the page. Server-side
|
|
7
|
+
# verification reuses AcledaV2's #check_transaction (getTxnStatus).
|
|
7
8
|
class Gateway::AcledaMiniApp < Gateway::AcledaV2
|
|
8
9
|
# override: partial to render in admin / checkout form lookup
|
|
9
10
|
def method_type
|
|
10
11
|
'acleda_mini_app'
|
|
11
12
|
end
|
|
12
13
|
|
|
13
|
-
# The mini app always
|
|
14
|
+
# The mini app always uses the deeplink + JS bridge, so admins don't need to
|
|
15
|
+
# set the ACLEDA V2 mode.
|
|
14
16
|
def deeplink?
|
|
15
17
|
true
|
|
16
18
|
end
|
|
@@ -11,12 +11,5 @@ module Spree
|
|
|
11
11
|
def auto_capture?
|
|
12
12
|
true
|
|
13
13
|
end
|
|
14
|
-
|
|
15
|
-
# override: Spree::Payment#cancel! calls payment_method.cancel(response_code, payment).
|
|
16
|
-
# Cash has no gateway to void against, so acknowledge success and let the payment
|
|
17
|
-
# transition to `void`.
|
|
18
|
-
def cancel(_response_code, _payment = nil)
|
|
19
|
-
ActiveMerchant::Billing::Response.new(true, 'Cash On: Payment has been canceled.')
|
|
20
|
-
end
|
|
21
14
|
end
|
|
22
15
|
end
|
|
@@ -10,7 +10,6 @@ module Vpago
|
|
|
10
10
|
TYPE_TRUE_MONEY = 'Spree::Gateway::TrueMoney'.freeze
|
|
11
11
|
TYPE_VATTANAC = 'Spree::Gateway::Vattanac'.freeze
|
|
12
12
|
TYPE_VATTANAC_MINI_APP = 'Spree::Gateway::VattanacMiniApp'.freeze
|
|
13
|
-
TYPE_WING_MINI_APP = 'Spree::Gateway::WingMiniApp'.freeze
|
|
14
13
|
TYPE_CASH_ON = 'Spree::PaymentMethod::CashOn'.freeze
|
|
15
14
|
|
|
16
15
|
def self.prepended(base)
|
|
@@ -29,7 +28,6 @@ module Vpago
|
|
|
29
28
|
Spree::PaymentMethod::TYPE_ACLEDA_MINI_APP,
|
|
30
29
|
Spree::PaymentMethod::TYPE_VATTANAC,
|
|
31
30
|
Spree::PaymentMethod::TYPE_VATTANAC_MINI_APP,
|
|
32
|
-
Spree::PaymentMethod::TYPE_WING_MINI_APP,
|
|
33
31
|
Spree::PaymentMethod::TYPE_TRUE_MONEY,
|
|
34
32
|
Spree::PaymentMethod::TYPE_CASH_ON
|
|
35
33
|
]
|
|
@@ -84,10 +82,6 @@ module Vpago
|
|
|
84
82
|
::Vpago::Acleda::PaymentRequestUpdater
|
|
85
83
|
elsif type_acleda_mobile?
|
|
86
84
|
::Vpago::AcledaMobile::PaymentRequestUpdater
|
|
87
|
-
elsif type_acleda_v2?
|
|
88
|
-
::Vpago::AcledaV2::PaymentRequestUpdater
|
|
89
|
-
elsif type_vattanac?
|
|
90
|
-
::Vpago::Vattanac::PaymentRequestUpdater
|
|
91
85
|
end
|
|
92
86
|
end
|
|
93
87
|
|
|
@@ -119,18 +113,10 @@ module Vpago
|
|
|
119
113
|
type == Spree::PaymentMethod::TYPE_WINGSDK
|
|
120
114
|
end
|
|
121
115
|
|
|
122
|
-
def type_vattanac?
|
|
123
|
-
type == Spree::PaymentMethod::TYPE_VATTANAC
|
|
124
|
-
end
|
|
125
|
-
|
|
126
116
|
def type_vattanac_mini_app?
|
|
127
117
|
type == Spree::PaymentMethod::TYPE_VATTANAC_MINI_APP
|
|
128
118
|
end
|
|
129
119
|
|
|
130
|
-
def type_wing_mini_app?
|
|
131
|
-
type == Spree::PaymentMethod::TYPE_WING_MINI_APP
|
|
132
|
-
end
|
|
133
|
-
|
|
134
120
|
def type_true_money?
|
|
135
121
|
type == Spree::PaymentMethod::TYPE_TRUE_MONEY
|
|
136
122
|
end
|
|
@@ -14,12 +14,6 @@ module Spree
|
|
|
14
14
|
|
|
15
15
|
pref.blank? || pref[:payment_option].blank? ? payment_method.method_type : pref[:payment_option]
|
|
16
16
|
end
|
|
17
|
-
|
|
18
|
-
# Overried the payment method type to show all payment methods as one list on App.
|
|
19
|
-
# Controlled by ENV["PAYMENT_METHOD_VIEW"] = "split" | "join" (default: "join").
|
|
20
|
-
base.attribute :type do |payment_method|
|
|
21
|
-
ENV.fetch('PAYMENT_METHOD_VIEW', 'join') == 'split' ? payment_method.type : 'payment_method'
|
|
22
|
-
end
|
|
23
17
|
end
|
|
24
18
|
end
|
|
25
19
|
end
|
|
@@ -3,32 +3,20 @@ module Vpago
|
|
|
3
3
|
module Session
|
|
4
4
|
# Partner Session Initialization (ACLEDA Mini App Integration Spec, Step 01).
|
|
5
5
|
#
|
|
6
|
-
# ACLEDA
|
|
7
|
-
#
|
|
8
|
-
# a session
|
|
9
|
-
#
|
|
6
|
+
# ACLEDA calls POST /miniapp/acleda with { phone, first_name, last_name }.
|
|
7
|
+
# We find or create the customer (tagged with the acleda_bank identity),
|
|
8
|
+
# mint a session JWT, and return a session-based miniAppUrl for ACLEDA to
|
|
9
|
+
# open in the WebView. The generic session_id OAuth grant validates the JWT
|
|
10
|
+
# when the WebView later authenticates.
|
|
10
11
|
class Create
|
|
11
12
|
prepend Spree::ServiceModule::Base
|
|
12
13
|
|
|
13
|
-
|
|
14
|
-
# silently breaks this object as a Hash key.
|
|
15
|
-
#
|
|
16
|
-
# `gate` answers who is calling, from where and how often. The controller builds it:
|
|
17
|
-
# the key header and the address exist only on the request.
|
|
18
|
-
def call(gate:, phone: nil, first_name: nil, last_name: nil, signature: nil)
|
|
14
|
+
def call(phone: nil, first_name: nil, last_name: nil)
|
|
19
15
|
return failure(nil, 'phone is required') if phone.blank?
|
|
20
16
|
|
|
21
17
|
@phone = phone
|
|
22
18
|
@first_name = first_name
|
|
23
19
|
@last_name = last_name
|
|
24
|
-
@signature = signature
|
|
25
|
-
@gate = gate
|
|
26
|
-
|
|
27
|
-
return failure({ status: :unauthorized }, 'missing or unknown api key') unless gate.api_key_accepted?
|
|
28
|
-
return failure({ status: :forbidden }, 'address not allowed') unless gate.address_allowed?
|
|
29
|
-
return failure(nil, 'invalid signature') unless valid_signature?
|
|
30
|
-
return failure(nil, 'phone is invalid') if intel_phone.blank?
|
|
31
|
-
return failure({ status: :too_many_requests }, 'too many requests') if gate.session_exceeded?(phone: intel_phone)
|
|
32
20
|
|
|
33
21
|
user = find_or_create_user
|
|
34
22
|
return failure(user, 'user creation failed') if user.nil? || !user.persisted?
|
|
@@ -38,20 +26,7 @@ module Vpago
|
|
|
38
26
|
|
|
39
27
|
private
|
|
40
28
|
|
|
41
|
-
attr_reader :phone, :first_name, :last_name
|
|
42
|
-
|
|
43
|
-
# Only asked where this call would mint an account — the damage a leaked key does.
|
|
44
|
-
# Returning customers never spend that quota.
|
|
45
|
-
def new_user_throttled?
|
|
46
|
-
!acleda_identity.persisted? && find_existing_user.nil? && gate.new_user_exceeded?(phone: intel_phone)
|
|
47
|
-
end
|
|
48
|
-
|
|
49
|
-
def valid_signature?
|
|
50
|
-
::Vpago::AcledaMiniApp::SessionHashValidator.new(
|
|
51
|
-
phone: phone, first_name: first_name, last_name: last_name, hash: signature,
|
|
52
|
-
secret_key: gate.mini_app&.preferred_secret_key
|
|
53
|
-
).call
|
|
54
|
-
end
|
|
29
|
+
attr_reader :phone, :first_name, :last_name
|
|
55
30
|
|
|
56
31
|
def find_or_create_user
|
|
57
32
|
identity = acleda_identity
|
|
@@ -59,10 +34,9 @@ module Vpago
|
|
|
59
34
|
# Returning customer: the ACLEDA identity already points at a user.
|
|
60
35
|
return identity.user if identity.persisted?
|
|
61
36
|
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
#
|
|
65
|
-
# tag them so the lookup above hits next time.
|
|
37
|
+
# New to ACLEDA: reuse a customer matched by phone, otherwise build one,
|
|
38
|
+
# then tag them with the acleda_bank identity so the lookup above hits
|
|
39
|
+
# next time.
|
|
66
40
|
user = find_existing_user || build_user
|
|
67
41
|
identity.name = full_name
|
|
68
42
|
user.user_identity_providers << identity
|
|
@@ -71,17 +45,14 @@ module Vpago
|
|
|
71
45
|
user
|
|
72
46
|
end
|
|
73
47
|
|
|
74
|
-
# Memoized: #new_user_throttled? asks the same questions, and this row is the one
|
|
75
|
-
# that gets tagged onto the user.
|
|
76
48
|
def acleda_identity
|
|
77
|
-
|
|
49
|
+
SpreeCmCommissioner::UserIdentityProvider.acleda_bank.find_or_initialize_by(sub: phone)
|
|
78
50
|
end
|
|
79
51
|
|
|
80
52
|
def find_existing_user
|
|
81
|
-
return
|
|
82
|
-
return @find_existing_user = nil if intel_phone.blank?
|
|
53
|
+
return if intel_phone.blank?
|
|
83
54
|
|
|
84
|
-
|
|
55
|
+
Spree::User.by_non_tenant.find_by(intel_phone_number: intel_phone)
|
|
85
56
|
end
|
|
86
57
|
|
|
87
58
|
def build_user
|
|
@@ -96,14 +67,15 @@ module Vpago
|
|
|
96
67
|
end
|
|
97
68
|
|
|
98
69
|
def mini_app_url(user)
|
|
99
|
-
# A JWT signed with the user's secure_token. `session_key
|
|
100
|
-
# the OAuth grant routes it to the ACLEDA authenticator
|
|
70
|
+
# A JWT signed with the user's secure_token. Passed as `session_key` (not
|
|
71
|
+
# `session_id`) so the OAuth grant routes it to the ACLEDA authenticator,
|
|
72
|
+
# which enforces the signature.
|
|
101
73
|
session_key = SpreeCmCommissioner::UserSessionJwtToken.encode(
|
|
102
74
|
{ user_id: user.id },
|
|
103
75
|
user.reload.secure_token
|
|
104
76
|
)
|
|
105
77
|
|
|
106
|
-
"#{Spree::Store.default.formatted_url}/mini_app/acleda?session_key=#{session_key}"
|
|
78
|
+
"#{Spree::Store.default.formatted_url}/mini_app/acleda?session_key=#{session_key}&ds=#{CGI.escape(disable_services)}"
|
|
107
79
|
end
|
|
108
80
|
|
|
109
81
|
def full_name
|
|
@@ -115,6 +87,12 @@ module Vpago
|
|
|
115
87
|
|
|
116
88
|
@intel_phone = SpreeCmCommissioner::PhoneNumberParser.call(phone_number: phone).intel_phone_number
|
|
117
89
|
end
|
|
90
|
+
|
|
91
|
+
# Services to disable in the mini app storefront. Configurable per ACLEDA's
|
|
92
|
+
# requirement; defaults to none.
|
|
93
|
+
def disable_services
|
|
94
|
+
ENV.fetch('ACLEDA_MINI_APP_DISABLE_SERVICES', '')
|
|
95
|
+
end
|
|
118
96
|
end
|
|
119
97
|
end
|
|
120
98
|
end
|
|
@@ -19,13 +19,6 @@ module Vpago
|
|
|
19
19
|
payment = Spree::Payment.find_by!(number: payload['paymentId'])
|
|
20
20
|
payment.update(transaction_response: payload)
|
|
21
21
|
payment
|
|
22
|
-
elsif wing_mini_app_callback?
|
|
23
|
-
payment = Spree::Payment.find_by!(number: params_hash[:orderRef])
|
|
24
|
-
verifier = Vpago::WingMiniApp::WebhookVerifier.new(params_hash, payment)
|
|
25
|
-
raise "Wing Mini App webhook: verification failed for payment #{payment.number}" unless verifier.valid?
|
|
26
|
-
|
|
27
|
-
payment.update(transaction_response: params_hash)
|
|
28
|
-
payment
|
|
29
22
|
elsif acleda_v2_callback?
|
|
30
23
|
# ACLEDA V2's static portal callback echoes back _transactionid, which is
|
|
31
24
|
# the payment number we sent as transactionID/txid at openSessionV2.
|
|
@@ -49,9 +42,5 @@ module Vpago
|
|
|
49
42
|
def acleda_v2_callback?
|
|
50
43
|
params_hash[:_paymenttokenid].present?
|
|
51
44
|
end
|
|
52
|
-
|
|
53
|
-
def wing_mini_app_callback?
|
|
54
|
-
params_hash[:orderRef].present? && params_hash[:secretKey].present?
|
|
55
|
-
end
|
|
56
45
|
end
|
|
57
46
|
end
|
|
@@ -50,7 +50,7 @@ module Vpago
|
|
|
50
50
|
|
|
51
51
|
def process_acleda_gateway
|
|
52
52
|
data = {
|
|
53
|
-
href: "#{ENV.fetch('
|
|
53
|
+
href: "#{ENV.fetch('DEFAULT_URL_HOST', nil)}/acleda_redirects?payment_number=#{@payment.number}"
|
|
54
54
|
}
|
|
55
55
|
|
|
56
56
|
@redirect_options = data
|
|
@@ -81,7 +81,7 @@ module Vpago
|
|
|
81
81
|
def process_payway_v2_card
|
|
82
82
|
## TO DO: generate redirect url
|
|
83
83
|
data = {
|
|
84
|
-
href: "#{ENV.fetch('
|
|
84
|
+
href: "#{ENV.fetch('DEFAULT_URL_HOST', nil)}/payway_v2_card_popups?payment_number=#{@payment.number}"
|
|
85
85
|
}
|
|
86
86
|
|
|
87
87
|
@redirect_options = data
|
|
@@ -115,7 +115,7 @@ module Vpago
|
|
|
115
115
|
end
|
|
116
116
|
|
|
117
117
|
conn.post(abapay_payment.checkout_url, gateway_params) do |request|
|
|
118
|
-
request.headers['Referer'] = ENV.fetch('
|
|
118
|
+
request.headers['Referer'] = ENV.fetch('DEFAULT_URL_HOST', nil)
|
|
119
119
|
end
|
|
120
120
|
end
|
|
121
121
|
|
|
@@ -127,7 +127,7 @@ module Vpago
|
|
|
127
127
|
def process_payway_card
|
|
128
128
|
## TO DO: generate redirect url
|
|
129
129
|
data = {
|
|
130
|
-
href: "#{ENV.fetch('
|
|
130
|
+
href: "#{ENV.fetch('DEFAULT_URL_HOST', nil)}/payway_card_popups?payment_number=#{@payment.number}"
|
|
131
131
|
}
|
|
132
132
|
|
|
133
133
|
@redirect_options = data
|
|
@@ -135,7 +135,7 @@ module Vpago
|
|
|
135
135
|
|
|
136
136
|
def process_wing_gateway
|
|
137
137
|
data = {
|
|
138
|
-
href: "#{ENV.fetch('
|
|
138
|
+
href: "#{ENV.fetch('DEFAULT_URL_HOST', nil)}/wing_redirects?payment_number=#{@payment.number}"
|
|
139
139
|
}
|
|
140
140
|
|
|
141
141
|
@redirect_options = data
|
|
@@ -169,7 +169,7 @@ module Vpago
|
|
|
169
169
|
end
|
|
170
170
|
|
|
171
171
|
@response = conn.post(abapay_payment.action_url, gateway_params) do |request|
|
|
172
|
-
request.headers['Referer'] = ENV.fetch('
|
|
172
|
+
request.headers['Referer'] = ENV.fetch('DEFAULT_URL_HOST', nil)
|
|
173
173
|
end
|
|
174
174
|
end
|
|
175
175
|
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
<%= render 'spree/admin/payments/source_views/vpago_payment_tmpl',
|
|
2
2
|
payment: payment,
|
|
3
|
-
check_status_url:
|
|
4
|
-
heal_payment_url:
|
|
3
|
+
check_status_url: '',
|
|
4
|
+
heal_payment_url: '',
|
|
5
5
|
manual_update_payment_url: '' %>
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
<%= render 'spree/admin/payments/source_views/vpago_payment_tmpl',
|
|
2
|
-
payment: payment,
|
|
3
|
-
check_status_url:
|
|
4
|
-
heal_payment_url:
|
|
2
|
+
payment: payment,
|
|
3
|
+
check_status_url: '',
|
|
4
|
+
heal_payment_url: '',
|
|
5
5
|
manual_update_payment_url: ''
|
|
6
6
|
%>
|
|
@@ -2,93 +2,92 @@
|
|
|
2
2
|
opr_device = request.user_agent.to_s.downcase.match?(/iphone|ipad|ipod/) ? 'ios' : 'android'
|
|
3
3
|
checkout = ::Vpago::AcledaMiniApp::Checkout.new(@payment, { platform: 'app', opr_device: opr_device })
|
|
4
4
|
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
rescue StandardError => e
|
|
11
|
-
Rails.logger.error("[Acleda] openSessionV2 raised: #{e.message}")
|
|
12
|
-
nil
|
|
13
|
-
end
|
|
14
|
-
|
|
15
|
-
Rails.logger.error("[Acleda] openSessionV2 failed: #{checkout.error_message}") if checkout.failed?
|
|
5
|
+
begin
|
|
6
|
+
checkout.call
|
|
7
|
+
rescue => e
|
|
8
|
+
Rails.logger.error("Acleda Mini App checkout.call failed: #{e.message}")
|
|
9
|
+
end
|
|
16
10
|
%>
|
|
17
11
|
|
|
18
|
-
<p id="
|
|
12
|
+
<p id="unsupported-message"
|
|
19
13
|
style="margin-top: 10px; font-weight: bold; color: red; display: none;">
|
|
20
14
|
</p>
|
|
21
15
|
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
const openWallet = () => {
|
|
63
|
-
window.top.location.href = acledaDeeplink;
|
|
64
|
-
};
|
|
65
|
-
|
|
66
|
-
// So ask our web app, the page embedding this one, which *is* the top frame. It obeys
|
|
67
|
-
// only inside a bank mini app: anywhere else nothing intercepts the link and the checkout
|
|
68
|
-
// would really travel to ACLEDA's Play Store listing. Silence is fine — the button still works.
|
|
69
|
-
const askWebAppToOpen = () => {
|
|
70
|
-
window.parent.postMessage({ code: 'open_deeplink', url: acledaDeeplink }, '*');
|
|
16
|
+
<% if checkout.failed? %>
|
|
17
|
+
<script>
|
|
18
|
+
console.error("[Vpago] Acleda Mini App checkout error: <%= j checkout.error_message.to_s %>");
|
|
19
|
+
document.addEventListener("DOMContentLoaded", () => {
|
|
20
|
+
const loadingContainer = document.getElementById('vpago_loading_container');
|
|
21
|
+
if (loadingContainer) {
|
|
22
|
+
loadingContainer.textContent = "We couldn't start your payment. Please go back and try again.";
|
|
23
|
+
}
|
|
24
|
+
});
|
|
25
|
+
</script>
|
|
26
|
+
<% else %>
|
|
27
|
+
<script>
|
|
28
|
+
// ACLEDA JS bridge (unified iOS + Android). Defined before use so it is
|
|
29
|
+
// available when the native layer injects its handlers.
|
|
30
|
+
window.acledaJSBridge = window.acledaJSBridge || {
|
|
31
|
+
call: function (action, data = {}) {
|
|
32
|
+
const payload = { action, data };
|
|
33
|
+
|
|
34
|
+
// iOS WKWebView
|
|
35
|
+
if (
|
|
36
|
+
window.webkit &&
|
|
37
|
+
window.webkit.messageHandlers &&
|
|
38
|
+
window.webkit.messageHandlers.acledaIOSJSBridge
|
|
39
|
+
) {
|
|
40
|
+
window.webkit.messageHandlers.acledaIOSJSBridge.postMessage(payload);
|
|
41
|
+
return true;
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
// Android WebView
|
|
45
|
+
if (
|
|
46
|
+
window.acledaAndroidJSBridge &&
|
|
47
|
+
typeof window.acledaAndroidJSBridge.postMessage === "function"
|
|
48
|
+
) {
|
|
49
|
+
window.acledaAndroidJSBridge.postMessage(JSON.stringify(payload));
|
|
50
|
+
return true;
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
console.warn("[acledaJSBridge] Native bridge not found");
|
|
54
|
+
return false;
|
|
55
|
+
}
|
|
71
56
|
};
|
|
72
57
|
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
const frame = document.createElement('iframe');
|
|
78
|
-
|
|
79
|
-
frame.style.display = 'none';
|
|
80
|
-
frame.src = acledaDeeplink;
|
|
58
|
+
function showRedirectContainer(buttonLabel, onClick) {
|
|
59
|
+
const loadingContainer = document.getElementById('vpago_loading_container');
|
|
60
|
+
const redirectContainer = document.getElementById('vpago_redirect_container');
|
|
61
|
+
const redirectButton = document.getElementById('vpago_redirect_button');
|
|
81
62
|
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
};
|
|
63
|
+
redirectButton.textContent = buttonLabel;
|
|
64
|
+
redirectButton.addEventListener('click', onClick);
|
|
85
65
|
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
66
|
+
loadingContainer.style.display = 'none';
|
|
67
|
+
redirectContainer.style.removeProperty('display');
|
|
68
|
+
}
|
|
89
69
|
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
70
|
+
document.addEventListener("DOMContentLoaded", () => {
|
|
71
|
+
const acledaDeeplink = "<%= raw checkout.acleda_deeplink %>";
|
|
72
|
+
const processingUrl = "<%= raw @payment.processing_url %>";
|
|
73
|
+
|
|
74
|
+
// Native -> JS after payment completes. Primary completion signal; the
|
|
75
|
+
// transaction checker polling is the fallback.
|
|
76
|
+
window.onPaymentResult = function (result) {
|
|
77
|
+
console.log("[acledaJSBridge] Payment result:", result);
|
|
78
|
+
// result.batchId, result.status = "success" | "failed" | "cancelled"
|
|
79
|
+
window.location.href = processingUrl;
|
|
80
|
+
};
|
|
81
|
+
|
|
82
|
+
const startPayment = () => window.acledaJSBridge.call("startPayment", { acleda_deeplink: acledaDeeplink });
|
|
83
|
+
|
|
84
|
+
if (startPayment()) {
|
|
85
|
+
showRedirectContainer("Continue", startPayment);
|
|
86
|
+
} else {
|
|
87
|
+
const unsupported = document.getElementById('unsupported-message');
|
|
88
|
+
unsupported.style.display = 'block';
|
|
89
|
+
unsupported.innerText = 'Unsupported environment';
|
|
90
|
+
}
|
|
91
|
+
});
|
|
92
|
+
</script>
|
|
93
|
+
<% end %>
|