io-complyance-unify-sdk 3.0.6 → 3.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.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 818b96f31985aa2454ff497c342713a313472d1ff935ce4ca2c05781e2610d62
4
- data.tar.gz: ccf0aaa28e2663d52d1a33fbf9d04d904f3264f4996dd9293e3ff1e1a88e51c7
3
+ metadata.gz: 1a36d70d360c931f556c4f663b96e05cbdcb49095e133dff1d962e919ad2dd47
4
+ data.tar.gz: 41e452e7169f3fa28f0c6562ed249c2ac1b1da158ef4320fa32da35cd6c5fc9e
5
5
  SHA512:
6
- metadata.gz: 65c672dc16899b2d2c7a282484bb791ea87e538fa49dd96bab3ea78eafb0a17058b0030e431a4c9aa58b1994547a51ad48b6ba8109879b6cb6c67ab42e8d79d6
7
- data.tar.gz: 8268faa0b449277088cc7ebce3c0558f149a22cb76d36f5a3b545780b31fdb26773937f2c9c5bba5eb85113d4bd724cf6da1ea9317f70f166c8176c59a42e327
6
+ metadata.gz: 7f980700e30a8d070e326278fd42218517fddd1cb294d0c2eaededb3ba54aa2901eb36dc52dd06df9214f06888eadd4717e84520237de8d584216d81971d57ba
7
+ data.tar.gz: 3b1205f174b11a72a51d85a3192a7022ff5f79f30b68221d9c3c373f2a7212b477f585b2a279d6529ae7999542034736be749a8c9334308f59765cc53f905750
@@ -12,6 +12,9 @@ module ComplyanceSDK
12
12
 
13
13
  # Environment (sandbox, production)
14
14
  attr_accessor :environment
15
+
16
+ # Client/workspace ID for purchase invoice APIs
17
+ attr_accessor :client_id
15
18
 
16
19
  # Array of sources
17
20
  attr_accessor :sources
@@ -36,6 +39,7 @@ module ComplyanceSDK
36
39
  # @param options [Hash] Configuration options
37
40
  # @option options [String] :api_key API key for authentication
38
41
  # @option options [String, Symbol] :environment Environment (sandbox, production)
42
+ # @option options [String] :client_id Client/workspace ID for purchase invoice APIs
39
43
  # @option options [Array<ComplyanceSDK::Models::Source>] :sources Array of sources
40
44
  # @option options [ComplyanceSDK::Config::RetryConfig] :retry_config Retry configuration
41
45
  # @option options [Boolean] :logging_enabled Whether logging is enabled
@@ -43,6 +47,7 @@ module ComplyanceSDK
43
47
  def initialize(options = {})
44
48
  @api_key = options[:api_key]
45
49
  @environment = parse_environment(options[:environment])
50
+ @client_id = options[:client_id]
46
51
  @sources = options[:sources] || []
47
52
  @retry_config = options[:retry_config] || RetryConfig.default
48
53
  @logging_enabled = options.fetch(:logging_enabled, true)
@@ -75,6 +80,7 @@ module ComplyanceSDK
75
80
  new(
76
81
  api_key: ENV["COMPLYANCE_API_KEY"],
77
82
  environment: ENV["COMPLYANCE_ENVIRONMENT"],
83
+ client_id: ENV["COMPLYANCE_CLIENT_ID"],
78
84
  logging_enabled: ENV.fetch("COMPLYANCE_LOGGING_ENABLED", "true") == "true",
79
85
  log_level: ENV.fetch("COMPLYANCE_LOG_LEVEL", "info").to_sym
80
86
  )
@@ -99,6 +105,7 @@ module ComplyanceSDK
99
105
  new(
100
106
  api_key: config[:api_key],
101
107
  environment: config[:environment],
108
+ client_id: config[:client_id],
102
109
  logging_enabled: config.fetch(:logging_enabled, true),
103
110
  log_level: config.fetch(:log_level, :info).to_sym
104
111
  )
@@ -94,6 +94,17 @@ module ComplyanceSDK
94
94
  end
95
95
  end
96
96
 
97
+ def extract_error_message(parsed_body, fallback)
98
+ if parsed_body.is_a?(Hash)
99
+ parsed_body['message'] || parsed_body[:message] ||
100
+ parsed_body['error_msg'] || parsed_body[:error_msg] ||
101
+ parsed_body['error'] || parsed_body[:error] ||
102
+ fallback
103
+ else
104
+ fallback
105
+ end
106
+ end
107
+
97
108
  def build_connection
98
109
  base_url = ComplyanceSDK::Models::Environment.base_url(@config.environment)
