spree_vpago 2.3.4 → 2.3.5.pre.pre.pre.1

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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 4e73bfb9e0eac7606f41017d8ca6c90e9853296a588f4fccd305331ec4c0c6bc
4
- data.tar.gz: d8180f240e40c47b8983c460892079d2d954638a486855deda122e7971c90bed
3
+ metadata.gz: c0262a0bad21d6ed9d53d73ba6805f307e6b9f82db837ac96fe4f3c4725ae49b
4
+ data.tar.gz: 71f83ae18d1c306419bbef87f291185e1835a653fde1d1f0a09e1c783cf6f54c
5
5
  SHA512:
6
- metadata.gz: 34e2bd88bce6cb6a090d57fe8e6ea7c9ade90f813d834c998a66a697a96b881700ac084b78dd1074a9ec62d63a87d77942f421a25d9f6c046272526a6a407231
7
- data.tar.gz: 231f3bdd5f51c7dd42b78dd1e93b45937031e32abf49383388f4c62c57de4668d2b64dd9bb89fa6f81d325a25db760c7daaa296b2dc5d69c64ee94b9b3badebf
6
+ metadata.gz: ffc03cf77c82129ee5cf13ca1d3abb1646a9d39878ea647e1fd2451c30c027a885d8e8cb99fe45fabef2d7308c73f70c11b654ef9043b59814ef4737a983392c
7
+ data.tar.gz: cde29375e88d3428cd5854b47bb597fac4697eaf60550dfb74573dd0d5edff55624ea0df78659328ba40343548c39b60d4284fe7c6bfcd495a24ba405b82fcea
data/Gemfile.lock CHANGED
@@ -1,7 +1,7 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- spree_vpago (2.3.4)
4
+ spree_vpago (2.3.5.pre.pre.pre.1)
5
5
  faraday
6
6
  google-cloud-firestore
7
7
  spree_api (>= 4.5)
@@ -12,6 +12,7 @@ module Vpago
12
12
  payway_abapay
13
13
  payway_alipay
14
14
  payway_wechat
15
+ acleda_v2
15
16
  acleda
16
17
  acleda_khqr
17
18
  acleda_cards
@@ -28,6 +29,10 @@ module Vpago
28
29
  %w[khqr deeplink all]
29
30
  end
30
31
 
32
+ def available_acleda_v2_modes
33
+ Spree::Gateway::AcledaV2::MODES
34
+ end
35
+
31
36
  def preference_field_for(form, field, options)
32
37
  case field
33
38
  when 'preferred_acleda_type'
@@ -45,6 +50,8 @@ module Vpago
45
50
  return form.select(:preferred_abapay_khqr_deeplink_option, Spree::Gateway::PaywayV2::ABAPAY_KHQR_DEEPLINK_OPTIONS, {}, class: 'fullwidth select2')
46
51
  when 'preferred_vattanac_payment_option'
47
52
  return form.select(:preferred_vattanac_payment_option, available_vattanac_payment_options, {}, class: 'fullwidth select2')
53
+ when 'preferred_acleda_v2_mode'
54
+ return form.select(:preferred_acleda_v2_mode, available_acleda_v2_modes, {}, class: 'fullwidth select2')
48
55
  end
49
56
  super
50
57
  end
