# GTIN Check Digit Validation in Elixir

Similar to other GTIN validations, the function should take the entire string of the read in barcode, calculate the check digit, and compare it to the check digit on the code. For example, the code 6291041500213 would take the first 12 digits (629104150021) and calculate the answer of 3.

this code should work for GTIN-8, GTIN-12, GTIN-13, GTIN-14, GSIN, SSCC.

I was hoping to get some feedback on the test cases and on the code itself on where it can be DRYed or made more explicit. I realized later on that Elixir now has a built in mod fuction which I'll switch to (I read an older Jose article that said it did not)...I think I need to also clean up the areas where it returns {:ok} and {:error}.

## Code:

  @doc """
Check for valid  GTIN-8, GTIN-12, GTIN-13, GTIN-14, GSIN, SSCC codes

Returns {:ok} or {:error}

## Examples

iex> gtin_check_digit("6291041500213")
{:ok}

iex> gtin_check_digit("6291041500214")
{:error}
"""
@spec gtin_check_digit(string) :: { atom }
def gtin_check_digit(number) do
{code, check_digit} = String.split_at(number, String.length(number) - 1)
calculated_check_digit = code
|> multiply_and_sum_array
|> subtract_from_nearest_multiple_of_ten

case calculated_check_digit == String.to_integer(check_digit) do
true -> {:ok}
_ -> {:error}
end
end

@doc """
Calculates the sum of the digits in a string and multiplied value based on index order

Returns sum of values

## Examples

iex> multiply_and_sum_array("629104150021")
57

"""
@spec multiply_and_sum_array(string) :: number
def multiply_and_sum_array(number) do
number
|> String.codepoints
|> Enum.map(fn(x) -> String.to_integer(x) end)
|> Enum.reverse
|> Stream.with_index
|> Enum.reduce(0, fn({num, idx}, acc) ->
acc + (num * mult_by_index_code(idx))
end)
end

@doc """
Calculates the difference of the highest rounded multiple of 10

Returns the difference of the highest rounded multiple of 10

## Examples

iex> subtract_from_nearest_multiple_of_ten(57)
3

"""
@spec subtract_from_nearest_multiple_of_ten(number) :: number
def subtract_from_nearest_multiple_of_ten(number) do
mod(10 - mod(number, 10), 10)
end

#def mult_by_index_code(index) when mod(index, 2) == 0, do: 3 #these did not work because I cannot call mod within the when
#def mult_by_index_code(index), do: 1
def mult_by_index_code(index) do
case mod(index, 2) do
0 -> 3
_ -> 1
end
end

defp mod(x,y) when x > 0, do: rem(x, y);
defp mod(x,y) when x < 0, do: rem(y+x, y);
defp mod(0,_y), do: 0


## Tests

 test "gtin_check_digit function with valid number" do
number = "6291041500213"
assert {:ok} == gtin_check_digit(number)
end

test "gtin_check_digit function with invalid number" do
number = "6291041500214"
assert {:error} == gtin_check_digit(number)
assert {:error} == gtin_check_digit("6291041533213")
end

test "mult_by_index_code function" do
assert mult_by_index_code(1) == 1
assert mult_by_index_code(2) == 3
assert mult_by_index_code(3) == 1
assert mult_by_index_code(4) == 3
end

test "multiply_and_sum_array function" do
number = "629104150021"
#number = [6,2,9,1,0,4,1,5,0,0,2,1]
assert 57 == multiply_and_sum_array(number)
end

test "subtract_from_nearest_multiple_of_ten function" do
assert 3 == subtract_from_nearest_multiple_of_ten(57)
end


As I refine this, I'll create a hex package to use a common utility library for the elixir community.