cpro-client 0.2.4 → 0.2.6

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: eed2218b6135210909bb231938a2adf3d8f9b432a19468576b232ffd2f352d7a
4
- data.tar.gz: 95739510c05be2fdc248b2f001e4b53e08b3487162dbb29f50bc26606d929e06
3
+ metadata.gz: 1f1452657739318ca5d2a71a6673d046dea03e4f5e3b00befc41ae210fcf3ee4
4
+ data.tar.gz: b36804bf664635e9d5f510fe8a8ed2e52a6aeb1753b9de3bc3b919475d3e51cb
5
5
  SHA512:
6
- metadata.gz: 7208819c95be0220d40498c3d09c5df5479619c652c6103aac41903ce1cac6054f47b53a7c87638fd7b474e99581a61b6924ab1d0f17b633bb18a72d431e8a94
7
- data.tar.gz: 4c292e8c13863bdff0fe54ab567e42880c4d25e5d928ca70fb6c1a83284198912cc14b5dd787f0733763e181a7923f08ab7768a0ee5007b5b4e52b3719c4b7f0
6
+ metadata.gz: 918adeba480ffaaec7508e21e68c31799708e568fb4dc5f2678072ab9f10971f31a03c8af893e57548cce0d5c93b9ad2b9d5387a50a7d629f40f945dfb16b93a
7
+ data.tar.gz: 299ffdbbc8b8c9f25b24c09d1577fdd4e0d1f3b9bc9f3b0eed7c6d607f428e86e87d1a1978bb55c10ab6e450bdb24c996b5909673113031cfb375bb65ab30255
data/CHANGELOG.md CHANGED
@@ -1,6 +1,48 @@
1
1
  ## [Unreleased]
2
2
 
3
3
 
4
+ ## [0.2.6] - 2026-09-05
5
+
6
+ ### Modifié
7
+ - `Cpro::Resources::Annuaire#find_identifiant_actif` devient **`#find_identifiant_adressage`**, et
8
+ ne filtre plus sur le statut de plateforme : il le fait départager. À proximité égale une adresse
9
+ active l'emporte, mais faute d'adresse active la plus proche est rendue quand même.
10
+
11
+ L'ancien comportement interdisait de facturer un destinataire non raccordé, alors que le dossier
12
+ de spécifications externes pose l'inverse : une telle facture est *déposée*, avec le motif
13
+ `NON_TRANSMISE`, et ce statut « permet à l'entité publique de justifier qu'elle a bien émis une
14
+ facture électronique et qu'elle a donc respecté ses obligations réglementaires ». L'émetteur doit
15
+ remettre un duplicata à son client, mais l'obligation réglementaire est remplie — la gem n'a pas
16
+ à s'y opposer.
17
+
18
+ L'appelant lit `plateforme_active?` sur la ligne rendue pour distinguer les deux cas, et `nil` ne
19
+ signifie plus qu'une chose : aucune adresse à aucun niveau.
20
+
21
+
22
+ ## [0.2.5] - 2026-09-05
23
+
24
+ ### Ajouté
25
+ - `Cpro::Client#suivi` enchaîne les appels de suivi d'un dépôt — statut du flux, recherche de la
26
+ facture, consultation avec son historique — et rend un `Cpro::Suivi` qui nomme l'étape atteinte :
27
+ `:flux_en_attente` (404 du PPF, cas nominal juste après un dépôt), `:flux_irrecevable`,
28
+ `:facture_introuvable` (204, ambigu par nature) ou `:facture_connue`. Il court-circuite dès
29
+ qu'un palier interdit d'aller plus loin : un appel tant que le flux n'est pas traité, trois au
30
+ plus. Il n'attend jamais — la cadence d'interrogation appartient à l'appelant — et laisse
31
+ `statut_flux` et `facture` accessibles pour ce qu'il n'interprète pas.
32
+ - `Cpro::Entities::Facture#dernier_incident`, relayé par `Cpro::Suivi#dernier_incident`, isole le
33
+ dernier changement de statut porteur de motifs — l'incident en cours — là où `motifs_rejet`
34
+ cumule tout l'historique. Il rend le changement et non le motif : un même changement en porte
35
+ plusieurs, une facture « Déposée » pouvant cumuler `NON_TRANSMISE` et `REJ_UNI`.
36
+ - `Cpro::Suivi#motifs` rassemble les motifs de rejet, qu'ils viennent du flux ou de l'historique de
37
+ la facture : l'appelant n'a plus à savoir où le dépôt s'est arrêté pour aller les chercher.
38
+ - `Cpro::Entities::Facture#en_echec?` — vrai dès qu'une facture demande une intervention, que son
39
+ statut l'annonce ou non. Chorus Pro accroche ses motifs de rejet au statut porteur, qui peut
40
+ être anodin : une facture « Déposée » assortie de `NON_TRANSMISE` ne parviendra pas à son
41
+ destinataire alors que `rejetee?` répond faux. Le prédicat couvre les statuts `REJETEE` et
42
+ `ERREUR_ROUTAGE` ainsi que tout motif présent dans l'historique — lequel n'est renseigné que
43
+ par `Factures#find`.
44
+
45
+
4
46
  ## [0.2.3] - 2026-08-31
