Commons and EDRPOU basic functionality (parser (but complete only), checksum with test coverage)
This commit is contained in:
68
lib/ukraine_taxid_ex/edrpou/check_sum.ex
Normal file
68
lib/ukraine_taxid_ex/edrpou/check_sum.ex
Normal file
@@ -0,0 +1,68 @@
|
||||
defmodule UkraineTaxidEx.Edrpou.CheckSum do
|
||||
alias UkraineTaxidEx.Commons, as: C
|
||||
|
||||
import UkraineTaxidEx.Commons, only: [value_digits: 1]
|
||||
|
||||
@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)
|
||||
"""
|
||||
@type weights_type :: :base | :alternative
|
||||
|
||||
@doc """
|
||||
Calculate checksum for EDRPOU number.
|
||||
The checksum for EDRPOU is calculated in several steps:
|
||||
1. Define the type of weights (base or alternative) as described in `weights_type/1`
|
||||
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
|
||||
"""
|
||||
@spec check_sum(digits :: C.digits()) :: integer()
|
||||
def check_sum(digits) do
|
||||
type =
|
||||
digits
|
||||
|> Integer.undigits()
|
||||
|> weights_type()
|
||||
|
||||
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 -> s
|
||||
end
|
||||
end
|
||||
|
||||
defguardp is_base_weights(value) when value < 30_000_000 or value > 60_000_000
|
||||
|
||||
@spec weights(type :: weights_type, double_added? :: boolean()) :: C.digits()
|
||||
defp weights(type \\ :base, double_added \\ false)
|
||||
defp weights(:base, false), do: Enum.to_list(1..7)
|
||||
|
||||
defp weights(:alternative, false) do
|
||||
base = weights()
|
||||
[List.last(base) | Enum.take(base, length(base) - 1)]
|
||||
end
|
||||
|
||||
defp weights(type, true) do
|
||||
type
|
||||
|> weights(false)
|
||||
|> Enum.map(&(&1 + 2))
|
||||
end
|
||||
|
||||
@spec divider() :: non_neg_integer()
|
||||
defp divider(), do: 11
|
||||
|
||||
@spec weights_type(value :: pos_integer()) :: C.digits()
|
||||
defp weights_type(value) when is_base_weights(value), do: :base
|
||||
defp weights_type(_value), do: :alternative
|
||||
|
||||
@spec calculate_check_sum(digits :: C.digits(), weights :: C.digits()) :: non_neg_integer()
|
||||
defp calculate_check_sum(digits, weights) do
|
||||
digits
|
||||
|> Enum.zip(weights)
|
||||
|> Enum.reduce(0, fn {digit, weight}, acc -> digit * weight + acc end)
|
||||
|> rem(divider())
|
||||
end
|
||||
end
|
||||
24
lib/ukraine_taxid_ex/edrpou/error.ex
Normal file
24
lib/ukraine_taxid_ex/edrpou/error.ex
Normal file
@@ -0,0 +1,24 @@
|
||||
defmodule UkraineTaxidEx.Edrpou.Error do
|
||||
@type error() ::
|
||||
:invalid_length
|
||||
| :invalid_checksum
|
||||
| :length_to_long
|
||||
| :length_to_short
|
||||
@type errors() :: [error()]
|
||||
@errors [
|
||||
:invalid_length,
|
||||
:invalid_checksum,
|
||||
:length_to_long,
|
||||
:length_to_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"
|
||||
]
|
||||
|
||||
@spec message(error()) :: String.t()
|
||||
def message(error) when error in @errors, do: @messages[error]
|
||||
def message(_error), do: "Undefined error"
|
||||
end
|
||||
23
lib/ukraine_taxid_ex/edrpou/parser.ex
Normal file
23
lib/ukraine_taxid_ex/edrpou/parser.ex
Normal file
@@ -0,0 +1,23 @@
|
||||
defmodule UkraineTaxidEx.Edrpou.Parser do
|
||||
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]
|
||||
|
||||
use UkraineTaxidEx.BaseParser
|
||||
|
||||
def parse(edrpou_string, incomplete: false) do
|
||||
digits = digits(edrpou_string, length())
|
||||
|
||||
%{
|
||||
code: edrpou_string,
|
||||
check_sum: check_sum(digits),
|
||||
check_digit: check_digit(digits)
|
||||
}
|
||||
|> create_struct()
|
||||
|> ok()
|
||||
end
|
||||
|
||||
defp create_struct(map), do: struct(Edrpou, map)
|
||||
end
|
||||
Reference in New Issue
Block a user