spree_vpago 2.0.7 → 2.0.8.pre.beta

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: eb3a7b1fa94262546a09d03510144c9a923d7db5cb13e5bb33cd937f591b7ac9
4
- data.tar.gz: 86a1ea9da9aaf8212fc03181ef1c2753fab9fc2f0472f667ef96d86a2043cf02
3
+ metadata.gz: a199976c2692ad4d201ea9890163e430f6ac62eaa65104585718ca081c303fa4
4
+ data.tar.gz: 076e9460e262219196e66ee01e280274d8920bba2d484989e5caf5eee86a9eeb
5
5
  SHA512:
6
- metadata.gz: 26fe7fe3afc893375ef4fd84a9c327d8031f62cc808dbb7e1b089a5f3364d8caac9658a9380d77088ecfc4d00cc920d1bf58b1cea28e09da05fd525e6a8b9d93
7
- data.tar.gz: d385494623090fa259f2bd827f09be1fe4cf7be96ba19959d988b81f068253377e3c7461cc9868663731eafc5dbf64a8006e9ac89cc2b56a457c8b2c16f5586d
6
+ metadata.gz: 67e72026f867e78955f05fe93aed5dfa86d1ef51a919d8af699c372db0067f6a40ad11cbe39d96f6354f33f49117084ecf17f09fc5a23b3f7dfa116635eff961
7
+ data.tar.gz: 877c24547ea819b7b10fe4c2410b30f6776e859b72b382e11c712854247b02cfa44bbcb39f7c1807d8bd6e2cbda344549e1c151ed7f18a43b95a34bdc92be1a1
data/Gemfile.lock CHANGED
@@ -1,7 +1,7 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- spree_vpago (2.0.7)
4
+ spree_vpago (2.0.8.pre.beta)
5
5
  faraday
6
6
  google-cloud-firestore
7
7
  spree_api (>= 4.5)
@@ -242,7 +242,7 @@ GEM
242
242
  gapic-common (~> 1.0)
243
243
  google-cloud-errors (~> 1.0)
244
244
  google-logging-utils (0.2.0)
245
- google-protobuf (4.31.1)
245
+ google-protobuf (4.31.1-arm64-darwin)
246
246
  bigdecimal
247
247
  rake (>= 13)
248
248
  googleapis-common-protos (1.8.0)
@@ -259,7 +259,7 @@ GEM
259
259
  multi_json (~> 1.11)
260
260
  os (>= 0.9, < 2.0)
261
261
  signet (>= 0.16, < 2.a)
262
- grpc (1.73.0)
262
+ grpc (1.73.0-arm64-darwin)
263
263
  google-protobuf (>= 3.25, < 5.0)
264
264
  googleapis-common-protos-types (~> 1.0)
265
265
  hashdiff (1.1.0)
@@ -19,6 +19,7 @@ module Vpago
19
19
  payway_cards
20
20
  wingpay
21
21
  vattanac_mini_app
22
+ true_money
22
23
  ]
23
24
  end
24
25
 
