billingrails 0.1.5 → 0.1.7

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: 7a5b67a14d5de893e9a3ee00b839d59c99661274987a60d80daf906962ad45a6
4
- data.tar.gz: 698cd398f19a126ba47bc1f045d36baf17d8e60968c4cbd6c0cdd35f82605115
3
+ metadata.gz: 6e7060b0d621a12ffd9d32d45ae3ae37008c7ccb639aeaa01c17fd3ed8d9db97
4
+ data.tar.gz: a3f901c1ddd2c84196041fbf5394d2e467ed188c052fef3323df1de42d3e3880
5
5
  SHA512:
6
- metadata.gz: d60ec418d12ada5c355e3fc1e5a121f38458ab9ba5ca727cfb333a215f6e5b98267c7fdc53eb9180fb71cfee600411611349b4975108c1c47e2cd2692ea0ebf9
7
- data.tar.gz: 5ec2da2339853212f4ca5ffc504fe6b7d3861344a196cb79ebc682da86ca3a2c4cf5342da3797b6f9874bcc30a900d0fa110485cfaaff690fa1704352f06b326
6
+ metadata.gz: c36ce4151f805a5e5b1e4b932996fd0b9c583787f3f3082fb607919cd1aaf02227cf21bb4ceaa29f7af7209ca732e7eb6b765470af6f207a83c497bd09ba00ad
7
+ data.tar.gz: 11334c3a58ab78315561ae71cdcd5509a53f9fb1d9b6416fab058b87f53616784acd6935eb1c3dec42f1deea4aadecc362befc72e0dd2a7b07462b8d04eb3ae4
@@ -9,8 +9,11 @@ module Billingrails
9
9
  class Client
10
10
  DEFAULT_BASE_URL = 'https://api.billingrails.com/v1'
11
11
  DEFAULT_TIMEOUT = 30
12
+ DEFAULT_MAX_RETRIES = 3
12
13
 
13
- attr_reader :api_key, :base_url, :timeout
14
+ RETRYABLE_HTTP_STATUSES = [429, 500, 502, 503, 504].freeze
15
+
16
+ attr_reader :api_key, :base_url, :timeout, :max_retries
14
17
  attr_reader :accounts, :invoices, :payments, :payment_links
15
18
  attr_reader :events, :meters, :plans, :fees, :prices, :subscriptions
16
19
  attr_reader :discounts, :credit_grants
@@ -20,10 +23,12 @@ module Billingrails
20
23
  # @param api_key [String] Your API key
21
24
  # @param base_url [String] Base URL for API requests
22
25
  # @param timeout [Integer] Request timeout in seconds
23
- def initialize(api_key:, base_url: DEFAULT_BASE_URL, timeout: DEFAULT_TIMEOUT)
26
+ # @param max_retries [Integer] Max attempts per call for retryable HTTP statuses (see RETRYABLE_HTTP_STATUSES); connection errors are not retried. Default 3.
27
+ def initialize(api_key:, base_url: DEFAULT_BASE_URL, timeout: DEFAULT_TIMEOUT, max_retries: DEFAULT_MAX_RETRIES)
24
28
  @api_key = api_key
25
29
  @base_url = base_url.chomp('/')
26
30
  @timeout = timeout
31
+ @max_retries = max_retries
27
32
  validate_config!
28
33
 
29
34
  # Initialize top-level resources
@@ -35,9 +40,8 @@ module Billingrails
35
40
 
36
41
  @subscriptions = Resources::Subscriptions.new(self)
37
42
  @products = Resources::Products.new(self)
38
- @fees = Resources::Fees.new(self)
39
43
  @prices = Resources::Prices.new(self)
40
- @offerings = Resources::Offerings.new(self)
44
+ @plans = Resources::Plans.new(self)
41
45
  @events = Resources::Events.new(self)
42
46
  @meters = Resources::Meters.new(self)
43
47
 
@@ -55,10 +59,43 @@ module Billingrails
55
59
  # @return [Hash] Parsed response body
56
60
  def request(method, path, body: nil, params: nil)
57
61
  uri = build_uri(path, params)
