spree_vpago 2.0.8.pre.beta3 → 2.0.8.pre.beta4

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: a60df6ffc7539631a90fd4076f856cb62517d0c589a6f0bb18f9e109e4708dc5
4
- data.tar.gz: 572c3179370f5ddc763cfffe3a4cbbce054537b0a26620c7e4e9041e2e5b14bb
3
+ metadata.gz: 347bcfd7a5120dff061943a3ac91bdc64e22dca81f9bf046b028c06bd7f50521
4
+ data.tar.gz: e7261ee32ab96b7e3f43e4089b88f6b7a2505674055e6d48e0da434c90b6dbf5
5
5
  SHA512:
6
- metadata.gz: bb331771b411e9b54d85d2810d4849e18574c5155a878922730014a0618393b27392d167c3596471e3322a32b12b111c8eda97718955675c72450d1ffee02a46
7
- data.tar.gz: 89f4e3adbb4a08772e0b32a584a412934b6697d9b96a92da2af2904ada71233f481886b50a9c863a98eea5015d41d969376b61e8af499a5be84938d318481b7a
6
+ metadata.gz: 3705d3643e441c22533dd68def749c8e7569afe2f78a6a0134046674d82d60d9e8416720817d9cebc7d351b4011081b3fb284822612bf2f324b53ab6f92acf77
7
+ data.tar.gz: bb38cab70179348c732fd2358086a8c3e4957f5fad20fa7a9ee18ef8abea2febcb01c9efae211882e8ad7f6fbbdc1803ec5e3d57bed923c0b1d35bdbe4f819cb
data/Gemfile.lock CHANGED
@@ -1,7 +1,7 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- spree_vpago (2.0.8.pre.beta3)
4
+ spree_vpago (2.0.8.pre.beta4)
5
5
  faraday
6
6
  google-cloud-firestore
7
7
  spree_api (>= 4.5)
@@ -198,7 +198,7 @@ GEM
198
198
  flatpickr (4.6.13.1)
199
199
  friendly_id (5.5.0)
200
200
  activerecord (>= 4.0.0)
201
- gapic-common (1.0.0)
201
+ gapic-common (1.0.1)
202
202
  faraday (>= 1.9, < 3.a)
203
203
  faraday-retry (>= 1.0, < 3.a)
204
204
  google-cloud-env (~> 2.2)
@@ -234,7 +234,7 @@ GEM
234
234
  google-cloud-core (~> 1.7)
235
235
  google-cloud-firestore-v1 (~> 2.0)
236
236
  rbtree (~> 0.4.2)
237
- google-cloud-firestore-v1 (2.1.0)
237
+ google-cloud-firestore-v1 (2.1.1)
238
238
  gapic-common (~> 1.0)
239
239
  google-cloud-errors (~> 1.0)
240
240
  google-cloud-location (~> 1.0)
@@ -1,3 +1,4 @@
1
1
  //= link_tree ../images
2
2
  //= link vpago/vpago_payments/request_process_payment.js
3
3
  //= link vpago/vpago_payments/user_informers/firebase.js
