spree_vpago 2.3.6 → 2.3.7.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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 92861b027f31b9c4239298967116f3cb34106575da30b650c7220a7981341a23
4
- data.tar.gz: 9a43d50434fb8e0eea79e9413219d62bdd10f32b7599534f2702b0143da61c67
3
+ metadata.gz: e9111b222dfcb967061ca1a6b19df5e171897bc74eaef45bc3a1a0a986214024
4
+ data.tar.gz: 8085228fc934b882f6de0177fe7c9e6d44237a193664d314d19f6fbaa5b03a08
5
5
  SHA512:
6
- metadata.gz: 791e046282f93cb5bbaf1683e788a9e440c394e5101f88fdb48431a517cbcf0367c1b5c49536577f438a31dc30fa37040bcad464b2ec617b30e3c4e2dcbbe6f9
7
- data.tar.gz: e31a474f731d18f6a65628bf8f901ed4fd73407a289fc354687ececedb3e0a4f45ab13933d70fba344085e03161b74d139155185db6826a5794f66fab62a0566
6
+ metadata.gz: 2c8fb4987db12fb7a40e8589023c500294efdcfffe5842c5c2ab6a651475e7a59accdbc62ae75be318edfbd8498a33a59f77adbf3bab96a6e17c483881fb60ab
7
+ data.tar.gz: 2d9e40a576de3be20a53e6c7db445f315edbf081c7807d5672e3ec1370d91a6ac19597f876fd698d1e061cf4f4b61f917787c95163335891581ff527d6acd18c
data/Gemfile.lock CHANGED
@@ -1,7 +1,7 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- spree_vpago (2.3.6)
4
+ spree_vpago (2.3.7.pre.pre1)
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,89 @@
1
+ module Spree
2
+ class Gateway::AcledaV2 < PaymentMethod
3
+ MODES = %w[khqr card deeplink].freeze
4
+
5
+ preference :merchant_name, :string
6
+ preference :xpay_service_base_url, :string
7
+ preference :payment_page_url, :string
8
+ preference :merchant_id, :string
9
+ preference :login_id, :string
10
+ preference :password, :string
11
+ preference :secret, :string # HMAC-SHA512 key
12
+ preference :payment_expiry_time_in_mn, :integer, default: 5
13
+ preference :acleda_v2_mode, :string, default: 'khqr'
14
+
15
+ validates :preferred_acleda_v2_mode, inclusion: { in: MODES }
16
+
17
+ def khqr?
18
+ preferred_acleda_v2_mode == 'khqr'
19
+ end
20
+
21
+ def card?
22
+ preferred_acleda_v2_mode == 'card'
23
+ end
24
+
25
+ def deeplink?
26
+ preferred_acleda_v2_mode == 'deeplink'
27
+ end
28
+
29
+ # KHQR (Scan with Bank under Bakong) = "0"; Credit/debit card = "1"
30
+ def payment_card_value
31
+ card? ? '1' : '0'
32
+ end
33
+
34
+ # override: partial to render in admin
35
+ def method_type
36
+ 'acleda_v2'
37
+ end
38
+
39
+ # override
40
+ def payment_source_class
41
+ Spree::VpagoPaymentSource
42
+ end
43
+
44
+ # override
45
+ def payment_profiles_supported?
46
+ false
47
+ end
48
+
49
+ # override
50
+ def available_for_order?(_order)
51
+ true
52
+ end
53
+
54
+ # override: process! -> purchase! immediately (no pre-auth for ACLEDA V2)
55
+ def auto_capture?
56
+ true
57
+ end
58
+
59
+ # override
60
+ def purchase(_amount, _source, gateway_options = {})
61
+ _, payment_number = gateway_options[:order_id].split('-')
62
+ payment = Spree::Payment.find_by(number: payment_number)
63
+
64
+ checker = check_transaction(payment)
65
+ payment.update(transaction_response: checker.json_response)
66
+
67
+ params = { check: { response: checker.json_response } }
68
+
69
+ if checker.success?
70
+ ActiveMerchant::Billing::Response.new(true, 'Acleda V2: Purchased', params)
71
+ else
72
+ ActiveMerchant::Billing::Response.new(false, 'Acleda V2: Purchasing Failed', params)
73
+ end
74
+ end
75
+
76
+ # Defining check_transaction makes support_check_transaction_api? true,
77
+ # enabling the /vpago_payments/check_transaction poller.
78
+ def check_transaction(payment)
79
+ checker = Vpago::AcledaV2::TransactionStatus.new(payment)
80
+ checker.call
81
+ checker
82
+ end
83
+
84
+ # override
85
+ def cancel(_response_code, _payment = nil)
86
+ ActiveMerchant::Billing::Response.new(true, 'Acleda V2: Payment has been canceled.')
87
+ end
88
+ end
89
+ end
@@ -75,6 +75,19 @@ module Vpago
75
75
  end
