Module: Ksef::FA3::AttachmentReader

Extended by:
NodeReader
Defined in:
lib/ksef/fa3/attachment_reader.rb

Overview

Reads Zalacznik into an Attachment.

Split out for the same reason RowReader and AdvanceReader are: the attachment is a small tree of its own, and none of it interacts with the invoice's arithmetic.

This reader does refuse some documents, and that was mis-described

An earlier version of this comment claimed "nothing here refuses a document" and named ModelValidator as the reporter. Both were false: the models refuse at construction, so eight structurally-invalid attachment shapes raised out of Ksef::FA3.parse — taking the whole invoice with them — and tier 1a did not look at the attachment at all. An audit found it on 2026-08-26; the reporter now exists (AttachmentChecks) and this says what the code does.

What refuses: an attachment with no BlokDanych, a block with no MetaDane, a MetaDane missing either half, a table with no TNaglowek or no Wiersz, a Wiersz with no WKom, a Kol with no Typ or a Typ outside the enumeration. Each is a document the XSD rejects, and each is a shape the model cannot represent.

Why that is the choice, and what the alternative was. The parser already refuses a nameless seller and a missing P_1, so refusing structurally-impossible input is consistent rather than novel. The alternative — relax the model's invariants so any readable document parses, and let tier 1a report — is coherent and is what Line#net did for an unpriced row (§8.6). It was not taken here because the attachment's invariants are cardinality rules the XSD states, not amounts the model would silently alter, so representing them wrongly buys nothing. The cost is real and worth knowing: a malformed attachment makes the invoice's tax figures unreadable, and the attachment is the one node with no tax meaning. If that bites someone, relaxing the invariants is the fix, not a rescue here.

Constant Summary

Constants included from NodeReader

NodeReader::NAMESPACES, NodeReader::PREFIX

Class Method Summary collapse

Class Method Details

.attachment_from(root) ⇒ Attachment?

Returns nil when the document carries no attachment.

Parameters:

  • root (Nokogiri::XML::Node) —

    the Faktura element

Returns:

  • (Attachment, nil) —

    nil when the document carries no attachment



40
41
42
43
44
45
# File 'lib/ksef/fa3/attachment_reader.rb', line 40

def attachment_from(root)
  node = element(root, "Zalacznik")
  return nil if node.nil?

  Attachment.new(blocks: elements(node, "BlokDanych").map { |block| block_from(block) })
end