spree_vpago 2.3.5.pre.pre.pre.1 → 2.3.5.pre.pre.pre.3

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: c0262a0bad21d6ed9d53d73ba6805f307e6b9f82db837ac96fe4f3c4725ae49b
4
- data.tar.gz: 71f83ae18d1c306419bbef87f291185e1835a653fde1d1f0a09e1c783cf6f54c
3
+ metadata.gz: 48d7c4c6d67178d69d9c79153a1faefed2988bee02b651d084305cf368642bf7
4
+ data.tar.gz: b2d865bb7e27a47c21f881e6412687864a79daa95827e8241cf5031e42e6c662
5
5
  SHA512:
6
- metadata.gz: ffc03cf77c82129ee5cf13ca1d3abb1646a9d39878ea647e1fd2451c30c027a885d8e8cb99fe45fabef2d7308c73f70c11b654ef9043b59814ef4737a983392c
7
- data.tar.gz: cde29375e88d3428cd5854b47bb597fac4697eaf60550dfb74573dd0d5edff55624ea0df78659328ba40343548c39b60d4284fe7c6bfcd495a24ba405b82fcea
6
+ metadata.gz: 9d691bcf146a73f3cb5ea24ac25b2dfc3c37ce45b5af81c6ccc870ca53600e195bdb8f94532bd80e61c5e00ad8ff8dd824f12bd079ec799976b31be694fe20f5
7
+ data.tar.gz: ece9f7bb49bc13462b63cae96090167ced2924259ec7bbed9bb5686aacc8c726fe2f5f1dddcce6f396d460c2288a9e019cbfb8dc745ba481eb8a91a73aaf364d
data/Gemfile.lock CHANGED
@@ -1,7 +1,7 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- spree_vpago (2.3.5.pre.pre.pre.1)
4
+ spree_vpago (2.3.5.pre.pre.pre.3)
5
5
  faraday
6
6
  google-cloud-firestore
7
7
  spree_api (>= 4.5)
@@ -2,11 +2,8 @@ module Spree
2
2
  class Gateway::AcledaV2 < PaymentMethod
3
3
  MODES = %w[khqr card deeplink].freeze
4
4
 
5
- # BOOKMEPLUS — sent as the "merchantName" field in getTxnStatus requests
6
5
  preference :merchant_name, :string
7
- # e.g. https://epaymentuat.acledabank.com.kh/BOOKMEPLUS/XPAYConnectorServiceInterfaceImplV2/XPAYConnectorServiceInterfaceImplV2RS
8
6
  preference :xpay_service_base_url, :string
9
- # e.g. https://epaymentuat.acledabank.com.kh/BOOKMEPLUS/paymentPage.jsp
10
7
  preference :payment_page_url, :string
11
8
  preference :merchant_id, :string
12
9
  preference :login_id, :string
@@ -60,7 +57,6 @@ module Spree
60
57
  end
61
58
 
62
59
  # override
63
- # mirror PayWay V2: gateway_options[:order_id] == "<order_number>-<payment_number>"
64
60
  def purchase(_amount, _source, gateway_options = {})
65
61
  _, payment_number = gateway_options[:order_id].split('-')
66
62
  payment = Spree::Payment.find_by(number: payment_number)
@@ -1,5 +1,5 @@
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
@@ -20,9 +20,9 @@ module Vpago
20
20
  payment.update(transaction_response: payload)
21
21
  payment
22
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
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])
26
26
  else
27
27
  order = Spree::Order.find_by!(number: params_hash[:order_number])
28
28
  verify_jwt!(order)
@@ -1 +1,5 @@
1
- <%= render 'spree/admin/payments/source_views/vpago_payment_tmpl', payment: payment %>
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: '' %>
@@ -19,7 +19,7 @@
19
19
  }
20
20
  });
21
21
  </script>
22
- <% elsif @payment.payment_method.deeplink? %>
22
+ <% elsif checkout.deeplink? %>
23
23
  <script>
24
24
  function showRedirectContainer(buttonLabel, onClick) {
25
25
  const loadingContainer = document.getElementById('vpago_loading_container');
@@ -37,8 +37,14 @@
37
37
  const redirectTo = (url) => { if (url) window.location.href = url; };
38
38
 
39
39
 
40
+ <<<<<<< Updated upstream
40
41
  redirectTo(deeplinkUrl);
41
42
  showRedirectContainer("Open ACLEDA", () => redirectTo(deeplinkUrl));
43
+ =======
44
+ redirectTo(deeplinkUrl);
45
+ showRedirectContainer("Open ACLEDA", () => redirectTo(deeplinkUrl));
46
+
47
+ >>>>>>> Stashed changes
42
48
  </script>
43
49
  <% else %>
44
50
  <%= render 'spree/checkout/payment/acleda_v2_checkout_form',
@@ -1,7 +1,7 @@
1
1
  module SpreeVpago
2
2
  module_function
3
3
 
4
- VERSION = '2.3.5-pre-1'.freeze
4
+ VERSION = '2.3.5-pre-3'.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
  }
