celitech 2.0.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.
Files changed (63) hide show
  1. checksums.yaml +7 -0
  2. data/README.md +225 -0
  3. data/lib/celitech/client.rb +81 -0
  4. data/lib/celitech/config.rb +48 -0
  5. data/lib/celitech/environment.rb +7 -0
  6. data/lib/celitech/error.rb +50 -0
  7. data/lib/celitech/http/connection.rb +321 -0
  8. data/lib/celitech/http/hooks.rb +17 -0
  9. data/lib/celitech/http/oauth_token_manager.rb +76 -0
  10. data/lib/celitech/http/response.rb +35 -0
  11. data/lib/celitech/models/bad_request.rb +47 -0
  12. data/lib/celitech/models/create_purchase_ok_response.rb +63 -0
  13. data/lib/celitech/models/create_purchase_ok_response_profile.rb +75 -0
  14. data/lib/celitech/models/create_purchase_ok_response_purchase.rb +111 -0
  15. data/lib/celitech/models/create_purchase_request.rb +155 -0
  16. data/lib/celitech/models/create_purchase_request_language.rb +14 -0
  17. data/lib/celitech/models/create_purchase_v2_ok_response.rb +63 -0
  18. data/lib/celitech/models/create_purchase_v2_ok_response_profile.rb +96 -0
  19. data/lib/celitech/models/create_purchase_v2_ok_response_purchase.rb +70 -0
  20. data/lib/celitech/models/create_purchase_v2_request.rb +156 -0
  21. data/lib/celitech/models/create_purchase_v2_request_language.rb +14 -0
  22. data/lib/celitech/models/destinations.rb +80 -0
  23. data/lib/celitech/models/device.rb +80 -0
  24. data/lib/celitech/models/edit_purchase_ok_response.rb +90 -0
  25. data/lib/celitech/models/edit_purchase_request.rb +90 -0
  26. data/lib/celitech/models/get_esim_device_ok_response.rb +52 -0
  27. data/lib/celitech/models/get_esim_history_ok_response.rb +52 -0
  28. data/lib/celitech/models/get_esim_history_ok_response_esim.rb +61 -0
  29. data/lib/celitech/models/get_esim_ok_response.rb +52 -0
  30. data/lib/celitech/models/get_esim_ok_response_esim.rb +116 -0
  31. data/lib/celitech/models/get_purchase_consumption_ok_response.rb +70 -0
  32. data/lib/celitech/models/grant_type.rb +10 -0
  33. data/lib/celitech/models/history.rb +70 -0
  34. data/lib/celitech/models/list_destinations_ok_response.rb +51 -0
  35. data/lib/celitech/models/list_packages_ok_response.rb +64 -0
  36. data/lib/celitech/models/list_purchases_ok_response.rb +64 -0
  37. data/lib/celitech/models/o_auth_token_request.rb +84 -0
  38. data/lib/celitech/models/o_auth_token_response.rb +60 -0
  39. data/lib/celitech/models/open_model.rb +30 -0
  40. data/lib/celitech/models/package.rb +111 -0
  41. data/lib/celitech/models/packages.rb +121 -0
  42. data/lib/celitech/models/purchases.rb +178 -0
  43. data/lib/celitech/models/purchases_esim.rb +51 -0
  44. data/lib/celitech/models/serializable.rb +63 -0
  45. data/lib/celitech/models/token_ok_response.rb +47 -0
  46. data/lib/celitech/models/top_up_esim_ok_response.rb +63 -0
  47. data/lib/celitech/models/top_up_esim_ok_response_profile.rb +51 -0
  48. data/lib/celitech/models/top_up_esim_ok_response_purchase.rb +111 -0
  49. data/lib/celitech/models/top_up_esim_request.rb +145 -0
  50. data/lib/celitech/models/unauthorized.rb +47 -0
  51. data/lib/celitech/models/union_type.rb +12 -0
  52. data/lib/celitech/serializers/form_serializer.rb +41 -0
  53. data/lib/celitech/serializers/json_serializer.rb +41 -0
  54. data/lib/celitech/services/destinations.rb +59 -0
  55. data/lib/celitech/services/e_sim.rb +108 -0
  56. data/lib/celitech/services/i_frame.rb +59 -0
  57. data/lib/celitech/services/o_auth.rb +49 -0
  58. data/lib/celitech/services/packages.rb +82 -0
  59. data/lib/celitech/services/purchases.rb +195 -0
  60. data/lib/celitech/validator.rb +42 -0
  61. data/lib/celitech/version.rb +5 -0
  62. data/lib/celitech.rb +64 -0
  63. metadata +162 -0