58
- request = build_request(method, uri, body)
59
-
60
- response = execute_request(uri, request)
61
- handle_response(response)
62
+ http_request = build_request(method, uri, body)
63
+
64
+ last_exception = nil
65
+ last_error_response = nil
66
+
67
+ @max_retries.times do |attempt|
68
+ begin
69
+ response = execute_request(uri, http_request)
70
+ rescue StandardError => e
71
+ last_exception = e
72
+ break
73
+ end
74
+
75
+ last_exception = nil
76
+ code = response.code.to_i
77
+
78
+ if (200..299).cover?(code)
79
+ return {} if response.body.nil? || response.body.empty?
80
+ return JSON.parse(response.body)
81
+ end
82
+
83
+ if attempt < @max_retries - 1 && retryable_status?(code)
84
+ sleep(2**attempt)
85
+ next
86
+ end
87
+
88
+ last_error_response = response
89
+ break
90
+ end
91
+
92
+ if last_error_response
93
+ handle_response(last_error_response)
94
+ elsif last_exception
95
+ raise ConnectionError, "Failed to connect to API: #{last_exception.message}"
96
+ else
97
+ raise ConnectionError, 'Failed to connect to API'
98
+ end
62
99
  end
63
100
 
64
101
  private
@@ -67,6 +104,10 @@ module Billingrails
67
104
  raise ArgumentError, 'api_key is required' if @api_key.nil? || @api_key.empty?
68
105
  end
69
106
 
107
+ def retryable_status?(code)
108
+ RETRYABLE_HTTP_STATUSES.include?(code)
109
+ end
110
+
70
111
  def build_uri(path, params)
71
112
  uri = URI.parse("#{@base_url}#{path}")
72
113
  if params && !params.empty?
@@ -104,11 +145,7 @@ module Billingrails
104
145
  http.read_timeout = @timeout
105
146
  http.open_timeout = @timeout
106
147
 
107
- begin
108
- http.request(request)
109
- rescue StandardError => e
110
- raise ConnectionError, "Failed to connect to API: #{e.message}"
111
- end
148
+ http.request(request)
112
149
  end
113
150
 
114
151
  def handle_response(response)
@@ -134,13 +171,15 @@ module Billingrails
134
171
  def handle_error_response(response, error_class)
135
172
  error_data = JSON.parse(response.body) rescue {}
136
173
  message = error_data['message'] || response.message
137
-
174
+ nested = error_data['error']
175
+ nested = {} unless nested.is_a?(Hash)
176
+
138
177
  raise error_class.new(
139
178
  message,
140
179
  status: response.code.to_i,
141
- code: error_data['error']['code'],
142
- type: error_data['error']['type'],
143
- details: error_data['error']['details']
180
+ code: nested['code'],
181
+ type: nested['type'],
182
+ details: nested['details']
144
183
  )
145
184
  end
146
185
  end
@@ -4,100 +4,100 @@
4
4
 
5
5
  module Billingrails
6
6
  module Resources
7
- # Offerings resource
8
- class Offerings
7
+ # Plans resource
8
+ class Plans
9
9
  # @param client [Client] The API client
10
10
  def initialize(client)
11
11
  @client = client
12
12
  end
13
13
 
14
- # List offerings
14
+ # List plans
15
15
  #
16
- # Retrieves a list of offerings.
16
+ # Retrieves a list of plans.
17
17
  #
18
18
  # @param params [Hash, nil] Query parameters
19
19
  # @return [Hash] Response data
20
20
  def list(params: nil)
21
- path = "/offerings"
21
+ path = "/plans"
22
22
  @client.request(:get, path, params: params)
23
23
  end
24
24
 
25
- # Create an offering
25
+ # Create a plan
26
26
  #
27
- # Creates an offering with optional items (products/fees and prices).
27
+ # Creates a plan.
28
28
  #
29
29
  # @param data [Hash] Request body
30
30
  # @return [Hash] Response data
31
31
  def create(data)
32
- path = "/offerings"
32
+ path = "/plans"
33
33
  @client.request(:post, path, body: data)
34
34
  end
35
35
 
36
- # Retrieve an offering
36
+ # Retrieve a plan
37
37
  #
38
- # Retrieves an offering by ID.
38
+ # Retrieves a plan by ID.
39
39
  #
40
40
  # @param id [String] Resource ID
41
41
  # @param params [Hash, nil] Query parameters
42
42
  # @return [Hash] Response data
43
43
  def retrieve(id, params: nil)
44
- path = "/offerings/#{id}"
44
+ path = "/plans/#{id}"
45
45
  @client.request(:get, path, params: params)
46
46
  end
47
47
 
48
- # Update an offering
48
+ # Update a plan
49
49
  #
50
- # Updates an offering (name, description, trial_period_days, items). Fails if the offering is used by any subscription.
50
+ # Updates a plan.
51
51
  #