@@ -0,0 +1,90 @@
1
+ module Spree
2
+ class Gateway::TrueMoney < PaymentMethod
3
+ preference :check_transaction_url, :string
4
+ preference :refund_url, :string
5
+ preference :generate_payment_url, :string
6
+ preference :access_token_url, :string
7
+
8
+ preference :client_id, :string
9
+ preference :client_secret, :string
10
+ preference :private_key, :text
11
+ preference :merchant_scheme, :string
12
+ preference :merchant_android_package_name, :string
13
+
14
+ def method_type
15
+ 'true_money'
16
+ end
17
+
18
+ def payment_source_class
19
+ Spree::VpagoPaymentSource
20
+ end
21
+
22
+ # force to purchase instead of authorize
23
+ def auto_capture?
24
+ true
25
+ end
26
+
27
+ # override
28
+ # purchase is used when pre auth disabled
29
+ def purchase(_amount, _source, gateway_options = {})
30
+ _, payment_number = gateway_options[:order_id].split('-')
31
+ payment = Spree::Payment.find_by(number: payment_number)
32
+
33
+ checker = check_transaction(payment)
34
+ payment.update(transaction_response: checker.json_response)
35
+
36
+ success = checker.success?
37
+ params = {}
38
+
39
+ params[:payment_response] = payment.transaction_response
40
+
41
+ if success
42
+ ActiveMerchant::Billing::Response.new(true, 'Payway Gateway: Purchased', params)
43
+ else
44
+ ActiveMerchant::Billing::Response.new(false, 'Payway Gateway: Purchasing Failed', params)
45
+ end
46
+ end
47
+
48
+ # override
49
+ def void(_response_code, gateway_options)
50
+ _, payment_number = gateway_options[:order_id].split('-')
51
+ payment = Spree::Payment.find_by(number: payment_number)
52
+
53
+ if payment.true_money_payment?
54
+ params = {}
55
+ success, params[:refund_response] = true_money_refund(payment)
56
+
57
+ if success
58
+ ActiveMerchant::Billing::Response.new(true, 'Payway Gateway: successfully canceled.', params)
59
+ else
60
+ ActiveMerchant::Billing::Response.new(false, 'Payway Gateway: Failed to canceleed', params)
61
+ end
62
+ else
63
+ ActiveMerchant::Billing::Response.new(true, 'Payway Gateway: Payment has been voided.')
64
+ end
65
+ end
66
+
67
+ def true_money_refund(payment)
68
+ refund_issuer = Vpago::TrueMoney::RefundIssuer.new(payment, {})
69
+ refund_issuer.call
70
+
71
+ [refund_issuer.success?, refund_issuer.response]
72
+ end
73
+
74
+ def cancel(_response_code, _payment)
75
+ # we can use this to send request to payment gateway api to cancel the payment ( void )
76
+ # currently Payway does not support to cancel the gateway
77
+
78
+ # in our case don't do anything
79
+ ActiveMerchant::Billing::Response.new(true, '')
80
+ end
81
+
82
+ private
83
+
84
+ def check_transaction(payment)
85
+ checker = Vpago::TrueMoney::TransactionStatus.new(payment)
86
+ checker.call
87
+ checker
88
+ end
89
+ end
90
+ end
@@ -8,6 +8,7 @@ module Vpago
8
8
  :processing_url,
9
9
  :success_url,
10
10
  :process_payment_url,
11
+ :processing_app_url,
11
12
  to: :url_constructor
12
13
  end
13
14
 
@@ -6,6 +6,7 @@ module Vpago
6
6
  TYPE_ACLEDA = 'Spree::Gateway::Acleda'.freeze
7
7
  TYPE_ACLEDA_MOBILE = 'Spree::Gateway::AcledaMobile'.freeze
8
8
  TYPE_VATTANAC_MINI_APP = 'Spree::Gateway::VattanacMiniApp'.freeze
9
+ TYPE_TRUE_MONEY = 'Spree::Gateway::TrueMoney'.freeze
9
10
 
10
11
  def self.prepended(base)
11
12
  base.preference :icon_name, :string, default: 'cheque'
@@ -18,7 +19,8 @@ module Vpago
18
19
  Spree::PaymentMethod::TYPE_WINGSDK,
19
20
  Spree::PaymentMethod::TYPE_ACLEDA,
20
21
  Spree::PaymentMethod::TYPE_ACLEDA_MOBILE,
21
- Spree::PaymentMethod::TYPE_VATTANAC_MINI_APP
22
+ Spree::PaymentMethod::TYPE_VATTANAC_MINI_APP,
23
+ Spree::PaymentMethod::TYPE_TRUE_MONEY
22
24
  ]
23
25
  end
24
26
  end
@@ -91,6 +93,10 @@ module Vpago
91
93
  def type_vattanac_mini_app?
92
94
  type == Spree::PaymentMethod::TYPE_VATTANAC_MINI_APP
93
95
  end
