Class: Ksef::FA3::Builder
- Inherits:
-
Object
- Object
- Ksef::FA3::Builder
- Includes:
- Advances, Corrections, Subjects
- Defined in:
- lib/ksef/fa3/builder.rb,
lib/ksef/fa3/builder/advances.rb,
lib/ksef/fa3/builder/subjects.rb,
lib/ksef/fa3/builder/corrections.rb
Overview
The object yielded by build. Collects fields, then hands them to Invoice — which keeps every computation and every schema default in one place rather than splitting them between the model and the DSL.
Two deliberate choices about strictness. An unknown or misspelled key raises,
listing what is permitted, because the alternative is a silently incomplete invoice
— the same reasoning as Serializer's treatment of unknown element names. But a
single-value field set twice simply takes the later value, which is what anyone
writing a builder expects, and what f.number called twice obviously ought to do.
Defined Under Namespace
Modules: Advances, Corrections, Subjects
Constant Summary collapse
- SUBJECT_KEYS =
%i[nip name address local_government_unit vat_group_member buyer_id].freeze
- ADDRESS_KEYS =
%i[line1 line2 country street city postal_code].freeze
- LINE_KEYS =
%i[name quantity unit net_unit_price vat_rate net_amount row_number state_before].freeze
- CORRECTION_KEYS =
%i[reason effect period corrected_number previous_seller previous_buyers paid_before exchange_rate_before].freeze
- CORRECTED_KEYS =
%i[number issue_date ksef_number].freeze
- ORDER_KEYS =
%i[total].freeze
- ORDER_LINE_KEYS =
%i[name quantity unit net_unit_price net_amount vat_amount vat_rate row_number state_before].freeze
- ADVANCE_KEYS =
%i[ksef_number number].freeze
- LINE_ALIASES =
English shorthand from DESIGN.md §8's example. The canonical names work too, so
qty:andquantity:are interchangeable — but passing both is an error rather than a silent last-one-wins. { qty: :quantity, vat: :vat_rate }.freeze
- REQUIRED =
Reported together, so one round trip tells the caller everything that is missing.
%i[seller buyer number issue_date].freeze
Instance Method Summary collapse
-
#attachment(value) ⇒ Object
The invoice attachment (
Zalacznik), a sibling ofFacarrying no amounts. - #buyer(**attributes) ⇒ Object
- #currency(value) ⇒ Object
-
#initialize ⇒ Builder
constructor
A new instance of Builder.
- #invoice_type(value) ⇒ Object
- #issue_date(value) ⇒ Object
- #issued_at(value) ⇒ Object
-
#line(**attributes) ⇒ Object
Appends a line.
- #number(value) ⇒ Object
-
#rounding(value) ⇒ Object
Polish VAT law permits both strategies and they can differ by a grosz, so this is explicit rather than inferred (DESIGN.md §7.3).
- #seller(**attributes) ⇒ Object
- #to_invoice ⇒ Invoice
-
#totals(gross:, net: {}, vat: {}) ⇒ Object
States the tax summary instead of having it computed from the lines — which a correction must do, its buckets being deltas its rows need not determine (docs/REFERENCE.md §8.4).
Methods included from Advances
Methods included from Corrections
Constructor Details
#initialize ⇒ Builder
Returns a new instance of Builder.
39 40 41 42 43 44 45 46 47 |
# File 'lib/ksef/fa3/builder.rb', line 39 def initialize @fields = {} @lines = [] @corrected = [] @correction = nil @order = nil @order_lines = [] @advances = [] end |
Instance Method Details
#attachment(value) ⇒ Object
The invoice attachment (Zalacznik), a sibling of Fa carrying no amounts.
Takes an Attachment, or the blocks to make one from — the one-block case is the common one and does not deserve two levels of ceremony:
f. Ksef::FA3::DataBlock.new(metadata: { "Kod PPE" => "999" })
85 |
# File 'lib/ksef/fa3/builder.rb', line 85 def (value) = @fields[:attachment] = Attachment.wrap(value) |
#buyer(**attributes) ⇒ Object
54 |
# File 'lib/ksef/fa3/builder.rb', line 54 def buyer(**attributes) = @fields[:buyer] = subject(attributes, role: :buyer) |
#currency(value) ⇒ Object
63 |
# File 'lib/ksef/fa3/builder.rb', line 63 def currency(value) = @fields[:currency] = value |
#invoice_type(value) ⇒ Object
75 |
# File 'lib/ksef/fa3/builder.rb', line 75 def invoice_type(value) = @fields[:invoice_type] = value |
#issue_date(value) ⇒ Object
60 |
# File 'lib/ksef/fa3/builder.rb', line 60 def issue_date(value) = @fields[:issue_date] = value |
#issued_at(value) ⇒ Object
67 |
# File 'lib/ksef/fa3/builder.rb', line 67 def issued_at(value) = @fields[:issued_at] = value |
#line(**attributes) ⇒ Object
Appends a line. Call once per line; row numbers are assigned on serialisation unless a line states its own.
93 94 95 |
# File 'lib/ksef/fa3/builder.rb', line 93 def line(**attributes) @lines << Line.new(**normalise(attributes, LINE_KEYS, LINE_ALIASES, "line")) end |
#number(value) ⇒ Object
57 |
# File 'lib/ksef/fa3/builder.rb', line 57 def number(value) = @fields[:number] = value |
#rounding(value) ⇒ Object
Polish VAT law permits both strategies and they can differ by a grosz, so this is explicit rather than inferred (DESIGN.md §7.3).
72 |
# File 'lib/ksef/fa3/builder.rb', line 72 def rounding(value) = @fields[:rounding] = value |
#seller(**attributes) ⇒ Object
51 |
# File 'lib/ksef/fa3/builder.rb', line 51 def seller(**attributes) = @fields[:seller] = subject(attributes, role: :seller) |
#to_invoice ⇒ Invoice
119 120 121 122 123 124 125 126 127 128 129 |
# File 'lib/ksef/fa3/builder.rb', line 119 def to_invoice missing = REQUIRED.reject { |key| @fields.key?(key) } unless missing.empty? raise ValidationError, "Incomplete invoice, missing #{missing.join(", ")}. " \ "Every invoice needs a seller, a buyer, a number and an issue date." end Invoice.new(**@fields, lines: @lines, correction: assembled_correction, order: assembled_order, advances: @advances) end |
#totals(gross:, net: {}, vat: {}) ⇒ Object
States the tax summary instead of having it computed from the lines — which a correction must do, its buckets being deltas its rows need not determine (docs/REFERENCE.md §8.4).
Keyed by rate code, as #line is, and mapped to summary buckets here. The model
stores the buckets, because that mapping is not invertible: "23" and "22" share
one (§8.1a).
108 109 110 111 112 113 114 115 |
# File 'lib/ksef/fa3/builder.rb', line 108 def totals(gross:, net: {}, vat: {}) buckets = {} # `nil` reads as "no buckets of this kind", which is what a caller who has only one # side of the summary naturally passes. Left alone it raised a bare NoMethodError. (net || {}).each { |code, amount| accumulate(buckets, VatRate.bucket(code).first, amount) } (vat || {}).each { |code, amount| accumulate(buckets, tax_element(code), amount) } @fields[:totals] = Totals.new(buckets: buckets, gross: gross) end |