paymos 1.5.1 → 1.5.2

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: '085824f8d197938805072bbe261b174157877f18edaff7602221a68ad1bbca52'
4
- data.tar.gz: 60d04d4f82f6baee7aa3b23953eb603213304f5022a87ab5a5ad8d04b5d507c4
3
+ metadata.gz: 282678405698ca18531bb7b76da1926623c28453e9ab380a0315842766ca639a
4
+ data.tar.gz: a7ff8402c3967ce7b56de24d990130e615b13e5aacad93ef5750917184a0d5a9
5
5
  SHA512:
6
- metadata.gz: 0f05fdb1aed2a83d2f9fdbac11ecd905eb8e013d3a2d84ffbfad02bff215412528fa8c2a3cd197492d6443d46e25b7d4389b362a3b6f00bfb504daf4a011d3de
7
- data.tar.gz: e7147f721cbb9d0c7230d9bdcb785e809d67d497a6da3d663e67e81b9325d6d7abd6b6ecc71046379f6e2a0fa0fb1df2840db9249dcd700e5a15f3185bddc247
6
+ metadata.gz: 608a21f234c78e20514dae73d8fa2e685c8a50160743b23dc9a82d4c580f8ed4bce221eb6eefddc104844165f4e5f61776f220abfc940bad72121e179cb7a02c
7
+ data.tar.gz: 397e8461b1ccf44093b66042319346da16900d5b141d70353551cfe67d956693647b06718c75c7faba76db5cd595bd8d1c45ecaa242ab11940836c5d64aa0ec3
data/CHANGELOG.md CHANGED
@@ -2,6 +2,15 @@
2
2
 
3
3
  ## [Unreleased]
4
4
 
5
+ ## [1.5.2] - 2026-11-02
6
+
7
+ - wip: snapshot shared working tree before merging main
8
+ - fix(merge): keep both sides for 126 conflicting files (union / semantic JSON merge); Balance.razor keeps ClickToCopy ID column
9
+ - wip(refunds): merchant refund plugin work (CMS adapters, PHP SDK, tests) - unverified WIP snapshot
10
+
11
+ - **403 is no longer reported as an authentication failure.** `Paymos::PermissionError` (subclasses `Paymos::AuthenticationError`, so existing `rescue` blocks keep working) now carries every 403.
12
+ - **Base URL must use HTTPS.** Plain HTTP is accepted only against a loopback host, which is what a local integration test points at. The API secret signs every request, so a plaintext base URL put that credential on the wire.
13
+
5
14
  ## [1.5.1] - 2026-11-01
6
15
 
7
16
  - refactor(invoices): remove the multiple-payment toggle
data/README.md CHANGED
@@ -67,6 +67,7 @@ outcome. Creation returns 201 and an identical replay returns 200; both yield a
67
67
  `Paymos::NotFoundError` (404). List periods use RFC 3339 timestamps, and
68
68
  `paymos.refunds.each` provides the same bounded cursor iteration as invoices.
69
69
  In sandbox, use `paymos.withdrawals.simulate_completion(refund.withdrawal_id)`,
70
+ In sandbox, use `paymos.refunds.simulate(refund.withdrawal_id, status: 'completed')`,
70
71
  then read the refund again. Refunds have their own list and do not appear in the
71
72
  ordinary withdrawals list.
72
73
 
data/lib/paymos/client.rb CHANGED
@@ -37,6 +37,7 @@ module Paymos
37
37
  @timeout = timeout
38
38
  @max_retries = max_retries
39
39
  @base_delay = base_delay
40
+ @refund_transport_is_default = !transport
40
41
  @transport = transport || method(:default_transport)
41
42
  @clock = clock
42
43
  @sleeper = sleeper
@@ -52,6 +53,7 @@ module Paymos
52
53
 
53
54
  def request(method, path, payload: nil, query: '')
54
55
  method = method.to_s.upcase
56
+ refund_transport = checked_refund_transport(method, path)
55
57
  body = payload.nil? ? '' : JSON.generate(payload)
56
58
  attempts = 0
57
59
 
@@ -65,7 +67,9 @@ module Paymos
65
67
  'Accept' => 'application/json',
66
68
  'User-Agent' => "paymos-ruby/#{VERSION}"
67
69
  }
68
- response = @transport.call(method, "#{@base_url}#{path}#{query}", headers, body.empty? ? nil : body, @timeout)
70
+ response = (refund_transport || @transport).call(
71
+ method, "#{@base_url}#{path}#{query}", headers, body.empty? ? nil : body, @timeout
72
+ )
69
73
  rescue IOError, SystemCallError, Timeout::Error, SocketError => e
70
74
  if attempts < @max_retries && SAFE_METHODS.include?(method)
71
75
  wait(attempts, nil)
@@ -79,7 +83,7 @@ module Paymos
79
83
  raise Error, 'Paymos transport returned an invalid response'
80
84
  end
81
85
 
