spree_vpago 2.0.8.pre.beta3 → 2.0.8.pre.beta5
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 +4 -4
- data/Gemfile.lock +3 -3
- data/app/assets/config/spree_vpago_manifest.js +1 -0
- data/app/assets/javascripts/vpago/vpago_payments/payment_processing_listener.js +46 -0
- data/app/controllers/spree/vpago_payments_controller.rb +0 -6
- data/app/models/vpago/payment_decorator.rb +0 -1
- data/app/models/vpago/payouts_generator.rb +36 -4
- data/app/services/vpago/payment_finder.rb +3 -8
- data/app/services/vpago/payment_url_constructor.rb +0 -1
- data/app/services/vpago/rsa_handler.rb +1 -1
- data/app/views/spree/vpago_payments/forms/spree/gateway/_true_money.html.erb +65 -5
- data/app/views/spree/vpago_payments/forms/spree/gateway/_vattanac_mini_app.html.erb +40 -81
- data/lib/spree_vpago/version.rb +1 -1
- metadata +3 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 301cc71a3e4d2b5034d5775a0cb2a38ea99d85d81493f16de91b5e665b9df824
|
4
|
+
data.tar.gz: 41b87f4e16cacd0d4ec3fe6e662c4f9eddbf05b01f2d5a09cd30da7d0c72ff57
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 76271cbcb8ac7961c5d3cb9c1903c2d1c610e1e070cbcb25731d9eafb27d4dcd846e74c21b5612f9a1a15d08cd70181aaf5cf0945299bf9422145afc2717f4b3
|
7
|
+
data.tar.gz: 17342da573c482da7f90214c0bc3230dd52e8c61883cb48cca0524176d5b6ddb8ed5d7b43ef9ada9f84468c261e1e8122ba375c3276bdfb7229ec8776f9ad1eb
|
data/Gemfile.lock
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
PATH
|
2
2
|
remote: .
|
3
3
|
specs:
|
4
|
-
spree_vpago (2.0.8.pre.
|
4
|
+
spree_vpago (2.0.8.pre.beta5)
|
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.
|
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.
|
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)
|
@@ -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
|
@@ -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
|
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 =
|
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
|
{
|
@@ -1,9 +1,69 @@
|
|
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
|
-
|
5
|
-
|
6
|
-
|
5
|
+
<p id="status-message" class="font-bold text-center my-4 text-primary">xcxcx</p>
|
6
|
+
|
7
|
+
<script>
|
8
|
+
document.addEventListener("DOMContentLoaded", () => {
|
9
|
+
|
10
|
+
const firebaseConfigs = <%= Rails.application.credentials.firebase_web_config.to_json.html_safe %>;
|
11
|
+
|
12
|
+
window.listenToProcessingState({
|
13
|
+
firebaseConfigs: firebaseConfigs,
|
14
|
+
documentReferencePath: "<%= @payment.user_informer.document_reference_path %>",
|
15
|
+
|
16
|
+
onPaymentIsProcessing: function (orderState, paymentState, processing, reasonCode, reasonMessage) {
|
17
|
+
updateStatusMessage("Payment is processing...");
|
18
|
+
},
|
19
|
+
|
20
|
+
onOrderIsProcessing: function (orderState, paymentState, processing, reasonCode, reasonMessage) {
|
21
|
+
updateStatusMessage("Order is processing...");
|
22
|
+
},
|
23
|
+
|
24
|
+
onOrderIsCompleted: function (orderState, paymentState, processing, reasonCode, reasonMessage) {
|
25
|
+
updateStatusMessage("Order is completed!");
|
26
|
+
},
|
27
|
+
|
28
|
+
onOrderProcessFailed: function (orderState, paymentState, processing, reasonCode, reasonMessage) {
|
29
|
+
updateStatusMessage("Order process failed: " + reasonMessage);
|
30
|
+
},
|
31
|
+
|
32
|
+
onPaymentIsRefunded: function (orderState, paymentState, processing, reasonCode, reasonMessage) {
|
33
|
+
updateStatusMessage("Payment has been refunded.");
|
34
|
+
},
|
35
|
+
|
36
|
+
onPaymentProcessFailed: function (orderState, paymentState, processing, reasonCode, reasonMessage) {
|
37
|
+
updateStatusMessage("Payment process failed: " + reasonMessage);
|
38
|
+
},
|
39
|
+
|
40
|
+
onCompleted: function (orderState, paymentState, processing, reasonCode, reasonMessage) {
|
41
|
+
updateStatusMessage("Completed — redirecting...");
|
42
|
+
let successPath = "<%= @payment.success_url %>";
|
43
|
+
window.location.href = successPath;
|
44
|
+
},
|
7
45
|
});
|
8
|
-
</script>
|
9
46
|
|
47
|
+
const statusMessageElement = document.getElementById("status-message");
|
48
|
+
|
49
|
+
function updateStatusMessage(message) {
|
50
|
+
if (statusMessageElement) {
|
51
|
+
statusMessageElement.textContent = message;
|
52
|
+
}
|
53
|
+
}
|
54
|
+
|
55
|
+
const setupConfirmPaymentButton = () => {
|
56
|
+
const confirmButton = document.getElementById("confirm-payment-button");
|
57
|
+
if (!confirmButton) return;
|
58
|
+
|
59
|
+
confirmButton.addEventListener("click", () => {
|
60
|
+
window.open("<%= j redirect_url %>", "_blank");
|
61
|
+
updateStatusMessage("Redirected to payment gateway...");
|
62
|
+
});
|
63
|
+
};
|
64
|
+
|
65
|
+
setupConfirmPaymentButton();
|
66
|
+
|
67
|
+
|
68
|
+
});
|
69
|
+
</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
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
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
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
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
|
-
|
57
|
-
|
58
|
-
|
59
|
-
console.log("
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
-
|
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>
|
data/lib/spree_vpago/version.rb
CHANGED
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.
|
4
|
+
version: 2.0.8.pre.beta5
|
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-
|
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
|