spree_vpago 2.3.13 → 2.3.14.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.
Files changed (30) hide show
  1. checksums.yaml +4 -4
  2. data/Gemfile.lock +1 -1
  3. data/app/assets/config/spree_vpago_manifest.js +2 -0
  4. data/app/assets/javascripts/vpago/wing_mini_app/login.js +75 -0
  5. data/app/assets/javascripts/vpago/wing_mini_app/web_jsbridge.bundle.js +1507 -0
  6. data/app/controllers/concerns/spree/mini_app_concern.rb +25 -0
  7. data/app/controllers/spree/mini_app/acledas_controller.rb +35 -0
  8. data/app/controllers/spree/mini_app/wings_controller.rb +58 -0
  9. data/app/models/spree/gateway/acleda_mini_app.rb +18 -0
  10. data/app/models/spree/gateway/wing_mini_app.rb +58 -0
  11. data/app/models/vpago/payment_decorator.rb +8 -0
  12. data/app/models/vpago/payment_method_decorator.rb +12 -0
  13. data/app/services/vpago/acleda_mini_app/session/create.rb +121 -0
  14. data/app/services/vpago/payment_finder.rb +11 -0
  15. data/app/services/vpago/wing_mini_app/session/create.rb +55 -0
  16. data/app/views/layouts/wing_mini_app.html.erb +20 -0
  17. data/app/views/spree/admin/payments/source_views/_acleda_mini_app.html.erb +6 -0
  18. data/app/views/spree/admin/payments/source_views/_wing_mini_app.html.erb +6 -0
  19. data/app/views/spree/mini_app/wings/show.html.erb +44 -0
  20. data/app/views/spree/vpago_payments/forms/spree/gateway/_acleda_mini_app.html.erb +94 -0
  21. data/app/views/spree/vpago_payments/forms/spree/gateway/_wing_mini_app.html.erb +88 -0
  22. data/app/views/spree/vpago_payments/processing_scripts/spree/gateway/_wing_mini_app.html.erb +15 -0
  23. data/config/routes.rb +14 -0
  24. data/lib/spree_vpago/engine.rb +2 -0
  25. data/lib/spree_vpago/version.rb +1 -1
  26. data/lib/vpago/acleda_mini_app/checkout.rb +19 -0
  27. data/lib/vpago/acleda_mini_app/session_hash_validator.rb +35 -0
  28. data/lib/vpago/wing_mini_app/checkout.rb +60 -0
  29. data/lib/vpago/wing_mini_app/webhook_verifier.rb +78 -0
  30. metadata +24 -4