52
52
  # @param id [String] Resource ID
53
53
  # @param data [Hash] Request body
54
54
  # @return [Hash] Response data
55
55
  def update(id, data)
56
- path = "/offerings/#{id}"
56
+ path = "/plans/#{id}"
57
57
  @client.request(:put, path, body: data)
58
58
  end
59
59
 
60
- # Delete an offering
60
+ # Delete a plan
61
61
  #
62
- # Soft-deletes an offering. Fails if the offering is used by any subscription.
62
+ # Deletes a plan.
63
63
  #
64
64
  # @param id [String] Resource ID
65
65
  # @return [Hash] Response data
66
66
  def delete(id)
67
- path = "/offerings/#{id}"
67
+ path = "/plans/#{id}"
68
68
  @client.request(:delete, path)
69
69
  end
70
70
 
71
- # Archive an offering
71
+ # Archive a plan
72
72
  #
73
- # Archives an offering. Fails if the offering is used by any subscription.
73
+ # Archives a plan.
74
74
  #
75
75
  # @param id [String] Resource ID
76
76
  # @return [Hash] Response data
77
77
  def archive(id)
78
- path = "/offerings/#{id}/archive"
78
+ path = "/plans/#{id}/archive"
79
79
  @client.request(:post, path)
80
80
  end
81
81
 
82
- # Unarchive an offering
82
+ # Unarchive a plan
83
83
  #
84
- # Restores an archived offering to active status.
84
+ # Restores an archived plan.
85
85
  #
86
86
  # @param id [String] Resource ID
87
87
  # @return [Hash] Response data
88
88
  def unarchive(id)
89
- path = "/offerings/#{id}/unarchive"
89
+ path = "/plans/#{id}/unarchive"
90
90
  @client.request(:post, path)
91
91
  end
92
92
 
93
- # Duplicate an offering
93
+ # Duplicate a plan
94
94
  #
95
- # Creates a new offering with the same attributes and items. The new offering's origin_id is set to the source offering.
95
+ # Creates a new plan with the same attributes and items. The new plan's origin_id is set to the source plan.
96
96
  #
97
97
  # @param id [String] Resource ID
98
98
  # @return [Hash] Response data
99
99
  def duplicate(id)
100
- path = "/offerings/#{id}/duplicate"
100
+ path = "/plans/#{id}/duplicate"
101
101
  @client.request(:post, path)
102
102
  end
103
103
 
@@ -11,6 +11,17 @@ module Billingrails
11
11
  @client = client
12
12
  end
13
13
 
14
+ # List prices
15
+ #
16
+ # Retrieves a paginated list of prices.
17
+ #
18
+ # @param params [Hash, nil] Query parameters
19
+ # @return [Hash] Response data
20
+ def list(params: nil)
21
+ path = "/prices"
22
+ @client.request(:get, path, params: params)
23
+ end
24
+
14
25
  # Create a price
15
26
  #
16
27
  # Creates a price.
@@ -59,7 +70,7 @@ module Billingrails
59
70
 
60
71
  # Archive a price
61
72
  #
62
- # Archives a price, making it inactive for new subscriptions.
73
+ # Archives a price.
63
74
  #
64
75
  # @param id [String] Resource ID
65
76
  # @return [Hash] Response data
@@ -70,7 +81,7 @@ module Billingrails
70
81
 
71
82
  # Unarchive a price
72
83
  #
73
- # Restores an archived price to active status.
84
+ # Restores an archived price.
74
85
  #
75
86
  # @param id [String] Resource ID
76
87
  # @return [Hash] Response data
@@ -59,7 +59,7 @@ module Billingrails
59
59
 
60
60
  # Archive a product
61
61
  #
62
- # Archives a product, making it inactive for new subscriptions.
62
+ # Archives a product.
63
63
  #
64
64
  # @param id [String] Resource ID
65
65
  # @return [Hash] Response data
@@ -70,7 +70,7 @@ module Billingrails
70
70
 
71
71
  # Unarchive a product
72
72
  #
73
- # Restores an archived product to active status.
73
+ # Restores an archived product.
74
74
  #
75
75
  # @param id [String] Resource ID
76
76
  # @return [Hash] Response data
@@ -70,7 +70,7 @@ module Billingrails
70
70
 
71
71
  # Archive a tax rate
72
72
  #
73
- # Archives a tax rate. Sets status to archived.
73
+ # Archives a tax rate.
74
74
  #
75
75
  # @param id [String] Resource ID