76
76
  end
77
77
 
78
+ # override
79
+ def collect_backend_payment_methods
80
+ payment_methods = if respond_to?(:tenant) && tenant.present?
81
+ tenant_payment_methods
82
+ elsif vendor_payment_methods.any?
83
+ vendor_payment_methods
84
+ else
85
+ store.payment_methods
86
+ end
87
+
88
+ payment_methods.available_on_back_end.select { |pm| pm.available_for_order?(self) }
89
+ end
90
+
78
91
  def early_adopter?
79
92
  user.present? && user.respond_to?(:early_adopter?) && user.early_adopter?
80
93
  end
@@ -1,9 +1,10 @@
1
1
  module Vpago
2
- module PaymentMethodDecorator
2
+ module PaymentMethodDecorator # rubocop:disable Metrics/ModuleLength
3
3
  TYPE_PAYWAY = 'Spree::Gateway::Payway'.freeze
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 echoes back _transactionid, which is
24
+ # the payment number we sent as transactionID/txid at openSessionV2.
25
+ Spree::Payment.find_by!(number: params_hash[:_transactionid])
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,5 @@
1
+ <%= render 'spree/admin/payments/source_views/vpago_payment_tmpl',
2
+ payment: payment,
3
+ check_status_url: '',
4
+ heal_payment_url: '',
5
+ manual_update_payment_url: '' %>
@@ -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,48 @@
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 checkout.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
+
43
+ </script>
44
+ <% else %>
45
+ <%= render 'spree/checkout/payment/acleda_v2_checkout_form',
46
+ gateway_params: checkout.gateway_params,
47
+ action_url: checkout.action_url %>
48
+ <% 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.6'.freeze
4
+ VERSION = '2.3.7-pre1'.freeze
5
5
 
6
6
  def version
7
7
  Gem::Version.new VERSION
@@ -60,7 +60,7 @@ module Vpago
60
60
  purchaseDate: purchase_date,
61
61
  purchaseDesc: 'items',
62
62
  item: '1',
63
- quantity: '1',
63
+ quantity: '1', # always 1: one payment = one transaction
64
64
  expiryTime: expiry_time,
65
65
  otherUrl: other_url
66
66
  }