@@ -0,0 +1,88 @@
1
+ <% content_for :head do %>
2
+ <%= javascript_include_tag 'vpago/wing_mini_app/web_jsbridge.bundle', 'data-turbo-track': 'reload' %>
3
+ <% end %>
4
+
5
+ <% checkout = ::Vpago::WingMiniApp::Checkout.new(@payment) %>
6
+
7
+ <p id="wing-message"
8
+ style="margin-top: 10px; font-weight: bold; color: red; display: none;">
9
+ </p>
10
+
11
+ <script>
12
+ function showRedirectContainer(buttonLabel, onClick) {
13
+ const loadingContainer = document.getElementById('vpago_loading_container');
14
+ const redirectContainer = document.getElementById('vpago_redirect_container');
15
+ const redirectButton = document.getElementById('vpago_redirect_button');
16
+
17
+ redirectButton.textContent = buttonLabel;
18
+ redirectButton.addEventListener('click', onClick);
19
+
20
+ loadingContainer.style.display = 'none';
21
+ redirectContainer.style.removeProperty('display');
22
+ }
23
+
24
+ function showError(detail) {
25
+ console.error('[Wing] ' + detail);
26
+
27
+ const message = document.getElementById('wing-message');
28
+ message.innerText = "We couldn't start your Wing payment.";
29
+ message.style.display = 'block';
30
+ }
31
+
32
+ document.addEventListener('DOMContentLoaded', () => {
33
+ const processingUrl = "<%= raw @payment.processing_url %>";
34
+ const bridge = window.WebJSBridge && window.WebJSBridge.$bridge;
35
+
36
+ if (!bridge || !bridge.isAvailable()) {
37
+ showError('This page only works inside the Wing app.');
38
+ return;
39
+ }
40
+
41
+ // Whichever signal lands first wins; the rest are then noise from the same
42
+ // payment. Also keeps the fallback button from replacing a page already leaving.
43
+ let handedOff = false;
44
+
45
+ const goToProcessing = () => {
46
+ if (handedOff) return;
47
+ handedOff = true;
48
+
49
+ window.location.replace(processingUrl);
50
+ };
51
+
52
+ const startPayment = () => {
53
+ // Screen only, both here and in the relay below. Settlement stays server to
54
+ // server, where WebhookVerifier checks Wing's webhook before anything is
55
+ // captured, and the processing page keeps polling until that lands — so it is
56
+ // the safe destination even for a payment that failed.
57
+ bridge
58
+ .callHandler('doPayment', <%= raw checkout.signed_payload.to_json %>)
59
+ .then(() => goToProcessing())
60
+ .catch((error) => showError('doPayment call failed: ' + error.message));
61
+ };
62
+
63
+ // Wing delivers native -> web calls by evaluating JS against the main frame,
64
+ // which is our web app embedding this page, not this document — so in a framed
65
+ // checkout it is mini_app/wing_bridge.js over there that hears getStatus and
66
+ // posts the bare code on. Sender identity, not origin: this page and the web app
67
+ // are deliberately on different hosts.
68
+ window.addEventListener('message', (event) => {
69
+ if (event.source !== window.parent) return;
70
+ if (!event.data || event.data.code !== 'wing_payment_status') return;
71
+
72
+ goToProcessing();
73
+ });
74
+
75
+ // The same signal for an unframed checkout, where this document *is* the main
76
+ // frame and Wing reaches it directly.
77
+ bridge.registerHandler('getStatus', () => goToProcessing());
78
+
79
+ startPayment();
80
+
81
+ setTimeout(() => {
82
+ if (document.visibilityState === 'hidden') return;
83
+ if (handedOff) return;
84
+
85
+ showRedirectContainer('Pay with Wing', startPayment);
86
+ }, 1000);
87
+ });
88
+ </script>
@@ -0,0 +1,15 @@
1
+ <script>
2
+ // Wing settles only on its webhook — #purchase reads nothing but the
3
+ // transaction_response PaymentFinder stores on callback, and there is no status
4
+ // API to ask instead. Processing before it lands paints "Payment process failed"
5
+ // over a payment already debited, so skip it; the webhook enqueues
6
+ // PaymentProcessorJob itself.
7
+ //
8
+ // The replacement holds because the real definition is a classic script in the
9
+ // layout's head while vpago_payment_controller only connects at domReady, leaving
10
+ // this inline script in between. Load either of those differently and it stops —
11
+ // the log is how you would notice.
12
+ window.requestProcessPayment = function () {
13
+ return Promise.resolve();
14
+ };
15
+ </script>
data/config/routes.rb CHANGED
@@ -17,6 +17,20 @@ Spree::Core::Engine.add_routes do
17
17
  resources :transactions, only: [:show]
18
18
  end
19
19
 
20
+ namespace :mini_app do
21
+ # ACLEDA calls POST /mini_app/acleda with { phone, first_name, last_name }
22
+ # and receives a session-based miniAppUrl.
23
+ resources :acleda, only: [:create], controller: 'acledas'
24
+
25
+ # Wing Mini App WebView entry. Wing opens GET /mini_app/wing cold and the page
26
+ # itself authenticates via getProfile.
27
+ resource :wing, only: %i[show create], controller: 'wings' do
28
+ # Wing's settlement webhook: #callback verifies the payment via PaymentFinder and
29
+ # queues PaymentProcessorJob to complete the order unless it is already paid.
30
+ post :callback, on: :collection
31
+ end
32
+ end
33
+
20
34
  resource :vpago_payments do
21
35
  collection do
22
36
  get :checkout
@@ -23,8 +23,10 @@ module SpreeVpago
23
23
  Spree::Gateway::Acleda,
24
24
  Spree::Gateway::AcledaV2,
25
25
  Spree::Gateway::AcledaMobile,
26
+ Spree::Gateway::AcledaMiniApp,
26
27
  Spree::Gateway::Vattanac,
27
28
  Spree::Gateway::VattanacMiniApp,
29
+ Spree::Gateway::WingMiniApp,
28
30
  Spree::Gateway::TrueMoney,
29
31
  Spree::PaymentMethod::CashOn