4
+ //= link vpago/vpago_payments/payment_processing_listener.js
@@ -0,0 +1,46 @@
1
+ window.initPaymentProcessingListener = async function (
2
+ firebaseConfigs,
3
+ documentReferencePath,
4
+ successUrl
5
+ ) {
6
+ function log(status, processing, reasonCode, reasonMessage) {
7
+ console.log(`Status: ${status}`);
8
+ console.log(`Reason Code: ${reasonCode}`);
9
+ console.log(`Processing: ${processing ? "Processing..." : "No more process."}`);
10
+ console.log(`Reason Message: ${reasonMessage}`);
11
+ }
12
+
13
+ window.listenToProcessingState({
14
+ firebaseConfigs,
15
+ documentReferencePath,
16
+
17
+ onPaymentIsProcessing(orderState, paymentState, processing, reasonCode, reasonMessage) {
18
+ log("Payment is processing", processing, reasonCode, reasonMessage);
19
+ },
20
+
21
+ onOrderIsProcessing(orderState, paymentState, processing, reasonCode, reasonMessage) {
22
+ log("Order is processing", processing, reasonCode, reasonMessage);
23
+ },
24
+
25
+ onOrderIsCompleted(orderState, paymentState, processing, reasonCode, reasonMessage) {
26
+ log("Order is completed", processing, reasonCode, reasonMessage);
27
+ },
28
+
29
+ onOrderProcessFailed(orderState, paymentState, processing, reasonCode, reasonMessage) {
30
+ log("Order process failed", processing, reasonCode, reasonMessage);
31
+ },
32
+
33
+ onPaymentIsRefunded(orderState, paymentState, processing, reasonCode, reasonMessage) {
34
+ log("Payment is refunded", processing, reasonCode, reasonMessage);
35
+ },
36
+
37
+ onPaymentProcessFailed(orderState, paymentState, processing, reasonCode, reasonMessage) {
38
+ log("Payment process failed", processing, reasonCode, reasonMessage);
39
+ },
40
+
41
+ onCompleted(orderState, paymentState, processing, reasonCode, reasonMessage) {
42
+ log("Completed — redirecting to success URL", processing, reasonCode, reasonMessage);
43
+ window.location.href = successUrl;
44
+ }
45
+ });
46
+ };
@@ -33,12 +33,6 @@ module Spree
33
33
 
34
34
  @order = @payment.order
35
35
  raise CanCan::AccessDenied unless @order.completed?
36
-
37
- if params[:offsite_payment].present?
38
- redirect_to @payment.payment_url, allow_other_host: true
39
- else
40
- render :success
41
- end
42
36
  end
43
37
 
44
38
  # POST
@@ -10,7 +10,6 @@ module Vpago
10
10
  :processing_deeplink_url,
11
11
  :success_url,
12
12
  :process_payment_url,
13
- :payment_url,
14
13
  to: :url_constructor
15
14
  end
16
15
 
@@ -30,7 +30,15 @@ module Vpago
30
30
  return [] if payouts.all?(&:default?)
31
31
  return [] unless payouts.all? { |payout| validated?(payout) }
32
32
 
33
- ActiveRecord::Base.transaction { payouts.each(&:save!) }
33
+ ActiveRecord::Base.transaction do
34
+ payouts.each(&:save!)
35
+
36
+ # If any payouts were rounded, the total may increase slightly.
37
+ # Update the payment amount to match the sum of payouts to avoid mismatch errors.
38
+ payment.update(amount: payouts.map(&:amount).sum)
39
+
40
+ payouts
41
+ end
34
42
  end
35
43
 
36
44
  def validated?(payout)
@@ -47,7 +55,7 @@ module Vpago
47
55
  total_confirmed_payouts = line_item.confirmed_payouts_for_vendor.sum(:amount)
48
56
  next if total_confirmed_payouts >= line_item.pre_commission_amount
49
57
 
50
- amount_owed_to_vendor = line_item.pre_commission_amount - total_confirmed_payouts
58
+ amount_owed_to_vendor = round_up(line_item.pre_commission_amount - total_confirmed_payouts)
51
59
  payout_amount = [amount_owed_to_vendor, remaining_amount].min
52
60
  outstanding_amount = [amount_owed_to_vendor - payout_amount, 0].max
53
61
 
@@ -80,7 +88,7 @@ module Vpago
80
88
  total_confirmed_payouts = shipment.confirmed_payouts_for_vendor.sum(:amount)
81
89
  next if total_confirmed_payouts >= shipment.cost_with_vendor_adjustment_total
82
90
 
83
- amount_owed_to_shipping_vendor = shipment.cost_with_vendor_adjustment_total - total_confirmed_payouts
91
+ amount_owed_to_shipping_vendor = round_up(shipment.cost_with_vendor_adjustment_total - total_confirmed_payouts)
84
92
  payout_amount = [amount_owed_to_shipping_vendor, remaining_amount].min
85
93
  outstanding_amount = [amount_owed_to_shipping_vendor - payout_amount, 0].max
86
94
 
@@ -117,9 +125,33 @@ module Vpago
117
125
  state: :created,
118
126
  payment: payment,
119
127
  payout_profile: Spree::PayoutProfiles::PaywayV2.default,
120
- amount: self.remaining_amount
128
+ amount: round_up(self.remaining_amount)
121
129
  )
122
130
  ]
