spree_vpago 2.3.10 → 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/controllers/spree/admin/payment_payway_queriers_controller.rb +0 -7
- data/app/controllers/spree/miniapp/acledas_controller.rb +29 -0
- data/app/controllers/spree/vpago_payments_controller.rb +0 -6
- data/app/models/spree/gateway/acleda_mini_app.rb +20 -0
- 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 +4 -0
- data/app/models/vpago/payment_method_decorator.rb +6 -0
- data/app/services/vpago/acleda_mini_app/session/create.rb +99 -0
- data/app/services/vpago/payment_redirect_handler.rb +6 -6
- data/app/views/spree/admin/payments/source_views/_acleda_mini_app.html.erb +6 -0
- data/app/views/spree/vpago_payments/forms/spree/gateway/_acleda_mini_app.html.erb +93 -0
- data/config/locales/en.yml +0 -1
- data/config/locales/km.yml +0 -1
- data/config/routes.rb +7 -0
- data/lib/spree_vpago/engine.rb +1 -0
- data/lib/spree_vpago/version.rb +1 -1
- data/lib/vpago/acleda_mini_app/checkout.rb +23 -0
- 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/wing_sdk/base.rb +1 -1
- metadata +10 -5
- data/lib/vpago/http_timeouts.rb +0 -6
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
|
@@ -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
|
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
module Spree
|
|
2
|
+
module Miniapp
|
|
3
|
+
# Partner Session Initialization API (ACLEDA Mini App Integration Spec, Step 01).
|
|
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
|
+
class AcledasController < Spree::Api::V2::BaseController
|
|
7
|
+
# POST /miniapp/acleda
|
|
8
|
+
def create
|
|
9
|
+
result = ::Vpago::AcledaMiniApp::Session::Create.call(
|
|
10
|
+
phone: session_params[:phone],
|
|
11
|
+
first_name: session_params[:first_name],
|
|
12
|
+
last_name: session_params[:last_name]
|
|
13
|
+
)
|
|
14
|
+
|
|
15
|
+
if result.success?
|
|
16
|
+
render json: { message: 'SUCCESS', miniAppUrl: result.value[:mini_app_url] }
|
|
17
|
+
else
|
|
18
|
+
render json: { message: 'FAILED', error: result.error.to_s }, status: :unprocessable_entity
|
|
19
|
+
end
|
|
20
|
+
end
|
|
21
|
+
|
|
22
|
+
private
|
|
23
|
+
|
|
24
|
+
def session_params
|
|
25
|
+
params.permit(:phone, :first_name, :last_name)
|
|
26
|
+
end
|
|
27
|
+
end
|
|
28
|
+
end
|
|
29
|
+
end
|
|
@@ -60,12 +60,6 @@ module Spree
|
|
|
60
60
|
else
|
|
61
61
|
render json: { status: :pending }, status: :ok
|
|
62
62
|
end
|
|
63
|
-
rescue Faraday::TimeoutError, Faraday::ConnectionFailed => e
|
|
64
|
-
VpagoLogger.error(
|
|
65
|
-
label: 'Spree::VpagoPaymentsController#check_transaction gateway_timeout',
|
|
66
|
-
data: vpago_log_context(error_class: e.class.name, error_message: e.message)
|
|
67
|
-
)
|
|
68
|
-
render json: { status: :pending }, status: :ok
|
|
69
63
|
end
|
|
70
64
|
|
|
71
65
|
# POST
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
module Spree
|
|
2
|
+
# ACLEDA Mini App payment method.
|
|
3
|
+
#
|
|
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).
|
|
8
|
+
class Gateway::AcledaMiniApp < Gateway::AcledaV2
|
|
9
|
+
# override: partial to render in admin / checkout form lookup
|
|
10
|
+
def method_type
|
|
11
|
+
'acleda_mini_app'
|
|
12
|
+
end
|
|
13
|
+
|
|
14
|
+
# The mini app always uses the deeplink + JS bridge, so admins don't need to
|
|
15
|
+
# set the ACLEDA V2 mode.
|
|
16
|
+
def deeplink?
|
|
17
|
+
true
|
|
18
|
+
end
|
|
19
|
+
end
|
|
20
|
+
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
|
|
@@ -6,6 +6,7 @@ module Vpago
|
|
|
6
6
|
TYPE_ACLEDA = 'Spree::Gateway::Acleda'.freeze
|
|
7
7
|
TYPE_ACLEDA_V2 = 'Spree::Gateway::AcledaV2'.freeze
|
|
8
8
|
TYPE_ACLEDA_MOBILE = 'Spree::Gateway::AcledaMobile'.freeze
|
|
9
|
+
TYPE_ACLEDA_MINI_APP = 'Spree::Gateway::AcledaMiniApp'.freeze
|
|
9
10
|
TYPE_TRUE_MONEY = 'Spree::Gateway::TrueMoney'.freeze
|
|
10
11
|
TYPE_VATTANAC = 'Spree::Gateway::Vattanac'.freeze
|
|
11
12
|
TYPE_VATTANAC_MINI_APP = 'Spree::Gateway::VattanacMiniApp'.freeze
|
|
@@ -24,6 +25,7 @@ module Vpago
|
|
|
24
25
|
Spree::PaymentMethod::TYPE_ACLEDA,
|
|
25
26
|
Spree::PaymentMethod::TYPE_ACLEDA_V2,
|
|
26
27
|
Spree::PaymentMethod::TYPE_ACLEDA_MOBILE,
|
|
28
|
+
Spree::PaymentMethod::TYPE_ACLEDA_MINI_APP,
|
|
27
29
|
Spree::PaymentMethod::TYPE_VATTANAC,
|
|
28
30
|
Spree::PaymentMethod::TYPE_VATTANAC_MINI_APP,
|
|
29
31
|
Spree::PaymentMethod::TYPE_TRUE_MONEY,
|
|
@@ -95,6 +97,10 @@ module Vpago
|
|
|
95
97
|
type == Spree::PaymentMethod::TYPE_ACLEDA_V2
|
|
96
98
|
end
|
|
97
99
|
|
|
100
|
+
def type_acleda_mini_app?
|
|
101
|
+
type == Spree::PaymentMethod::TYPE_ACLEDA_MINI_APP
|
|
102
|
+
end
|
|
103
|
+
|
|
98
104
|
def type_payway?
|
|
99
105
|
type == Spree::PaymentMethod::TYPE_PAYWAY
|
|
100
106
|
end
|
|
@@ -0,0 +1,99 @@
|
|
|
1
|
+
module Vpago
|
|
2
|
+
module AcledaMiniApp
|
|
3
|
+
module Session
|
|
4
|
+
# Partner Session Initialization (ACLEDA Mini App Integration Spec, Step 01).
|
|
5
|
+
#
|
|
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.
|
|
11
|
+
class Create
|
|
12
|
+
prepend Spree::ServiceModule::Base
|
|
13
|
+
|
|
14
|
+
def call(phone: nil, first_name: nil, last_name: nil)
|
|
15
|
+
return failure(nil, 'phone is required') if phone.blank?
|
|
16
|
+
|
|
17
|
+
@phone = phone
|
|
18
|
+
@first_name = first_name
|
|
19
|
+
@last_name = last_name
|
|
20
|
+
|
|
21
|
+
user = find_or_create_user
|
|
22
|
+
return failure(user, 'user creation failed') if user.nil? || !user.persisted?
|
|
23
|
+
|
|
24
|
+
success(mini_app_url: mini_app_url(user))
|
|
25
|
+
end
|
|
26
|
+
|
|
27
|
+
private
|
|
28
|
+
|
|
29
|
+
attr_reader :phone, :first_name, :last_name
|
|
30
|
+
|
|
31
|
+
def find_or_create_user
|
|
32
|
+
identity = acleda_identity
|
|
33
|
+
|
|
34
|
+
# Returning customer: the ACLEDA identity already points at a user.
|
|
35
|
+
return identity.user if identity.persisted?
|
|
36
|
+
|
|
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.
|
|
40
|
+
user = find_existing_user || build_user
|
|
41
|
+
identity.name = full_name
|
|
42
|
+
user.user_identity_providers << identity
|
|
43
|
+
user.save
|
|
44
|
+
|
|
45
|
+
user
|
|
46
|
+
end
|
|
47
|
+
|
|
48
|
+
def acleda_identity
|
|
49
|
+
SpreeCmCommissioner::UserIdentityProvider.acleda_bank.find_or_initialize_by(sub: phone)
|
|
50
|
+
end
|
|
51
|
+
|
|
52
|
+
def find_existing_user
|
|
53
|
+
return if intel_phone.blank?
|
|
54
|
+
|
|
55
|
+
Spree::User.by_non_tenant.find_by(intel_phone_number: intel_phone)
|
|
56
|
+
end
|
|
57
|
+
|
|
58
|
+
def build_user
|
|
59
|
+
Spree::User.new(
|
|
60
|
+
first_name: first_name,
|
|
61
|
+
last_name: last_name,
|
|
62
|
+
phone_number: phone,
|
|
63
|
+
intel_phone_number: intel_phone,
|
|
64
|
+
password: SecureRandom.base64(16),
|
|
65
|
+
confirmed_at: Time.zone.now
|
|
66
|
+
)
|
|
67
|
+
end
|
|
68
|
+
|
|
69
|
+
def mini_app_url(user)
|
|
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.
|
|
73
|
+
session_key = SpreeCmCommissioner::UserSessionJwtToken.encode(
|
|
74
|
+
{ user_id: user.id },
|
|
75
|
+
user.reload.secure_token
|
|
76
|
+
)
|
|
77
|
+
|
|
78
|
+
"#{Spree::Store.default.formatted_url}/mini_app/acleda?session_key=#{session_key}&ds=#{CGI.escape(disable_services)}"
|
|
79
|
+
end
|
|
80
|
+
|
|
81
|
+
def full_name
|
|
82
|
+
[first_name, last_name].compact.join(' ').presence
|
|
83
|
+
end
|
|
84
|
+
|
|
85
|
+
def intel_phone
|
|
86
|
+
return @intel_phone if defined?(@intel_phone)
|
|
87
|
+
|
|
88
|
+
@intel_phone = SpreeCmCommissioner::PhoneNumberParser.call(phone_number: phone).intel_phone_number
|
|
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
|
|
96
|
+
end
|
|
97
|
+
end
|
|
98
|
+
end
|
|
99
|
+
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
|
|
|
@@ -0,0 +1,93 @@
|
|
|
1
|
+
<%
|
|
2
|
+
opr_device = request.user_agent.to_s.downcase.match?(/iphone|ipad|ipod/) ? 'ios' : 'android'
|
|
3
|
+
checkout = ::Vpago::AcledaMiniApp::Checkout.new(@payment, { platform: 'app', opr_device: opr_device })
|
|
4
|
+
|
|
5
|
+
begin
|
|
6
|
+
checkout.call
|
|
7
|
+
rescue => e
|
|
8
|
+
Rails.logger.error("Acleda Mini App checkout.call failed: #{e.message}")
|
|
9
|
+
end
|
|
10
|
+
%>
|
|
11
|
+
|
|
12
|
+
<p id="unsupported-message"
|
|
13
|
+
style="margin-top: 10px; font-weight: bold; color: red; display: none;">
|
|
14
|
+
</p>
|
|
15
|
+
|
|
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
|
+
}
|
|
56
|
+
};
|
|
57
|
+
|
|
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');
|
|
62
|
+
|
|
63
|
+
redirectButton.textContent = buttonLabel;
|
|
64
|
+
redirectButton.addEventListener('click', onClick);
|
|
65
|
+
|
|
66
|
+
loadingContainer.style.display = 'none';
|
|
67
|
+
redirectContainer.style.removeProperty('display');
|
|
68
|
+
}
|
|
69
|
+
|
|
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 %>
|
data/config/locales/en.yml
CHANGED
|
@@ -35,6 +35,5 @@ en:
|
|
|
35
35
|
failed_require_updated_reason: "You must provide update reason"
|
|
36
36
|
payment_found_with_result: "Found payment with result: %{result}"
|
|
37
37
|
payment_not_found_with_error: "Payment not found with error: %{error}"
|
|
38
|
-
gateway_timeout: "The payment gateway did not respond in time. Please try again shortly."
|
|
39
38
|
query_status: "Query payment status"
|
|
40
39
|
confirm_manual_update: "Are you sure to update this order to complete"
|
data/config/locales/km.yml
CHANGED
|
@@ -31,6 +31,5 @@ spree:
|
|
|
31
31
|
failed_require_updated_reason: "អ្នកត្រូវតែផ្តល់ហេតុផល"
|
|
32
32
|
payment_found_with_result: "រកឃើញការទូទាត់ជាមួយលទ្ធផល %{result}"
|
|
33
33
|
payment_not_found_with_error: "ការទូទាត់មិនត្រូវបានរកឃើញដោយកំហុស: %{error}"
|
|
34
|
-
gateway_timeout: "ផ្នែកទូទាត់មិនបានឆ្លើយតបទាន់ពេលទេ។ សូមព្យាយាមម្តងទៀតក្នុងពេលឆាប់ៗនេះ។"
|
|
35
34
|
query_status: "សួរស្ថានភាពបង់ប្រាក់"
|
|
36
35
|
confirm_manual_update: "តើអ្នកប្រាកដជាធ្វើបច្ចុប្បន្នភាពការបញ្ជាទិញនេះដើម្បីបញ្ចប់"
|
data/config/routes.rb
CHANGED
|
@@ -17,6 +17,13 @@ Spree::Core::Engine.add_routes do
|
|
|
17
17
|
resources :transactions, only: [:show]
|
|
18
18
|
end
|
|
19
19
|
|
|
20
|
+
# ACLEDA Mini App session init (ACLEDA Mini App Integration Spec, Step 01).
|
|
21
|
+
# ACLEDA calls POST /miniapp/acleda with { phone, first_name, last_name }
|
|
22
|
+
# and receives a session-based miniAppUrl.
|
|
23
|
+
namespace :miniapp do
|
|
24
|
+
resources :acleda, only: [:create], controller: 'acledas'
|
|
25
|
+
end
|
|
26
|
+
|
|
20
27
|
resource :vpago_payments do
|
|
21
28
|
collection do
|
|
22
29
|
get :checkout
|
data/lib/spree_vpago/engine.rb
CHANGED
data/lib/spree_vpago/version.rb
CHANGED
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
module Vpago
|
|
2
|
+
module AcledaMiniApp
|
|
3
|
+
# ACLEDA Mini App checkout. Reuses ACLEDA V2's openSessionV2 flow to obtain a
|
|
4
|
+
# deeplink, which is passed to the ACLEDA super-app via the acledaJSBridge
|
|
5
|
+
# (startPayment) instead of redirecting the page.
|
|
6
|
+
class Checkout < Vpago::AcledaV2::Checkout
|
|
7
|
+
# The mini app always uses the deeplink + JS bridge, regardless of the
|
|
8
|
+
# gateway's configured mode.
|
|
9
|
+
def deeplink?
|
|
10
|
+
true
|
|
11
|
+
end
|
|
12
|
+
|
|
13
|
+
# The deeplink string handed to
|
|
14
|
+
# acledaJSBridge.call('startPayment', { acleda_deeplink: ... })
|
|
15
|
+
# Ensures openSessionV2 has run (persisting paymentTokenid for later
|
|
16
|
+
# getTxnStatus verification) before returning the deeplinkUrl.
|
|
17
|
+
def acleda_deeplink
|
|
18
|
+
call if @response.nil?
|
|
19
|
+
deeplink_url
|
|
20
|
+
end
|
|
21
|
+
end
|
|
22
|
+
end
|
|
23
|
+
end
|
|
@@ -28,11 +28,6 @@ module Vpago
|
|
|
28
28
|
elsif checker.failed?
|
|
29
29
|
mark_payment_as_failed(checker.error_message)
|
|
30
30
|
end
|
|
31
|
-
rescue Faraday::TimeoutError, Faraday::ConnectionFailed => e
|
|
32
|
-
VpagoLogger.error(
|
|
33
|
-
label: 'Vpago::PaywayV2::PaymentRequestUpdater#process_payment_status gateway_timeout',
|
|
34
|
-
data: { payment_number: @payment.number, error_class: e.class.name, error_message: e.message }
|
|
35
|
-
)
|
|
36
31
|
end
|
|
37
32
|
|
|
38
33
|
def mark_payment_as_success(checker)
|
|
@@ -37,8 +37,6 @@ module Vpago
|
|
|
37
37
|
def check_remote_status
|
|
38
38
|
conn = Faraday::Connection.new do |faraday|
|
|
39
39
|
faraday.request :url_encoded
|
|
40
|
-
faraday.options.open_timeout = Vpago::HttpTimeouts::OPEN_TIMEOUT
|
|
41
|
-
faraday.options.timeout = Vpago::HttpTimeouts::TIMEOUT
|
|
42
40
|
end
|
|
43
41
|
|
|
44
42
|
data = {
|
|
@@ -52,8 +52,6 @@ module Vpago
|
|
|
52
52
|
def check_remote_status
|
|
53
53
|
conn = Faraday::Connection.new do |faraday|
|
|
54
54
|
faraday.request :url_encoded
|
|
55
|
-
faraday.options.open_timeout = Vpago::HttpTimeouts::OPEN_TIMEOUT
|
|
56
|
-
faraday.options.timeout = Vpago::HttpTimeouts::TIMEOUT
|
|
57
55
|
end
|
|
58
56
|
|
|
59
57
|
data = {
|
|
@@ -100,7 +100,7 @@ module Vpago
|
|
|
100
100
|
end
|
|
101
101
|
|
|
102
102
|
def fetch_access_token
|
|
103
|
-
response = Faraday.
|
|
103
|
+
response = Faraday.post(
|
|
104
104
|
access_token_url,
|
|
105
105
|
URI.encode_www_form(
|
|
106
106
|
grant_type: 'client_credentials',
|
|
@@ -2,7 +2,7 @@ module Vpago
|
|
|
2
2
|
module TrueMoney
|
|
3
3
|
class TransactionStatus < Base
|
|
4
4
|
def call
|
|
5
|
-
@response = Faraday.
|
|
5
|
+
@response = Faraday.get(check_transaction_url, nil, default_headers)
|
|
6
6
|
end
|
|
7
7
|
|
|
8
8
|
def success?
|
data/lib/vpago/vattanac/base.rb
CHANGED
|
@@ -70,8 +70,7 @@ module Vpago
|
|
|
70
70
|
private
|
|
71
71
|
|
|
72
72
|
def fetch_access_token
|
|
73
|
-
response = Faraday.
|
|
74
|
-
.post(access_token_url, { username: username, password: password }.to_json, { 'Content-Type' => CONTENT_TYPE_JSON })
|
|
73
|
+
response = Faraday.post(access_token_url, { username: username, password: password }.to_json, { 'Content-Type' => CONTENT_TYPE_JSON })
|
|
75
74
|
|
|
76
75
|
raise "Access Token Error: #{response.status} - #{response.body}" unless response.success?
|
|
77
76
|
|
|
@@ -79,7 +78,7 @@ module Vpago
|
|
|
79
78
|
end
|
|
80
79
|
|
|
81
80
|
def post(url, body)
|
|
82
|
-
response = Faraday.
|
|
81
|
+
response = Faraday.post(url, body.to_json, default_headers)
|
|
83
82
|
parse_json(response.body)
|
|
84
83
|
end
|
|
85
84
|
end
|
data/lib/vpago/wing_sdk/base.rb
CHANGED
|
@@ -33,7 +33,7 @@ module Vpago
|
|
|
33
33
|
end
|
|
34
34
|
|
|
35
35
|
def return_url
|
|
36
|
-
"#{ENV.fetch('
|
|
36
|
+
"#{ENV.fetch('DEFAULT_URL_HOST', nil)}/webhook/wings/#{payment_number}/return?app_checkout=#{app_checkout}"
|
|
37
37
|
end
|
|
38
38
|
|
|
39
39
|
def app_checkout
|
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.
|
|
4
|
+
version: 2.4.0.pre.pre1
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- You
|
|
8
8
|
autorequire:
|
|
9
9
|
bindir: bin
|
|
10
10
|
cert_chain: []
|
|
11
|
-
date: 2026-08-
|
|
11
|
+
date: 2026-08-17 00:00:00.000000000 Z
|
|
12
12
|
dependencies:
|
|
13
13
|
- !ruby/object:Gem::Dependency
|
|
14
14
|
name: faraday
|
|
@@ -167,6 +167,7 @@ files:
|
|
|
167
167
|
- app/controllers/spree/admin/payouts_controller.rb
|
|
168
168
|
- app/controllers/spree/admin/suspicious_orders_controller.rb
|
|
169
169
|
- app/controllers/spree/api/v2/storefront/checkout_controller_decorator.rb
|
|
170
|
+
- app/controllers/spree/miniapp/acledas_controller.rb
|
|
170
171
|
- app/controllers/spree/payway_card_popups_controller.rb
|
|
171
172
|
- app/controllers/spree/payway_results_controller.rb
|
|
172
173
|
- app/controllers/spree/payway_v2_card_popups_controller.rb
|
|
@@ -192,6 +193,7 @@ files:
|
|
|
192
193
|
- app/models/.gitkeep
|
|
193
194
|
- app/models/concerns/vpago/payoutable.rb
|
|
194
195
|
- app/models/spree/gateway/acleda.rb
|
|
196
|
+
- app/models/spree/gateway/acleda_mini_app.rb
|
|
195
197
|
- app/models/spree/gateway/acleda_mobile.rb
|
|
196
198
|
- app/models/spree/gateway/acleda_v2.rb
|
|
197
199
|
- app/models/spree/gateway/payway.rb
|
|
@@ -256,6 +258,7 @@ files:
|
|
|
256
258
|
- app/serializers/spree/v2/storefront/payment_serializer_decorator.rb
|
|
257
259
|
- app/serializers/spree/v2/storefront/vpago_payment_source_serializer.rb
|
|
258
260
|
- app/services/.gitkeep
|
|
261
|
+
- app/services/vpago/acleda_mini_app/session/create.rb
|
|
259
262
|
- app/services/vpago/aes_encrypter.rb
|
|
260
263
|
- app/services/vpago/payment_finder.rb
|
|
261
264
|
- app/services/vpago/payment_processable.rb
|
|
@@ -283,6 +286,7 @@ files:
|
|
|
283
286
|
- app/views/spree/admin/payments/source_forms/_payment_payway.html.erb
|
|
284
287
|
- app/views/spree/admin/payments/source_forms/_payway_v2.html.erb
|
|
285
288
|
- app/views/spree/admin/payments/source_views/_acleda.html.erb
|
|
289
|
+
- app/views/spree/admin/payments/source_views/_acleda_mini_app.html.erb
|
|
286
290
|
- app/views/spree/admin/payments/source_views/_acleda_mobile.html.erb
|
|
287
291
|
- app/views/spree/admin/payments/source_views/_acleda_v2.html.erb
|
|
288
292
|
- app/views/spree/admin/payments/source_views/_payment_payway.html.erb
|
|
@@ -340,6 +344,7 @@ files:
|
|
|
340
344
|
- app/views/spree/payway_v2_card_popups/show.html.erb
|
|
341
345
|
- app/views/spree/vpago_payments/_transaction_checker.html.erb
|
|
342
346
|
- app/views/spree/vpago_payments/checkout.html.erb
|
|
347
|
+
- app/views/spree/vpago_payments/forms/spree/gateway/_acleda_mini_app.html.erb
|
|
343
348
|
- app/views/spree/vpago_payments/forms/spree/gateway/_acleda_v2.html.erb
|
|
344
349
|
- app/views/spree/vpago_payments/forms/spree/gateway/_payway_v2.html.erb
|
|
345
350
|
- app/views/spree/vpago_payments/forms/spree/gateway/_true_money.html.erb
|
|
@@ -391,6 +396,7 @@ files:
|
|
|
391
396
|
- lib/vpago/acleda/deeplink_checkout.rb
|
|
392
397
|
- lib/vpago/acleda/payment_request_updater.rb
|
|
393
398
|
- lib/vpago/acleda/transaction_status.rb
|
|
399
|
+
- lib/vpago/acleda_mini_app/checkout.rb
|
|
394
400
|
- lib/vpago/acleda_mobile/base.rb
|
|
395
401
|
- lib/vpago/acleda_mobile/callback_validator.php
|
|
396
402
|
- lib/vpago/acleda_mobile/callback_validator.rb
|
|
@@ -401,7 +407,6 @@ files:
|
|
|
401
407
|
- lib/vpago/acleda_v2/base.rb
|
|
402
408
|
- lib/vpago/acleda_v2/checkout.rb
|
|
403
409
|
- lib/vpago/acleda_v2/transaction_status.rb
|
|
404
|
-
- lib/vpago/http_timeouts.rb
|
|
405
410
|
- lib/vpago/payment_amount_calculator.rb
|
|
406
411
|
- lib/vpago/payment_request_updater.rb
|
|
407
412
|
- lib/vpago/payment_status_marker.rb
|
|
@@ -457,9 +462,9 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
|
457
462
|
version: 3.2.0
|
|
458
463
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
|
459
464
|
requirements:
|
|
460
|
-
- - "
|
|
465
|
+
- - ">"
|
|
461
466
|
- !ruby/object:Gem::Version
|
|
462
|
-
version:
|
|
467
|
+
version: 1.3.1
|
|
463
468
|
requirements:
|
|
464
469
|
- none
|
|
465
470
|
rubygems_version: 3.4.1
|