30
32
  )
@@ -1,7 +1,7 @@
1
1
  module SpreeVpago
2
2
  module_function
3
3
 
4
- VERSION = '2.3.13'.freeze
4
+ VERSION = '2.3.14-pre1'.freeze
5
5
 
6
6
  def version
7
7
  Gem::Version.new VERSION
@@ -0,0 +1,19 @@
1
+ module Vpago
2
+ module AcledaMiniApp
3
+ # ACLEDA Mini App checkout. Reuses ACLEDA V2's openSessionV2 flow to obtain the deeplink
4
+ # the payment page opens, instead of redirecting the page to ACLEDA.
5
+ class Checkout < Vpago::AcledaV2::Checkout
6
+ # The mini app always pays by deeplink, regardless of the gateway's configured mode.
7
+ def deeplink?
8
+ true
9
+ end
10
+
11
+ # The deeplink _acleda_mini_app.html.erb opens. Ensures openSessionV2 has run
12
+ # (persisting paymentTokenid for the later getTxnStatus check) before returning it.
13
+ def acleda_deeplink
14
+ call if @response.nil?
15
+ deeplink_url
16
+ end
17
+ end
18
+ end
19
+ end
@@ -0,0 +1,35 @@
1
+ module Vpago
2
+ module AcledaMiniApp
3
+ # Verifies the HMAC-SHA256 signature ACLEDA sends via the X-Acleda-Signature
4
+ # header on the Session Initialization request (POST /mini_app/acleda), before
5
+ # we look up or create the user. Mirrors AcledaMobile::CallbackValidator's
6
+ # keyed-HMAC pattern, but out-of-band in a header instead of the JSON body.
7
+ class SessionHashValidator
8
+ def initialize(options)
9
+ @options = options
10
+ end
11
+
12
+ def call
13
+ valid?
14
+ end
15
+
16
+ # The key ACLEDA signs with lives only on their Spree::OauthApplication
17
+ # (MiniAppProvider::AcledaBank#secret_key), so it can be rotated from the admin
18
+ def secret_key
19
+ @options[:secret_key].presence
20
+ end
21
+
22
+ def valid?
23
+ return false if secret_key.blank? || @options[:hash].blank?
24
+
25
+ ActiveSupport::SecurityUtils.secure_compare(computed_hash, @options[:hash].to_s)
26
+ end
27
+
28
+ def computed_hash
29
+ message = "#{@options[:phone]}#{@options[:first_name]}#{@options[:last_name]}"
30
+
31
+ OpenSSL::HMAC.hexdigest(OpenSSL::Digest.new('sha256'), secret_key, message)
32
+ end
33
+ end
34
+ end
35
+ end
@@ -0,0 +1,60 @@
1
+ module Vpago
2
+ module WingMiniApp
3
+ # Builds the doPayment() payload (Wing Web JS Bridge SDK spec, Native API #2).
4
+ #
5
+ # useDefault is hardcoded true for this first cut — no "let the user pick
6
+ # another account" UI yet, same scope cut as shipping login before payment.
7
+ class Checkout
8
+ def initialize(payment)
9
+ @payment = payment
10
+ end
11
+
12
+ # Pure fields only — no payment_method preference lookup involved, safe to
13
+ # render/log/test directly. appId is left out here: it needs the gateway's
14
+ # own app_id, so it's added in #signed_payload alongside additionalKey instead.
15
+ def payload
16
+ {
17
+ account: account,
18
+ amount: amount,
19
+ currency: currency,
20
+ useDefault: true
21
+ }
22
+ end
23
+
24
+ # The full payload doPayment() actually needs, with appId and the
25
+ # server-side-only additionalKey.hash merged in. Never render
26
+ # `secret_api_key` itself into the page — only this derived hash.
27
+ def signed_payload
28
+ payload.merge(appId: app_id, additionalKey: { hash: hash, remark: '' })
29
+ end
30
+
31
+ def account
32
+ @payment.number
33
+ end
34
+
35
+ def amount
36
+ format('%.2f', @payment.amount)
37
+ end
38
+
39
+ def currency
40
+ @payment.currency
41
+ end
42
+
43
+ private
44
+
45
+ def app_id
46
+ payment_method.app_id
47
+ end
48
+
49
+ # uppercase(account+amount+currency+secretApiKey), per the spec.
50
+ def hash
51
+ plaintext = "#{account}#{amount}#{currency}#{payment_method.secret_api_key}"
52
+ Digest::SHA256.hexdigest(plaintext.upcase).upcase
53
+ end
54
+
55
+ def payment_method
56
+ @payment.payment_method
57
+ end
58
+ end
59
+ end
60
+ end
@@ -0,0 +1,78 @@
1
+ module Vpago
2
+ module WingMiniApp
3
+ # Verifies a Wing getStatus/webhook payload (Wing Web JS Bridge SDK spec,
4
+ # Native-App Invoke #1 getStatus) is both authentic and correct for the
5
+ # payment it claims to settle. Both checks live here, in one place:
6
+ #
7
+ # - the secretKey signature (proves Wing sent this, for this orderRef —
8
+ # unlike getProfile, appId is our own configured value here, not a payload
9
+ # field, since the spec's getStatus response never includes one)
10
+ # - the doc-mandated amount/currency match (catches a validly-signed webhook
11
+ # that reports the wrong amount, since Wing holds the keys and could sign
12
+ # any amount for a real orderRef if something on their end got it wrong —
13
+ # not a forgery guard, since orderRef is itself part of what secretKey
14
+ # signs, so a valid signature is already bound to exactly this payment)
15
+ class WebhookVerifier
16
+ FIELDS = %w[orderRef debitAmount debitCcy transactionId transactionDate].freeze
17
+
18
+ # payment is the specific one this settlement claims to be for — both what
19
+ # verifies the signature (via its own payment_method's app_id/secret_api_key)
20
+ # and what the amount/currency check runs against.
21
+ def initialize(payload, payment)
22
+ @payload = payload.with_indifferent_access
23
+ @payment = payment
24
+ end
25
+
26
+ def valid?
27
+ valid_signature? && amount_matches?
28
+ end
29
+
30
+ private
31
+
32
+ attr_reader :payload, :payment
33
+
34
+ def payment_method
35
+ payment.payment_method
36
+ end
37
+
38
+ def valid_signature?
39
+ received = payload['secretKey']
40
+ received.present? && candidates.value?(received.to_s.upcase)
41
+ end
42
+
43
+ # Numeric comparison, not string: Wing's own spec says debitAmount is always
44
+ # 2-decimal ("1.00"), but real payloads have sent "1" (no decimals) — same
45
+ # kind of spec-vs-reality gap as getProfile's `sex` field.
46
+ def amount_matches?
47
+ payment.amount == BigDecimal(payload['debitAmount'].to_s) &&
48
+ payment.currency.to_s.casecmp(payload['debitCcy'].to_s).zero?
49
+ rescue ArgumentError, TypeError
50
+ false
51
+ end
52
+
53
+ # Same spec-vs-reality gap, applied to the signature itself: Wing's own
54
+ # secretKey may have been computed against the canonical 2-decimal
55
+ # debitAmount even though what actually reached us isn't. Try both so a
56
+ # formatting-only mismatch between what Wing hashed and what Wing sent
57
+ # still verifies.
58
+ def candidates
59
+ {
60
+ raw: hash_for(payload['debitAmount'].to_s),
61
+ normalized: hash_for(normalized_debit_amount)
62
+ }
63
+ end
64
+
65
+ def normalized_debit_amount
66
+ format('%.2f', BigDecimal(payload['debitAmount'].to_s))
67
+ rescue ArgumentError, TypeError
68
+ payload['debitAmount'].to_s
69
+ end
70
+
71
+ def hash_for(debit_amount)
72
+ fields = FIELDS.map { |field| field == 'debitAmount' ? debit_amount : payload[field].to_s }.join
73
+ plaintext = "#{payment_method.app_id}#{fields}#{payment_method.secret_api_key}"
74
+ Digest::SHA256.hexdigest(plaintext.upcase).upcase
75
+ end
76
+ end
77
+ end
78
+ 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.13
4
+ version: 2.3.14.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-09-30 00:00:00.000000000 Z
11
+ date: 2026-10-06 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: faraday
@@ -149,7 +149,10 @@ files:
149
149
  - app/assets/javascripts/vpago/vpago_payments/check_transaction_periodically.js