@@ -0,0 +1,321 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'json'
4
+ require 'net/http'
5
+ require 'time'
6
+ require 'uri'
7
+
8
+ module Celitech
9
+ module HTTP
10
+ class Connection
11
+ attr_accessor :default_headers
12
+ attr_reader :base_url, :timeout, :retry_config
13
+
14
+ def base_url=(new_url)
15
+ new_uri = URI.parse(new_url.chomp('/'))
16
+ @mutex.synchronize do
17
+ # A caller-supplied client owns its own connection target; never tear it down
18
+ # or repoint it. Warn on a host/port change so requests aren't silently sent
19
+ # to the injected client's original host with the new path.
20
+ if @custom_http
21
+ if new_uri.host != @http.address || new_uri.port != @http.port
22
+ warn '[Celitech] base_url host/port change ignored: a custom ' \
23
+ 'http_client is in use and keeps its own connection target.'
24
+ end
25
+ @base_url = new_url
26
+ @uri = new_uri
27
+ next
28
+ end
29
+
30
+ @base_url = new_url
31
+ @uri = new_uri
32
+ begin
33
+ @http&.finish
34
+ rescue StandardError
35
+ nil
36
+ end
37
+ @http = Net::HTTP.new(@uri.host, @uri.port)
38
+ @http.use_ssl = @uri.scheme == 'https'
39
+ if @timeout
40
+ @http.open_timeout = @timeout
41
+ @http.read_timeout = @timeout
42
+ end
43
+ # Don't call @http.start here — the execute/reconnect path starts it
44
+ # lazily on the first request, which avoids eager DNS lookups when
45
+ # switching environments before a request is actually made.
46
+ end
47
+ end
48
+
49
+ def initialize(base_url, default_headers = {}, timeout: nil, refresh_manager: nil, retry_config: nil, http_client: nil)
50
+ @base_url = base_url
51
+ @timeout = timeout
52
+ @retry_config = retry_config
53
+ @uri = URI.parse(base_url.chomp('/'))
54
+ # A caller-supplied http_client is used as-is: the SDK never reconfigures its
55
+ # transport (TLS, timeouts, proxy) — the caller owns those settings.
56
+ @custom_http = !http_client.nil?
57
+ @http = http_client || Net::HTTP.new(@uri.host, @uri.port)
58
+ @default_headers = { 'User-Agent' => 'postman-codegen/2.6.0 celitech/2.0.7 (ruby)' }.merge(default_headers)
59
+ @refresh_manager = refresh_manager
60
+ @mutex = Mutex.new
61
+ @hook = Hooks.new
62
+ unless @custom_http
63
+ @http.use_ssl = @uri.scheme == 'https'
64
+ if timeout
65
+ @http.open_timeout = timeout
66
+ @http.read_timeout = timeout
67
+ end
68
+ end
69
+ @http.start unless @http.started?
70
+ end
71
+
72
+ def get(path, params = {}, headers = {})
73
+ execute(Net::HTTP::Get.new(build_path(path, params), normalize_headers(@default_headers.merge(headers))))
74
+ end
75
+
76
+ def post(path, body = nil, content_type: 'application/json', headers: {})
77
+ req = Net::HTTP::Post.new(base_path(path), normalize_headers(@default_headers.merge(headers)))
78
+ set_body(req, body, content_type)
79
+ execute(req)
80
+ end
81
+
82
+ def put(path, body = nil, content_type: 'application/json', headers: {})
83
+ req = Net::HTTP::Put.new(base_path(path), normalize_headers(@default_headers.merge(headers)))
84
+ set_body(req, body, content_type)
85
+ execute(req)
86
+ end
87
+
88
+ def patch(path, body = nil, content_type: 'application/json', headers: {})
89
+ req = Net::HTTP::Patch.new(base_path(path), normalize_headers(@default_headers.merge(headers)))
90
+ set_body(req, body, content_type)
91
+ execute(req)
92
+ end
93
+
94
+ def delete(path, headers = {})
95
+ execute(Net::HTTP::Delete.new(base_path(path), normalize_headers(@default_headers.merge(headers))))
96
+ end
97
+
98
+ def head(path, params = {}, headers = {})
99
+ execute(Net::HTTP::Head.new(build_path(path, params), normalize_headers(@default_headers.merge(headers))))
100
+ end
101
+
102
+ def options(path, params = {}, headers = {})
103
+ execute(Net::HTTP::Options.new(build_path(path, params), normalize_headers(@default_headers.merge(headers))))
104
+ end
105
+
106
+ def stream_get(path, params = {}, headers = {})
107
+ stream_execute(Net::HTTP::Get.new(build_path(path, params), normalize_headers(@default_headers.merge(headers))))
108
+ end
109
+
110
+ def stream_post(path, body = nil, content_type: 'application/json', headers: {})
111
+ req = Net::HTTP::Post.new(base_path(path), normalize_headers(@default_headers.merge(headers)))
112
+ set_body(req, body, content_type)
113
+ stream_execute(req)
114
+ end
115
+
116
+ private
117
+
118
+ # Connection is opened once in initialize and reused across requests.
119
+ # If the server closes the socket (idle timeout, restart, etc.) we
120
+ # transparently reconnect once before giving up.
121
+ def execute(req)
122
+ attempts = 0
123
+ params = {}
124
+ @hook.before_request(req, params)
125
+ begin
126
+ attempts += 1
127
+ raw = @mutex.synchronize do
128
+ @http.request(req)
129
+ rescue IOError, Errno::ECONNRESET, Errno::EPIPE
130
+ reconnect
131
+ @http.request(req)
132
+ end
133
+ response = Response.new(raw)
134
+ raise APIError.new(response.status, response.body, response.headers) unless response.success?
135
+ @hook.after_response(req, response, params)
136
+ response
137
+ rescue APIError => e
138
+ if attempts < (@retry_config&.fetch(:attempts, nil) || 3) && %w[GET POST PUT DELETE PATCH HEAD OPTIONS].include?(req.method.upcase) && (e.status >= 500 || e.status == 408 || e.status == 429)
139
+ sleep(retry_after_delay(e) || retry_delay(attempts))
140
+ retry
141
+ end
142
+ @hook.on_error(e, req, params)
143
+ raise
144
+ end
145
+ rescue Net::ReadTimeout, Net::OpenTimeout => e
146
+ raise TimeoutError, e.message
147
+ end
148
+
149
+ def stream_execute(req)
150
+ Enumerator.new do |yielder|
151
+ opts = { use_ssl: @uri.scheme == 'https' }
152
+ if @timeout
153
+ opts[:open_timeout] = @timeout
154
+ opts[:read_timeout] = @timeout
155
+ end
156
+ params = {}
157
+ @hook.before_request(req, params)
158
+ begin
159
+ Net::HTTP.start(@uri.host, @uri.port, **opts) do |http|
160
+ http.request(req) do |raw|
161
+ status = raw.code.to_i
162
+ unless status >= 200 && status < 300
163
+ error = APIError.new(status, raw.read_body, raw.each_header.to_h)
164
+ @hook.on_error(error, req, params)
165
+ raise error
166
+ end
167
+
168
+ content_type = raw['content-type'].to_s.split(';').first&.strip || ''
169
+ is_sse = content_type == 'text/event-stream'
170
+ buffer = +''
171
+
172
+ raw.read_body do |chunk|
173
+ buffer << chunk
174
+ while (idx = buffer.index("\n"))
175
+ line = buffer.slice!(0, idx + 1).chomp
176
+ if is_sse
177
+ next unless line.start_with?('data:')
178
+
179
+ data = line[5..].delete_prefix(' ')
180
+ next if data == '[DONE]'
181
+
182
+ yielder << JSON.parse(data)
183
+ else
184
+ yielder << JSON.parse(line) unless line.empty?
185
+ end
186
+ end
187
+ end
188
+
189
+ unless buffer.empty?
190
+ if is_sse
191
+ if buffer.start_with?('data:')
192
+ data = buffer[5..].delete_prefix(' ')
193
+ yielder << JSON.parse(data) unless data == '[DONE]'
194
+ end
195
+ else
196
+ yielder << JSON.parse(buffer)
197
+ end
198
+ end
199
+ end
200
+ end
201
+ rescue Net::ReadTimeout, Net::OpenTimeout => e
202
+ raise TimeoutError, e.message
203
+ end
204
+ end
205
+ end
206
+
207
+ # Returns seconds to wait before the next retry attempt.
208
+ # Uses exponential backoff capped at maxDelay, plus random jitter.
209
+ def retry_delay(attempt)
210
+ base_ms = 150 * (2**(attempt - 1))
211
+ capped_ms = [base_ms, 5000].min
212
+ jitter_ms = rand(0..50)
213
+ (capped_ms + jitter_ms) / 1000.0
214
+ end
215
+
216
+ # Honors a server-directed retry delay from rate-limit response headers:
217
+ # Retry-After (delta-seconds or HTTP-date), or X-RateLimit-Reset (epoch seconds)
218
+ # when Retry-After is absent. Returns the delay in seconds clamped to
219
+ # [0, maxRetryAfterDelay], or nil when no usable header is present so the caller
220
+ # falls back to the computed exponential backoff.
221
+ def retry_after_delay(error)
222
+ headers = error.respond_to?(:headers) ? error.headers : nil
223
+ return nil unless headers.is_a?(Hash)
224
+
225
+ max_s = 60_000 / 1000.0
226
+ return nil unless max_s.positive?
227
+
228
+ # Normalize keys to lowercase hyphenated strings so lookups are robust to
229
+ # header casing and symbol keys regardless of how the error was constructed.
230
+ normalized = headers.each_with_object({}) do |(k, v), acc|
231
+ acc[k.to_s.downcase.tr('_', '-')] = v
232
+ end
233
+
234
+ # retry-after-ms (milliseconds) is a non-standard but finer-grained hint some
235
+ # APIs send (e.g. OpenAI); it takes precedence over the whole-second Retry-After.
236
+ ms = normalized['retry-after-ms'].to_s.strip
237
+ return (ms.to_f / 1000.0).clamp(0.0, max_s) if ms.match?(/\A\d+(\.\d+)?\z/)
238
+
239
+ seconds = parse_retry_after(normalized['retry-after'])
240
+ return seconds.clamp(0.0, max_s) unless seconds.nil?
241
+
242
+ # X-RateLimit-Reset is interpreted as epoch seconds (the common convention).
243
+ reset = normalized['x-ratelimit-reset']
244
+ unless reset.nil? || reset.to_s.strip.empty?
245
+ seconds = reset.to_f - Time.now.to_f
246
+ return seconds.clamp(0.0, max_s) if seconds.positive?
247
+ end
248
+ nil
249
+ end
250
+
251
+ # Parses a Retry-After header value: an integer/float number of seconds, or an
252
+ # HTTP-date. Returns the delay in seconds (Float) or nil if unparseable.
253
+ def parse_retry_after(value)
254
+ return nil if value.nil?
255
+
256
+ str = value.to_s.strip
257
+ return nil if str.empty?
258
+ return str.to_f if str.match?(/\A\d+(\.\d+)?\z/)
259
+
260
+ begin
261
+ Time.httpdate(str).to_f - Time.now.to_f
262
+ rescue ArgumentError
263
+ nil
264
+ end
265
+ end
266
+
267
+ # Collapses array header values into a comma-separated string.
268
+ # Matches OpenAPI style=simple, explode=false (the default for header parameters).
269
+ def normalize_headers(hdrs)
270
+ return hdrs unless hdrs.any? { |_, v| v.is_a?(Array) }
271
+
272
+ hdrs.transform_values { |v| v.is_a?(Array) ? v.join(',') : v }
273
+ end
274
+
275
+ def reconnect
276
+ begin
277
+ @http.finish
278
+ rescue StandardError
279
+ nil
280
+ end
281
+ @http.start
282
+ end
283
+
284
+ def set_body(req, body, content_type)
285
+ return unless body
286
+
287
+ case content_type
288
+ when /json/
289
+ req.body = Serializers::Json.serialize(body).to_json
290
+ req['Content-Type'] = content_type
291
+ when 'application/xml'
292
+ req.body = Serializers::Xml.serialize(body)
293
+ req['Content-Type'] = 'application/xml'
294
+ when 'application/x-www-form-urlencoded'
295
+ req.body = Serializers::Form.to_urlencoded(body)
296
+ req['Content-Type'] = 'application/x-www-form-urlencoded'
297
+ when 'multipart/form-data'
298
+ Serializers::Form.set_multipart(req, body)
299
+ when %r{^text/}
300
+ req.body = body.to_s
301
+ req['Content-Type'] = content_type
302
+ else
303
+ # Binary and other raw types
304
+ req.body = body.respond_to?(:read) ? body.read : body.to_s
305
+ req['Content-Type'] = content_type
306
+ end
307
+ end
308
+
309
+ def base_path(path)
310
+ "#{@uri.path.chomp('/')}#{path}"
311
+ end
312
+
313
+ def build_path(path, params)
314
+ return base_path(path) if params.nil? || params.empty?
315
+
316
+ query = params.is_a?(Hash) ? URI.encode_www_form(params) : params
317
+ "#{base_path(path)}?#{query}"
318
+ end
319
+ end
320
+ end
321
+ end
@@ -0,0 +1,17 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Celitech
4
+ module HTTP
5
+ # Lifecycle hooks for intercepting HTTP requests and responses.
6
+ # Override these methods in a subclass to add custom behaviour.
7
+ # Hook implementations should not raise exceptions; uncaught errors
8
+ # will propagate out of the connection and bypass subsequent hooks.
9
+ class Hooks
10
+ def before_request(request, params = {}); end
11
+
12
+ def after_response(request, response, params = {}); end
13
+
14
+ def on_error(error, request, params = {}); end
15
+ end
16
+ end
17
+ end
@@ -0,0 +1,76 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'json'
4
+ require 'net/http'
5
+ require 'uri'
6
+
7
+ module Celitech
8
+ module HTTP
9
+ class OAuthError < StandardError; end
10
+
11
+ # Manages OAuth 2.0 client credentials tokens: fetches, caches, and refreshes them.
12
+ # Token refresh is triggered when the token is absent or within REFRESH_BUFFER_SECS
13
+ # of expiry. A Mutex ensures thread-safe access to the cached token.
14
+ # Note: token refresh blocks all threads calling `headers` until the HTTP request
15
+ # completes. This is intentional — only one fetch occurs and others reuse the result.
16
+ class OAuthTokenManager
17
+ REFRESH_BUFFER_SECS = 5
18
+
19
+ def initialize(client_id:, client_secret:, token_url:)
20
+ @client_id = client_id
21
+ @client_secret = client_secret
22
+ @token_url = token_url
23
+ @access_token = nil
24
+ @expires_at = nil
25
+ @mutex = Mutex.new
26
+ end
27
+
28
+ attr_writer :client_id, :client_secret
29
+
30
+ def headers
31
+ { 'Authorization' => "Bearer #{token}" }
32
+ end
33
+
34
+ # Force the next call to re-fetch a fresh token.
35
+ def invalidate
36
+ @mutex.synchronize { @access_token = nil }
37
+ end
38
+
39
+ private
40
+
41
+ def token
42
+ @mutex.synchronize do
43
+ fetch_token if token_expired?
44
+ @access_token
45
+ end
46
+ end
47
+
48
+ def token_expired?
49
+ @access_token.nil? || (@expires_at && Time.now + REFRESH_BUFFER_SECS >= @expires_at)
50
+ end
51
+
52
+ def fetch_token
53
+ uri = URI.parse(@token_url)
54
+ req = Net::HTTP::Post.new(uri.request_uri)
55
+ req.set_form_data(
56
+ grant_type: 'client_credentials',
57
+ client_id: @client_id,
58
+ client_secret: @client_secret,
59
+ )
60
+
61
+ # Net::HTTP.start with a block opens and closes the connection automatically.
62
+ response = Net::HTTP.start(uri.host, uri.port, use_ssl: uri.scheme == 'https') do |http|
63
+ http.request(req)
64
+ end
65
+ raise OAuthError, "token request failed (HTTP #{response.code}): #{response.body}" unless response.is_a?(Net::HTTPSuccess)
66
+
67
+ body = JSON.parse(response.body)
68
+ raise OAuthError, 'access_token missing from token response' unless body.key?('access_token')
69
+
70
+ @access_token = body['access_token']
71
+ expires_in = body['expires_in']
72
+ @expires_at = expires_in ? Time.now + expires_in.to_i : nil
73
+ end
74
+ end
75
+ end
76
+ end
@@ -0,0 +1,35 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Celitech
4
+ module HTTP
5
+ class Response
6
+ attr_reader :status, :headers, :body, :raw_body
7
+
8
+ def initialize(raw)
9
+ @status = raw.code.to_i
10
+ @headers = raw.each_header.to_h
11
+ @raw_body = raw.body
12
+ @body = parse_body(raw.body, @headers['content-type'])
13
+ end
14
+
15
+ def success?
16
+ status >= 200 && status < 300
17
+ end
18
+
19
+ private
20
+
21
+ def parse_body(raw_body, content_type)
22
+ return nil if raw_body.nil? || raw_body.empty?
23
+
24
+ ct = content_type.to_s.split(';').first&.strip || ''
25
+ return JSON.parse(raw_body) if ct.include?('json')
26
+ return raw_body if ct.start_with?('text/') || ct == 'application/xml'
27
+
28
+ # For binary and unknown types try JSON first, fall back to raw
29
+ JSON.parse(raw_body)
30
+ rescue JSON::ParserError
31
+ raw_body
32
+ end
33
+ end
34
+ end
35
+ end
@@ -0,0 +1,47 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Celitech
4
+ module Models
5
+ class BadRequest
6
+ include ::Celitech::Models::Serializable
7
+ include ::Celitech::Models::OpenModel
8
+
9
+ def self.wire_keys
10
+ {
11
+ message: 'message',
12
+ }.freeze
13
+ end
14
+
15
+ def message
16
+ val = @message
17
+ val.equal?(::Celitech::Models::UNSET) ? nil : val
18
+ end
19
+
20
+ attr_reader :additional_properties
21
+
22
+ def initialize(message: ::Celitech::Models::UNSET, additional_properties: {})
23
+ @message = message
24
+ @additional_properties = additional_properties
25
+ end
26
+
27
+ def self.from_hash(hash)
28
+ return unless hash
29
+
30
+ new(
31
+ message: hash.fetch('message', ::Celitech::Models::UNSET),
32
+ additional_properties: hash.except('message'),
33
+ )
34
+ end
35
+
36
+ def attributes
37
+ {
38
+ message: @message,
39
+ }
40
+ end
41
+
42
+ def open_model_extras
43
+ @additional_properties
44
+ end
45
+ end
46
+ end
47
+ end
@@ -0,0 +1,63 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Celitech
4
+ module Models
5
+ class CreatePurchaseOkResponse
6
+ include ::Celitech::Models::Serializable
7
+ include ::Celitech::Models::OpenModel
8
+
9
+ def self.wire_keys
10
+ {
11
+ purchase: 'purchase',
12
+ profile: 'profile',
13
+ }.freeze
14
+ end
15
+
16
+ def purchase
17
+ val = @purchase
18
+ val.equal?(::Celitech::Models::UNSET) ? nil : val
19
+ end
20
+
21
+ def profile
22
+ val = @profile
23
+ val.equal?(::Celitech::Models::UNSET) ? nil : val
24
+ end
25
+
26
+ attr_reader :additional_properties
27
+
28
+ def initialize(purchase: ::Celitech::Models::UNSET, profile: ::Celitech::Models::UNSET, additional_properties: {})
29
+ @purchase = purchase
30
+ @profile = profile
31
+ @additional_properties = additional_properties
32
+ end
33
+
34
+ def self.from_hash(hash)
35
+ return unless hash
36
+
37
+ new(
38
+ purchase:
39
+ hash.key?('purchase') ? ::Celitech::Models::CreatePurchaseOkResponsePurchase.from_hash(hash['purchase']) : ::Celitech::Models::UNSET,
40
+ profile:
41
+ hash.key?('profile') ? ::Celitech::Models::CreatePurchaseOkResponseProfile.from_hash(hash['profile']) : ::Celitech::Models::UNSET,
42
+ additional_properties: hash.except('purchase', 'profile'),
43
+ )
44
+ end
45
+
46
+ def attributes
47
+ {
48
+ purchase: @purchase,
49
+ profile: @profile,
50
+ }
51
+ end
52
+
53
+ def validate!
54
+ @purchase&.validate! if !@purchase.equal?(::Celitech::Models::UNSET) && @purchase.respond_to?(:validate!)
55
+ @profile&.validate! if !@profile.equal?(::Celitech::Models::UNSET) && @profile.respond_to?(:validate!)
56
+ end
57
+
58
+ def open_model_extras
59
+ @additional_properties
60
+ end
61
+ end
62
+ end
63
+ end
@@ -0,0 +1,75 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Celitech
4
+ module Models
5
+ class CreatePurchaseOkResponseProfile
6
+ include ::Celitech::Models::Serializable
7
+ include ::Celitech::Models::OpenModel
8
+
9
+ def self.wire_keys
10
+ {
11
+ iccid: 'iccid',
12
+ activation_code: 'activationCode',
13
+ manual_activation_code: 'manualActivationCode',
14
+ }.freeze
15
+ end
16
+
17
+ def iccid
18
+ val = @iccid
19
+ val.equal?(::Celitech::Models::UNSET) ? nil : val
20
+ end
21
+
22
+ def activation_code
23
+ val = @activation_code
24
+ val.equal?(::Celitech::Models::UNSET) ? nil : val
25
+ end
26
+
27
+ def manual_activation_code
28
+ val = @manual_activation_code
29
+ val.equal?(::Celitech::Models::UNSET) ? nil : val
30
+ end
31
+
32
+ attr_reader :additional_properties
33
+
34
+ def initialize(
35
+ iccid: ::Celitech::Models::UNSET,
36
+ activation_code: ::Celitech::Models::UNSET,
37
+ manual_activation_code: ::Celitech::Models::UNSET,
38
+ additional_properties: {}
39
+ )
40
+ @iccid = iccid
41
+ @activation_code = activation_code
42
+ @manual_activation_code = manual_activation_code
43
+ @additional_properties = additional_properties
44
+ end
45
+
46
+ def self.from_hash(hash)
47
+ return unless hash
48
+
49
+ new(
50
+ iccid: hash.fetch('iccid', ::Celitech::Models::UNSET),
51
+ activation_code: hash.fetch('activationCode', ::Celitech::Models::UNSET),
52
+ manual_activation_code: hash.fetch('manualActivationCode', ::Celitech::Models::UNSET),
53
+ additional_properties: hash.except('iccid', 'activationCode', 'manualActivationCode'),
54
+ )
55
+ end
56
+
57
+ def attributes
58
+ {
59
+ iccid: @iccid,
60
+ activation_code: @activation_code,
61
+ manual_activation_code: @manual_activation_code,
62
+ }
63
+ end
64
+
65
+ def validate!
66
+ Validator.validate_string!(@iccid, 'iccid', min_length: 18, max_length: 22) unless @iccid.equal?(::Celitech::Models::UNSET)
67
+ Validator.validate_string!(@activation_code, 'activationCode', min_length: 1000, max_length: 8000) unless @activation_code.equal?(::Celitech::Models::UNSET)
68
+ end
69
+
70
+ def open_model_extras
71
+ @additional_properties
72
+ end
73
+ end
74
+ end
75
+ end