96
+
97
+ def type_true_money?
98
+ type == Spree::PaymentMethod::TYPE_TRUE_MONEY
99
+ end
94
100
  end
95
101
  end
96
102
 
@@ -14,6 +14,8 @@ module Vpago
14
14
  def success_url = "#{base_url}/vpago_payments/success?#{query}"
15
15
  def process_payment_url = "#{base_url}/vpago_payments/process_payment?#{query}"
16
16
 
17
+ def processing_app_url = "#{@payment.payment_method.preferred_merchant_scheme}/vpago_payments/processing?#{query}"
18
+
17
19
  def query
18
20
  { payment_number: payment.number, order_number: order.number, order_jwt_token: order_jwt_token }.to_query
19
21
  end
@@ -23,5 +23,11 @@ module Vpago
23
23
  signature_bytes = Base64.decode64(signature)
24
24
  public_key_object.verify(OpenSSL::Digest.new('SHA256'), signature_bytes, data)
25
25
  end
26
+
27
+ def generate_signature(payload)
28
+ sign_hash = OpenSSL::Digest.new('SHA256')
29
+ private_key = OpenSSL::PKey::RSA.new(@private_key)
30
+ Base64.strict_encode64(private_key.sign(sign_hash, payload))
31
+ end
26
32
  end
27
- end
33
+ end
@@ -0,0 +1,6 @@
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: ''
6
+ %>
@@ -0,0 +1,12 @@
1
+ <% @checkout = ::Vpago::TrueMoney::Checkout.new(@payment) %>
2
+ <% webview_url = @checkout.generate_payment_urls[:deeplink] rescue nil %>
3
+
4
+ <% if webview_url.present? %>
5
+ <script>
6
+ document.addEventListener("DOMContentLoaded", function () {
7
+ window.location.href = "<%= j webview_url %>";
8
+ });
9
+ </script>
10
+ <% else %>
11
+ <p>Unable to generate the payment URL. Please try again.</p>
12
+ <% end %>
@@ -22,7 +22,8 @@ module SpreeVpago
22
22
  Spree::Gateway::WingSdk,
23
23
  Spree::Gateway::Acleda,
24
24
  Spree::Gateway::AcledaMobile,
25
- Spree::Gateway::VattanacMiniApp
25
+ Spree::Gateway::VattanacMiniApp,
26
+ Spree::Gateway::TrueMoney
26
27
  )
27
28
  end
28
29
 
@@ -1,7 +1,7 @@
1
1
  module SpreeVpago
2
2
  module_function
3
3
 
4
- VERSION = '2.0.7'.freeze
4
+ VERSION = '2.0.8-beta'.freeze
5
5
 
6
6
  def version
7
7
  Gem::Version.new VERSION