@@ -0,0 +1,158 @@
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
+ def amount
22
+ format('%.2f', @payment.amount)
23
+ end
24
+
25
+ # txid <= 16 chars; payment.number fits.
26
+ alias transaction_id payment_number
27
+
28
+ def order_number
29
+ @payment.order.number
30
+ end
31
+
32
+ def merchant_name
33
+ payment_method.preferences[:merchant_name]
34
+ end
35
+
36
+ def merchant_id
37
+ payment_method.preferences[:merchant_id]
38
+ end
39
+
40
+ def login_id
41
+ payment_method.preferences[:login_id]
42
+ end
43
+
44
+ def password
45
+ payment_method.preferences[:password]
46
+ end
47
+
48
+ def secret
49
+ payment_method.preferences[:secret]
50
+ end
51
+
52
+ # Dynamically mirrors the shopper's remaining seat/inventory hold time so the bank's
53
+ # QR/session doesn't outlive the hold. Falls back to the admin-configured preference
54
+ # when the order has no hold (e.g. non-inventory items) or the hold has already lapsed.
55
+ def expiry_time
56
+ @expiry_time ||= (remaining_hold_minutes || payment_method.preferences[:payment_expiry_time_in_mn]).to_s
57
+ end
58
+
59
+ def purchase_date
60
+ @payment.created_at.utc.strftime('%Y-%m-%d')
61
+ end
62
+
63
+ def purchase_currency
64
+ @payment.order.currency
65
+ end
66
+
67
+ def xpay_service_base_url
68
+ strip_whitespace(payment_method.preferences[:xpay_service_base_url])
69
+ end
70
+
71
+ def open_session_url
72
+ "#{xpay_service_base_url}/openSessionV2"
73
+ end
74
+
75
+ def get_txn_status_url # rubocop:disable Naming/AccessorMethodName
76
+ "#{xpay_service_base_url}/getTxnStatus"
77
+ end
78
+
79
+ # KHQR/Card secure web redirect target
80
+ def action_url
81
+ strip_whitespace(payment_method.preferences[:payment_page_url])
82
+ end
83
+
84
+ # successUrlToReturn / errorUrl. The bank appends its own query string
85
+ # (_paymenttokenid, _resultCode, ...) when it redirects back.
86
+ def continue_success_url
87
+ @payment.processing_url
88
+ end
89
+
90
+ def callback_url
91
+ # return continue_success_url unless deeplink? && app_scheme.present?
92
+
93
+ # uri = URI.parse(continue_success_url)
94
+ # uri.scheme = app_scheme
95
+ # uri.to_s
96
+
97
+ continue_success_url
98
+ end
99
+
100
+ def app_scheme
101
+ payment_method.preferences[:app_scheme]
102
+ end
103
+
104
+ # android | ios (defaults to android when not supplied by the caller)
105
+ def opr_device
106
+ @options[:opr_device].presence || 'android'
107
+ end
108
+
109
+ def platform
110
+ @options[:platform]
111
+ end
112
+
113
+ def deeplink?
114
+ payment_method.deeplink? && platform == 'app'
115
+ end
116
+
117
+ # --- HMAC-SHA512 (uppercase hex) signing ---
118
+ # openSessionV2 message: merchantID + loginId + password + txid
119
+ def open_session_hash
120
+ hmac512("#{merchant_id}#{login_id}#{password}#{payment_number}")
121
+ end
122
+
123
+ # getTxnStatus message: merchantId + loginId + password + paymentTokenid
124
+ def txn_status_hash(token)
125
+ hmac512("#{merchant_id}#{login_id}#{password}#{token}")
126
+ end
127
+
128
+ def hmac512(message)
129
+ OpenSSL::HMAC.hexdigest(OpenSSL::Digest.new('sha512'), secret, message).upcase
130
+ end
131
+
132
+ def parse_json(body)
133
+ JSON.parse(body)
134
+ rescue JSON::ParserError
135
+ {}
136
+ end
137
+
138
+ private
139
+
140
+ # Minutes left on the order's seat/inventory hold, rounded up so we never quote the
141
+ # bank less time than is actually left. nil when the order has no hold, the hold has
142
+ # already lapsed, or hold_expires_at isn't defined (spree_cm_commissioner not loaded).
143
+ def remaining_hold_minutes
144
+ return nil unless @payment.order.respond_to?(:hold_expires_at)
145
+
146
+ hold_expires_at = @payment.order.hold_expires_at
147
+ return nil if hold_expires_at.blank?
148
+
149
+ minutes = ((hold_expires_at - Time.current) / 60.0).ceil
150
+ minutes if minutes.positive?
151
+ end
152
+
153
+ def strip_whitespace(value)
154
+ value.to_s.gsub(/\s+/, '')
155
+ end
156
+ end
157
+ end
158
+ end
@@ -0,0 +1,120 @@
1
+ require 'faraday'
2
+
3
+ module Vpago
4
+ module AcledaV2
5
+ class Checkout < Base
6
+ attr_reader :error_message
7
+
8
+ def call
9
+ @error_message = nil
10
+ @response = open_session
11
+
12
+ if @response.status != 500 && @response.status != 200
13
+ @error_message = 'Server Error'
14
+ elsif @response.status == 500 # mostly when passing a wrong parameter name
15
+ @error_message = @response.body
16
+ elsif json_response.dig('result', 'code') != 0 # invalid payload, wrong loginId, etc.
17
+ @error_message = json_response.dig('result', 'errorDetails') || 'Unknown Error'
18
+ end
19
+
20
+ update_payment_source
21
+
22
+ self
23
+ end
24
+
25
+ def failed?
26
+ @error_message.present?
27
+ end
28
+
29
+ def json_response
30
+ @json_response ||= parse_json(@response.body)
31
+ end
32
+
33
+ # KHQR/Card secure web redirect form fields (auto-POSTed to paymentPage.jsp).
34
+ def gateway_params
35
+ return {} if failed?
36
+
37
+ {
38
+ merchantID: merchant_id,
39
+ sessionid: json_response.dig('result', 'sessionid'),
40
+ paymenttokenid: payment_token_id,
41
+ description: Base::PURCHASE_DESC,
42
+ expirytime: expiry_time,
43
+ amount: amount,
44
+ quantity: '1',
45
+ item: '1',
46
+ invoiceid: order_number,
47
+ currencytype: purchase_currency,
48
+ transactionID: payment_number,
49
+ successUrlToReturn: continue_success_url,
50
+ errorUrl: continue_success_url
51
+ }
52
+ end
53
+
54
+ # Deep Link redirect target.
55
+ def deeplink_url
56
+ return nil if failed?
57
+
58
+ json_response.dig('result', 'deeplinkUrl')
59
+ end
60
+
61
+ private
62
+
63
+ def open_session
64
+ conn = Faraday::Connection.new
65
+
66
+ conn.post(open_session_url) do |request|
67
+ request.headers['Content-Type'] = Base::CONTENT_TYPE_JSON
68
+ request.body = open_session_payload.to_json
69
+ end
70
+ end
71
+
72
+ def open_session_payload
73
+ base = {
74
+ password: password,
75
+ loginId: login_id,
76
+ merchantID: merchant_id,
77
+ hash: open_session_hash,
78
+ xpayTransaction: xpay_transaction_base
79
+ }
80
+
81
+ if deeplink?
82
+ base[:xpayTransaction].merge!(oprDevice: opr_device, callBackUrl: callback_url)
83
+ else
84
+ base[:xpayTransaction][:paymentCard] = payment_method.payment_card_value
85
+ end
86
+
87
+ base
88
+ end
89
+
90
+ def xpay_transaction_base
91
+ {
92
+ txid: payment_number,
93
+ invoiceid: order_number,
94
+ purchaseAmount: amount,
95
+ purchaseCurrency: purchase_currency,
96
+ purchaseDate: purchase_date,
97
+ purchaseDesc: Base::PURCHASE_DESC,
98
+ item: '1',
99
+ quantity: '1',
100
+ expiryTime: expiry_time
101
+ }
102
+ end
103
+
104
+ def payment_token_id
105
+ json_response.dig('result', 'xTran', 'paymentTokenid')
106
+ end
107
+
108
+ # Persist the paymentTokenid so check_transaction / the bank callback can
109
+ # resolve the payment later. Wrap only the write in the writing role, since
110
+ # the checkout form partial runs on a GET request (replica connection).
111
+ def update_payment_source
112
+ return if failed?
113
+
114
+ ActiveRecord::Base.connected_to(role: :writing) do
115
+ @payment.source.update_column(:transaction_id, payment_token_id)
116
+ end
117
+ end
118
+ end
119
+ end
120
+ end
@@ -0,0 +1,83 @@
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
+ return false if token.blank?
35
+
36
+ http_success? && result_code.zero? && error_message == 'SUCCESS'
37
+ end
38
+
39
+ def failed?
40
+ return false if token.blank?
41
+ return false unless http_success?
42
+
43
+ FAILED_ERROR_DETAILS.include?(error_message.to_s.upcase)
44
+ end
45
+
46
+ def pending?
47
+ !success? && !failed?
48
+ end
49
+
50
+ private
51
+
52
+ def http_success?
53
+ @response&.status == 200
54
+ end
55
+
56
+ def token
57
+ @payment.source&.transaction_id
58
+ end
59
+
60
+ def check_remote_status
61
+ conn = Faraday::Connection.new
62
+
63
+ conn.post(get_txn_status_url) do |request|
64
+ request.headers['Content-Type'] = Base::CONTENT_TYPE_JSON
65
+ request.body = payload.to_json
66
+ end
67
+ end
68
+
69
+ # NOTE: getTxnStatus uses merchantId (lowercase d) and an extra merchantName
70
+ # field. merchantName is NOT part of the HMAC message.
71
+ def payload
72
+ {
73
+ loginId: login_id,
74
+ password: password,
75
+ merchantId: merchant_id,
76
+ merchantName: merchant_name,
77
+ hash: txn_status_hash(token),
78
+ paymentTokenid: token
79
+ }
80
+ end
81
+ end
82
+ end
83
+ end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: spree_vpago
3
3
  version: !ruby/object:Gem::Version