99
110
 
@@ -146,21 +157,21 @@ module ComplyanceSDK
146
157
  when 200..299
147
158
  parsed_body || {}
148
159
  when 400..499
149
- error_message = parsed_body&.dig('message') || parsed_body&.dig('error_msg') || response.reason_phrase
160
+ error_message = extract_error_message(parsed_body, response.reason_phrase)
150
161
  raise ComplyanceSDK::Exceptions::APIError.new(
151
162
  "Client error: #{error_message}",
152
163
  status_code: response.status,
153
164
  context: { response_body: parsed_body }
154
165
  )
155
166
  when 500..599
156
- error_message = parsed_body&.dig('message') || parsed_body&.dig('error_msg') || response.reason_phrase
167
+ error_message = extract_error_message(parsed_body, response.reason_phrase)
157
168
  raise ComplyanceSDK::Exceptions::APIError.new(
158
169
  "Server error: #{error_message}",
159
170
  status_code: response.status,
160
171
  context: { response_body: parsed_body }
161
172
  )
162
173
  else
163
- error_message = parsed_body&.dig('message') || parsed_body&.dig('error_msg') || "Unexpected response"
174
+ error_message = extract_error_message(parsed_body, "Unexpected response")
164
175
  raise ComplyanceSDK::Exceptions::APIError.new(
165
176
  "#{error_message}: #{response.status}",
166
177
  status_code: response.status,
@@ -220,4 +231,4 @@ module ComplyanceSDK
220
231
  end
221
232
  end
222
233
  end
223
- end
234
+ end
@@ -85,6 +85,17 @@ module ComplyanceSDK
85
85
  CONSOLIDATED = GetsDocumentModifier::CONSOLIDATED
86
86
  end
87
87
 
88
+ module VARIANT
89
+ STANDARD = GetsDocumentVariant::STANDARD
90
+ ADVANCE = GetsDocumentVariant::ADVANCE
91
+ REFUND = GetsDocumentVariant::REFUND
92
+ PARTIAL = GetsDocumentVariant::PARTIAL
93
+ PARTIAL_CONSTRUCTION = GetsDocumentVariant::PARTIAL_CONSTRUCTION
94
+ PARTIAL_FINAL_CONSTRUCTION = GetsDocumentVariant::PARTIAL_FINAL_CONSTRUCTION
95
+ FINAL_CONSTRUCTION = GetsDocumentVariant::FINAL_CONSTRUCTION
96
+ CORRECTIVE = GetsDocumentVariant::CORRECTIVE
97
+ end
98
+
88
99
  class GetsDocumentTypeV2
89
100
  attr_accessor :base, :modifiers, :variant
90
101
 
@@ -0,0 +1,218 @@
1
+ # frozen_string_literal: true
2
+
3
+ module ComplyanceSDK
4
+ module PurchaseInvoice
5
+ module ModelHelpers
6
+ module_function
7
+
8
+ def value_for(hash, key)
9
+ return nil unless hash.is_a?(Hash)
10
+
11
+ hash[key] || hash[key.to_s] || hash[key.to_sym]
12
+ end
13
+ end
14
+
15
+ class PurchaseInvoiceArtifacts
16
+ attr_reader :invoice_xml_base64, :invoice_xml_encoding, :tdd_xml_base64
17
+
18
+ def initialize(invoice_xml_base64:, invoice_xml_encoding:, tdd_xml_base64:)
19
+ @invoice_xml_base64 = invoice_xml_base64
20
+ @invoice_xml_encoding = invoice_xml_encoding
21
+ @tdd_xml_base64 = tdd_xml_base64
22
+ end
23
+
24
+ def self.from_h(data)
25
+ return nil unless data.is_a?(Hash)
26
+
27
+ new(
28
+ invoice_xml_base64: ModelHelpers.value_for(data, :invoiceXmlBase64),
29
+ invoice_xml_encoding: ModelHelpers.value_for(data, :invoiceXmlEncoding),
30
+ tdd_xml_base64: ModelHelpers.value_for(data, :tddXmlBase64)
31
+ )
32
+ end
33
+ end
34
+
35
+ class PurchaseInvoiceGovernmentStatus
36
+ attr_reader :document_id, :country, :environment, :success, :error_code, :error_message, :timestamp, :status
37
+
38
+ def initialize(document_id:, country:, environment:, success:, error_code:, error_message:, timestamp:, status:)
39
+ @document_id = document_id
40
+ @country = country
41
+ @environment = environment
42
+ @success = success
43
+ @error_code = error_code
44
+ @error_message = error_message
45
+ @timestamp = timestamp
46
+ @status = status
47
+ end
48
+
49
+ def self.from_h(data)
50
+ return nil unless data.is_a?(Hash)
51
+
52
+ new(
53
+ document_id: ModelHelpers.value_for(data, :documentId),
54
+ country: ModelHelpers.value_for(data, :country),
55
+ environment: ModelHelpers.value_for(data, :environment),
56
+ success: ModelHelpers.value_for(data, :success),
57
+ error_code: ModelHelpers.value_for(data, :errorCode),
58
+ error_message: ModelHelpers.value_for(data, :errorMessage),
59
+ timestamp: ModelHelpers.value_for(data, :timestamp),
60
+ status: ModelHelpers.value_for(data, :status)
61
+ )
62
+ end
63
+ end
64
+
65
+ class PurchaseInvoiceCompliance
66
+ attr_reader :uuid, :fta_approved_status, :business_process_identifier, :specification_identifier
67
+
68
+ def initialize(uuid:, fta_approved_status:, business_process_identifier:, specification_identifier:)
69
+ @uuid = uuid
70
+ @fta_approved_status = fta_approved_status
71
+ @business_process_identifier = business_process_identifier
72
+ @specification_identifier = specification_identifier
73
+ end
74
+
75
+ def self.from_h(data)
76
+ return nil unless data.is_a?(Hash)
77
+
78
+ new(
79
+ uuid: ModelHelpers.value_for(data, :uuid),
80
+ fta_approved_status: ModelHelpers.value_for(data, :ftaApprovedStatus),
81
+ business_process_identifier: ModelHelpers.value_for(data, :businessProcessIdentifier),
82
+ specification_identifier: ModelHelpers.value_for(data, :specificationIdentifier)
83
+ )
84
+ end
85
+ end
86
+
87
+ class PurchaseInvoiceValidationErrorEntry
88
+ attr_reader :code, :message, :path, :source
89
+
90
+ def initialize(code:, message:, path:, source:)
91
+ @code = code
92
+ @message = message
93
+ @path = path || []
94
+ @source = source
95
+ end
96
+
97
+ def self.from_h(data)
98
+ return nil unless data.is_a?(Hash)
99
+
100
+ new(
101
+ code: ModelHelpers.value_for(data, :code),
102
+ message: ModelHelpers.value_for(data, :message),
103
+ path: ModelHelpers.value_for(data, :path) || [],
104
+ source: ModelHelpers.value_for(data, :source)
105
+ )
106
+ end
107
+ end
108
+
109
+ class PurchaseInvoiceValidationStep
110
+ attr_reader :name, :status, :error
111
+
112
+ def initialize(name:, status:, error:)
113
+ @name = name
114
+ @status = status
115
+ @error = error
116
+ end
117
+
118
+ def self.from_h(data)
119
+ return nil unless data.is_a?(Hash)
120
+
121
+ new(
122
+ name: ModelHelpers.value_for(data, :name),
123
+ status: ModelHelpers.value_for(data, :status),
124
+ error: ModelHelpers.value_for(data, :error)
125
+ )
126
+ end
127
+ end
128
+
129
+ class PurchaseInvoiceValidationResults
130
+ attr_reader :status, :validation_steps
131
+
132
+ def initialize(status:, validation_steps:)
133
+ @status = status
134
+ @validation_steps = validation_steps || []
135
+ end
136
+
137
+ def self.from_h(data)
138
+ return nil unless data.is_a?(Hash)
139
+
140
+ validation_steps = Array(ModelHelpers.value_for(data, :validationSteps)).filter_map do |step|
141
+ PurchaseInvoiceValidationStep.from_h(step)
142
+ end
143
+
144
+ new(
145
+ status: ModelHelpers.value_for(data, :status),
146
+ validation_steps: validation_steps
147
+ )
148
+ end
149
+ end
150
+
151
+ class PurchaseInvoiceResult
152
+ attr_reader :document_id,
153
+ :client_id,
154
+ :country,
155
+ :environment,
156
+ :document_number,
157
+ :state,
158
+ :is_terminal,
159
+ :last_updated_at,
160
+ :invoice,
161
+ :xml,
162
+ :xml_response,
163
+ :artifacts,
164
+ :government,
165
+ :compliance,
166
+ :errors,
167
+ :validation_results
168
+
169
+ def initialize(document_id:, client_id:, country:, environment:, document_number:, state:, is_terminal:,
170
+ last_updated_at:, invoice:, xml:, xml_response:, artifacts:, government:, compliance:,
171
+ errors:, validation_results:)
172
+ @document_id = document_id
173
+ @client_id = client_id
174
+ @country = country
175
+ @environment = environment
176
+ @document_number = document_number
177
+ @state = state
178
+ @is_terminal = is_terminal
179
+ @last_updated_at = last_updated_at
180
+ @invoice = invoice
181
+ @xml = xml
182
+ @xml_response = xml_response
183
+ @artifacts = artifacts
184
+ @government = government
185
+ @compliance = compliance
186
+ @errors = errors || []
187
+ @validation_results = validation_results
188
+ end
189
+
190
+ def self.from_h(data)
191
+ return nil unless data.is_a?(Hash)
192
+
193
+ errors = Array(ModelHelpers.value_for(data, :errors)).filter_map do |entry|
194
+ PurchaseInvoiceValidationErrorEntry.from_h(entry)
195
+ end
196
+
197
+ new(
198
+ document_id: ModelHelpers.value_for(data, :documentId),
199
+ client_id: ModelHelpers.value_for(data, :clientId),
200
+ country: ModelHelpers.value_for(data, :country),
201
+ environment: ModelHelpers.value_for(data, :environment),
202
+ document_number: ModelHelpers.value_for(data, :documentNumber),
203
+ state: ModelHelpers.value_for(data, :state),
204
+ is_terminal: ModelHelpers.value_for(data, :isTerminal),
205
+ last_updated_at: ModelHelpers.value_for(data, :lastUpdatedAt),
206
+ invoice: ModelHelpers.value_for(data, :invoice),
207
+ xml: ModelHelpers.value_for(data, :xml),
208
+ xml_response: ModelHelpers.value_for(data, :xmlResponse),
209
+ artifacts: PurchaseInvoiceArtifacts.from_h(ModelHelpers.value_for(data, :artifacts)),
210
+ government: PurchaseInvoiceGovernmentStatus.from_h(ModelHelpers.value_for(data, :government)),
211
+ compliance: PurchaseInvoiceCompliance.from_h(ModelHelpers.value_for(data, :compliance)),
212
+ errors: errors,
213
+ validation_results: PurchaseInvoiceValidationResults.from_h(ModelHelpers.value_for(data, :validationResults))
214
+ )
215
+ end
216
+ end
217
+ end
218
+ end
@@ -24,7 +24,7 @@ module ComplyanceSDK
24
24
  # @yield The block to execute
25
25
  # @return The result of the block
26
26
  def execute(operation_name, context = {})
27
- circuit_breaker = get_circuit_breaker(operation_name)
27
+ circuit_breaker = @config.retry_config&.circuit_breaker_enabled ? get_circuit_breaker(operation_name) : nil
28
28
  retry_strategy = RetryStrategy.new(@config.retry_config, circuit_breaker)
29
29
 
30
30
  retry_strategy.execute(context.merge(operation: operation_name)) do
@@ -98,11 +98,11 @@ module ComplyanceSDK
98
98
 
99
99
  def get_circuit_breaker(operation_name)
100
100
  @circuit_breakers[operation_name] ||= CircuitBreaker.new(
101
- operation_name,
102
- @config.retry_config,
103
- @redis_config
101
+ failure_threshold: @config.retry_config.failure_threshold,
102
+ timeout_seconds: @config.retry_config.circuit_breaker_timeout.to_i,
103
+ success_threshold: 1
104
104
  )
105
105
  end
106
106
  end
107
107
  end
108
- end
108
+ end
@@ -141,6 +141,9 @@ module ComplyanceSDK
141
141
  def should_retry?(error, attempt)
142
142
  return false if attempt >= @config.max_attempts
143
143
 
144
+ return true if retryable_error_class?(error)
145
+ return true if retryable_api_error?(error)
146
+
144
147
  error_detail = error.context
145
148
  return false unless error_detail
146
149
 
@@ -222,4 +225,4 @@ module ComplyanceSDK
222
225
  end
223
226
  end
224
227
  end
225
- end
228
+ end
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module ComplyanceSDK
4
- VERSION = "3.0.6"
4
+ VERSION = "3.0.7"
5
5
  end
@@ -22,10 +22,11 @@ require "complyance_sdk/exceptions/sdk_exception"
22
22
  require "complyance_sdk/exceptions/circuit_breaker_open_error"
23
23
  # require "complyance_sdk/middleware/rack_middleware" # Removed - not needed
24
24
  require "complyance_sdk/http/client"
25
- # require "complyance_sdk/retry/retry_manager" # Removed - not needed
25
+ require "complyance_sdk/retry/retry_manager"
26
26
  require "complyance_sdk/retry/circuit_breaker"
27
27
  require "complyance_sdk/retry/retry_strategy"
28
28
  require "complyance_sdk/queue/persistent_queue_manager"
29
+ require "complyance_sdk/purchase_invoice/models"
29
30
  require "openssl"
30
31
  require "uri"
31
32
 
@@ -108,7 +109,16 @@ module ComplyanceSDK
108
109
  # @param payload [Hash] The business data payload
109
110
  # @param destinations [Array, nil] Optional destinations (auto-generated if nil)
110
111
  # @return [ComplyanceSDK::Models::UnifyResponse] The response object
111
- def push_to_unify(source_name, source_version, logical_doc_type, country, operation, mode, purpose, payload, destinations = nil)
112
+ def push_to_unify(*args)
113
+ if args.length == 1 && (args[0].is_a?(Hash) || args[0].is_a?(ComplyanceSDK::Models::UnifyRequest))
114
+ return push_to_unify_request(args[0])
115
+ end
116
+
117
+ if args.length < 8 || args.length > 9
118
+ raise ArgumentError, "wrong number of arguments (given #{args.length}, expected 1 or 8..9)"
119
+ end
120
+
121
+ source_name, source_version, logical_doc_type, country, operation, mode, purpose, payload, destinations = args
112
122
  push_to_unify_logical(source_name, source_version, logical_doc_type, country, operation, mode, purpose, payload, destinations)
113
123
  end
114
124
 
@@ -672,7 +682,7 @@ module ComplyanceSDK
672
682
  def list_purchase_invoices(filters = {})
673
683
  ensure_configured_for_purchase_api!
674
684
  query = { type: "purchases" }.merge(filters.reject { |_key, value| value.nil? })
675
- http_client.get("/documents", query)
685
+ http_client.get("/api/v3/documents", query)
676
686
  end
677
687
 
678
688
  def get_purchase_invoice(id)
@@ -685,7 +695,19 @@ module ComplyanceSDK
685
695
  )