123
131
  end
132
+
133
+ # ABA does not support amounts with more than 2 decimal places.
134
+ # Therefore, we must round all 3-decimal payouts to 2 decimals beforehand.
135
+ #
136
+ # Our rounding strategy:
137
+ # - We round up for vendors & shipment payouts (to favor external parties).
138
+ # - The remaining amount is adjusted in the platform's share (may be slightly less).
139
+ #
140
+ # Example:
141
+ # Total amount: $5.00
142
+ #
143
+ # Vendor payouts:
144
+ # - Vendor 1: $0.625 → $0.63
145
+ # - Vendor 2: $0.625 → $0.63
146
+ #
147
+ # Shipment payouts:
148
+ # - Shipment 1: $0.625 → $0.63
149
+ # - Shipment 2: $0.625 → $0.63
150
+ #
151
+ # Platform payout:
152
+ # - $2.50 → $2.48 (adjusted to ensure total remains $5.00)
153
+ def round_up(amount)
154
+ (amount * 100).ceil / 100.0
155
+ end
124
156
  end
125
157
  end
@@ -7,7 +7,6 @@ module Vpago
7
7
  end
8
8
 
9
9
  def find_and_verify
10
-
11
10
  find_and_verify!
12
11
  rescue StandardError, ActiveRecord::RecordNotFound => e
13
12
  Rails.logger.error("PaymentJwtVerifier#find_and_verify error: #{e.class} - #{e.message}")
@@ -15,16 +14,15 @@ module Vpago
15
14
  end
16
15
 
17
16
  def find_and_verify!
18
-
19
17
  if vattanac_mini_app_payload?
20
- payload = Vpago::VattanacMiniAppDataHandler.new.decrypt_data(@params_hash[:data])
18
+ payload = Vpago::VattanacMiniAppDataHandler.new.decrypt_data(@params_hash[:data])
21
19
  payment = Spree::Payment.find_by!(number: payload['paymentId'])
22
20
  payment.update(transaction_response: payload)
23
21
  payment
24
- else
22
+ else
25
23
  order = Spree::Order.find_by!(number: params_hash[:order_number])
26
24
  verify_jwt!(order)
27
-
25
+
28
26
  Spree::Payment.find_by!(number: params_hash[:payment_number])
29
27
  end
30
28
  end
@@ -36,8 +34,5 @@ module Vpago
36
34
  def vattanac_mini_app_payload?
37
35
  params_hash[:data].present?
38
36
  end
39
-
40
37
  end
41
38
  end
42
-
43
-
@@ -15,7 +15,6 @@ module Vpago
15
15
  def processing_deeplink_url = "#{@payment.payment_method.preferred_return_url_scheme}/vpago_payments/processing?#{query}"
16
16
  def success_url = "#{base_url}/vpago_payments/success?#{query}"
17
17
  def process_payment_url = "#{base_url}/vpago_payments/process_payment?#{query}"
18
- def payment_url = "#{base_url}/book/payment?number=#{@payment.order.number}&tk=#{@payment.order.token}"
19
18
 
20
19
  def query
