Itin parser and validator added

This commit is contained in:
2024-12-12 21:17:30 -05:00
parent 0edc3c3139
commit 695ffc31c5
14 changed files with 513 additions and 108 deletions

View File

@@ -2,31 +2,8 @@ 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.Edrpou.Validator, only: [validate: 1]
import UkraineTaxidEx.Commons, only: [check_digit: 1, digits: 1, digits: 3, undigits: 1, ok: 1]
use UkraineTaxidEx.BaseParser
@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_checksum}
@impl BaseParser
@doc """
Parses an EDRPOU code string into a structured format (clean and normalize, validate and decompose).
Parses an EDRPOU code string into a structured format (clean and normalize, validate and decompo).
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.
@@ -34,6 +11,7 @@ defmodule UkraineTaxidEx.Edrpou.Parser do
## Examples
```elixir
iex> UkraineTaxidEx.Edrpou.Parser.parse("00032112")
{:ok, %UkraineTaxidEx.Edrpou{code: "00032112", check_digit: 2, check_sum: 2}}
@@ -54,33 +32,34 @@ defmodule UkraineTaxidEx.Edrpou.Parser do
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)
alias UkraineTaxidEx.Edrpou
edrpou_string
|> digits(length, clean?)
|> undigits()
|> validate()
|> generate_edrpou()
end
import UkraineTaxidEx.Edrpou, only: [length: 0]
import UkraineTaxidEx.Edrpou.CheckSum, only: [check_sum: 1]
import UkraineTaxidEx.Edrpou.Validator, only: [validate: 1]
import UkraineTaxidEx.Commons, only: [check_digit: 1, digits: 1, digits: 3, undigits: 1, ok: 1]
defp generate_edrpou({:error, error}), do: {:error, error}
use UkraineTaxidEx.BaseParser
defp generate_edrpou({:ok, edrpou_string}) do
digits = digits(edrpou_string)
@type edrpou_string() :: String.t()
@type edrpou() :: Edrpou.t()
@type edrpou_or_error() ::
{:ok, Edrpou.t()}
| {:error,
:length_too_short
| :length_too_long
| :invalid_checksum}
%{code: edrpou_string, check_sum: check_sum(digits), check_digit: check_digit(digits)}
|> create_struct()
defp generate({:error, error}), do: {:error, error}
defp generate({:ok, string}) do
digits = digits(string)
%{code: string, check_sum: check_sum(digits), check_digit: check_digit(digits)}
|> to_struct()
|> ok()
end
defp create_struct(map), do: struct(Edrpou, map)
end

View File

@@ -3,13 +3,7 @@ defmodule UkraineTaxidEx.Edrpou.Validator do
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:
@@ -17,44 +11,25 @@ defmodule UkraineTaxidEx.Edrpou.Validator do
* `{: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
## Examples
```elixir
iex> UkraineTaxidEx.Edrpou.Validator.validate("00032112")
{:ok, "00032112"}
iex> UkraineTaxidEx.Edrpou.Validator.validate("0003211")
{:error, :length_too_short}
iex> UkraineTaxidEx.Edrpou.Validator.validate("000321122")
{:error, :length_too_long}
iex> UkraineTaxidEx.Edrpou.Validator.validate("00032113")
{:error, :invalid_checksum}
```
"""
@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
import UkraineTaxidEx.Edrpou, only: [length: 0]
import UkraineTaxidEx.Edrpou.CheckSum, only: [check_sum: 1]
@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
use UkraineTaxidEx.BaseValidator
end