Parser for EDRPOU completed
This commit is contained in:
@@ -5,8 +5,8 @@ defmodule UkraineTaxidEx.Edrpou.CheckSum do
|
||||
|
||||
@typedoc """
|
||||
Coefficients (weights) for digits to calculate EDRPOU check sum may be two types:
|
||||
base ([1, 2, 3, 4, 5, 6, 7] for EDRPOU < 30M or EDRPOU > 60M)
|
||||
or alternative ([7, 1, 2, 3, 4, 5, 6] if EDRPOU between 30M and 60M)
|
||||
base (`[1, 2, 3, 4, 5, 6, 7] for EDRPOU < 30M or EDRPOU > 60M`)
|
||||
or alternative (`[7, 1, 2, 3, 4, 5, 6] if EDRPOU between 30M and 60M`)
|
||||
"""
|
||||
@type weights_type :: :base | :alternative
|
||||
|
||||
@@ -17,7 +17,7 @@ defmodule UkraineTaxidEx.Edrpou.CheckSum do
|
||||
2. Multiply each digit by its corresponding weight
|
||||
3. Sum the products
|
||||
4. Take mod 11 of the sum
|
||||
5. If mod 11 is greater or equal than 10, repeat steps 2-4 with doubled weights
|
||||
5. If mod 11 is greater or equal than 10, repeat steps 2-4 with weights +2
|
||||
"""
|
||||
@spec check_sum(digits :: C.digits()) :: integer()
|
||||
def check_sum(digits) do
|
||||
@@ -29,7 +29,7 @@ defmodule UkraineTaxidEx.Edrpou.CheckSum do
|
||||
value_digits = value_digits(digits)
|
||||
|
||||
case calculate_check_sum(value_digits, weights(type, false)) do
|
||||
s when s >= 10 -> calculate_check_sum(value_digits, weights(type, true))
|
||||
s when s >= 10 -> rem(calculate_check_sum(value_digits, weights(type, true)), 10)
|
||||
s -> s
|
||||
end
|
||||
end
|
||||
|
||||
@@ -2,23 +2,24 @@ defmodule UkraineTaxidEx.Edrpou.Error do
|
||||
@type error() ::
|
||||
:invalid_length
|
||||
| :invalid_checksum
|
||||
| :length_to_long
|
||||
| :length_to_short
|
||||
| :length_too_long
|
||||
| :length_too_short
|
||||
@type errors() :: [error()]
|
||||
@errors [
|
||||
:invalid_length,
|
||||
:invalid_checksum,
|
||||
:length_to_long,
|
||||
:length_to_short
|
||||
:length_too_long,
|
||||
:length_too_short
|
||||
]
|
||||
@messages [
|
||||
invalid_length: "EDRPOU violates the required length",
|
||||
invalid_checksum: "EDRPOU checksum is invalid",
|
||||
length_to_long: "EDRPOU longer then required length",
|
||||
length_to_short: "EDRPOU shorter then required length"
|
||||
length_too_long: "EDRPOU longer then required length",
|
||||
length_too_short: "EDRPOU shorter then required length"
|
||||
]
|
||||
|
||||
@spec message(error()) :: String.t()
|
||||
@spec message({:error, error()} | error()) :: String.t()
|
||||
def message({:error, error}) when error in @errors, do: @messages[error]
|
||||
def message(error) when error in @errors, do: @messages[error]
|
||||
def message(_error), do: "Undefined error"
|
||||
end
|
||||
|
||||
@@ -1,20 +1,84 @@
|
||||
defmodule UkraineTaxidEx.Edrpou.Parser do
|
||||
@moduledoc """
|
||||
Parser module for EDRPOU (Unified State Register of Ukrainian Enterprises and Organizations) codes.
|
||||
Handles validation and structure creation for EDRPOU codes with additional options for normalization and cleaning.
|
||||
"""
|
||||
|
||||
alias UkraineTaxidEx.Edrpou
|
||||
|
||||
import UkraineTaxidEx.Edrpou, only: [length: 0]
|
||||
import UkraineTaxidEx.Edrpou.CheckSum, only: [check_sum: 1]
|
||||
import UkraineTaxidEx.Commons, only: [check_digit: 1, digits: 2, ok: 1]
|
||||
import UkraineTaxidEx.Edrpou.Validator, only: [validate: 1]
|
||||
import UkraineTaxidEx.Commons, only: [check_digit: 1, digits: 1, digits: 3, undigits: 1, ok: 1]
|
||||
|
||||
use UkraineTaxidEx.BaseParser
|
||||
|
||||
def parse(edrpou_string, incomplete: false) do
|
||||
digits = digits(edrpou_string, length())
|
||||
@type edrpou_string() :: String.t()
|
||||
@type edrpou_string_or_ok() :: edrpou_string() | {:ok, edrpou_string()}
|
||||
@type edrpou() :: Edrpou.t()
|
||||
@type edrpou_or_error() ::
|
||||
{:ok, Edrpou.t()}
|
||||
| {:error,
|
||||
:length_too_short
|
||||
| :length_too_long
|
||||
| :invalid_length
|
||||
| :invalid_checksum}
|
||||
|
||||
%{
|
||||
code: edrpou_string,
|
||||
check_sum: check_sum(digits),
|
||||
check_digit: check_digit(digits)
|
||||
}
|
||||
@impl BaseParser
|
||||
|
||||
@doc """
|
||||
Parses an EDRPOU code string into a structured format.
|
||||
Options:
|
||||
- normalize?: When true, pads string to full EDRPOU length. Defaults to false.
|
||||
- clean?: When true, removes non-digit characters before processing. Defaults to false.
|
||||
Returns {:ok, %Edrpou{}} for valid codes or {:error, reason} for invalid.
|
||||
|
||||
## Examples
|
||||
|
||||
iex> UkraineTaxidEx.Edrpou.Parser.parse("00032112")
|
||||
{:ok, %UkraineTaxidEx.Edrpou{code: "00032112", check_digit: 2, check_sum: 2}}
|
||||
|
||||
iex> UkraineTaxidEx.Edrpou.Parser.parse({:ok, "00032112"})
|
||||
{:ok, %UkraineTaxidEx.Edrpou{code: "00032112", check_digit: 2, check_sum: 2}}
|
||||
|
||||
iex> UkraineTaxidEx.Edrpou.Parser.parse("32129", normalize?: true)
|
||||
{:ok, %UkraineTaxidEx.Edrpou{code: "00032129", check_digit: 9, check_sum: 9}}
|
||||
|
||||
iex> UkraineTaxidEx.Edrpou.Parser.parse("9 30test62 78", normalize?: true, clean?: true)
|
||||
{:ok, %UkraineTaxidEx.Edrpou{code: "09306278", check_digit: 8, check_sum: 8}}
|
||||
|
||||
iex> UkraineTaxidEx.Edrpou.Parser.parse("123")
|
||||
{:error, :length_too_short}
|
||||
|
||||
iex> UkraineTaxidEx.Edrpou.Parser.parse("123456789")
|
||||
{:error, :length_too_long}
|
||||
|
||||
iex> UkraineTaxidEx.Edrpou.Parser.parse("123", normalize?: true)
|
||||
{:error, :invalid_checksum}
|
||||
"""
|
||||
@spec parse(data :: edrpou_string_or_ok, options :: BaseParser.options()) ::
|
||||
edrpou_or_error()
|
||||
def parse(data, options \\ [normalize?: false, clean?: false])
|
||||
def parse({:ok, edrpou_string}, options), do: parse(edrpou_string, options)
|
||||
def parse({:error, error}, _options), do: {:error, error}
|
||||
|
||||
def parse(edrpou_string, options) do
|
||||
length = (Keyword.get(options, :normalize?, false) && length()) || 0
|
||||
clean? = Keyword.get(options, :clean?, false)
|
||||
|
||||
edrpou_string
|
||||
|> digits(length, clean?)
|
||||
|> undigits()
|
||||
|> validate()
|
||||
|> generate_edrpou()
|
||||
end
|
||||
|
||||
defp generate_edrpou({:error, error}), do: {:error, error}
|
||||
|
||||
defp generate_edrpou({:ok, edrpou_string}) do
|
||||
digits = digits(edrpou_string)
|
||||
|
||||
%{code: edrpou_string, check_sum: check_sum(digits), check_digit: check_digit(digits)}
|
||||
|> create_struct()
|
||||
|> ok()
|
||||
end
|
||||
|
||||
60
lib/ukraine_taxid_ex/edrpou/validator.ex
Normal file
60
lib/ukraine_taxid_ex/edrpou/validator.ex
Normal file
@@ -0,0 +1,60 @@
|
||||
defmodule UkraineTaxidEx.Edrpou.Validator do
|
||||
@moduledoc """
|
||||
Functions for validating EDRPOU number format and checksum.
|
||||
|
||||
This module provides validation functions to verify if an EDRPOU number meets the standard requirements including length and checksum validation.
|
||||
"""
|
||||
|
||||
import UkraineTaxidEx.Commons, only: [digits: 1, digits_and_check_digit: 1, error: 1, ok: 1]
|
||||
import UkraineTaxidEx.Edrpou, only: [length: 0]
|
||||
import UkraineTaxidEx.Edrpou.CheckSum, only: [check_sum: 1]
|
||||
|
||||
@doc """
|
||||
Validates an EDRPOU number to check if it meets length requirements and has a valid checksum.
|
||||
|
||||
Returns:
|
||||
* `{:ok, edrpou}` if validation successful
|
||||
* `{:error, :length_too_short}` if shorter than required length
|
||||
* `{:error, :length_too_long}` if longer than required length
|
||||
* `{:error, :invalid_checksum}` if checksum is invalid
|
||||
"""
|
||||
@spec validate(String.t()) ::
|
||||
{:ok, String.t()}
|
||||
| {:error, :length_too_short | :length_too_long | :invalid_length | :invalid_checksum}
|
||||
def validate(edrpou) do
|
||||
cond do
|
||||
violates_length_too_short?(edrpou) -> error(:length_too_short)
|
||||
violates_length_too_long?(edrpou) -> error(:length_too_long)
|
||||
violates_checksum?(edrpou) -> error(:invalid_checksum)
|
||||
true -> ok(edrpou)
|
||||
end
|
||||
end
|
||||
|
||||
@doc "Check whether a given EDRPOU violates the required length"
|
||||
@spec violates_length?(String.t()) :: boolean
|
||||
def violates_length?(edrpou),
|
||||
do: String.length(edrpou) != length()
|
||||
|
||||
@doc "Check whether a given EDRPOU too short"
|
||||
@spec violates_length_too_short?(String.t()) :: boolean
|
||||
def violates_length_too_short?(edrpou),
|
||||
do: String.length(edrpou) < length()
|
||||
|
||||
@doc "Check whether a given EDRPOU too long"
|
||||
@spec violates_length_too_long?(String.t()) :: boolean
|
||||
def violates_length_too_long?(edrpou),
|
||||
do: String.length(edrpou) > length()
|
||||
|
||||
@doc "Check whether a given EDRPOU has correct checksum"
|
||||
@spec violates_checksum?(String.t()) :: boolean
|
||||
def violates_checksum?(edrpou) do
|
||||
{digits, check_digit} =
|
||||
edrpou
|
||||
|> digits()
|
||||
|> digits_and_check_digit()
|
||||
|
||||
check_sum = check_sum(digits)
|
||||
|
||||
check_sum != check_digit
|
||||
end
|
||||
end
|
||||
Reference in New Issue
Block a user