Module: Cpro::Facturx
- Defined in:
- lib/cpro/facturx.rb
Overview
Inspection minimale d'un PDF/A-3 Factur-X, sans dépendance à un analyseur PDF : de quoi attraper le mauvais fichier avant de le déposer, pas de quoi valider la facture.
Constant Summary collapse
- ENTETE_PDF =
"%PDF"- RACINE_CII =
"CrossIndustryInvoice"
Class Method Summary collapse
- .inflate(flux) ⇒ Object
-
.montant_total(contenu) ⇒ Object
Montant TTC déclaré par le XML embarqué (BT-112), à comparer par l'appelant à ce qu'il attend.
- .pdf?(contenu) ⇒ Boolean
-
.xml(contenu) ⇒ Object
Les pièces jointes d'un PDF/A-3 sont presque toujours compressées en FlateDecode : on décompresse les flux jusqu'à retrouver la racine CII.
- .xml?(contenu) ⇒ Boolean
Class Method Details
.inflate(flux) ⇒ Object
47 48 49 50 51 |
# File 'lib/cpro/facturx.rb', line 47 def inflate(flux) Zlib::Inflate.inflate(flux) rescue Zlib::Error nil end |
.montant_total(contenu) ⇒ Object
Montant TTC déclaré par le XML embarqué (BT-112), à comparer par l'appelant à ce qu'il attend. La gem ne lit pas le PDF lisible et ne peut donc rien confronter elle-même.
39 40 41 42 43 44 45 |
# File 'lib/cpro/facturx.rb', line 39 def montant_total(contenu) document = xml(contenu) or return nil valeur = document[%r{<ram:GrandTotalAmount[^>]*>([^<]+)</ram:GrandTotalAmount>}, 1] valeur && BigDecimal(valeur.strip) rescue ArgumentError nil end |
.pdf?(contenu) ⇒ Boolean
15 16 17 |
# File 'lib/cpro/facturx.rb', line 15 def pdf?(contenu) contenu.to_s.byteslice(0, ENTETE_PDF.bytesize) == ENTETE_PDF end |
.xml(contenu) ⇒ Object
Les pièces jointes d'un PDF/A-3 sont presque toujours compressées en FlateDecode : on
décompresse les flux jusqu'à retrouver la racine CII. Un XML stocké sans compression
échapperait à cette recherche, d'où xml_absent? qui ne conclut que sur le cas certain.
22 23 24 25 26 27 28 29 30 31 |
# File 'lib/cpro/facturx.rb', line 22 def xml(contenu) octets = contenu.to_s.b octets.enum_for(:scan, /stream\r?\n/).each do debut = Regexp.last_match.end(0) fin = octets.index("endstream", debut) || next decompresse = inflate(octets[debut...fin]) || next return decompresse if decompresse.include?(RACINE_CII) end nil end |
.xml?(contenu) ⇒ Boolean
33 34 35 |
# File 'lib/cpro/facturx.rb', line 33 def xml?(contenu) !xml(contenu).nil? end |