150
150
  - app/assets/javascripts/vpago/vpago_payments/request_process_payment.js
151
151
  - app/assets/javascripts/vpago/vpago_payments/user_informers/firebase.js
152
+ - app/assets/javascripts/vpago/wing_mini_app/login.js
153
+ - app/assets/javascripts/vpago/wing_mini_app/web_jsbridge.bundle.js
152
154
  - app/controllers/.gitkeep
155
+ - app/controllers/concerns/spree/mini_app_concern.rb
153
156
  - app/controllers/spree/acleda_redirects_controller.rb
154
157
  - app/controllers/spree/admin/payment_acleda_v2_base_controller.rb
155
158
  - app/controllers/spree/admin/payment_acleda_v2_checkers_controller.rb
@@ -173,6 +176,8 @@ files:
173
176
  - app/controllers/spree/admin/payouts_controller.rb
174
177
  - app/controllers/spree/admin/suspicious_orders_controller.rb
175
178
  - app/controllers/spree/api/v2/storefront/checkout_controller_decorator.rb
179
+ - app/controllers/spree/mini_app/acledas_controller.rb
180
+ - app/controllers/spree/mini_app/wings_controller.rb
176
181
  - app/controllers/spree/payway_card_popups_controller.rb
177
182
  - app/controllers/spree/payway_results_controller.rb