82
- if attempts < @max_retries && retryable?(method, response.status)
86
+ if attempts < @max_retries && retryable_request?(method, path, response.status)
83
87
  wait(attempts, header(response.headers, 'retry-after'))
84
88
  attempts += 1
85
89
  next
@@ -136,6 +140,24 @@ module Paymos
136
140
  headers: response.to_hash.transform_values(&:first))
137
141
  end
138
142
 
143
+ def refund_create?(method, path)
144
+ method == 'POST' && path == '/v1/refunds'
145
+ end
146
+
147
+ def checked_refund_transport(method, path)
148
+ return nil unless refund_create?(method, path)
149
+
150
+ transport = @transport
151
+ trusted = Paymos::Client.instance_method(:default_transport).bind(self)
152
+ return transport if @refund_transport_is_default && trusted == transport
153
+
154
+ raise ConfigurationError, 'Refund creation requires the standard Net::HTTP transport'
155
+ end
156
+
157
+ def retryable_request?(method, path, status)
158
+ !refund_create?(method, path) && retryable?(method, status)
159
+ end
160
+
139
161
  def retryable?(method, status)
140
162
  status == 429 || (status >= 500 && SAFE_METHODS.include?(method))
141
163
  end
@@ -298,6 +320,22 @@ module Paymos
298
320
  end
299
321
 
300
322
  class Refunds < Resource
323
+ UNSPECIFIED_STATUS = Object.new.freeze
324
+ private_constant :UNSPECIFIED_STATUS
325
+
326
+ def simulate(refund_id, positional_status = UNSPECIFIED_STATUS, status: UNSPECIFIED_STATUS)
327
+ if positional_status.equal?(UNSPECIFIED_STATUS) == status.equal?(UNSPECIFIED_STATUS)
328
+ raise ArgumentError, 'Provide exactly one refund simulation status'
329
+ end
330
+
331
+ status = positional_status unless positional_status.equal?(UNSPECIFIED_STATUS)
332
+ unless %w[completed failed cancelled].include?(status)
333
+ raise ArgumentError, 'A terminal refund simulation status is required'
334
+ end
335
+
336
+ Refund.from(@client.request('POST', "/v1/sandbox/refunds/#{segment(refund_id)}/simulate", payload: { status: }))
337
+ end
338
+
301
339
  def create(invoice_id:, mode:, external_order_id:)
302
340
  values = { invoice_id:, mode:, external_order_id: }
303
341
  missing = values.select { |_name, value| !value.is_a?(String) || value.strip.empty? }.keys
@@ -307,11 +345,6 @@ module Paymos
307
345
  Refund.from(@client.request('POST', '/v1/refunds', payload: values))
308
346
  end
309
347
 
310
- def simulate(refund_id, status)
311
- Refund.from(@client.request('POST', "/v1/sandbox/refunds/#{segment(refund_id)}/simulate",
312
- payload: { status: }))
313
- end
314
-
315
348
  def get(refund_id) = Refund.from(@client.request('GET', "/v1/refunds/#{segment(refund_id)}"))
316
349
 
317
350
  def list(limit: nil, cursor: nil, invoice_id: nil, status: nil, created_from: nil, created_to: nil)
data/lib/paymos/models.rb CHANGED
@@ -133,9 +133,9 @@ module Paymos
133
133
  end
134
134
 
135
135
  class Refund < Model
136
- fields :withdrawal_id, :invoice_id, :mode, :external_order_id, :status, :is_final, :is_test,
136
+ fields :type, :project_id, :withdrawal_id, :invoice_id, :mode, :external_order_id, :status, :is_final, :is_test,
137
137
  :amount, :fee, :currency, :network, :destination_address, :first_sender, :tx_hash,
138
- :explorer_url, :created_at, :completed_at, :failed_at, :cancelled_at, :type, :project_id,
138
+ :explorer_url, :created_at, :completed_at, :failed_at, :cancelled_at,
139
139
  required: %i[withdrawal_id invoice_id mode external_order_id status is_final is_test amount
140
140
  currency network destination_address first_sender created_at]
141
141
  end
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Paymos
4
- VERSION = '1.5.1'
4
+ VERSION = '1.5.2'
5
5
  end
data/sig/paymos.rbs CHANGED
@@ -276,6 +276,7 @@ module Paymos
276
276
 
277
277
  class Refunds
278
278
  def simulate: (String refund_id, String status) -> Refund
279
+ | (String refund_id, status: String) -> Refund
279
280
  def create: (invoice_id: String, mode: "full" | "overpayment", external_order_id: String) -> Refund
280
281
  def get: (String refund_id) -> Refund
281
282
  def list: (?limit: Integer?, ?cursor: String?, ?invoice_id: String?, ?status: String | Array[String]?, ?created_from: String?, ?created_to: String?) -> Page[Refund]
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: paymos
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.5.1
4
+ version: 1.5.2
5
5
  platform: ruby
6
6
  authors:
7
7
  - Paymos Labs