76
76
  # @return [Hash] Response data
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Billingrails
4
- VERSION = '0.1.5'
4
+ VERSION = '0.1.7'
5
5
  end
data/lib/billingrails.rb CHANGED
@@ -1,7 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- # This file is auto-generated. Do not edit manually.
4
-
5
3
  require_relative 'billingrails/version'
6
4
  require_relative 'billingrails/errors'
7
5
  require_relative 'billingrails/client'
@@ -9,8 +7,7 @@ require_relative 'billingrails/client'
9
7
  require_relative 'billingrails/resources/accounts'
10
8
  require_relative 'billingrails/resources/checkout_sessions'
11
9
  require_relative 'billingrails/resources/events'
12
- require_relative 'billingrails/resources/fees'
13
- require_relative 'billingrails/resources/offerings'
10
+ require_relative 'billingrails/resources/plans'
14
11
  require_relative 'billingrails/resources/meters'
15
12
  require_relative 'billingrails/resources/products'
16
13
  require_relative 'billingrails/resources/subscriptions'
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: billingrails
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.5
4
+ version: 0.1.7
5
5
  platform: ruby
6
6
  authors:
7
7
  - Billingrails
@@ -84,12 +84,11 @@ files:
84
84
  - lib/billingrails/resources/credit_grants.rb
85
85
  - lib/billingrails/resources/discounts.rb
86
86
  - lib/billingrails/resources/events.rb
87
- - lib/billingrails/resources/fees.rb
88
87
  - lib/billingrails/resources/invoices.rb
89
88
  - lib/billingrails/resources/meters.rb
90
- - lib/billingrails/resources/offerings.rb
91
89
  - lib/billingrails/resources/payment_links.rb
92
90
  - lib/billingrails/resources/payments.rb
91
+ - lib/billingrails/resources/plans.rb
93
92
  - lib/billingrails/resources/prices.rb
94
93
  - lib/billingrails/resources/products.rb
95
94
  - lib/billingrails/resources/subscriptions.rb
@@ -1,94 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- # This file is auto-generated. Do not edit manually.
4
-
5
- module Billingrails
6
- module Resources
7
- # Fees resource
8
- class Fees
9
- # @param client [Client] The API client
10
- def initialize(client)
11
- @client = client
12
- end
13
-
14
- # List fees
15
- #
16
- # Retrieve a list of fees.
17
- #
18
- # @return [Hash] Response data
19
- def list()
20
- path = "/fees"
21
- @client.request(:get, path)
22
- end
23
-
24
- # Create a fee
25
- #
26
- # Creates a fee.
27
- #
28
- # @param data [Hash] Request body
29
- # @return [Hash] Response data
30
- def create(data)
31
- path = "/fees"
32
- @client.request(:post, path, body: data)
33
- end
34
-
35
- # Retrieve fee
36
- #
37
- # Retrieves a fee by ID.
38
- #
39
- # @param id [String] Resource ID
40
- # @param params [Hash, nil] Query parameters
41
- # @return [Hash] Response data
42
- def retrieve(id, params: nil)
43
- path = "/fees/#{id}"
44
- @client.request(:get, path, params: params)
45
- end
46
-
47
- # Update a fee
48
- #
49
- # Updates a fee.
50
- #
51
- # @param id [String] Resource ID
52
- # @param data [Hash] Request body
53
- # @return [Hash] Response data
54
- def update(id, data)
55
- path = "/fees/#{id}"
56
- @client.request(:put, path, body: data)
57
- end
58
-
59
- # Delete a fee
60
- #
61
- # Deletes a fee.
62
- #
63
- # @param id [String] Resource ID
64
- # @return [Hash] Response data
65
- def delete(id)
66
- path = "/fees/#{id}"
67
- @client.request(:delete, path)
68
- end
69
-
70
- # Archive a fee
71
- #
72
- # Archives a fee, making it inactive for new subscriptions.
73
- #
74
- # @param id [String] Resource ID
75
- # @return [Hash] Response data
76
- def archive(id)
77
- path = "/fees/#{id}/archive"
78
- @client.request(:post, path)
79
- end
80
-
81
- # Unarchive a fee
82
- #
83
- # Restores an archived fee to active status.
84
- #
85
- # @param id [String] Resource ID
86
- # @return [Hash] Response data
87
- def unarchive(id)
88
- path = "/fees/#{id}/unarchive"
89
- @client.request(:post, path)
90
- end
91
-
92
- end
93
- end
94
- end