5
47
 
6
48
  ### Ajouté
data/Gemfile.lock CHANGED
@@ -1,7 +1,7 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- cpro-client (0.2.4)
4
+ cpro-client (0.2.6)
5
5
  faraday (>= 0.9, < 3.0)
6
6
 
7
7
  GEM
data/README.md CHANGED
@@ -142,27 +142,40 @@ BT-49, l'adresse électronique de l'acheteur, ne se transmet pas à l'API : elle
142
142
  Factur-X, et c'est d'elle que le PPF déduit l'acheminement. Une facture qui la porte mal est
143
143
  rejetée `REJ_ADR` — « le destinataire n'est pas trouvable » — plusieurs minutes après le dépôt.
144
144
 
145
- `find_identifiant_actif` fait la résolution en un appel. Il accepte les quatre formes d'une valeur
146
- d'adressage — SIREN, SIRET, SIRET_SERVICE, SIREN_SIRET_SERVICE — et remonte la hiérarchie
147
- SIREN → SIRET → service jusqu'à trouver une ligne dont la plateforme est active :
145
+ `find_identifiant_adressage` fait la résolution en un appel. Il accepte les quatre formes d'une
146
+ valeur d'adressage — SIREN, SIRET, SIRET_SERVICE, SIREN_SIRET_SERVICE — et remonte la hiérarchie
147
+ SIREN → SIRET → service pour rendre l'adresse la plus proche que l'annuaire connaisse :
148
148
 
149
149
  ```ruby
150
- ligne = client.annuaire.find_identifiant_actif("71915767420316")
150
+ ligne = client.annuaire.find_identifiant_adressage("71915767420316")
151
151
  ligne.to_s # => "719157674_71915767420316", à porter en BT-49
152
- ligne.identifiant_routage # => "" l'adresse de base de l'établissement
152
+ ligne.plateforme_active? # => la facture sera-t-elle transmise ?
153
153
 
154
- client.annuaire.find_identifiant_actif("71915767420316_SERVICE_INEXISTANT").to_s
154
+ client.annuaire.find_identifiant_adressage("71915767420316_SERVICE_INEXISTANT").to_s
155
155
  # => "719157674_71915767420316" — service inconnu, on retombe sur son parent
156
156
  ```
157
157
 
158
- `nil` signifie qu'aucun niveau n'est adressable, donc qu'on ne peut pas facturer. Pour savoir
159
- *pourquoi*, `find_lignes_adressage` rend les mêmes lignes sans filtrer : une unité légale inconnue
160
- lève une `Cpro::NotFoundError`, tandis qu'une unité connue mais non raccordée rend ses lignes avec
161
- `plateforme_active?` à faux.
158
+ **Le statut de plateforme départage, il n'exclut pas.** À égalité de proximité, une adresse dont la
159
+ plateforme est active l'emporte ; mais si aucune ne l'est, l'adresse est rendue quand même. Elle
160
+ reste la bonne : une facture destinée à un non-raccordé est bien *déposée*, avec le motif
161
+ `NON_TRANSMISE`, et ce statut « permet à l'entité publique de justifier qu'elle a bien émis une
162
+ facture électronique et qu'elle a donc respecté ses obligations réglementaires ». L'émetteur devra
163
+ remettre un duplicata à son client, mais l'obligation est remplie.
162
164
 