@@ -0,0 +1,93 @@
1
+ module Spree
2
+ class Gateway::AcledaV2 < PaymentMethod
3
+ MODES = %w[khqr card deeplink].freeze
4
+
5
+ # BOOKMEPLUS — sent as the "merchantName" field in getTxnStatus requests
6
+ preference :merchant_name, :string
7
+ # e.g. https://epaymentuat.acledabank.com.kh/BOOKMEPLUS/XPAYConnectorServiceInterfaceImplV2/XPAYConnectorServiceInterfaceImplV2RS
8
+ preference :xpay_service_base_url, :string
9
+ # e.g. https://epaymentuat.acledabank.com.kh/BOOKMEPLUS/paymentPage.jsp
10
+ preference :payment_page_url, :string
11
+ preference :merchant_id, :string
12
+ preference :login_id, :string
13
+ preference :password, :string
14
+ preference :secret, :string # HMAC-SHA512 key
15
+ preference :payment_expiry_time_in_mn, :integer, default: 5
16
+ preference :acleda_v2_mode, :string, default: 'khqr'
17
+
18
+ validates :preferred_acleda_v2_mode, inclusion: { in: MODES }
19
+
20
+ def khqr?
21
+ preferred_acleda_v2_mode == 'khqr'
22
+ end
23
+
24
+ def card?
25
+ preferred_acleda_v2_mode == 'card'
26
+ end
27
+
28
+ def deeplink?
29
+ preferred_acleda_v2_mode == 'deeplink'
30
+ end
31
+
32
+ # KHQR (Scan with Bank under Bakong) = "0"; Credit/debit card = "1"
33
+ def payment_card_value
34
+ card? ? '1' : '0'
35
+ end
36
+
37
+ # override: partial to render in admin
38
+ def method_type
39
+ 'acleda_v2'
40
+ end
41
+
42
+ # override
43
+ def payment_source_class
44
+ Spree::VpagoPaymentSource
45
+ end
46
+
47
+ # override
48
+ def payment_profiles_supported?
49
+ false
50
+ end
51
+
52
+ # override
53
+ def available_for_order?(_order)
54
+ true
55
+ end
56
+
57
+ # override: process! -> purchase! immediately (no pre-auth for ACLEDA V2)
58
+ def auto_capture?
59
+ true
60
+ end
61
+
62
+ # override
63
+ # mirror PayWay V2: gateway_options[:order_id] == "<order_number>-<payment_number>"
64
+ def purchase(_amount, _source, gateway_options = {})
65
+ _, payment_number = gateway_options[:order_id].split('-')
66
+ payment = Spree::Payment.find_by(number: payment_number)
67
+
68
+ checker = check_transaction(payment)
69
+ payment.update(transaction_response: checker.json_response)
70
+
71
+ params = { check: { response: checker.json_response } }
72
+
73
+ if checker.success?
74
+ ActiveMerchant::Billing::Response.new(true, 'Acleda V2: Purchased', params)
75
+ else
76
+ ActiveMerchant::Billing::Response.new(false, 'Acleda V2: Purchasing Failed', params)
77
+ end
78
+ end
79
+
80
+ # Defining check_transaction makes support_check_transaction_api? true,
81
+ # enabling the /vpago_payments/check_transaction poller.
82
+ def check_transaction(payment)
83
+ checker = Vpago::AcledaV2::TransactionStatus.new(payment)
84
+ checker.call
85
+ checker
86
+ end
87
+
88
+ # override
89
+ def cancel(_response_code, _payment = nil)
90
+ ActiveMerchant::Billing::Response.new(true, 'Acleda V2: Payment has been canceled.')
91
+ end
92
+ end
93
+ end
@@ -4,6 +4,7 @@ module Vpago
4
4
  TYPE_PAYWAY_V2 = 'Spree::Gateway::PaywayV2'.freeze
5
5
  TYPE_WINGSDK = 'Spree::Gateway::WingSdk'.freeze
6
6
  TYPE_ACLEDA = 'Spree::Gateway::Acleda'.freeze
7
+ TYPE_ACLEDA_V2 = 'Spree::Gateway::AcledaV2'.freeze
7
8
  TYPE_ACLEDA_MOBILE = 'Spree::Gateway::AcledaMobile'.freeze
8
9
  TYPE_TRUE_MONEY = 'Spree::Gateway::TrueMoney'.freeze
9
10
  TYPE_VATTANAC = 'Spree::Gateway::Vattanac'.freeze
@@ -21,6 +22,7 @@ module Vpago
21
22
  Spree::PaymentMethod::TYPE_PAYWAY,
22
23
  Spree::PaymentMethod::TYPE_WINGSDK,
23
24
  Spree::PaymentMethod::TYPE_ACLEDA,
25
+ Spree::PaymentMethod::TYPE_ACLEDA_V2,
24
26
  Spree::PaymentMethod::TYPE_ACLEDA_MOBILE,
25
27
  Spree::PaymentMethod::TYPE_VATTANAC,
26
28
  Spree::PaymentMethod::TYPE_VATTANAC_MINI_APP,
@@ -89,6 +91,10 @@ module Vpago
89
91
  type == Spree::PaymentMethod::TYPE_ACLEDA