@@ -0,0 +1,131 @@
1
+ module Vpago
2
+ module TrueMoney
3
+ class Base
4
+ TOKEN_HEADERS = { 'Content-Type' => 'application/x-www-form-urlencoded' }.freeze
5
+ CONTENT_TYPE_JSON = 'application/json'.freeze
6
+ DEFAULT_ALGORITHM = 'rsa-sha256'.freeze
7
+ DEFAULT_KEY_VERSION = 1
8
+
9
+ def initialize(payment, options = {})
10
+ @payment = payment
11
+ @options = options
12
+ end
13
+
14
+ def client_id
15
+ payment_method.preferred_client_id
16
+ end
17
+
18
+ def client_secret
19
+ payment_method.preferred_client_secret
20
+ end
21
+
22
+ def private_key
23
+ payment_method.preferred_private_key
24
+ end
25
+
26
+ def external_ref_id
27
+ @payment.number
28
+ end
29
+
30
+ def service_type = '01'
31
+ def currency = 'USD'
32
+ def user_type = 'CUSTOMER'
33
+
34
+ def amount
35
+ @payment.amount
36
+ end
37
+
38
+ def timestamp
39
+ @timestamp ||= Time.now.to_i
40
+ end
41
+
42
+ def access_token
43
+ @access_token ||= fetch_access_token
44
+ end
45
+
46
+ def payload
47
+ {
48
+ service_type: service_type,
49
+ external_ref_id: external_ref_id,
50
+ amount: amount,
51
+ currency: currency,
52
+ user_type: user_type
53
+ }
54
+ end
55
+
56
+ def signature
57
+ Vpago::RsaHandler
58
+ .new(private_key: private_key)
59
+ .generate_signature(signature_input)
60
+ end
61
+
62
+ def default_headers
63
+ {
64
+ 'Client-Id' => client_id,
65
+ 'Authorization' => "Bearer #{access_token}",
66
+ 'Signature' => "algorithm=#{algorithm};keyVersion=#{key_version};signature=#{signature}",
67
+ 'Timestamp' => timestamp.to_s,
68
+ 'Content-Type' => CONTENT_TYPE_JSON
69
+ }
70
+ end
71
+
72
+ def check_transaction_url
73
+ "#{payment_method.preferred_check_transaction_url}/#{external_ref_id}"
74
+ end
75
+
76
+ def refund_url
77
+ payment_method.preferred_refund_url
78
+ end
79
+
80
+ def generate_payment_url
81
+ payment_method.preferred_generate_payment_url
82
+ end
83
+
84
+ def access_token_url
85
+ payment_method.preferred_access_token_url
86
+ end
87
+
88
+ def merchant_android_package_name
89
+ payment_method.preferred_merchant_android_package_name
90
+ end
91
+
92
+ def parse_json(body)
93
+ JSON.parse(body)
94
+ rescue JSON::ParserError
95
+ {}
96
+ end
97
+
98
+ def payment_method
99
+ @payment.payment_method
100
+ end
101
+
102
+ def fetch_access_token
103
+ response = Faraday.post(
104
+ access_token_url,
105
+ URI.encode_www_form(
106
+ grant_type: 'client_credentials',
107
+ client_id: client_id,
108
+ client_secret: client_secret
109
+ ),
110
+ TOKEN_HEADERS
111
+ )
112
+
113
+ raise "Access Token Error: #{response.status} - #{response.body}" unless response.success?
114
+
115
+ JSON.parse(response.body).fetch('access_token')
116
+ end
117
+
118
+ def algorithm
119
+ DEFAULT_ALGORITHM
120
+ end
121
+
122
+ def key_version
123
+ DEFAULT_KEY_VERSION
124
+ end
125
+
126
+ def signature_input
127
+ "#{timestamp}#{payload.to_json}"
128
+ end
129
+ end
130
+ end
131
+ end
@@ -0,0 +1,26 @@
1
+ module Vpago
2
+ module TrueMoney
3
+ class Checkout < Base
4
+ def generate_payment_urls
5
+ response = Faraday.post(generate_payment_url) do |req|
6
+ req.headers = default_headers
7
+ req.body = {
8
+ payment_info: payload.to_json,
9
+ redirectionType: 'mobileapp',
10
+ merchantDeepLink: @payment.processing_app_url,
11
+ merchantAndroidPackageName: merchant_android_package_name
12
+ }.to_json
13
+ end
14
+
15
+ body = parse_json(response.body)
16
+
17
+ raise "Generate Payment Error: #{response.status} - #{body['message'] || response.body}" unless response.success? && body['status']['code'] == '000001'
18
+
19
+ {
20
+ webview: body['data']['webview'],
21
+ deeplink: body['data']['deeplink']
22
+ }
23
+ end
24
+ end
25
+ end
26
+ end
@@ -0,0 +1,21 @@
1
+ module Vpago
2
+ module TrueMoney
3
+ class RefundIssuer < Base
4
+ def call
5
+ @response = Faraday.post(refund_url, payload.to_json, default_headers)
6
+ end
7
+
8
+ def success?
9
+ parsed_response.dig('status', 'code') == '000001'
10
+ end
11
+
12
+ def payload
13
+ { external_ref_id: external_ref_id }
14
+ end
15
+
16
+ def parsed_response
17
+ @parsed_response ||= parse_json(@response.body)
18
+ end
19
+ end
20
+ end
21
+ end
@@ -0,0 +1,25 @@
1
+ module Vpago
2
+ module TrueMoney
3
+ class TransactionStatus < Base
4
+ def call
5
+ @response = Faraday.get(check_transaction_url, nil, default_headers)
6
+ end
7
+
8
+ def success?
9
+ response_code == '000001'
10
+ end
11
+
12
+ def response_code
13
+ json_response.dig('status', 'code')
14
+ end
15
+
16
+ def signature_input
17
+ timestamp.to_s
18
+ end
19
+
20
+ def json_response
21
+ @json_response ||= parse_json(@response.body)
22
+ end
23
+ end
24
+ end
25
+ 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.0.7
4
+ version: 2.0.8.pre.beta
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-01 00:00:00.000000000 Z
11
+ date: 2025-07-15 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: faraday
@@ -179,6 +179,7 @@ files:
179
179
  - app/models/spree/gateway/acleda_mobile.rb