163
- Deux limites à connaître. La résolution ne redescend jamais vers les enfants : un SIREN nu ne
164
- remonte rien si la structure n'a d'adresses qu'au niveau SIRET. Et une adresse active n'est pas une
165
- promesse d'acheminement elle garantit que le destinataire est identifiable, pas qu'il recevra.
165
+ L'appelant lit donc `plateforme_active?` sur la ligne rendue pour savoir dans quel cas il est :
166
+
167
+ | Résultat | Ce qui se passera |
168
+ | --- | --- |
169
+ | ligne, `plateforme_active?` vrai | la facture est transmise au destinataire |
170
+ | ligne, `plateforme_active?` faux | déposée et conforme, mais non transmise — duplicata à prévoir |
171
+ | `nil` | aucune adresse à aucun niveau : on ne peut pas facturer |
172
+
173
+ Pour distinguer « unité légale inconnue » de « connue mais sans adresse exploitable »,
174
+ `find_lignes_adressage` rend les mêmes lignes sans les départager et laisse remonter la
175
+ `Cpro::NotFoundError`.
176
+
177
+ Une limite à connaître : la résolution ne redescend jamais vers les enfants. Un SIREN nu ne remonte
178
+ rien si la structure n'a d'adresses qu'au niveau SIRET.
166
179
 
167
180
  ## Transmission d'une facture Factur-X
168
181
 
@@ -254,6 +267,48 @@ aucune facture ne correspond que lorsque le compte technique n'est rattaché ni
254
267
  callback, et les statuts des factures G2B ne sont pas consultables sur le portail Chorus Pro : le
255
268
  suivi passe nécessairement par une interrogation périodique de cette API.
256
269
 
270
+ ## Suivre un dépôt en un appel
271
+
272
+ Les quatre étapes du suivi — statut du flux, recherche par `nomFlux`, consultation, lecture des
273
+ motifs — se réduisent à une méthode, qui nomme l'étape atteinte plutôt que de lever ou de rendre
274
+ `nil` :
275
+
276
+ ```ruby
277
+ suivi = client.suivi(depot)
278
+
279
+ suivi.etape # :flux_en_attente, :flux_irrecevable, :facture_introuvable, :facture_connue
280
+ suivi.en_echec? # au niveau de l'enveloppe comme à celui de la facture
281
+ suivi.motifs # les motifs, d'où qu'ils viennent
282
+ suivi.facture # la facture et son historique, à l'étape :facture_connue
283
+ suivi.statut_flux # le statut brut du flux, dès qu'il est connu
284
+ ```
285
+
286
+ `motifs` cumule tout l'historique — un incident réglé y côtoie l'incident courant. Pour n'avoir que
287
+ le plus récent, avec le statut qui le portait et sa date :
288
+
289
+ ```ruby
290
+ incident = suivi.dernier_incident # un ChangementStatut, ou nil
291
+
292
+ incident.statut # "DEPOSEE"
293
+ incident.date # 2026-09-04 19:18:31 UTC
294
+ incident.motifs_rejet.map(&:code) # ["NON_TRANSMISE", "REJ_UNI"]
295
+ ```
296
+
297
+ Il rend le changement et non le motif : un même changement en porte plusieurs, et n'en exposer
298
+ qu'un les masquerait. Il vaut `nil` à l'étape `:flux_irrecevable`, où il n'y a pas encore de
299
+ facture — `motifs` reste alors l'accès uniforme.
300
+
301
+ | Étape | Ce qui s'est passé | Appels | Suite |
302
+ | --- | --- | :-: | --- |
303
+ | `:flux_en_attente` | 404 sur le flux — cas nominal | 1 | réinterroger |
304
+ | `:flux_irrecevable` | enveloppe refusée, motifs sur le flux | 1 | terminal |
305
+ | `:facture_introuvable` | flux recevable, recherche vide | 2 | réinterroger, puis vérifier le rattachement du compte |
306
+ | `:facture_connue` | facture et historique disponibles | 3 | lire `en_echec?` et les motifs |
307
+
308
+ La méthode **n'attend pas** : c'est une photographie, la cadence d'interrogation reste à l'appelant.
309
+ Seuls le 404 du flux et la recherche vide deviennent des étapes ; un 401, un 403 ou un 5xx
310
+ continuent de lever.
311
+
257
312
  ## Servir plusieurs entités