90
92
  end
91
93
 
94
+ def type_acleda_v2?
95
+ type == Spree::PaymentMethod::TYPE_ACLEDA_V2
96
+ end
97
+
92
98
  def type_payway?
93
99
  type == Spree::PaymentMethod::TYPE_PAYWAY
94
100
  end
@@ -14,11 +14,15 @@ module Vpago
14
14
  end
15
15
 
16
16
  def find_and_verify!
17
- if vattanac_mini_app_payload?
17
+ if vattanac_mini_app_callback?
18
18
  payload = Vpago::VattanacMiniAppDataHandler.new.decrypt_data(@params_hash[:data])
19
19
  payment = Spree::Payment.find_by!(number: payload['paymentId'])
20
20
  payment.update(transaction_response: payload)
21
21
  payment
22
+ elsif acleda_v2_callback?
23
+ # ACLEDA V2's static portal callback carries only _paymenttokenid, which we
24
+ # stored on the payment source at openSessionV2. Resolve the payment by it.
25
+ Spree::VpagoPaymentSource.find_by!(transaction_id: params_hash[:_paymenttokenid]).payment
22
26
  else
23
27
  order = Spree::Order.find_by!(number: params_hash[:order_number])
24
28
  verify_jwt!(order)
@@ -31,8 +35,12 @@ module Vpago
31
35
  JWT.decode(params_hash[:order_jwt_token], order.token, 'HS256')
32
36
  end
33
37
 
34
- def vattanac_mini_app_payload?
38
+ def vattanac_mini_app_callback?
35
39
  params_hash[:data].present?
36
40
  end
41
+
42
+ def acleda_v2_callback?
43
+ params_hash[:_paymenttokenid].present?
44
+ end
37
45
  end
38
46
  end
@@ -0,0 +1 @@
1
+ <%= render 'spree/admin/payments/source_views/vpago_payment_tmpl', payment: payment %>
@@ -0,0 +1,12 @@
1
+ <form method="post" action="<%= action_url %>" id="acleda_v2_checkout_form" style="display:none;">
2
+ <% gateway_params.each do |name, value| %>
3
+ <input type="hidden" name="<%= name %>" value="<%= value %>">
4
+ <% end %>
5
+ </form>
6
+
7
+ <script>
8
+ (function () {
9
+ var form = document.getElementById("acleda_v2_checkout_form");
10
+ if (form) form.submit();
11
+ })();
12
+ </script>
@@ -0,0 +1,47 @@
1
+ <%
2
+ opr_device = request.user_agent.to_s.downcase.match?(/iphone|ipad|ipod/) ? 'ios' : 'android'
3
+ checkout = ::Vpago::AcledaV2::Checkout.new(@payment, { platform: params[:platform], opr_device: opr_device })
4
+
5
+ begin
6
+ checkout.call
7
+ rescue => e
8
+ Rails.logger.error("Acleda V2 checkout.call failed: #{e.message}")
9
+ end
10
+ %>
11
+
12
+ <% if checkout.failed? %>
13
+ <script>
14
+ console.error("[Vpago] Acleda V2 checkout error: <%= j checkout.error_message.to_s %>");
15
+ document.addEventListener("DOMContentLoaded", () => {
16
+ const loadingContainer = document.getElementById('vpago_loading_container');
17
+ if (loadingContainer) {
18
+ loadingContainer.textContent = "We couldn't start your payment. Please go back and try again.";
19
+ }
20
+ });
21
+ </script>
22
+ <% elsif @payment.payment_method.deeplink? %>
23
+ <script>
24
+ function showRedirectContainer(buttonLabel, onClick) {
25
+ const loadingContainer = document.getElementById('vpago_loading_container');
26
+ const redirectContainer = document.getElementById('vpago_redirect_container');
27
+ const redirectButton = document.getElementById('vpago_redirect_button');
28
+
29
+ redirectButton.textContent = buttonLabel;
30
+ redirectButton.addEventListener('click', onClick);
31
+
32
+ loadingContainer.style.display = 'none';
33
+ redirectContainer.style.removeProperty('display');
34
+ }
35
+
36
+ const deeplinkUrl = "<%= raw checkout.deeplink_url %>";
37
+ const redirectTo = (url) => { if (url) window.location.href = url; };
38
+
39
+
40
+ redirectTo(deeplinkUrl);
41
+ showRedirectContainer("Open ACLEDA", () => redirectTo(deeplinkUrl));
42
+ </script>
43
+ <% else %>
44
+ <%= render 'spree/checkout/payment/acleda_v2_checkout_form',
45
+ gateway_params: checkout.gateway_params,
46
+ action_url: checkout.action_url %>
47
+ <% end %>
@@ -21,6 +21,7 @@ module SpreeVpago
21
21
  Spree::Gateway::PaywayV2,