4
- version: 2.3.6
4
+ version: 2.3.7.pre.pre1
5
5
  platform: ruby
6
6
  authors:
7
7
  - You
@@ -193,6 +193,7 @@ files:
193
193
  - app/models/concerns/vpago/payoutable.rb
194
194
  - app/models/spree/gateway/acleda.rb
195
195
  - app/models/spree/gateway/acleda_mobile.rb
196
+ - app/models/spree/gateway/acleda_v2.rb
196
197
  - app/models/spree/gateway/payway.rb
197
198
  - app/models/spree/gateway/payway_v2.rb
198
199
  - app/models/spree/gateway/true_money.rb
@@ -283,6 +284,7 @@ files:
283
284
  - app/views/spree/admin/payments/source_forms/_payway_v2.html.erb
284
285
  - app/views/spree/admin/payments/source_views/_acleda.html.erb
285
286
  - app/views/spree/admin/payments/source_views/_acleda_mobile.html.erb
287
+ - app/views/spree/admin/payments/source_views/_acleda_v2.html.erb
286
288
  - app/views/spree/admin/payments/source_views/_payment_payway.html.erb
287
289
  - app/views/spree/admin/payments/source_views/_payway_v2.html.erb
288
290
  - app/views/spree/admin/payments/source_views/_true_money.html.erb
