factpulse 2.0.17 → 2.0.18

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: 89a55e4054e4ebf0bed61cc92362c9df2cc29ac778f53042f55caa68a8319f5e
4
- data.tar.gz: ae5084503de6f649e51b6ebe165cef83174bc87300271c4b03846b63ae7cfe6d
3
+ metadata.gz: f8c3b0a899b4de47edbb4b0430d2ccfd74bccf4df25b94051e0dbc79dcae0e97
4
+ data.tar.gz: 84913bfdf248d67d1a0aeb3054173ddd106097288445266767097c80487dfa9c
5
5
  SHA512:
6
- metadata.gz: e5dded9461e4792afb0ff9b647f7a58b7e99a548f6810c3905614df6e6bcfc679773445d0fa51bb0db6e0f86fe4a3a9101811dc45304483de4ce66b421cf3195
7
- data.tar.gz: 23abccc40e68b4a9ff60606033a142f021efde90da0c6cb53b234807f749490e51a195532d13788436cb78d035cb89fa2d2f3ebc388442b8da2bd373c5da901a
6
+ metadata.gz: 8db1cb3ed9a898dbd8ee368fe2d47e659964f2c0f2f071063becced842f151c652297e8601ed65d41e54e1cd893d8ec04ba60beb8ea953b1d015535116492042
7
+ data.tar.gz: bf90ed0c9ce3d375f00b5357ac1d8d557f21a772ca2de6129620a04f614397a8b4403810e3c0fb990a0c5ee42414de12b20275228b681c870854491a48ce7cee
data/CHANGELOG.md CHANGED
@@ -7,7 +7,7 @@ et ce projet adhère au [Semantic Versioning](https://semver.org/spec/v2.0.0.htm
7
7
 
8
8
  ## [Unreleased]
9
9
 
10
- ## [2.0.17] - 2025-11-26
10
+ ## [2.0.18] - 2025-11-26
11
11
 
12
12
  ### Added
13
13
  - Version initiale du SDK ruby
@@ -24,5 +24,5 @@ et ce projet adhère au [Semantic Versioning](https://semver.org/spec/v2.0.0.htm
24
24
  - Guide d'authentification JWT
25
25
  - Configuration avancée (timeout, proxy, debug)
26
26
 
27
- [Unreleased]: https://github.com/factpulse/sdk-ruby/compare/v2.0.17...HEAD
28
- [2.0.17]: https://github.com/factpulse/sdk-ruby/releases/tag/v2.0.17
27
+ [Unreleased]: https://github.com/factpulse/sdk-ruby/compare/v2.0.18...HEAD
28
+ [2.0.18]: https://github.com/factpulse/sdk-ruby/releases/tag/v2.0.18
data/Gemfile.lock CHANGED
@@ -1,7 +1,7 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- factpulse (2.0.17)
4
+ factpulse (2.0.18)
5
5
  typhoeus (~> 1.0, >= 1.0.1)
6
6
 
7
7
  GEM
@@ -113,7 +113,7 @@ module FactPulse
113
113
  start_time, current_interval = (Time.now.to_f * 1000).to_i, interval_ms.to_f
114
114
  loop do
115
115
  raise FactPulsePollingTimeout.new(task_id, timeout_ms) if (Time.now.to_f * 1000).to_i - start_time > timeout_ms
116
- ensure_authenticated; response = http_get(URI("#{@api_url}/api/facturation/v1/traitement/taches/#{task_id}/statut"))
116
+ ensure_authenticated; response = http_get(URI("#{@api_url}/api/v1/traitement/taches/#{task_id}/statut"))
117
117
  reset_auth and next if response.code == '401'
118
118
  data = JSON.parse(response.body)
119
119
  return data['resultat'] || {} if data['statut'] == 'SUCCESS'
@@ -127,6 +127,114 @@ module FactPulse
127
127
 
128
128
  def self.format_montant(m); MontantHelpers.montant(m); end
129
129
 
130
+ # Génère une facture Factur-X à partir d'un dict/hash et d'un PDF source.
131
+ # Accepte un Hash, un String JSON, ou tout objet avec une méthode to_h/to_hash.
132
+ # @param facture_data [Hash, String, Object] Données de la facture
133
+ # @param pdf_source [String, File] Chemin vers le PDF source ou objet File
134
+ # @param profil [String] Profil Factur-X (MINIMUM, BASIC, EN16931, EXTENDED)
135
+ # @param format_sortie [String] Format de sortie (pdf, xml, both)
136
+ # @param sync [Boolean] Mode synchrone (true) ou asynchrone (false)
137
+ # @param timeout [Integer, nil] Timeout en ms pour le polling
138
+ # @return [String] Contenu binaire du PDF généré
139
+ def generer_facturx(facture_data, pdf_source, profil: 'EN16931', format_sortie: 'pdf', sync: true, timeout: nil)
140
+ # Conversion des données en JSON string
141
+ json_data = case facture_data
142
+ when String then facture_data
143
+ when Hash then JSON.generate(facture_data)
144
+ else
145
+ if facture_data.respond_to?(:to_h)
146
+ JSON.generate(facture_data.to_h)
147
+ elsif facture_data.respond_to?(:to_hash)
148
+ JSON.generate(facture_data.to_hash)
149
+ else
150
+ raise FactPulseValidationError.new("Type de données non supporté: #{facture_data.class}")
151
+ end
152
+ end
153
+
154
+ # Lecture du PDF source
155
+ pdf_content = case pdf_source
156
+ when String then File.binread(pdf_source)
157
+ when File then pdf_source.read
158
+ else
159
+ if pdf_source.respond_to?(:read)
160
+ pdf_source.read
161
+ else
162
+ raise FactPulseValidationError.new("Type de PDF non supporté: #{pdf_source.class}")
163
+ end
164
+ end
165
+ pdf_filename = pdf_source.is_a?(String) ? File.basename(pdf_source) : 'facture.pdf'
166
+
167
+ ensure_authenticated
168
+ uri = URI("#{@api_url}/api/v1/traitement/generer-facture")
169
+
170
+ # Construire la requête multipart
171
+ boundary = "----RubyFormBoundary#{SecureRandom.hex(16)}"
172
+ body = []
173
+
174
+ # Champ donnees_facture
175
+ body << "--#{boundary}\r\n"
176
+ body << "Content-Disposition: form-data; name=\"donnees_facture\"\r\n\r\n"
177
+ body << "#{json_data}\r\n"
178
+
179
+ # Champ profil
180
+ body << "--#{boundary}\r\n"
181
+ body << "Content-Disposition: form-data; name=\"profil\"\r\n\r\n"
182
+ body << "#{profil}\r\n"
183
+
184
+ # Champ format_sortie
185
+ body << "--#{boundary}\r\n"
186
+ body << "Content-Disposition: form-data; name=\"format_sortie\"\r\n\r\n"
187
+ body << "#{format_sortie}\r\n"
188
+
189
+ # Champ source_pdf (fichier)
190
+ body << "--#{boundary}\r\n"
191
+ body << "Content-Disposition: form-data; name=\"source_pdf\"; filename=\"#{pdf_filename}\"\r\n"
192
+ body << "Content-Type: application/pdf\r\n\r\n"
193
+ body << pdf_content
194
+ body << "\r\n"
195
+
196
+ body << "--#{boundary}--\r\n"
197
+ body_str = body.join
198
+
199
+ http = Net::HTTP.new(uri.host, uri.port)
200
+ http.use_ssl = uri.scheme == 'https'
201
+ http.read_timeout = 120
202
+
203
+ request = Net::HTTP::Post.new(uri)
204
+ request['Authorization'] = "Bearer #{@access_token}"
205
+ request['Content-Type'] = "multipart/form-data; boundary=#{boundary}"
206
+ request.body = body_str
207
+
208
+ response = http.request(request)
209
+
210
+ if response.code == '401'
211
+ reset_auth
212
+ ensure_authenticated
213
+ request['Authorization'] = "Bearer #{@access_token}"
214
+ response = http.request(request)
215
+ end
216
+
217
+ unless response.is_a?(Net::HTTPSuccess)
218
+ error_data = JSON.parse(response.body) rescue { 'detail' => response.body }
219
+ raise FactPulseValidationError.new("Erreur API: #{error_data['detail'] || response.body}")
220
+ end
221
+
222
+ data = JSON.parse(response.body)
223
+
224
+ if sync && data['id_tache']
225
+ result = poll_task(data['id_tache'], timeout: timeout)
226
+ if result['contenu_b64']
227
+ require 'base64'
228
+ return Base64.decode64(result['contenu_b64'])
229
+ elsif result['contenu_xml']
230
+ return result['contenu_xml']
231
+ end
232
+ raise FactPulseValidationError.new("Résultat inattendu: #{result.keys.join(', ')}")
233
+ end
234
+
235
+ data
236
+ end
237
+
130
238
  private
131
239
  def http_post(uri, payload)
132
240
  Net::HTTP.new(uri.host, uri.port).tap { |h| h.use_ssl = uri.scheme == 'https'; h.read_timeout = 30 }
@@ -11,5 +11,5 @@ Generator version: 7.18.0-SNAPSHOT
11
11
  =end
12
12
 
13
13
  module FactPulse
14
- VERSION = '2.0.17'
14
+ VERSION = '2.0.18'
15
15
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: factpulse
3
3
  version: !ruby/object:Gem::Version
4
- version: 2.0.17
4
+ version: 2.0.18
5
5
  platform: ruby
6
6
  authors:
7
7
  - OpenAPI-Generator