22
22
  Spree::Gateway::WingSdk,
23
23
  Spree::Gateway::Acleda,
24
+ Spree::Gateway::AcledaV2,
24
25
  Spree::Gateway::AcledaMobile,
25
26
  Spree::Gateway::Vattanac,
26
27
  Spree::Gateway::VattanacMiniApp,
@@ -1,7 +1,7 @@
1
1
  module SpreeVpago
2
2
  module_function
3
3
 
4
- VERSION = '2.3.4'.freeze
4
+ VERSION = '2.3.5-pre-1'.freeze
5
5
 
6
6
  def version
7
7
  Gem::Version.new VERSION
@@ -0,0 +1,149 @@
1
+ module Vpago
2
+ module AcledaV2
3
+ class Base
4
+ CONTENT_TYPE_JSON = 'application/json'.freeze
5
+ # ACLEDA requires purchaseDesc to be <= 16 chars, English only.
6
+ PURCHASE_DESC = 'Purchase goods'.freeze
7
+
8
+ def initialize(payment, options = {})
9
+ @options = options
10
+ @payment = payment
11
+ end
12
+
13
+ def payment_method
14
+ @payment.payment_method
15
+ end
16
+
17
+ def payment_number
18
+ @payment.number
19
+ end
20
+
21
+ # PDF samples quote every xpayTransaction field as a JSON string.
22
+ def amount
23
+ format('%.2f', @payment.amount)
24
+ end
25
+
26
+ # txid <= 16 chars; payment.number fits.
27
+ alias transaction_id payment_number
28
+
29
+ def order_number
30
+ @payment.order.number
31
+ end
32
+
33
+ def merchant_name
34
+ payment_method.preferences[:merchant_name]
35
+ end
36
+
37
+ def merchant_id
38
+ payment_method.preferences[:merchant_id]
39
+ end
40
+
41
+ def login_id
42
+ payment_method.preferences[:login_id]
43
+ end
44
+
45
+ def password
46
+ payment_method.preferences[:password]
47
+ end
48
+
49
+ def secret
50
+ payment_method.preferences[:secret]
51
+ end
52
+
53
+ # PDF samples quote every xpayTransaction field as a JSON string, even ones
54
+ # labeled "Numeric" in the field tables (paymentCard, quantity, expiryTime).
55
+ def expiry_time
56
+ payment_method.preferences[:payment_expiry_time_in_mn].to_s
57
+ end
58
+
59
+ # PDF: "Date of Transaction in UTC Time", sent as a YYYY-MM-DD string in the
60
+ # samples. Explicit .utc so this stays correct even if config.time_zone is
61
+ # ever changed away from UTC.
62
+ def purchase_date
63
+ @payment.created_at.utc.strftime('%Y-%m-%d')
64
+ end
65
+
66
+ def purchase_currency
67
+ @payment.order.currency
68
+ end
69
+
70
+ # --- Endpoints (each stored as a full URL preference) ---
71
+ # Strip embedded whitespace: these URLs are long and wrap across lines in
72
+ # the bank's PDFs, so a copy-paste into the admin preference easily carries
73
+ # over a stray space/line-break where the PDF wrapped.
74
+
75
+ def xpay_service_base_url
76
+ strip_whitespace(payment_method.preferences[:xpay_service_base_url])
77
+ end
78
+
79
+ def open_session_url
80
+ "#{xpay_service_base_url}/openSessionV2"
81
+ end
82
+
83
+ def get_txn_status_url # rubocop:disable Naming/AccessorMethodName
84
+ "#{xpay_service_base_url}/getTxnStatus"
85
+ end
86
+
87
+ # KHQR/Card secure web redirect target
88
+ def action_url
89
+ strip_whitespace(payment_method.preferences[:payment_page_url])
90
+ end
91
+
92
+ # successUrlToReturn / errorUrl. The bank appends its own query string
93
+ # (_paymenttokenid, _resultCode, ...) when it redirects back.
94
+ def continue_success_url
95
+ @payment.processing_url
96
+ end
97
+
98
+ def callback_url
99
+ if platform == 'app' && app_scheme.present?
100
+ uri = URI.parse(@payment.processing_url)
101
+ uri.scheme = app_scheme
102
+ uri.to_s
103
+ else
104
+ @payment.processing_url
105
+ end
106
+ end
107
+
108
+ def app_scheme
109
+ payment_method.preferences[:app_scheme]
110
+ end
111
+
112
+ # android | ios (defaults to android when not supplied by the caller)
113
+ def opr_device
114
+ @options[:opr_device].presence || 'android'
115
+ end
116
+
117
+ def platform
118
+ @options[:platform]
119
+ end
120
+
121
+ # --- HMAC-SHA512 (uppercase hex) signing ---
122
+ # openSessionV2 message: merchantID + loginId + password + txid
123
+ def open_session_hash
124
+ hmac512("#{merchant_id}#{login_id}#{password}#{payment_number}")
125
+ end
126
+
127
+ # getTxnStatus message: merchantId + loginId + password + paymentTokenid
128
+ def txn_status_hash(token)
129
+ hmac512("#{merchant_id}#{login_id}#{password}#{token}")
130
+ end
131
+
132
+ def hmac512(message)
133
+ OpenSSL::HMAC.hexdigest(OpenSSL::Digest.new('sha512'), secret, message).upcase
134
+ end
135
+
136
+ def parse_json(body)
137
+ JSON.parse(body)
138
+ rescue JSON::ParserError
139
+ {}
140
+ end
141
+
142
+ private
143
+
144
+ def strip_whitespace(value)
145
+ value.to_s.gsub(/\s+/, '')
146
+ end
147
+ end
148
+ end
149
+ end
@@ -0,0 +1,124 @@
1
+ require 'faraday'
2
+
3
+ module Vpago
4
+ module AcledaV2
5
+ # Single class handling all three modes (khqr, card, deeplink).
6
+ # Two-step ACLEDA flow: openSessionV2 (JSON, here) yields paymentTokenid +
7
+ # sessionid, then either an auto-POST form to paymentPage.jsp (KHQR/Card) or
8
+ # a JS deeplink redirect (Deep Link).
9
+ class Checkout < Base
10
+ attr_reader :error_message
11
+
12
+ def call
13
+ @error_message = nil
14
+ @response = open_session
15
+
16
+ if @response.status != 500 && @response.status != 200
17
+ @error_message = 'Server Error'
18
+ elsif @response.status == 500 # mostly when passing a wrong parameter name
19
+ @error_message = @response.body
20
+ elsif json_response.dig('result', 'code') != 0 # invalid payload, wrong loginId, etc.
21
+ @error_message = json_response.dig('result', 'errorDetails') || 'Unknown Error'
22
+ end
23
+
24
+ update_payment_source
25
+
26
+ self
27
+ end
28
+
29
+ def failed?
30
+ @error_message.present?
31
+ end
32
+
33
+ def json_response
34
+ @json_response ||= parse_json(@response.body)
35
+ end
36
+
37
+ # KHQR/Card secure web redirect form fields (auto-POSTed to paymentPage.jsp).
38
+ def gateway_params
39
+ return {} if failed?
40
+
41
+ {
42
+ merchantID: merchant_id,
43
+ sessionid: json_response.dig('result', 'sessionid'),
44
+ paymenttokenid: payment_token_id,
45
+ description: Base::PURCHASE_DESC,
46
+ expirytime: expiry_time,
47
+ amount: amount,
48
+ quantity: '1',
49
+ item: '1',
50
+ invoiceid: order_number,
51
+ currencytype: purchase_currency,
52
+ transactionID: payment_number,
53
+ successUrlToReturn: continue_success_url,
54
+ errorUrl: continue_success_url
55
+ }
56
+ end
57
+
58
+ # Deep Link redirect target.
59
+ def deeplink_url
60
+ return nil if failed?
61
+
62
+ json_response.dig('result', 'deeplinkUrl')
63
+ end
64
+
65
+ private
66
+
67
+ def open_session
68
+ conn = Faraday::Connection.new
69
+
70
+ conn.post(open_session_url) do |request|
71
+ request.headers['Content-Type'] = Base::CONTENT_TYPE_JSON
72
+ request.body = open_session_payload.to_json
73
+ end
74
+ end
75
+
76
+ def open_session_payload
77
+ base = {
78
+ password: password,
79
+ loginId: login_id,
80
+ merchantID: merchant_id,
81
+ hash: open_session_hash,
82
+ xpayTransaction: xpay_transaction_base
83
+ }
84
+
85
+ if payment_method.deeplink?
86
+ base[:xpayTransaction].merge!(oprDevice: opr_device, callBackUrl: callback_url)
87
+ else
88
+ base[:xpayTransaction][:paymentCard] = payment_method.payment_card_value
89
+ end
90
+
91
+ base
92
+ end
93
+
94
+ def xpay_transaction_base
95
+ {
96
+ txid: payment_number,
97
+ invoiceid: order_number,
98
+ purchaseAmount: amount,
99
+ purchaseCurrency: purchase_currency,
100
+ purchaseDate: purchase_date,
101
+ purchaseDesc: Base::PURCHASE_DESC,
102
+ item: '1',
103
+ quantity: '1',
104
+ expiryTime: expiry_time
105
+ }
106
+ end
107
+
108
+ def payment_token_id
109
+ json_response.dig('result', 'xTran', 'paymentTokenid')
110
+ end
111
+
112
+ # Persist the paymentTokenid so check_transaction / the bank callback can
113
+ # resolve the payment later. Wrap only the write in the writing role, since
114
+ # the checkout form partial runs on a GET request (replica connection).
115
+ def update_payment_source
116
+ return if failed?
117
+
118
+ ActiveRecord::Base.connected_to(role: :writing) do
119
+ @payment.source.update_column(:transaction_id, payment_token_id)
120
+ end
121
+ end
122
+ end
123
+ end
124
+ end
@@ -0,0 +1,80 @@
1
+ require 'faraday'
2
+
3
+ module Vpago
4
+ module AcledaV2
5
+ class TransactionStatus < Base
6
+ # Terminal failure indicators in result.errorDetails. The PDFs only document
7
+ # code 0 / "SUCCESS"; decline/expiry wording is conservative and should be
8
+ # confirmed against real responses during UAT. Anything not success and not
9
+ # terminal is treated as pending so the poller keeps trying.
10
+ FAILED_ERROR_DETAILS = %w[EXPIRED DECLINED CANCELLED FAILED REJECTED].freeze
11
+
12
+ def call
13
+ @response = check_remote_status
14
+ self
15
+ end
16
+
17
+ def json_response
18
+ @json_response ||= parse_json(@response.body)
19
+ end
20
+
21
+ def result
22
+ json_response['result'] || {}
23
+ end
24
+
25
+ def result_code
26
+ result['code']
27
+ end
28
+
29
+ def error_message
30
+ result['errorDetails']
31
+ end
32
+
33
+ def success?
34
+ http_success? && result_code == 0 && error_message == 'SUCCESS'
35
+ end
36
+
37
+ def failed?
38
+ return false unless http_success?
39
+
40
+ FAILED_ERROR_DETAILS.include?(error_message.to_s.upcase)
41
+ end
42
+
43
+ def pending?
44
+ !success? && !failed?
45
+ end
46
+
47
+ private
48
+
49
+ def http_success?
50
+ @response&.status == 200
51
+ end
52
+
53
+ def token
54
+ @payment.source&.transaction_id
55
+ end
56
+
57
+ def check_remote_status
58
+ conn = Faraday::Connection.new
59
+
60
+ conn.post(get_txn_status_url) do |request|
61
+ request.headers['Content-Type'] = Base::CONTENT_TYPE_JSON
62
+ request.body = payload.to_json
63
+ end
64
+ end
65
+
66
+ # NOTE: getTxnStatus uses merchantId (lowercase d) and an extra merchantName
67
+ # field. merchantName is NOT part of the HMAC message.
68
+ def payload
69
+ {
70
+ loginId: login_id,
71
+ password: password,
72
+ merchantId: merchant_id,
73
+ merchantName: merchant_name,
74
+ hash: txn_status_hash(token),
75
+ paymentTokenid: token
76
+ }
77
+ end
78
+ end
79
+ end
80
+ 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.3.4
4
+ version: 2.3.5.pre.pre.pre.1
5
5
  platform: ruby