21
20
  {
@@ -30,4 +30,4 @@ module Vpago
30
30
  Base64.strict_encode64(private_key.sign(sign_hash, payload))
31
31
  end
32
32
  end
33
- end
33
+ end
@@ -1,9 +1,33 @@
1
1
  <% @checkout = ::Vpago::TrueMoney::Checkout.new(@payment) %>
2
- <% redirect_url = @checkout.generate_payment_urls(params[:platform])%>
2
+ <% redirect_url = @checkout.generate_payment_urls(params[:platform]) %>
3
+ <% @payment.user_informer.payment_is_processing(processing: true) %>
3
4
 
4
- <script>
5
- document.addEventListener("DOMContentLoaded", function () {
6
- window.top.location.href = "<%= j redirect_url %>";
7
- });
8
- </script>
5
+ <script>
6
+ document.addEventListener("DOMContentLoaded", () => {
9
7
 
8
+ const setupConfirmPaymentButton = () => {
9
+ const confirmButton = document.getElementById("confirm-payment-button");
10
+ if (!confirmButton) return;
11
+
12
+ confirmButton.addEventListener("click", () => {
13
+ window.open("<%= j redirect_url %>", "_blank");
14
+ });
15
+ };
16
+
17
+ const setupPaymentProcessingListener = () => {
18
+ const firebaseConfigs = <%= Rails.application.credentials.firebase_web_config.to_json.html_safe %>;
19
+ const documentReferencePath = "<%= @payment.user_informer.document_reference_path %>";
20
+ const successUrl = "<%= @payment.success_url %>";
21
+
22
+ if (window.initPaymentProcessingListener) {
23
+ window.initPaymentProcessingListener(firebaseConfigs, documentReferencePath, successUrl);
24
+ } else {
25
+ console.warn("initPaymentProcessingListener is not defined");
26
+ }
27
+ };
28
+
29
+ setupConfirmPaymentButton();
30
+ setupPaymentProcessingListener();
31
+
32
+ });
33
+ </script>
@@ -2,92 +2,51 @@
2
2
  <% @payment.user_informer.payment_is_processing(processing: true) %>
3
3
 
4
4
  <p id="unsupported-message"
5
- style="margin-top: 10px;
6
- font-weight: bold;
7
- color: red;
8
- display: none;">
5
+ style="margin-top: 10px; font-weight: bold; color: red; display: none;">
9
6
  </p>
10
7
 
11
8
  <script>
12
- function detectMobileOS() {
13
- const ua = navigator.userAgent || navigator.vendor || window.opera;
14
- if (/iPad|iPhone|iPod/.test(ua) && !window.MSStream) return 'iOS';
15
- if (/Android/i.test(ua)) return 'Android';
16
- return 'unknown';
17
- }
18
-
19
- document.addEventListener('DOMContentLoaded', () => {
20
- const os = detectMobileOS();
21
- const payload = {
22
- data: "<%= j @checkout.signed_payload %>",
23
- paymentId: "<%= @checkout.payment_id %>"
9
+ document.addEventListener("DOMContentLoaded", () => {
10
+
11
+ const setupMiniAppPayment = () => {
12
+ const detectMobileOS = () => {
13
+ const ua = navigator.userAgent || navigator.vendor || window.opera;
14
+ if (/iPad|iPhone|iPod/.test(ua) && !window.MSStream) return 'iOS';
15
+ if (/Android/i.test(ua)) return 'Android';
16
+ return 'unknown';
17
+ };
18
+
19
+ const os = detectMobileOS();
20
+ const payload = {
21
+ data: "<%= j @checkout.signed_payload %>",
22
+ paymentId: "<%= @checkout.payment_id %>"
23
+ };
24
+
25
+ if (os === 'iOS' && window.webkit?.messageHandlers?.startPayment) {
26
+ window.webkit.messageHandlers.startPayment.postMessage(JSON.stringify(payload));
27
+ } else if (os === 'Android' && window.AndroidInterface?.startPayment) {
28
+ window.AndroidInterface.startPayment(JSON.stringify(payload));
29
+ } else {
30
+ const unsupported = document.getElementById('unsupported-message');
31
+ unsupported.style.display = 'block';
32
+ unsupported.innerText = 'Unsupported OS';
33
+ }
24
34
  };
25
35
 
26
- if (os === 'iOS' && window.webkit?.messageHandlers?.startPayment) {
27
- window.webkit.messageHandlers.startPayment.postMessage(JSON.stringify(payload));
28
- } else if (os === 'Android' && window.AndroidInterface?.startPayment) {
29
- window.AndroidInterface.startPayment(JSON.stringify(payload));
30
- } else {
31
- const unsupported = document.getElementById('unsupported-message');
32
- unsupported.style.display = 'block';
33
- unsupported.innerText = 'Unsupported OS';
34
- }
35
-
36
- const firebaseConfigs = <%= Rails.application.credentials.firebase_web_config.to_json.html_safe %>;
37
-
38
- window.listenToProcessingState({
39
- firebaseConfigs: firebaseConfigs,
40
- documentReferencePath: "<%= @payment.user_informer.document_reference_path %>",
41
-
42
- onPaymentIsProcessing: function (orderState, paymentState, processing, reasonCode, reasonMessage) {
43
- console.log("Status: Payment is processing");
44
- console.log("Reason Code:", reasonCode);
45
- console.log("Processing:", processing ? "Processing..." : "No more process.");
46
- console.log("Reason Message:", reasonMessage);
47
- },
48
-
49
- onOrderIsProcessing: function (orderState, paymentState, processing, reasonCode, reasonMessage) {
50
- console.log("Status: Order is processing");
51
- console.log("Reason Code:", reasonCode);
52
- console.log("Processing:", processing ? "Processing..." : "No more process.");
53
- console.log("Reason Message:", reasonMessage);
54
- },
36
+ const setupPaymentProcessingListener = () => {
37
+ const firebaseConfigs = <%= Rails.application.credentials.firebase_web_config.to_json.html_safe %>;
38
+ const documentReferencePath = "<%= @payment.user_informer.document_reference_path %>";
39
+ const successUrl = "<%= @payment.success_url %>";
55
40
 
56
- onOrderIsCompleted: function (orderState, paymentState, processing, reasonCode, reasonMessage) {
57
- console.log("Status: Order is completed");
58
- console.log("Reason Code:", reasonCode);
59
- console.log("Processing:", processing ? "Processing..." : "No more process.");
60
- console.log("Reason Message:", reasonMessage);
61
- },
62
-
63
- onOrderProcessFailed: function (orderState, paymentState, processing, reasonCode, reasonMessage) {
64
- console.log("Status: Order process failed");
65
- console.log("Reason Code:", reasonCode);
66
- console.log("Processing:", processing ? "Processing..." : "No more process.");
67
- console.log("Reason Message:", reasonMessage);
68
- },
69
-
70
- onPaymentIsRefunded: function (orderState, paymentState, processing, reasonCode, reasonMessage) {
71
- console.log("Status: Payment is refunded");
72
- console.log("Reason Code:", reasonCode);
73
- console.log("Processing:", processing ? "Processing..." : "No more process.");
74
- console.log("Reason Message:", reasonMessage);
75
- },
76
-
77
- onPaymentProcessFailed: function (orderState, paymentState, processing, reasonCode, reasonMessage) {
78
- console.log("Status: Payment process failed");
79
- console.log("Reason Code:", reasonCode);
80
- console.log("Processing:", processing ? "Processing..." : "No more process.");
81
- console.log("Reason Message:", reasonMessage);
82
- },
83
-
84
- onCompleted: function (orderState, paymentState, processing, reasonCode, reasonMessage) {
85
- console.log("Status: Completed — redirecting to success URL");
86
- console.log("Reason Code:", reasonCode);
87
- console.log("Reason Message:", reasonMessage);
88
- let successPath = "<%= @payment.success_url %>";
89
- window.location.href = successPath;
90
- },
91
- });
41
+ if (window.initPaymentProcessingListener) {
42
+ window.initPaymentProcessingListener(firebaseConfigs, documentReferencePath, successUrl);
43
+ } else {
44
+ console.log("initPaymentProcessingListener is not defined");
45
+ }
46
+ };
47
+
48
+ setupMiniAppPayment();
49
+ setupPaymentProcessingListener();
50
+
92
51
  });
93
52
  </script>
@@ -1,7 +1,7 @@
1
1
  module SpreeVpago
2
2
  module_function
3
3
 
4
- VERSION = '2.0.8-beta3'.freeze
4
+ VERSION = '2.0.8-beta4'.freeze
5
5
 
6
6
  def version
7
7
  Gem::Version.new VERSION
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.0.8.pre.beta3
4
+ version: 2.0.8.pre.beta4
5
5
  platform: ruby
6
6
  authors:
7
7
  - You
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2025-07-18 00:00:00.000000000 Z
11
+ date: 2025-07-19 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: faraday
@@ -134,6 +134,7 @@ files:
134
134
  - app/assets/images/backend-process.svg
135
135
  - app/assets/images/vpago/payway/abapay.png
136
136
  - app/assets/images/vpago/payway/cards.png
137
+ - app/assets/javascripts/vpago/vpago_payments/payment_processing_listener.js
137
138
  - app/assets/javascripts/vpago/vpago_payments/request_process_payment.js
138
139
  - app/assets/javascripts/vpago/vpago_payments/user_informers/firebase.js
139
140
  - app/controllers/.gitkeep