180
180
  - app/models/spree/gateway/payway.rb
181
181
  - app/models/spree/gateway/payway_v2.rb
182
+ - app/models/spree/gateway/true_money.rb
182
183
  - app/models/spree/gateway/vattanac_mini_app.rb
183
184
  - app/models/spree/gateway/wing_sdk.rb
184
185
  - app/models/spree/payout.rb
@@ -262,6 +263,7 @@ files:
262
263
  - app/views/spree/admin/payments/source_views/_acleda_mobile.html.erb
263
264
  - app/views/spree/admin/payments/source_views/_payment_payway.html.erb
264
265
  - app/views/spree/admin/payments/source_views/_payway_v2.html.erb
266
+ - app/views/spree/admin/payments/source_views/_true_money.html.erb
265
267
  - app/views/spree/admin/payments/source_views/_vattanac_mini_app.html.erb
266
268
  - app/views/spree/admin/payments/source_views/_vpago_payment_tmpl.html.erb
267
269
  - app/views/spree/admin/payments/source_views/_wingsdk.html.erb
@@ -309,6 +311,7 @@ files:
309
311
  - app/views/spree/payway_v2_card_popups/show.html.erb
310
312
  - app/views/spree/vpago_payments/checkout.html.erb
311
313
  - app/views/spree/vpago_payments/forms/spree/gateway/_payway_v2.html.erb
314
+ - app/views/spree/vpago_payments/forms/spree/gateway/_true_money.html.erb
312
315
  - app/views/spree/vpago_payments/forms/spree/gateway/_vattanac_mini_app.html.erb
313
316
  - app/views/spree/vpago_payments/processing.html.erb
314
317
  - app/views/spree/vpago_payments/success.html.erb
@@ -378,6 +381,10 @@ files:
378
381
  - lib/vpago/payway_v2/pre_auth_canceler.rb
379
382
  - lib/vpago/payway_v2/pre_auth_completer.rb
380
383
  - lib/vpago/payway_v2/transaction_status.rb
384
+ - lib/vpago/true_money/base.rb
385
+ - lib/vpago/true_money/checkout.rb
386
+ - lib/vpago/true_money/refund_issuer.rb
387
+ - lib/vpago/true_money/transaction_status.rb
381
388
  - lib/vpago/vattanac_mini_app/base.rb
382
389
  - lib/vpago/vattanac_mini_app/checkout.rb
383
390
  - lib/vpago/vattanac_mini_app/refund_issuer.rb
@@ -408,9 +415,9 @@ required_ruby_version: !ruby/object:Gem::Requirement
408
415
  version: 3.2.0
409
416
  required_rubygems_version: !ruby/object:Gem::Requirement
410
417
  requirements:
411
- - - ">="
418
+ - - ">"
412
419
  - !ruby/object:Gem::Version
413
- version: '0'
420
+ version: 1.3.1
414
421
  requirements:
415
422
  - none
416
423
  rubygems_version: 3.4.1