6
6
  authors:
7
7
  - You
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2026-06-19 00:00:00.000000000 Z
11
+ date: 2026-07-03 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: faraday
@@ -192,6 +192,7 @@ files:
192
192
  - app/models/concerns/vpago/payoutable.rb
193
193
  - app/models/spree/gateway/acleda.rb
194
194
  - app/models/spree/gateway/acleda_mobile.rb
195
+ - app/models/spree/gateway/acleda_v2.rb
195
196
  - app/models/spree/gateway/payway.rb
196
197
  - app/models/spree/gateway/payway_v2.rb
197
198
  - app/models/spree/gateway/true_money.rb
@@ -280,6 +281,7 @@ files:
280
281
  - app/views/spree/admin/payments/source_forms/_payway_v2.html.erb
281
282
  - app/views/spree/admin/payments/source_views/_acleda.html.erb
282
283
  - app/views/spree/admin/payments/source_views/_acleda_mobile.html.erb
284
+ - app/views/spree/admin/payments/source_views/_acleda_v2.html.erb
283
285
  - app/views/spree/admin/payments/source_views/_payment_payway.html.erb
284
286
  - app/views/spree/admin/payments/source_views/_payway_v2.html.erb
285
287
  - app/views/spree/admin/payments/source_views/_true_money.html.erb