@@ -18,7 +18,6 @@ module Vpago
18
18
  @payment.number
19
19
  end
20
20
 
21
- # PDF samples quote every xpayTransaction field as a JSON string.
22
21
  def amount
23
22
  format('%.2f', @payment.amount)
24
23
  end
@@ -50,15 +49,13 @@ module Vpago
50
49
  payment_method.preferences[:secret]
51
50
  end
52
51
 
53
- # PDF samples quote every xpayTransaction field as a JSON string, even ones
54
- # labeled "Numeric" in the field tables (paymentCard, quantity, expiryTime).
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
55
  def expiry_time
56
- payment_method.preferences[:payment_expiry_time_in_mn].to_s
56
+ @expiry_time ||= (remaining_hold_minutes || payment_method.preferences[:payment_expiry_time_in_mn]).to_s
57
57
  end
58
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
59
  def purchase_date
63
60
  @payment.created_at.utc.strftime('%Y-%m-%d')
64
61
  end
@@ -67,11 +64,6 @@ module Vpago
67
64
  @payment.order.currency
68
65
  end
69
66
 
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
67
  def xpay_service_base_url
76
68
  strip_whitespace(payment_method.preferences[:xpay_service_base_url])
77
69
  end
@@ -96,13 +88,11 @@ module Vpago
96
88
  end
97
89
 
98
90
  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
91
+ return continue_success_url unless app_scheme.present? && platform == 'app'
92
+
93
+ uri = URI.parse(continue_success_url)
94
+ uri.scheme = app_scheme
95
+ uri.to_s
106
96
  end
107
97
 
108
98
  def app_scheme
@@ -118,6 +108,10 @@ module Vpago
118
108
  @options[:platform]
119
109
  end
120
110
 
111
+ def deeplink?
112
+ payment_method.deeplink? && platform == 'app'
113
+ end
114
+
121
115
  # --- HMAC-SHA512 (uppercase hex) signing ---
122
116
  # openSessionV2 message: merchantID + loginId + password + txid
123
117
  def open_session_hash
@@ -141,6 +135,19 @@ module Vpago
141
135
 
142
136
  private
143
137
 
138
+ # Minutes left on the order's seat/inventory hold, rounded up so we never quote the
139
+ # bank less time than is actually left. nil when the order has no hold, the hold has
140
+ # already lapsed, or hold_expires_at isn't defined (spree_cm_commissioner not loaded).
141
+ def remaining_hold_minutes
142
+ return nil unless @payment.order.respond_to?(:hold_expires_at)
143
+
144
+ hold_expires_at = @payment.order.hold_expires_at
145
+ return nil if hold_expires_at.blank?
146
+
147
+ minutes = ((hold_expires_at - Time.current) / 60.0).ceil
148
+ minutes if minutes.positive?
149
+ end
150
+
144
151
  def strip_whitespace(value)
145
152
  value.to_s.gsub(/\s+/, '')
146
153
  end
@@ -2,10 +2,6 @@ require 'faraday'
2
2
 
3
3
  module Vpago
4
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
5
  class Checkout < Base
10
6
  attr_reader :error_message
11
7
 
@@ -82,7 +78,7 @@ module Vpago
82
78
  xpayTransaction: xpay_transaction_base
83
79
  }
84
80
 
85
- if payment_method.deeplink?
81
+ if deeplink?
86
82
  base[:xpayTransaction].merge!(oprDevice: opr_device, callBackUrl: callback_url)
87
83
  else
88
84
  base[:xpayTransaction][:paymentCard] = payment_method.payment_card_value
@@ -31,10 +31,13 @@ module Vpago
31
31
  end
32
32
 
33
33
  def success?
34
- http_success? && result_code == 0 && error_message == 'SUCCESS'
34
+ return false if token.blank?
35
+
36
+ http_success? && result_code.zero? && error_message == 'SUCCESS'
35
37
  end
36
38
 
37
39
  def failed?
40
+ return false if token.blank?
38
41
  return false unless http_success?
39
42
 
40
43
  FAILED_ERROR_DETAILS.include?(error_message.to_s.upcase)
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.5.pre.pre.pre.1
4
+ version: 2.3.5.pre.pre.pre.3
5
5
  platform: ruby
6
6
  authors:
7
7
  - You
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2026-07-03 00:00:00.000000000 Z
11
+ date: 2026-07-08 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: faraday