cpro-client 0.2.5 → 0.2.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 +4 -4
- data/CHANGELOG.md +34 -0
- data/Gemfile.lock +1 -1
- data/README.md +50 -13
- data/lib/cpro/resources/annuaire.rb +25 -13
- data/lib/cpro/suivi.rb +151 -0
- data/lib/cpro/version.rb +1 -1
- metadata +3 -2
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 56e12349c80b29ebc7190354cefea789a6a9114d42260bc40e2851529255a043
|
|
4
|
+
data.tar.gz: 35ec2d79aace35593b9493dd6e07b3ede842726ba9b2cc9b63491ca269844272
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: e3372fac6b533cb8b24b08dbae14c2dce8f495a93d4b53161d553b874ab208bee3099f53efa0af7159e4690cd5aea8414c9da2fef33a38c8cd875796aff99d60
|
|
7
|
+
data.tar.gz: fae64931447cd4708e173bca2790890bad33ed65bbc370ad49dc40e60a1f12185af579d947eec2a766fbb79f1dd5da07f77e1c99d18a54678532866b664ae206
|
data/CHANGELOG.md
CHANGED
|
@@ -1,6 +1,40 @@
|
|
|
1
1
|
## [Unreleased]
|
|
2
2
|
|
|
3
3
|
|
|
4
|
+
## [0.2.7] - 2026-09-07
|
|
5
|
+
|
|
6
|
+
### Ajouté
|
|
7
|
+
- `Cpro::Suivi#orientation` nomme la situation d'un dépôt en une valeur sur laquelle brancher —
|
|
8
|
+
`:en_attente`, `:enveloppe_irrecevable`, `:facture_introuvable`, `:en_cours`, `:rejetee`,
|
|
9
|
+
`:non_transmise`, `:erreur_routage`, `:transmise` — en aplatissant l'étape du suivi et l'état de
|
|
10
|
+
la facture. Ne repose que sur des codes : statut, code motif, étape. Un statut d'acheminement
|
|
11
|
+
l'emporte sur un `NON_TRANSMISE` devenu caduc, et c'est l'incident courant qui décide.
|
|
12
|
+
|
|
13
|
+
Deux distinctions restent à l'appelant : séparer les deux `NON_TRANSMISE` supposerait de lire le
|
|
14
|
+
texte d'une note rédigée par l'AIFE, et séparer un rejet corrigeable d'un rejet définitif repose
|
|
15
|
+
sur une lecture de la spécification que nous n'avons pas mesurée.
|
|
16
|
+
- `CHORUS_PRO.md` — les séquences de statuts et de motifs renvoyées par la plateforme, scénario par
|
|
17
|
+
scénario, en distinguant les relevés sandbox des comportements seulement documentés.
|
|
18
|
+
|
|
19
|
+
|
|
20
|
+
## [0.2.6] - 2026-09-05
|
|
21
|
+
|
|
22
|
+
### Modifié
|
|
23
|
+
- `Cpro::Resources::Annuaire#find_identifiant_actif` devient **`#find_identifiant_adressage`**, et
|
|
24
|
+
ne filtre plus sur le statut de plateforme : il le fait départager. À proximité égale une adresse
|
|
25
|
+
active l'emporte, mais faute d'adresse active la plus proche est rendue quand même.
|
|
26
|
+
|
|
27
|
+
L'ancien comportement interdisait de facturer un destinataire non raccordé, alors que le dossier
|
|
28
|
+
de spécifications externes pose l'inverse : une telle facture est *déposée*, avec le motif
|
|
29
|
+
`NON_TRANSMISE`, et ce statut « permet à l'entité publique de justifier qu'elle a bien émis une
|
|
30
|
+
facture électronique et qu'elle a donc respecté ses obligations réglementaires ». L'émetteur doit
|
|
31
|
+
remettre un duplicata à son client, mais l'obligation réglementaire est remplie — la gem n'a pas
|
|
32
|
+
à s'y opposer.
|
|
33
|
+
|
|
34
|
+
L'appelant lit `plateforme_active?` sur la ligne rendue pour distinguer les deux cas, et `nil` ne
|
|
35
|
+
signifie plus qu'une chose : aucune adresse à aucun niveau.
|
|
36
|
+
|
|
37
|
+
|
|
4
38
|
## [0.2.5] - 2026-09-05
|
|
5
39
|
|
|
6
40
|
### Ajouté
|
data/Gemfile.lock
CHANGED
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
|
-
`
|
|
146
|
-
d'adressage — SIREN, SIRET, SIRET_SERVICE, SIREN_SIRET_SERVICE — et remonte la hiérarchie
|
|
147
|
-
SIREN → SIRET → service
|
|
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.
|
|
150
|
+
ligne = client.annuaire.find_identifiant_adressage("71915767420316")
|
|
151
151
|
ligne.to_s # => "719157674_71915767420316", à porter en BT-49
|
|
152
|
-
ligne.
|
|
152
|
+
ligne.plateforme_active? # => la facture sera-t-elle transmise ?
|
|
153
153
|
|
|
154
|
-
client.annuaire.
|
|
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
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
`
|
|
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
|
-
|
|
164
|
-
|
|
165
|
-
|
|
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
|
|
|
@@ -270,6 +283,24 @@ suivi.facture # la facture et son historique, à l'étape :facture_connue
|
|
|
270
283
|
suivi.statut_flux # le statut brut du flux, dès qu'il est connu
|
|
271
284
|
```
|
|
272
285
|
|
|
286
|
+
Pour brancher directement sans reconstruire le même `if` dans chaque application,
|
|
287
|
+
`orientation` aplatit l'étape et l'état de la facture en une valeur :
|
|
288
|
+
|
|
289
|
+
```ruby
|
|
290
|
+
case suivi.orientation
|
|
291
|
+
when :en_attente, :en_cours, :facture_introuvable then reprogrammer_le_suivi
|
|
292
|
+
when :enveloppe_irrecevable, :rejetee then signaler(suivi.motifs)
|
|
293
|
+
when :non_transmise then preparer_un_duplicata
|
|
294
|
+
when :erreur_routage then alerter
|
|
295
|
+
when :transmise then classer
|
|
296
|
+
end
|
|
297
|
+
```
|
|
298
|
+
|
|
299
|
+
Elle ne repose que sur des codes — statut, code motif, étape — jamais sur le texte d'une note.
|
|
300
|
+
Deux distinctions restent donc à l'appelant, et [CHORUS_PRO.md](CHORUS_PRO.md) explique comment les
|
|
301
|
+
obtenir : séparer les deux causes de `:non_transmise`, et distinguer un rejet corrigeable d'un rejet
|
|
302
|
+
définitif.
|
|
303
|
+
|
|
273
304
|
`motifs` cumule tout l'historique — un incident réglé y côtoie l'incident courant. Pour n'avoir que
|
|
274
305
|
le plus récent, avec le statut qui le portait et sa date :
|
|
275
306
|
|
|
@@ -456,6 +487,12 @@ client.annuaire.find_by_siren("474775418").lignes_annuaire.map(&:identifiant_adr
|
|
|
456
487
|
C'est cet identifiant qui doit alimenter BT-49 sur la facture et MDT-73 sur le cycle de vie.
|
|
457
488
|
Vérifiez `plateforme_active?` avant de compter sur un acheminement.
|
|
458
489
|
|
|
490
|
+
## Comportements de la plateforme
|
|
491
|
+
|
|
492
|
+
[CHORUS_PRO.md](CHORUS_PRO.md) rassemble, scénario par scénario, la séquence de statuts et de motifs
|
|
493
|
+
que renvoie réellement la plateforme — enveloppe irrecevable, adressage introuvable, destinataire
|
|
494
|
+
non raccordé, doublon — en distinguant ce qui a été mesuré en sandbox de ce qui n'est que documenté.
|
|
495
|
+
|
|
459
496
|
## Licence
|
|
460
497
|
|
|
461
498
|
Disponible en open source sous les termes de la [licence MIT](https://opensource.org/licenses/MIT).
|
|
@@ -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
|
|
81
|
-
#
|
|
82
|
-
#
|
|
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
|
-
#
|
|
85
|
-
#
|
|
86
|
-
#
|
|
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
|
|
95
|
+
def find_identifiant_adressage(valeur)
|
|
90
96
|
adressage = Adressage.parse(valeur)
|
|
91
|
-
|
|
92
|
-
adressage.
|
|
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,151 @@
|
|
|
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
|
+
ORIENTATIONS = %i[en_attente enveloppe_irrecevable facture_introuvable en_cours
|
|
14
|
+
rejetee non_transmise erreur_routage transmise].freeze
|
|
15
|
+
|
|
16
|
+
# Statuts qui prouvent que la facture a quitté Chorus Pro : d'après la colonne « Sens flux »
|
|
17
|
+
# de l'annexe des statuts, ils proviennent de la plateforme du destinataire ou constatent
|
|
18
|
+
# l'émission par la plateforme.
|
|
19
|
+
#
|
|
20
|
+
# `APPROUVEE`, `REFUSEE` et `VISEE` circulent dans les deux sens. Ils figurent ici parce que
|
|
21
|
+
# les recevoir est le cas courant, et que les omettre ferait passer une facture refusée par
|
|
22
|
+
# l'acheteur pour une facture encore en cours. Une application qui les émet elle-même le sait.
|
|
23
|
+
STATUTS_TRANSMISE = %w[
|
|
24
|
+
EMISE_PAR_LA_PLATEFORME RECUE_DE_LA_PLATEFORME MISE_A_DISPOSITION PRISE_EN_CHARGE
|
|
25
|
+
APPROUVEE APPROUVEE_PARTIELLEMENT EN_LITIGE SUSPENDUE PAIEMENT_TRANSMIS REFUSEE VISEE
|
|
26
|
+
].freeze
|
|
27
|
+
|
|
28
|
+
MOTIF_NON_TRANSMISE = "NON_TRANSMISE"
|
|
29
|
+
STATUT_ERREUR_ROUTAGE = "ERREUR_ROUTAGE"
|
|
30
|
+
|
|
31
|
+
attr_reader :etape, :statut_flux, :facture
|
|
32
|
+
|
|
33
|
+
# Un 404 sur le flux et une recherche vide sont des états du parcours, pas des erreurs : ils
|
|
34
|
+
# deviennent des étapes. Tout le reste — 401, 403, 5xx — continue de lever.
|
|
35
|
+
def self.pour(client, depot)
|
|
36
|
+
statut = client.flux.status(depot)
|
|
37
|
+
return new(etape: :flux_en_attente) if statut.nil?
|
|
38
|
+
return new(etape: :flux_irrecevable, statut_flux: statut) unless statut.recevable?
|
|
39
|
+
|
|
40
|
+
facture = premiere_facture(client, statut)
|
|
41
|
+
return new(etape: :facture_introuvable, statut_flux: statut) if facture.nil?
|
|
42
|
+
|
|
43
|
+
new(etape: :facture_connue, statut_flux: statut, facture: facture)
|
|
44
|
+
end
|
|
45
|
+
|
|
46
|
+
# `find` seul renseigne l'historique, et c'est lui qui porte les motifs.
|
|
47
|
+
def self.premiere_facture(client, statut)
|
|
48
|
+
return nil if statut.nom_flux.nil? || statut.nom_flux.empty?
|
|
49
|
+
|
|
50
|
+
resultat = client.factures.search_by_nom_flux(statut).first
|
|
51
|
+
resultat && client.factures.find(resultat)
|
|
52
|
+
end
|
|
53
|
+
private_class_method :premiere_facture
|
|
54
|
+
|
|
55
|
+
def initialize(etape:, statut_flux: nil, facture: nil)
|
|
56
|
+
raise ArgumentError, "étape inconnue : #{etape.inspect}" unless ETAPES.include?(etape)
|
|
57
|
+
|
|
58
|
+
@etape = etape
|
|
59
|
+
@statut_flux = statut_flux
|
|
60
|
+
@facture = facture
|
|
61
|
+
end
|
|
62
|
+
|
|
63
|
+
def en_attente?
|
|
64
|
+
etape == :flux_en_attente
|
|
65
|
+
end
|
|
66
|
+
|
|
67
|
+
def irrecevable?
|
|
68
|
+
etape == :flux_irrecevable
|
|
69
|
+
end
|
|
70
|
+
|
|
71
|
+
# Ambigu par nature : l'API répond 204 aussi bien parce que la facture n'est pas encore
|
|
72
|
+
# indexée que parce que le compte technique n'est rattaché à aucune des deux structures.
|
|
73
|
+
def introuvable?
|
|
74
|
+
etape == :facture_introuvable
|
|
75
|
+
end
|
|
76
|
+
|
|
77
|
+
def connue?
|
|
78
|
+
etape == :facture_connue
|
|
79
|
+
end
|
|
80
|
+
|
|
81
|
+
# Vrai que l'incident soit survenu au niveau de l'enveloppe ou à celui de la facture.
|
|
82
|
+
def en_echec?
|
|
83
|
+
irrecevable? || facture&.en_echec? || false
|
|
84
|
+
end
|
|
85
|
+
|
|
86
|
+
# Les motifs vivent à deux endroits selon l'endroit où le dépôt s'est arrêté : l'appelant n'a
|
|
87
|
+
# pas à savoir lequel.
|
|
88
|
+
def motifs
|
|
89
|
+
return statut_flux.motifs_rejet if irrecevable?
|
|
90
|
+
|
|
91
|
+
facture ? facture.motifs_rejet : []
|
|
92
|
+
end
|
|
93
|
+
|
|
94
|
+
# Le dernier changement de statut porteur de motifs. Nil à l'étape `:flux_irrecevable` : il
|
|
95
|
+
# n'y a alors pas de facture, et les motifs sont portés par le flux — `motifs` reste l'accès
|
|
96
|
+
# uniforme, quelle que soit l'étape atteinte.
|
|
97
|
+
def dernier_incident
|
|
98
|
+
facture&.dernier_incident
|
|
99
|
+
end
|
|
100
|
+
|
|
101
|
+
# Nomme la situation en une valeur sur laquelle brancher, l'étape du suivi et l'état de la
|
|
102
|
+
# facture étant aplatis ensemble. Ne repose que sur des codes — statut, code motif, étape.
|
|
103
|
+
#
|
|
104
|
+
# Deux distinctions sont délibérément laissées à l'appelant, parce que les porter ici serait
|
|
105
|
+
# fragile :
|
|
106
|
+
#
|
|
107
|
+
# - séparer les deux `NON_TRANSMISE` — destinataire sans plateforme, qui ne recevra jamais, ou
|
|
108
|
+
# plateforme non encore raccordée, qui recevra plus tard — suppose de lire le texte d'une
|
|
109
|
+
# note rédigée par l'AIFE. L'annuaire le dit plus sûrement avant le dépôt, par
|
|
110
|
+
# `Annuaire#find_identifiant_adressage(siret).statut_plateforme` ;
|
|
111
|
+
# - séparer un rejet corrigeable d'un rejet définitif repose sur l'idée qu'un rejet de
|
|
112
|
+
# conformité n'intègre pas la facture et ne consomme donc pas son numéro. La spécification
|
|
113
|
+
# le laisse entendre, nous ne l'avons pas mesuré.
|
|
114
|
+
#
|
|
115
|
+
# `motifs` et `dernier_incident` restent disponibles pour qui veut trancher lui-même.
|
|
116
|
+
def orientation
|
|
117
|
+
case etape
|
|
118
|
+
when :flux_en_attente then :en_attente
|
|
119
|
+
when :flux_irrecevable then :enveloppe_irrecevable
|
|
120
|
+
when :facture_introuvable then :facture_introuvable
|
|
121
|
+
else orientation_facture
|
|
122
|
+
end
|
|
123
|
+
end
|
|
124
|
+
|
|
125
|
+
def nom_flux
|
|
126
|
+
statut_flux&.nom_flux
|
|
127
|
+
end
|
|
128
|
+
|
|
129
|
+
def to_s
|
|
130
|
+
[etape, facture&.statut, motifs.map(&:code).join(", ")].reject { |v| v.nil? || v.to_s.empty? }
|
|
131
|
+
.join(" — ")
|
|
132
|
+
end
|
|
133
|
+
|
|
134
|
+
private
|
|
135
|
+
|
|
136
|
+
# L'ordre compte : un statut d'acheminement l'emporte sur un NON_TRANSMISE devenu caduc, et
|
|
137
|
+
# c'est l'incident courant — non le cumul de l'historique — qui décrit la situation présente.
|
|
138
|
+
def orientation_facture
|
|
139
|
+
return :erreur_routage if facture.statut == STATUT_ERREUR_ROUTAGE
|
|
140
|
+
return :rejetee if facture.rejetee?
|
|
141
|
+
return :transmise if STATUTS_TRANSMISE.include?(facture.statut)
|
|
142
|
+
return :non_transmise if non_transmise?
|
|
143
|
+
|
|
144
|
+
:en_cours
|
|
145
|
+
end
|
|
146
|
+
|
|
147
|
+
def non_transmise?
|
|
148
|
+
dernier_incident&.motifs_rejet.to_a.any? { |motif| motif.code == MOTIF_NON_TRANSMISE }
|
|
149
|
+
end
|
|
150
|
+
end
|
|
151
|
+
end
|
data/lib/cpro/version.rb
CHANGED
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
|
+
version: 0.2.7
|
|
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-
|
|
11
|
+
date: 2026-09-07 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:
|