@@ -315,6 +317,7 @@ files:
315
317
  - app/views/spree/checkout/payment/_acleda.html.erb
316
318
  - app/views/spree/checkout/payment/_acleda_checkout_form.html.erb
317
319
  - app/views/spree/checkout/payment/_acleda_mobile.html.erb
320
+ - app/views/spree/checkout/payment/_acleda_v2_checkout_form.html.erb
318
321
  - app/views/spree/checkout/payment/_payment_payway.html.erb
319
322
  - app/views/spree/checkout/payment/_payway_loader.html.erb
320
323
  - app/views/spree/checkout/payment/_payway_root.html.erb
@@ -337,6 +340,7 @@ files:
337
340
  - app/views/spree/payway_v2_card_popups/show.html.erb
338
341
  - app/views/spree/vpago_payments/_transaction_checker.html.erb
339
342
  - app/views/spree/vpago_payments/checkout.html.erb
343
+ - app/views/spree/vpago_payments/forms/spree/gateway/_acleda_v2.html.erb
340
344
  - app/views/spree/vpago_payments/forms/spree/gateway/_payway_v2.html.erb
341
345
  - app/views/spree/vpago_payments/forms/spree/gateway/_true_money.html.erb
342
346
  - app/views/spree/vpago_payments/forms/spree/gateway/_vattanac.html.erb
@@ -394,6 +398,9 @@ files:
394
398
  - lib/vpago/acleda_mobile/payment_request_updater.rb
395
399
  - lib/vpago/acleda_mobile/payment_retriever.rb
396
400
  - lib/vpago/acleda_mobile/transaction_status.rb
401
+ - lib/vpago/acleda_v2/base.rb
402
+ - lib/vpago/acleda_v2/checkout.rb
403
+ - lib/vpago/acleda_v2/transaction_status.rb
397
404
  - lib/vpago/payment_amount_calculator.rb
398
405
  - lib/vpago/payment_request_updater.rb
399
406
  - lib/vpago/payment_status_marker.rb
@@ -449,9 +456,9 @@ required_ruby_version: !ruby/object:Gem::Requirement
449
456
  version: 3.2.0
450
457
  required_rubygems_version: !ruby/object:Gem::Requirement
451
458
  requirements:
452
- - - ">="
459
+ - - ">"
453
460
  - !ruby/object:Gem::Version
454
- version: '0'
461
+ version: 1.3.1
455
462
  requirements:
456
463
  - none
457
464
  rubygems_version: 3.4.1