Class: Ksef::FA3::Totals

Inherits:
Data
  • Object
show all
Includes:
Canonical
Defined in:
lib/ksef/fa3/totals.rb,
lib/ksef/fa3/totals.rb

Overview

Membership, arithmetic and serialisation for Totals.

Constant Summary collapse

ELEMENTS =

The summary buckets, read from the generated schema metadata rather than restated here (DESIGN.md §7.1). The W twins — P_14_1W and its siblings — are excluded: they are the PLN equivalents a foreign-currency invoice carries alongside a bucket, not buckets of their own, and summing them would double-count the tax.

Generated::Types.ordered_elements("Faktura/Fa")
.map { |particle| particle[:name] }
.grep(/\AP_1[34]_\d/)
.reject { |name| name.end_with?("W") }
.freeze
NET_ELEMENTS =

P_13_* is a net amount and P_14_* the tax on it. That split is what lets Summaries#net_total and Summaries#vat_total keep answering for a stated summary.

ELEMENTS.grep(/\AP_13_/).freeze
TAX_ELEMENTS =
ELEMENTS.grep(/\AP_14_/).freeze

Instance Attribute Summary collapse

Class Method Summary collapse

Instance Method Summary collapse

Methods included from Canonical

#with

Constructor Details

#initialize(gross:, buckets: {}) ⇒ Totals

Returns a new instance of Totals.

Parameters:

  • gross (BigDecimal, Integer, String) —

    P_15, the total amount due

  • buckets (Hash{String => BigDecimal, Integer, String}) (defaults to: {}) —

    element name => amount, for the buckets this invoice states; omitted buckets are simply absent

Raises:

  • (Ksef::ValidationError) —

    on an element name that is not a summary bucket, or an amount that is not a decimal — a Float included (DESIGN.md §4.4)



54
55
56
57
58
59
60
61
# File 'lib/ksef/fa3/totals.rb', line 54

def initialize(gross:, buckets: {})
  # Rounded to the scale `TKwotowy` permits, for the same reason {Line} rounds: the
  # model reports the figure the document will actually carry (§8.2b).
  super(
    buckets: self.class.verified_buckets(buckets),
    gross: Formatting.decimal(gross).round(Formatting::AMOUNT_SCALE)
  )
end

Instance Attribute Details

#buckets ⇒ Object (readonly)

Returns the value of attribute buckets

Returns:

  • (Object) —

    the current value of buckets



27
28
29
# File 'lib/ksef/fa3/totals.rb', line 27

def buckets
  @buckets
end

#gross ⇒ Object (readonly)

Returns the value of attribute gross

Returns:

  • (Object) —

    the current value of gross



27
28
29
# File 'lib/ksef/fa3/totals.rb', line 27

def gross
  @gross
end

Class Method Details

.verified_buckets(buckets) ⇒ Hash{String => BigDecimal}

Returns frozen, checked for spelling and for collisions.

Returns:

  • (Hash{String => BigDecimal}) —

    frozen, checked for spelling and for collisions



64
65
66
67
68
69
70
71
72
73
74
75
# File 'lib/ksef/fa3/totals.rb', line 64

def self.verified_buckets(buckets)
  unless buckets.respond_to?(:to_h)
    raise ValidationError, "Totals buckets must be a Hash of element name => amount, got #{buckets.inspect}"
  end

  pairs = buckets.to_h.map { |name, amount| [name.to_s, amount] }
  reject_duplicates(pairs.map(&:first))
  reject_unknown(pairs.map(&:first))

  pairs.to_h { |name, amount| [name, Formatting.decimal(amount).round(Formatting::AMOUNT_SCALE)] }
       .freeze
end

Instance Method Details

#net ⇒ BigDecimal

Returns the sum of every P_13_* bucket stated.

Returns:

  • (BigDecimal) —

    the sum of every P_13_* bucket stated



78
# File 'lib/ksef/fa3/totals.rb', line 78

def net = sum_of(NET_ELEMENTS)

#to_fa3 ⇒ Object



83
84
85
86
# File 'lib/ksef/fa3/totals.rb', line 83

def to_fa3
  buckets.to_h { |name, amount| [name, Formatting.amount(amount)] }
         .merge("P_15" => Formatting.amount(gross))
end

#vat ⇒ BigDecimal

Returns the sum of every P_14_* bucket stated.

Returns:

  • (BigDecimal) —

    the sum of every P_14_* bucket stated



81
# File 'lib/ksef/fa3/totals.rb', line 81

def vat = sum_of(TAX_ELEMENTS)