258
313
 
259
314
  L'AIFE distingue trois types de raccordement API. Celui qui s'applique détermine le modèle à
data/lib/cpro/client.rb CHANGED
@@ -19,6 +19,12 @@ module Cpro
19
19
  self.class.new(configuration, account: account, token_provider: token_provider, connections: connections)
20
20
  end
21
21
 
22
+ # Enchaîne les appels de suivi d'un dépôt et rend une synthèse. Traverse deux ressources,
23
+ # d'où sa place ici plutôt que sur l'une d'elles.
24
+ def suivi(depot)
25
+ Suivi.pour(self, depot)
26
+ end
27
+
22
28
  def annuaire
23
29
  @annuaire ||= Resources::Annuaire.new(self, connection_for(ANNUAIRE_PATH))
24
30
  end
@@ -10,6 +10,11 @@ module Cpro
10
10
  CHANGEMENT_DE_COMPTE_A_PAYER NON_AFFACTUREE AFFACTUREE AFFACTUREE_CONFIDENTIEL
11
11
  ].freeze
12
12
 
13
+ EPOQUE = Time.at(0).utc
14
+
15
+ # Statuts qui constatent par eux-mêmes qu'une facture n'arrivera pas.
16
+ STATUTS_EN_ECHEC = %w[REJETEE ERREUR_ROUTAGE].freeze
17
+
13
18
  CHAMPS = {
14
19
  uid: "uidFacture",
15
20
  numero: "numeroFacture",
@@ -77,6 +82,36 @@ module Cpro
77
82
  historique.flat_map(&:motifs_rejet)
78
83
  end
79
84
 
85
+ # Le dernier changement de statut porteur de motifs — celui qui décrit l'incident en cours,
86
+ # là où `motifs_rejet` cumule tout l'historique, motifs devenus caducs compris.
87
+ #
88
+ # Rend le changement et non le motif : un même changement en porte plusieurs — une facture
89
+ # « Déposée » peut cumuler NON_TRANSMISE et REJ_UNI — et n'en exposer qu'un les masquerait.
90
+ # Le rang départage deux changements de même date, le plus récent l'emportant.
91
+ def dernier_incident
92
+ incidents = historique.select(&:rejet?)
93
+ incidents.each_with_index.max_by { |changement, rang| [changement.date || EPOQUE, rang] }&.first
94
+ end
95
+
96
+ # Vrai dès qu'une facture demande une intervention, que son statut l'annonce ou non : un
97
+ # motif de rejet peut être porté par un statut anodin. Une facture « Déposée » accompagnée
98
+ # de NON_TRANSMISE en est le cas type — `rejetee?` répond faux, et pourtant le destinataire
99
+ # ne la recevra pas par la plateforme.
100
+ #
101
+ # Attention au mot « échec » : NON_TRANSMISE n'invalide pas la facture. Le dossier de
102
+ # spécifications externes est explicite — ce statut « permet à l'entité publique de
103
+ # justifier qu'elle a bien émis une facture électronique et qu'elle a donc respecté ses
104
+ # obligations réglementaires ». Il n'y a donc rien à redéposer ; il y a à livrer autrement.
105
+ #
106
+ # Le refus de l'acheteur (REFUSEE) n'en fait pas partie : c'est une décision métier, une
107
+ # étape normale du cycle de vie, pas un incident. Elle se lit par `refusee?`.
108
+ #
109
+ # L'historique n'étant renseigné que par `Factures#find`, une facture issue d'une recherche
110
+ # ne peut être jugée que sur son statut.
111
+ def en_echec?
112
+ STATUTS_EN_ECHEC.include?(statut) || historique.any?(&:rejet?)
113
+ end
114
+
80
115
  def to_s
81
116
  [numero, statut].compact.join(" ")
82
117
  end
@@ -77,23 +77,25 @@ module Cpro
77
77
  Entities::ResultatRecherche.new(payload, item_class: Entities::CodeRoutage, total_key: TOTAL_KEY)
78
78
  end
79
79
 
80
- # Adresse active la plus proche d'une valeur d'adressage : la valeur elle-même si elle porte
81
- # une plateforme active, sinon son parent le plus proche, et ainsi de suite jusqu'au SIREN.
82
- # Rend la ligne d'annuaire, dont `to_s` donne l'identifiant à porter en BT-49.
80
+ # Adresse à porter en BT-49 pour une valeur d'adressage : la plus proche que l'annuaire
81
+ # connaisse, en privilégiant celles dont la plateforme est active. Rend la ligne d'annuaire,
82
+ # dont `to_s` donne l'identifiant.
83
83
  #
84
- # `nil` a un sens unique aucun niveau n'est adressable, donc on ne peut pas facturer. Pour
85
- # distinguer « SIREN inconnu » de « connu mais sans plateforme active », voir
86
- # `#find_lignes_adressage`, qui ne filtre pas et laisse remonter le 404.
84
+ # Le statut de plateforme départage, il n'exclut pas. Une adresse sans plateforme reste
85
+ # utilisable : le dossier de spécifications externes pose qu'une facture destinée à un
86
+ # destinataire non raccordé prend le statut « Déposée » avec le motif NON_TRANSMISE, et que
87
+ # ce statut « permet à l'entité publique de justifier qu'elle a bien émis une facture
88
+ # électronique et qu'elle a donc respecté ses obligations réglementaires ». L'émetteur devra
89
+ # remettre un duplicata à son client, mais la facture est valide et l'obligation remplie.
90
+ #
91
+ # L'appelant lit `plateforme_active?` sur la ligne rendue pour savoir dans lequel des deux
92
+ # cas il se trouve. `nil` ne signifie plus qu'une chose : aucune adresse, à aucun niveau.
87
93
  #
88
94
  # Un seul appel réseau : `GET /siren/code-insee:` retourne aussi les lignes SIRET et service.
89
- def find_identifiant_actif(valeur)
95
+ def find_identifiant_adressage(valeur)
90
96
  adressage = Adressage.parse(valeur)
91
- actives = find_lignes_adressage(adressage).select(&:plateforme_active?)
92
- adressage.paliers.each do |palier|
93
- ligne = actives.find { |active| palier.correspond?(active) }
94
- return ligne if ligne
95
- end
96
- nil
97
+ lignes = find_lignes_adressage(adressage)
98
+ plus_proche(adressage, lignes.select(&:plateforme_active?)) || plus_proche(adressage, lignes)
97
99
  rescue NotFoundError
98
100
  nil
99
101
  end
@@ -110,6 +112,16 @@ module Cpro
110
112
 
111
113
  private
112
114
 
115
+ # Descend les paliers du plus précis au plus général et rend la première ligne qui
116
+ # corresponde. Appelée deux fois : sur les adresses actives d'abord, sur toutes ensuite.
117
+ def plus_proche(adressage, lignes)
118
+ adressage.paliers.each do |palier|
119
+ ligne = lignes.find { |candidate| palier.correspond?(candidate) }
120
+ return ligne if ligne
121
+ end
122
+ nil
123
+ end
124
+
113
125
  def normalize(value, length, label)
114
126
  digits = value.to_s.gsub(/\s+/, "")
115
127
  return digits if digits.match?(/\A\d{#{length}}\z/)
data/lib/cpro/suivi.rb ADDED
@@ -0,0 +1,92 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Cpro
4
+ # Photographie du parcours d'un dépôt, à un instant donné. Elle enchaîne les appels que l'hôte
5
+ # devrait sinon écrire lui-même — statut du flux, recherche de la facture, consultation avec son
6
+ # historique — et s'arrête dès qu'un palier ne permet pas d'aller plus loin.
7
+ #
8
+ # Elle n'attend pas : la cadence d'interrogation appartient à l'appelant. Et elle n'avale rien,
9
+ # `statut_flux` et `facture` restant accessibles pour ce qu'elle n'interprète pas.
10
+ class Suivi
11
+ ETAPES = %i[flux_en_attente flux_irrecevable facture_introuvable facture_connue].freeze
12
+
13
+ attr_reader :etape, :statut_flux, :facture
14
+
15
+ # Un 404 sur le flux et une recherche vide sont des états du parcours, pas des erreurs : ils
16
+ # deviennent des étapes. Tout le reste — 401, 403, 5xx — continue de lever.
17
+ def self.pour(client, depot)
18
+ statut = client.flux.status(depot)
19
+ return new(etape: :flux_en_attente) if statut.nil?
20
+ return new(etape: :flux_irrecevable, statut_flux: statut) unless statut.recevable?
21
+
22
+ facture = premiere_facture(client, statut)
23
+ return new(etape: :facture_introuvable, statut_flux: statut) if facture.nil?
24
+
25
+ new(etape: :facture_connue, statut_flux: statut, facture: facture)
26
+ end
27
+
28
+ # `find` seul renseigne l'historique, et c'est lui qui porte les motifs.
29
+ def self.premiere_facture(client, statut)
30
+ return nil if statut.nom_flux.nil? || statut.nom_flux.empty?
31
+
32
+ resultat = client.factures.search_by_nom_flux(statut).first
33
+ resultat && client.factures.find(resultat)
34
+ end
35
+ private_class_method :premiere_facture
36
+
37
+ def initialize(etape:, statut_flux: nil, facture: nil)
38
+ raise ArgumentError, "étape inconnue : #{etape.inspect}" unless ETAPES.include?(etape)
39
+
40
+ @etape = etape
41
+ @statut_flux = statut_flux
42
+ @facture = facture
43
+ end
44
+
45
+ def en_attente?
46
+ etape == :flux_en_attente
47
+ end
48
+
49
+ def irrecevable?
50
+ etape == :flux_irrecevable
51
+ end
52
+
53
+ # Ambigu par nature : l'API répond 204 aussi bien parce que la facture n'est pas encore
54
+ # indexée que parce que le compte technique n'est rattaché à aucune des deux structures.
55
+ def introuvable?
56
+ etape == :facture_introuvable
57
+ end
58
+
59
+ def connue?
60
+ etape == :facture_connue
61
+ end
62
+
63
+ # Vrai que l'incident soit survenu au niveau de l'enveloppe ou à celui de la facture.
64
+ def en_echec?
65
+ irrecevable? || facture&.en_echec? || false
66
+ end
67
+
68
+ # Les motifs vivent à deux endroits selon l'endroit où le dépôt s'est arrêté : l'appelant n'a
69
+ # pas à savoir lequel.
70
+ def motifs
71
+ return statut_flux.motifs_rejet if irrecevable?
72
+
73
+ facture ? facture.motifs_rejet : []
74
+ end
75
+
76
+ # Le dernier changement de statut porteur de motifs. Nil à l'étape `:flux_irrecevable` : il
77
+ # n'y a alors pas de facture, et les motifs sont portés par le flux — `motifs` reste l'accès
78
+ # uniforme, quelle que soit l'étape atteinte.
79
+ def dernier_incident
80
+ facture&.dernier_incident
81
+ end
82
+
83
+ def nom_flux
84
+ statut_flux&.nom_flux
85
+ end
86
+
87
+ def to_s
88
+ [etape, facture&.statut, motifs.map(&:code).join(", ")].reject { |v| v.nil? || v.to_s.empty? }
89
+ .join(" — ")
90
+ end
91
+ end
92
+ end
data/lib/cpro/version.rb CHANGED
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Cpro
4
- VERSION = "0.2.4"
4
+ VERSION = "0.2.6"
5
5
  end
data/lib/cpro.rb CHANGED
@@ -35,6 +35,7 @@ require_relative "cpro/resources/base"
35
35
  require_relative "cpro/resources/annuaire"
36
36
  require_relative "cpro/resources/flux"
37
37
  require_relative "cpro/resources/factures"
38
+ require_relative "cpro/suivi"
38
39
  require_relative "cpro/client"
39
40
 
40
41
  module Cpro
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: cpro-client
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.2.4
4
+ version: 0.2.6
5
5
  platform: ruby
6
6
  authors:
7
7
  - Hôtentic
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2026-09-04 00:00:00.000000000 Z
11
+ date: 2026-09-05 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: faraday
@@ -85,6 +85,7 @@ files:
85
85
  - lib/cpro/resources/base.rb
86
86
  - lib/cpro/resources/factures.rb
87
87
  - lib/cpro/resources/flux.rb
88
+ - lib/cpro/suivi.rb
88
89
  - lib/cpro/version.rb
89
90
  homepage: https://hotentic.com
90
91
  licenses: