Module: Ksef::FA3::NIP

Defined in:
lib/ksef/fa3/nip.rb

Overview

Polish tax identifier (NIP) validation (DESIGN.md §7.2).

Worth validating locally rather than letting KSeF reject the invoice: a mistyped NIP is one of the likeliest data-entry errors, and the round trip to find out is slow.

Constant Summary collapse

WEIGHTS =

Positional weights for digits 1-9. The weighted sum mod 11 must equal digit 10.

[6, 5, 7, 2, 3, 4, 5, 6, 7].freeze
LENGTH =
10

Class Method Summary collapse

Class Method Details

.normalize(value) ⇒ String

Accepts the common written forms — "123-456-32-18", "PL1234563218" — since that is how a NIP arrives from an ERP or a human.

Returns:

  • (String) —

    ten digits



19
20
21
# File 'lib/ksef/fa3/nip.rb', line 19

def normalize(value)
  value.to_s.strip.sub(/\A[Pp][Ll]/, "").gsub(/[\s-]/, "")
end

.valid?(value) ⇒ Boolean

Returns:

  • (Boolean)


24
25
26
27
28
29
# File 'lib/ksef/fa3/nip.rb', line 24

def valid?(value)
  digits = normalize(value)
  return false unless /\A\d{#{LENGTH}}\z/o.match?(digits)

  checksum(digits) == digits[9].to_i
end

.validate!(value, field: "NIP") ⇒ Object

Raises:

  • (Ksef::ValidationError) —

    with the reason, since "invalid NIP" alone does not tell a user whether they mistyped a digit or pasted the wrong field



33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
# File 'lib/ksef/fa3/nip.rb', line 33

def validate!(value, field: "NIP")
  digits = normalize(value)

  unless /\A\d{#{LENGTH}}\z/o.match?(digits)
    raise ValidationError,
          "#{field} must be #{LENGTH} digits, got #{value.inspect} " \
          "(#{digits.length} digit(s) after normalisation)"
  end

  expected = checksum(digits)
  return digits if expected == digits[9].to_i

  raise ValidationError,
        "#{field} #{digits} has an invalid check digit: expected #{expected}, got #{digits[9]}"
end