178
183
  - app/controllers/spree/payway_v2_card_popups_controller.rb
@@ -198,6 +203,7 @@ files:
198
203
  - app/models/.gitkeep
199
204
  - app/models/concerns/vpago/payoutable.rb
200
205
  - app/models/spree/gateway/acleda.rb
206
+ - app/models/spree/gateway/acleda_mini_app.rb
201
207
  - app/models/spree/gateway/acleda_mobile.rb
202
208
  - app/models/spree/gateway/acleda_v2.rb
203
209
  - app/models/spree/gateway/payway.rb
@@ -205,6 +211,7 @@ files:
205
211
  - app/models/spree/gateway/true_money.rb
206
212
  - app/models/spree/gateway/vattanac.rb
207
213
  - app/models/spree/gateway/vattanac_mini_app.rb
214
+ - app/models/spree/gateway/wing_mini_app.rb
208
215
  - app/models/spree/gateway/wing_sdk.rb
209
216
  - app/models/spree/payment_method/cash_on.rb
210
217
  - app/models/spree/payout.rb
@@ -262,6 +269,7 @@ files:
262
269
  - app/serializers/spree/v2/storefront/payment_serializer_decorator.rb
263
270
  - app/serializers/spree/v2/storefront/vpago_payment_source_serializer.rb
264
271
  - app/services/.gitkeep
272
+ - app/services/vpago/acleda_mini_app/session/create.rb
265
273
  - app/services/vpago/aes_encrypter.rb
266
274
  - app/services/vpago/payment_finder.rb
267
275
  - app/services/vpago/payment_processable.rb
@@ -278,17 +286,20 @@ files:
278
286
  - app/services/vpago/rsa_handler.rb
279
287
  - app/services/vpago/user_informers/firebase.rb
280
288
  - app/services/vpago/vattanac_mini_app_data_handler.rb
289
+ - app/services/vpago/wing_mini_app/session/create.rb
281
290
  - app/views/.gitkeep
282
291
  - app/views/layouts/acleda.html.erb
283
292
  - app/views/layouts/payway.html.erb
284
293
  - app/views/layouts/payway_v2.html.erb
285
294
  - app/views/layouts/vpago_payments.html.erb
286
295
  - app/views/layouts/wing.html.erb
296
+ - app/views/layouts/wing_mini_app.html.erb
287
297
  - app/views/spree/_payment_icon.html.erb
288
298
  - app/views/spree/acleda_redirects/show.html.erb
289
299
  - app/views/spree/admin/payments/source_forms/_payment_payway.html.erb
290
300
  - app/views/spree/admin/payments/source_forms/_payway_v2.html.erb
291
301
  - app/views/spree/admin/payments/source_views/_acleda.html.erb
302
+ - app/views/spree/admin/payments/source_views/_acleda_mini_app.html.erb
292
303
  - app/views/spree/admin/payments/source_views/_acleda_mobile.html.erb
293
304
  - app/views/spree/admin/payments/source_views/_acleda_v2.html.erb
294
305
  - app/views/spree/admin/payments/source_views/_payment_payway.html.erb
@@ -297,6 +308,7 @@ files:
297
308
  - app/views/spree/admin/payments/source_views/_vattanac.html.erb