@@ -309,6 +311,7 @@ files:
309
311
  - app/views/spree/checkout/payment/_acleda.html.erb
310
312
  - app/views/spree/checkout/payment/_acleda_checkout_form.html.erb
311
313
  - app/views/spree/checkout/payment/_acleda_mobile.html.erb
314
+ - app/views/spree/checkout/payment/_acleda_v2_checkout_form.html.erb
312
315
  - app/views/spree/checkout/payment/_payment_payway.html.erb
313
316
  - app/views/spree/checkout/payment/_payway_loader.html.erb
314
317
  - app/views/spree/checkout/payment/_payway_root.html.erb
@@ -331,6 +334,7 @@ files:
331
334
  - app/views/spree/payway_v2_card_popups/show.html.erb
332
335
  - app/views/spree/vpago_payments/_transaction_checker.html.erb
333
336
  - app/views/spree/vpago_payments/checkout.html.erb
337
+ - app/views/spree/vpago_payments/forms/spree/gateway/_acleda_v2.html.erb
334
338
  - app/views/spree/vpago_payments/forms/spree/gateway/_payway_v2.html.erb
335
339
  - app/views/spree/vpago_payments/forms/spree/gateway/_true_money.html.erb
336
340
  - app/views/spree/vpago_payments/forms/spree/gateway/_vattanac.html.erb
@@ -388,6 +392,9 @@ files:
388
392
  - lib/vpago/acleda_mobile/payment_request_updater.rb
389
393
  - lib/vpago/acleda_mobile/payment_retriever.rb
390
394
  - lib/vpago/acleda_mobile/transaction_status.rb
395
+ - lib/vpago/acleda_v2/base.rb
396
+ - lib/vpago/acleda_v2/checkout.rb
397
+ - lib/vpago/acleda_v2/transaction_status.rb
391
398
  - lib/vpago/payment_amount_calculator.rb
392
399
  - lib/vpago/payment_request_updater.rb
393
400
  - lib/vpago/payment_status_marker.rb
@@ -443,9 +450,9 @@ required_ruby_version: !ruby/object:Gem::Requirement
443
450
  version: 3.2.0
444
451
  required_rubygems_version: !ruby/object:Gem::Requirement
445
452
  requirements:
446
- - - ">="
453
+ - - ">"
447
454
  - !ruby/object:Gem::Version
448
- version: '0'
455
+ version: 1.3.1
449
456
  requirements:
450
457
  - none
451
458
  rubygems_version: 3.4.1