686
696
  end
687
697
 
688
- http_client.get("/documents/#{URI.encode_www_form_component(id.to_s)}", { type: "purchases" })
698
+ response = http_client.get(
699
+ "/api/v3/documents/#{URI.encode_www_form_component(id.to_s)}?type=purchases",
700
+ {},
701
+ purchase_invoice_headers
702
+ )
703
+
704
+ payload = if response.is_a?(Hash)
705
+ response[:data] || response['data'] || response
706
+ else
707
+ response
708
+ end
709
+
710
+ ComplyanceSDK::PurchaseInvoice::PurchaseInvoiceResult.from_h(payload)
689
711
  end
690
712
 
691
713
  def verify_webhook_signature(payload, signature, secret, algorithm = "sha256")
@@ -718,6 +740,25 @@ module ComplyanceSDK
718
740
  "SDK must be configured before making API calls"
719
741
  )
720
742
  end
743
+
744
+ if configuration.client_id.to_s.strip.empty?
745
+ raise ComplyanceSDK::Exceptions::ConfigurationError.new(
746
+ "client_id is required for purchase invoice APIs",
747
+ suggestion: "Set client_id on SDKConfig or COMPLYANCE_CLIENT_ID in the environment."
748
+ )
749
+ end
750
+ end
751
+
752
+ def purchase_invoice_headers
753
+ {
754
+ "Authorization" => "Bearer #{configuration.api_key}",
755
+ "x-client-id" => configuration.client_id.to_s,
756
+ "x-api-key-environment" => purchase_invoice_api_environment
757
+ }
758
+ end
759
+
760
+ def purchase_invoice_api_environment
761
+ configuration.environment == ComplyanceSDK::Models::Environment::PRODUCTION ? "production" : "mock"
721
762
  end
722
763
 
723
764
  def secure_compare(left, right)
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: io-complyance-unify-sdk
3
3
  version: !ruby/object:Gem::Version
4
- version: 3.0.6
4
+ version: 3.0.7
5
5
  platform: ruby
6
6
  authors:
7
7
  - Complyance Team
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2026-05-02 00:00:00.000000000 Z
11
+ date: 2026-06-05 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: faraday
@@ -282,6 +282,7 @@ files:
282
282
  - lib/complyance_sdk/models/source_ref.rb
283
283
  - lib/complyance_sdk/models/unify_request.rb
284
284
  - lib/complyance_sdk/models/unify_response.rb
285
+ - lib/complyance_sdk/purchase_invoice/models.rb
285
286
  - lib/complyance_sdk/queue/persistent_queue_manager.rb
286
287
  - lib/complyance_sdk/railtie.rb
287
288
  - lib/complyance_sdk/retry/circuit_breaker.rb