298
309
  - app/views/spree/admin/payments/source_views/_vattanac_mini_app.html.erb
299
310
  - app/views/spree/admin/payments/source_views/_vpago_payment_tmpl.html.erb
311
+ - app/views/spree/admin/payments/source_views/_wing_mini_app.html.erb
300
312
  - app/views/spree/admin/payments/source_views/_wingsdk.html.erb
301
313
  - app/views/spree/admin/payout_profile_products/_form.html.erb
302
314
  - app/views/spree/admin/payout_profile_products/edit.html.erb
@@ -338,6 +350,7 @@ files:
338
350
  - app/views/spree/checkout/payment/payway_form.html.erb
339
351
  - app/views/spree/checkout/payment/payway_v2_form.html.erb
340
352
  - app/views/spree/checkout/payment/wingsdk_form.html.erb
353
+ - app/views/spree/mini_app/wings/show.html.erb
341
354
  - app/views/spree/payway_card_popups/_form.html.erb
342
355
  - app/views/spree/payway_card_popups/show.html.erb
343
356
  - app/views/spree/payway_results/failed.html.erb
@@ -347,13 +360,16 @@ files:
347
360
  - app/views/spree/vpago_payments/_success_script.html.erb
348
361
  - app/views/spree/vpago_payments/_transaction_checker.html.erb
349
362
  - app/views/spree/vpago_payments/checkout.html.erb
363
+ - app/views/spree/vpago_payments/forms/spree/gateway/_acleda_mini_app.html.erb
350
364
  - app/views/spree/vpago_payments/forms/spree/gateway/_acleda_v2.html.erb
351
365
  - app/views/spree/vpago_payments/forms/spree/gateway/_payway_v2.html.erb
352
366
  - app/views/spree/vpago_payments/forms/spree/gateway/_true_money.html.erb
353
367
  - app/views/spree/vpago_payments/forms/spree/gateway/_vattanac.html.erb
354
368
  - app/views/spree/vpago_payments/forms/spree/gateway/_vattanac_mini_app.html.erb
369
+ - app/views/spree/vpago_payments/forms/spree/gateway/_wing_mini_app.html.erb
355
370
  - app/views/spree/vpago_payments/processing.html.erb
356
371
  - app/views/spree/vpago_payments/processing_scripts/spree/gateway/_payway_v2.html.erb
372
+ - app/views/spree/vpago_payments/processing_scripts/spree/gateway/_wing_mini_app.html.erb
357
373
  - app/views/spree/vpago_payments/success.html.erb
358
374
  - app/views/spree/wing_redirects/show.html.erb
359
375
  - bin/rails
@@ -398,6 +414,8 @@ files:
398
414
  - lib/vpago/acleda/deeplink_checkout.rb
399
415
  - lib/vpago/acleda/payment_request_updater.rb
400
416
  - lib/vpago/acleda/transaction_status.rb
417
+ - lib/vpago/acleda_mini_app/checkout.rb
418
+ - lib/vpago/acleda_mini_app/session_hash_validator.rb
401
419
  - lib/vpago/acleda_mobile/base.rb
402
420
  - lib/vpago/acleda_mobile/callback_validator.php
403
421
  - lib/vpago/acleda_mobile/callback_validator.rb
@@ -438,6 +456,8 @@ files:
438
456
  - lib/vpago/vattanac_mini_app/base.rb
439
457
  - lib/vpago/vattanac_mini_app/checkout.rb
440
458
  - lib/vpago/vattanac_mini_app/refund_issuer.rb
459
+ - lib/vpago/wing_mini_app/checkout.rb
460
+ - lib/vpago/wing_mini_app/webhook_verifier.rb
441
461
  - lib/vpago/wing_sdk/base.rb
442
462
  - lib/vpago/wing_sdk/checkout.rb
443
463
  - lib/vpago/wing_sdk/payment_request_updater.rb
@@ -466,9 +486,9 @@ required_ruby_version: !ruby/object:Gem::Requirement
466
486
  version: 3.2.0
467
487
  required_rubygems_version: !ruby/object:Gem::Requirement
468
488
  requirements:
469
- - - ">="
489
+ - - ">"
470
490
  - !ruby/object:Gem::Version
471
- version: '0'
491
+ version: 1.3.1
472
492
  requirements:
473
493
  - none
474
494
  rubygems_version: 3.4.1