From fdf28f7609ef8fceac79e2956bc69c0e4cc39a91 Mon Sep 17 00:00:00 2001 From: Danylo Negrienko Date: Sun, 10 Mar 2024 20:02:20 -0400 Subject: [PATCH] Added all SEPA countries (IBANs from European Union countries) and minimal test coverage for countries --- lib/iban_ex/country.ex | 24 ++++++- lib/iban_ex/country/at.ex | 7 +++ lib/iban_ex/country/be.ex | 7 +++ lib/iban_ex/country/bg.ex | 7 +++ lib/iban_ex/country/ch.ex | 7 +++ lib/iban_ex/country/cy.ex | 7 +++ lib/iban_ex/country/cz.ex | 7 +++ lib/iban_ex/country/de.ex | 7 +++ lib/iban_ex/country/dk.ex | 7 +++ lib/iban_ex/country/ee.ex | 7 +++ lib/iban_ex/country/es.ex | 7 +++ lib/iban_ex/country/fi.ex | 7 +++ lib/iban_ex/country/fr.ex | 7 +++ lib/iban_ex/country/gb.ex | 7 +++ lib/iban_ex/country/gi.ex | 17 +++++ lib/iban_ex/country/gr.ex | 35 +++++++++++ lib/iban_ex/country/hr.ex | 7 +++ lib/iban_ex/country/hu.ex | 35 +++++++++++ lib/iban_ex/country/ie.ex | 35 +++++++++++ lib/iban_ex/country/it.ex | 35 +++++++++++ lib/iban_ex/country/li.ex | 17 +++++ lib/iban_ex/country/lt.ex | 7 +++ lib/iban_ex/country/lu.ex | 7 +++ lib/iban_ex/country/lv.ex | 7 +++ lib/iban_ex/country/mc.ex | 35 +++++++++++ lib/iban_ex/country/mt.ex | 7 +++ lib/iban_ex/country/nl.ex | 7 +++ lib/iban_ex/country/no.ex | 35 +++++++++++ lib/iban_ex/country/pl.ex | 7 +++ lib/iban_ex/country/pt.ex | 7 +++ lib/iban_ex/country/ro.ex | 17 +++++ lib/iban_ex/country/se.ex | 17 +++++ lib/iban_ex/country/si.ex | 37 +++++++++++ lib/iban_ex/country/sk.ex | 17 +++++ lib/iban_ex/country/sm.ex | 35 +++++++++++ lib/iban_ex/country/ua.ex | 8 ++- lib/iban_ex/country/va.ex | 17 +++++ mix.exs | 2 +- test/iban_ex_test.exs | 129 ++++++++++++++++++++++++++++++++++++-- 39 files changed, 685 insertions(+), 9 deletions(-) create mode 100644 lib/iban_ex/country/gi.ex create mode 100644 lib/iban_ex/country/gr.ex create mode 100644 lib/iban_ex/country/hu.ex create mode 100644 lib/iban_ex/country/ie.ex create mode 100644 lib/iban_ex/country/it.ex create mode 100644 lib/iban_ex/country/li.ex create mode 100644 lib/iban_ex/country/mc.ex create mode 100644 lib/iban_ex/country/no.ex create mode 100644 lib/iban_ex/country/ro.ex create mode 100644 lib/iban_ex/country/se.ex create mode 100644 lib/iban_ex/country/si.ex create mode 100644 lib/iban_ex/country/sk.ex create mode 100644 lib/iban_ex/country/sm.ex create mode 100644 lib/iban_ex/country/va.ex diff --git a/lib/iban_ex/country.ex b/lib/iban_ex/country.ex index 2a83641..301df0e 100644 --- a/lib/iban_ex/country.ex +++ b/lib/iban_ex/country.ex @@ -15,23 +15,38 @@ defmodule IbanEx.Country do "CZ" => IbanEx.Country.CZ, "DE" => IbanEx.Country.DE, "DK" => IbanEx.Country.DK, - "ES" => IbanEx.Country.ES, "EE" => IbanEx.Country.EE, - "FR" => IbanEx.Country.FR, + "ES" => IbanEx.Country.ES, "FI" => IbanEx.Country.FI, + "FR" => IbanEx.Country.FR, "GB" => IbanEx.Country.GB, + "GI" => IbanEx.Country.GI, + "GR" => IbanEx.Country.GR, "HR" => IbanEx.Country.HR, + "HU" => IbanEx.Country.HU, + "IE" => IbanEx.Country.IE, + "IT" => IbanEx.Country.IT, + "LI" => IbanEx.Country.LI, "LT" => IbanEx.Country.LT, "LU" => IbanEx.Country.LU, "LV" => IbanEx.Country.LV, + "MC" => IbanEx.Country.MC, "MT" => IbanEx.Country.MT, "NL" => IbanEx.Country.NL, + "NO" => IbanEx.Country.NO, "PL" => IbanEx.Country.PL, "PT" => IbanEx.Country.PT, - "UA" => IbanEx.Country.UA + "RO" => IbanEx.Country.RO, + "SE" => IbanEx.Country.SE, + "SM" => IbanEx.Country.SM, + "SI" => IbanEx.Country.SI, + "SK" => IbanEx.Country.SK, + "UA" => IbanEx.Country.UA, + "VA" => IbanEx.Country.VA } @supported_country_codes Map.keys(@supported_countries) + @supported_country_modules Map.values(@supported_countries) @spec supported_countries() :: map() defp supported_countries(), do: @supported_countries @@ -39,6 +54,9 @@ defmodule IbanEx.Country do @spec supported_country_codes() :: [country_code()] | [] def supported_country_codes(), do: @supported_country_codes + @spec supported_country_modules() :: [module()] | [] + def supported_country_modules(), do: @supported_country_modules + @spec country_module(country_code) :: Module.t() | error_tuple() def country_module(country_code) when is_binary(country_code) or is_atom(country_code) do normalized_country_code = normalize(country_code) diff --git a/lib/iban_ex/country/at.ex b/lib/iban_ex/country/at.ex index a69b8ba..6c09adc 100644 --- a/lib/iban_ex/country/at.ex +++ b/lib/iban_ex/country/at.ex @@ -1,6 +1,13 @@ defmodule IbanEx.Country.AT do @moduledoc """ Austria IBAN parsing rules + + ## Examples + + iex> %IbanEx.Iban{country_code: "AT", check_digits: "61", bank_code: "19043", branch_code: nil, national_check: nil, account_number: "00234573201"} + iex> |> IbanEx.Country.UA.to_string() + "AT 61 19043 00234573201" + """ @size 20 diff --git a/lib/iban_ex/country/be.ex b/lib/iban_ex/country/be.ex index 56df70e..1209d40 100644 --- a/lib/iban_ex/country/be.ex +++ b/lib/iban_ex/country/be.ex @@ -1,6 +1,13 @@ defmodule IbanEx.Country.BE do @moduledoc """ Belgium IBAN parsing rules + + ## Examples + + iex> %IbanEx.Iban{country_code: "BE", check_digits: "68", bank_code: "539", branch_code: nil, national_check: "34", account_number: "0075470"} + iex> |> IbanEx.Country.BE.to_string() + "BE 68 539 0075470 34" + """ @size 16 diff --git a/lib/iban_ex/country/bg.ex b/lib/iban_ex/country/bg.ex index 64e5a38..6148105 100644 --- a/lib/iban_ex/country/bg.ex +++ b/lib/iban_ex/country/bg.ex @@ -1,6 +1,13 @@ defmodule IbanEx.Country.BG do @moduledoc """ Bulgaria IBAN parsing rules + + ## Examples + + iex> %IbanEx.Iban{country_code: "BG", check_digits: "80", bank_code: "BNBG", branch_code: "9661", national_check: nil, account_number: "1020345678"} + iex> |> IbanEx.Country.BG.to_string() + "BG 80 BNBG 9661 1020345678" + """ @size 22 diff --git a/lib/iban_ex/country/ch.ex b/lib/iban_ex/country/ch.ex index f2f10e7..c071513 100644 --- a/lib/iban_ex/country/ch.ex +++ b/lib/iban_ex/country/ch.ex @@ -1,6 +1,13 @@ defmodule IbanEx.Country.CH do @moduledoc """ Switzerland IBAN parsing rules + + ## Examples + + iex> %IbanEx.Iban{country_code: "CH", check_digits: "93", bank_code: "00762", branch_code: nil, national_check: nil, account_number: "011623852957"} + iex> |> IbanEx.Country.CH.to_string() + "CH 93 00762 011623852957" + """ @size 21 diff --git a/lib/iban_ex/country/cy.ex b/lib/iban_ex/country/cy.ex index 113a8fa..5387061 100644 --- a/lib/iban_ex/country/cy.ex +++ b/lib/iban_ex/country/cy.ex @@ -1,6 +1,13 @@ defmodule IbanEx.Country.CY do @moduledoc """ Cyprus IBAN parsing rules + + ## Examples + + iex> %IbanEx.Iban{country_code: "CY", check_digits: "17", bank_code: "002", branch_code: "00128", national_check: nil, account_number: "0000001200527600"} + iex> |> IbanEx.Country.CY.to_string() + "CY 17 002 00128 0000001200527600" + """ @size 28 diff --git a/lib/iban_ex/country/cz.ex b/lib/iban_ex/country/cz.ex index 2f0c873..21f8aa5 100644 --- a/lib/iban_ex/country/cz.ex +++ b/lib/iban_ex/country/cz.ex @@ -1,6 +1,13 @@ defmodule IbanEx.Country.CZ do @moduledoc """ Czech Republic IBAN parsing rules + + ## Examples + + iex> %IbanEx.Iban{country_code: "CZ", check_digits: "65", bank_code: "0800", branch_code: nil, national_check: nil, account_number: "0000192000145399"} + iex> |> IbanEx.Country.CZ.to_string() + "CZ 65 0800 0000192000145399" + """ @size 24 diff --git a/lib/iban_ex/country/de.ex b/lib/iban_ex/country/de.ex index 4ba5d00..7a71b31 100644 --- a/lib/iban_ex/country/de.ex +++ b/lib/iban_ex/country/de.ex @@ -1,6 +1,13 @@ defmodule IbanEx.Country.DE do @moduledoc """ Germany IBAN parsing rules + + ## Examples + + iex> %IbanEx.Iban{country_code: "DE", check_digits: "89", bank_code: "37040044", branch_code: nil, national_check: nil, account_number: "0532013000"} + iex> |> IbanEx.Country.DE.to_string() + "DE 89 37040044 0532013000" + """ @size 22 diff --git a/lib/iban_ex/country/dk.ex b/lib/iban_ex/country/dk.ex index ad00436..d218de2 100644 --- a/lib/iban_ex/country/dk.ex +++ b/lib/iban_ex/country/dk.ex @@ -1,6 +1,13 @@ defmodule IbanEx.Country.DK do @moduledoc """ Denmark IBAN parsing rules + + ## Examples + + iex> %IbanEx.Iban{country_code: "DK", check_digits: "50", bank_code: "0040", branch_code: nil, national_check: nil, account_number: "0440116243"} + iex> |> IbanEx.Country.DK.to_string() + "DK 50 0040 0440116243" + """ @size 18 @rule ~r/^(?[0-9]{4})(?[0-9]{10})$/i diff --git a/lib/iban_ex/country/ee.ex b/lib/iban_ex/country/ee.ex index 8cde443..0779353 100644 --- a/lib/iban_ex/country/ee.ex +++ b/lib/iban_ex/country/ee.ex @@ -1,6 +1,13 @@ defmodule IbanEx.Country.EE do @moduledoc """ Estonian IBAN parsing rules + + ## Examples + + iex> %IbanEx.Iban{country_code: "EE", check_digits: "38", bank_code: "22", branch_code: "00", national_check: "5", account_number: "22102014568"} + iex> |> IbanEx.Country.EE.to_string() + "EE 38 22 00 22102014568 5" + """ @size 20 diff --git a/lib/iban_ex/country/es.ex b/lib/iban_ex/country/es.ex index 4f9a457..cca4b58 100644 --- a/lib/iban_ex/country/es.ex +++ b/lib/iban_ex/country/es.ex @@ -1,6 +1,13 @@ defmodule IbanEx.Country.ES do @moduledoc """ Spain IBAN parsing rules + + ## Examples + + iex> %IbanEx.Iban{country_code: "ES", check_digits: "91", bank_code: "2100", branch_code: "0418", national_check: "45", account_number: "0200051332"} + iex> |> IbanEx.Country.ES.to_string() + "ES 91 2100 0418 45 0200051332" + """ @size 24 diff --git a/lib/iban_ex/country/fi.ex b/lib/iban_ex/country/fi.ex index cafa9b8..5e3be14 100644 --- a/lib/iban_ex/country/fi.ex +++ b/lib/iban_ex/country/fi.ex @@ -1,6 +1,13 @@ defmodule IbanEx.Country.FI do @moduledoc """ Finland IBAN parsing rules + + ## Examples + + iex> %IbanEx.Iban{country_code: "FI", check_digits: "21", bank_code: "123456", branch_code: nil, national_check: "5", account_number: "0000078"} + iex> |> IbanEx.Country.FI.to_string() + "FI 21 123456 0000078 5" + """ @size 18 diff --git a/lib/iban_ex/country/fr.ex b/lib/iban_ex/country/fr.ex index cc8d11a..758fe6e 100644 --- a/lib/iban_ex/country/fr.ex +++ b/lib/iban_ex/country/fr.ex @@ -1,6 +1,13 @@ defmodule IbanEx.Country.FR do @moduledoc """ France IBAN parsing rules + + ## Examples + + iex> %IbanEx.Iban{country_code: "FR", check_digits: "14", bank_code: "20041", branch_code: "01005", national_check: "06", account_number: "0500013M026"} + iex> |> IbanEx.Country.FR.to_string() + "FR 14 20041 01005 0500013M026 06" + """ @size 27 diff --git a/lib/iban_ex/country/gb.ex b/lib/iban_ex/country/gb.ex index 61cb7dd..56f9029 100644 --- a/lib/iban_ex/country/gb.ex +++ b/lib/iban_ex/country/gb.ex @@ -1,6 +1,13 @@ defmodule IbanEx.Country.GB do @moduledoc """ United Kingdom IBAN parsing rules + + ## Examples + + iex> %IbanEx.Iban{country_code: "GB", check_digits: "29", bank_code: "NWBK", branch_code: "601613", national_check: "06", account_number: "31926819"} + iex> |> IbanEx.Country.GB.to_string() + "GB 29 NWBK 601613 31926819" + """ @size 22 diff --git a/lib/iban_ex/country/gi.ex b/lib/iban_ex/country/gi.ex new file mode 100644 index 0000000..f537693 --- /dev/null +++ b/lib/iban_ex/country/gi.ex @@ -0,0 +1,17 @@ +defmodule IbanEx.Country.GI do + @moduledoc """ + Gibraltar IBAN parsing rules + + ## Examples + + iex> %IbanEx.Iban{country_code: "GI", check_digits: "75", bank_code: "NWBK", branch_code: nil, national_check: nil, account_number: "000000007099453"} + iex> |> IbanEx.Country.GI.to_string() + "GI 75 NWBK 000000007099453" + + """ + + @size 23 + @rule ~r/^(?[A-Z]{4})(?[0-9A-Z]{15})$/i + + use IbanEx.Country.Template +end diff --git a/lib/iban_ex/country/gr.ex b/lib/iban_ex/country/gr.ex new file mode 100644 index 0000000..3675de8 --- /dev/null +++ b/lib/iban_ex/country/gr.ex @@ -0,0 +1,35 @@ +defmodule IbanEx.Country.GR do + @moduledoc """ + Greece IBAN parsing rules + + ## Examples + + iex> %IbanEx.Iban{country_code: "GR", check_digits: "16", bank_code: "011", branch_code: "0125", national_check: nil, account_number: "0000000012300695"} + iex> |> IbanEx.Country.GR.to_string() + "GR 16 011 0125 0000000012300695" + + """ + + @size 27 + @rule ~r/^(?[0-9]{3})(?[0-9]{4})(?[0-9A-Z]{16})$/i + + use IbanEx.Country.Template + + @impl IbanEx.Country.Template + @spec to_string(Iban.t()) :: binary() + @spec to_string(Iban.t(), binary()) :: binary() + def to_string( + %Iban{ + country_code: country_code, + check_digits: check_digits, + bank_code: bank_code, + branch_code: branch_code, + national_check: _national_check, + account_number: account_number + } = _iban, + joiner \\ " " + ) do + [country_code, check_digits, bank_code, branch_code, account_number] + |> Enum.join(joiner) + end +end diff --git a/lib/iban_ex/country/hr.ex b/lib/iban_ex/country/hr.ex index bc321e1..7bffba8 100644 --- a/lib/iban_ex/country/hr.ex +++ b/lib/iban_ex/country/hr.ex @@ -1,6 +1,13 @@ defmodule IbanEx.Country.HR do @moduledoc """ Croatia IBAN parsing rules + + ## Examples + + iex> %IbanEx.Iban{country_code: "HR", check_digits: "12", bank_code: "1001005", branch_code: nil, national_check: nil, account_number: "1863000160"} + iex> |> IbanEx.Country.HR.to_string() + "HR 12 1001005 1863000160" + """ @size 21 diff --git a/lib/iban_ex/country/hu.ex b/lib/iban_ex/country/hu.ex new file mode 100644 index 0000000..fa3da3a --- /dev/null +++ b/lib/iban_ex/country/hu.ex @@ -0,0 +1,35 @@ +defmodule IbanEx.Country.HU do + @moduledoc """ + Hungary IBAN parsing rules + + ## Examples + + iex> %IbanEx.Iban{country_code: "HU", check_digits: "42", bank_code: "117", branch_code: "7301", national_check: "0", account_number: "6111110180000000"} + iex> |> IbanEx.Country.HU.to_string() + "HU 42 117 7301 6111110180000000 0" + + """ + + @size 28 + @rule ~r/^(?[0-9]{3})(?[0-9]{4})(?[0-9]{16})(?[0-9]{1})$/i + + use IbanEx.Country.Template + + @impl IbanEx.Country.Template + @spec to_string(Iban.t()) :: binary() + @spec to_string(Iban.t(), binary()) :: binary() + def to_string( + %Iban{ + country_code: country_code, + check_digits: check_digits, + bank_code: bank_code, + branch_code: branch_code, + national_check: national_check, + account_number: account_number + } = _iban, + joiner \\ " " + ) do + [country_code, check_digits, bank_code, branch_code, account_number, national_check] + |> Enum.join(joiner) + end +end diff --git a/lib/iban_ex/country/ie.ex b/lib/iban_ex/country/ie.ex new file mode 100644 index 0000000..3f08a4c --- /dev/null +++ b/lib/iban_ex/country/ie.ex @@ -0,0 +1,35 @@ +defmodule IbanEx.Country.IE do + @moduledoc """ + Ireland IBAN parsing rules + + ## Examples + + iex> %IbanEx.Iban{country_code: "IE", check_digits: "29", bank_code: "AIBK", branch_code: "931152", national_check: nil, account_number: "12345678"} + iex> |> IbanEx.Country.IE.to_string() + "IE 29 AIBK 931152 12345678" + + """ + + @size 22 + @rule ~r/^(?[A-Z]{4})(?[0-9]{6})(?[0-9]{8})$/i + + use IbanEx.Country.Template + + @impl IbanEx.Country.Template + @spec to_string(Iban.t()) :: binary() + @spec to_string(Iban.t(), binary()) :: binary() + def to_string( + %Iban{ + country_code: country_code, + check_digits: check_digits, + bank_code: bank_code, + branch_code: branch_code, + national_check: _national_check, + account_number: account_number + } = _iban, + joiner \\ " " + ) do + [country_code, check_digits, bank_code, branch_code, account_number] + |> Enum.join(joiner) + end +end diff --git a/lib/iban_ex/country/it.ex b/lib/iban_ex/country/it.ex new file mode 100644 index 0000000..aebaabb --- /dev/null +++ b/lib/iban_ex/country/it.ex @@ -0,0 +1,35 @@ +defmodule IbanEx.Country.IT do + @moduledoc """ + Italy IBAN parsing rules + + ## Examples + + iex> %IbanEx.Iban{country_code: "IT", check_digits: "60", bank_code: "05428", branch_code: "11101", national_check: "X", account_number: "000000123456"} + iex> |> IbanEx.Country.IT.to_string() + "IT 60 X 05428 11101 000000123456" + + """ + + @size 27 + @rule ~r/^(?[A-Z]{1})(?[0-9]{5})(?[0-9]{5})(?[0-9A-Z]{12})$/i + + use IbanEx.Country.Template + + @impl IbanEx.Country.Template + @spec to_string(Iban.t()) :: binary() + @spec to_string(Iban.t(), binary()) :: binary() + def to_string( + %Iban{ + country_code: country_code, + check_digits: check_digits, + bank_code: bank_code, + branch_code: branch_code, + national_check: national_check, + account_number: account_number + } = _iban, + joiner \\ " " + ) do + [country_code, check_digits, national_check, bank_code, branch_code, account_number] + |> Enum.join(joiner) + end +end diff --git a/lib/iban_ex/country/li.ex b/lib/iban_ex/country/li.ex new file mode 100644 index 0000000..e8d6f73 --- /dev/null +++ b/lib/iban_ex/country/li.ex @@ -0,0 +1,17 @@ +defmodule IbanEx.Country.LI do + @moduledoc """ + Liechtenstein IBAN parsing rules + + ## Examples + + iex> %IbanEx.Iban{country_code: "LI", check_digits: "21", bank_code: "08810", branch_code: nil, national_check: nil, account_number: "0002324013AA"} + iex> |> IbanEx.Country.LI.to_string() + "LI 21 08810 0002324013AA" + + """ + + @size 21 + @rule ~r/^(?[0-9]{5})(?[0-9A-Z]{12})$/i + + use IbanEx.Country.Template +end diff --git a/lib/iban_ex/country/lt.ex b/lib/iban_ex/country/lt.ex index dba384e..6b55434 100644 --- a/lib/iban_ex/country/lt.ex +++ b/lib/iban_ex/country/lt.ex @@ -1,6 +1,13 @@ defmodule IbanEx.Country.LT do @moduledoc """ Lithuanian IBAN parsing rules + + ## Examples + + iex> %IbanEx.Iban{country_code: "LT", check_digits: "12", bank_code: "10000", branch_code: nil, national_check: nil, account_number: "11101001000"} + iex> |> IbanEx.Country.LT.to_string() + "LT 12 10000 11101001000" + """ @size 20 diff --git a/lib/iban_ex/country/lu.ex b/lib/iban_ex/country/lu.ex index 3ebc71e..96ba26c 100644 --- a/lib/iban_ex/country/lu.ex +++ b/lib/iban_ex/country/lu.ex @@ -1,6 +1,13 @@ defmodule IbanEx.Country.LU do @moduledoc """ Luxembourg IBAN parsing rules + + ## Examples + + iex> %IbanEx.Iban{country_code: "LU", check_digits: "28", bank_code: "001", branch_code: nil, national_check: nil, account_number: "9400644750000"} + iex> |> IbanEx.Country.LU.to_string() + "LU 28 001 9400644750000" + """ @size 20 diff --git a/lib/iban_ex/country/lv.ex b/lib/iban_ex/country/lv.ex index ca6f5da..a57769e 100644 --- a/lib/iban_ex/country/lv.ex +++ b/lib/iban_ex/country/lv.ex @@ -1,6 +1,13 @@ defmodule IbanEx.Country.LV do @moduledoc """ Latvian IBAN parsing rules + + ## Examples + + iex> %IbanEx.Iban{country_code: "LV", check_digits: "80", bank_code: "BANK", branch_code: nil, national_check: nil, account_number: "0000435195001"} + iex> |> IbanEx.Country.LV.to_string() + "LV 80 BANK 0000435195001" + """ @size 21 diff --git a/lib/iban_ex/country/mc.ex b/lib/iban_ex/country/mc.ex new file mode 100644 index 0000000..cf541f2 --- /dev/null +++ b/lib/iban_ex/country/mc.ex @@ -0,0 +1,35 @@ +defmodule IbanEx.Country.MC do + @moduledoc """ + Monaco IBAN parsing rules + + ## Examples + + iex> %IbanEx.Iban{country_code: "MC", check_digits: "58", bank_code: "11222", branch_code: "00001", national_check: "30", account_number: "01234567890"} + iex> |> IbanEx.Country.MC.to_string() + "MC 58 11222 00001 01234567890 30" + + """ + + @size 27 + @rule ~r/^(?[0-9]{5})(?[0-9]{5})(?[0-9A-Z]{11})(?[0-9]{2})$/i + + use IbanEx.Country.Template + + @impl IbanEx.Country.Template + @spec to_string(Iban.t()) :: binary() + @spec to_string(Iban.t(), binary()) :: binary() + def to_string( + %Iban{ + country_code: country_code, + check_digits: check_digits, + bank_code: bank_code, + branch_code: branch_code, + national_check: national_check, + account_number: account_number + } = _iban, + joiner \\ " " + ) do + [country_code, check_digits, bank_code, branch_code, account_number, national_check] + |> Enum.join(joiner) + end +end diff --git a/lib/iban_ex/country/mt.ex b/lib/iban_ex/country/mt.ex index 596edfa..477432a 100644 --- a/lib/iban_ex/country/mt.ex +++ b/lib/iban_ex/country/mt.ex @@ -1,6 +1,13 @@ defmodule IbanEx.Country.MT do @moduledoc """ Malta IBAN parsing rules + + ## Examples + + iex> %IbanEx.Iban{country_code: "MT", check_digits: "84", bank_code: "MALT", branch_code: "01100", national_check: nil, account_number: "0012345MTLCAST001S"} + iex> |> IbanEx.Country.MT.to_string() + "MT 84 MALT 01100 0012345MTLCAST001S" + """ @size 31 diff --git a/lib/iban_ex/country/nl.ex b/lib/iban_ex/country/nl.ex index b76534c..8875c12 100644 --- a/lib/iban_ex/country/nl.ex +++ b/lib/iban_ex/country/nl.ex @@ -1,6 +1,13 @@ defmodule IbanEx.Country.NL do @moduledoc """ Netherlands IBAN parsing rules + + ## Examples + + iex> %IbanEx.Iban{country_code: "NL", check_digits: "91", bank_code: "ABNA", branch_code: nil, national_check: nil, account_number: "0417164300"} + iex> |> IbanEx.Country.NL.to_string() + "NL 91 ABNA 0417164300" + """ @size 18 diff --git a/lib/iban_ex/country/no.ex b/lib/iban_ex/country/no.ex new file mode 100644 index 0000000..b30dd8d --- /dev/null +++ b/lib/iban_ex/country/no.ex @@ -0,0 +1,35 @@ +defmodule IbanEx.Country.NO do + @moduledoc """ + Norway IBAN parsing rules + + ## Examples + + iex> %IbanEx.Iban{country_code: "NO", check_digits: "93", bank_code: "8601", branch_code: nil, national_check: "7", account_number: "111794"} + iex> |> IbanEx.Country.NO.to_string() + "NO 93 8601 111794 7" + + """ + + @size 15 + @rule ~r/^(?[0-9]{4})(?[0-9]{6})(?[0-9]{1})$/i + + use IbanEx.Country.Template + + @impl IbanEx.Country.Template + @spec to_string(Iban.t()) :: binary() + @spec to_string(Iban.t(), binary()) :: binary() + def to_string( + %Iban{ + country_code: country_code, + check_digits: check_digits, + bank_code: bank_code, + branch_code: _branch_code, + national_check: national_check, + account_number: account_number + } = _iban, + joiner \\ " " + ) do + [country_code, check_digits, bank_code, account_number, national_check] + |> Enum.join(joiner) + end +end diff --git a/lib/iban_ex/country/pl.ex b/lib/iban_ex/country/pl.ex index e140bba..3a94d09 100644 --- a/lib/iban_ex/country/pl.ex +++ b/lib/iban_ex/country/pl.ex @@ -1,6 +1,13 @@ defmodule IbanEx.Country.PL do @moduledoc """ Poland IBAN parsing rules + + ## Examples + + iex> %IbanEx.Iban{country_code: "PL", check_digits: "61", bank_code: "109", branch_code: "0101", national_check: "4", account_number: "0000071219812874"} + iex> |> IbanEx.Country.PL.to_string() + "PL 61 109 0101 4 0000071219812874" + """ @size 28 diff --git a/lib/iban_ex/country/pt.ex b/lib/iban_ex/country/pt.ex index 5909178..d485910 100644 --- a/lib/iban_ex/country/pt.ex +++ b/lib/iban_ex/country/pt.ex @@ -1,6 +1,13 @@ defmodule IbanEx.Country.PT do @moduledoc """ Portugal IBAN parsing rules + + ## Examples + + iex> %IbanEx.Iban{country_code: "PT", check_digits: "50", bank_code: "0002", branch_code: "0123", national_check: "54", account_number: "12345678901"} + iex> |> IbanEx.Country.PT.to_string() + "PT 50 0002 0123 12345678901 54" + """ @size 25 diff --git a/lib/iban_ex/country/ro.ex b/lib/iban_ex/country/ro.ex new file mode 100644 index 0000000..8e34b4e --- /dev/null +++ b/lib/iban_ex/country/ro.ex @@ -0,0 +1,17 @@ +defmodule IbanEx.Country.RO do + @moduledoc """ + Romania IBAN parsing rules + + ## Examples + + iex> %IbanEx.Iban{country_code: "RO", check_digits: "49", bank_code: "AAAA", branch_code: nil, national_check: nil, account_number: "1B31007593840000"} + iex> |> IbanEx.Country.RO.to_string() + "RO 49 AAAA 1B31007593840000" + + """ + + @size 24 + @rule ~r/^(?[A-Z]{4})(?[0-9A-Z]{16})$/i + + use IbanEx.Country.Template +end diff --git a/lib/iban_ex/country/se.ex b/lib/iban_ex/country/se.ex new file mode 100644 index 0000000..3eaa3ac --- /dev/null +++ b/lib/iban_ex/country/se.ex @@ -0,0 +1,17 @@ +defmodule IbanEx.Country.SE do + @moduledoc """ + Sweden IBAN parsing rules + + ## Examples + + iex> %IbanEx.Iban{country_code: "SE", check_digits: "45", bank_code: "500", branch_code: nil, national_check: nil, account_number: "00000058398257466"} + iex> |> IbanEx.Country.SE.to_string() + "SE 45 500 00000058398257466" + + """ + + @size 24 + @rule ~r/^(?[0-9]{3})(?[0-9]{17})$/i + + use IbanEx.Country.Template +end diff --git a/lib/iban_ex/country/si.ex b/lib/iban_ex/country/si.ex new file mode 100644 index 0000000..74bea8a --- /dev/null +++ b/lib/iban_ex/country/si.ex @@ -0,0 +1,37 @@ +defmodule IbanEx.Country.SI do + @moduledoc """ + Slovenia IBAN parsing rules + + ## Examples + + iex> %IbanEx.Iban{country_code: "SI", check_digits: "56", bank_code: "26", branch_code: "330", national_check: "86", account_number: "00120390"} + iex> |> IbanEx.Country.SI.to_string() + "SI 56 26 330 00120390 86" + + """ + + @size 19 + @rule ~r/^(?[0-9]{2})(?[0-9]{3})(?[0-9]{8})(?[0-9]{2})$/i + + use IbanEx.Country.Template + + + @impl IbanEx.Country.Template + @spec to_string(Iban.t()) :: binary() + @spec to_string(Iban.t(), binary()) :: binary() + def to_string( + %Iban{ + country_code: country_code, + check_digits: check_digits, + bank_code: bank_code, + branch_code: branch_code, + national_check: national_check, + account_number: account_number + } = _iban, + joiner \\ " " + ) do + [country_code, check_digits, bank_code, branch_code, account_number, national_check] + |> Enum.join(joiner) + end + +end diff --git a/lib/iban_ex/country/sk.ex b/lib/iban_ex/country/sk.ex new file mode 100644 index 0000000..5db8f03 --- /dev/null +++ b/lib/iban_ex/country/sk.ex @@ -0,0 +1,17 @@ +defmodule IbanEx.Country.SK do + @moduledoc """ + Slovakia IBAN parsing rules + + ## Examples + + iex> %IbanEx.Iban{country_code: "SK", check_digits: "31", bank_code: "1200", branch_code: nil, national_check: nil, account_number: "0000198742637541"} + iex> |> IbanEx.Country.SK.to_string() + "SK 31 1200 0000198742637541" + + """ + + @size 24 + @rule ~r/^(?[0-9]{4})(?[0-9]{16})$/i + + use IbanEx.Country.Template +end diff --git a/lib/iban_ex/country/sm.ex b/lib/iban_ex/country/sm.ex new file mode 100644 index 0000000..41103c0 --- /dev/null +++ b/lib/iban_ex/country/sm.ex @@ -0,0 +1,35 @@ +defmodule IbanEx.Country.SM do + @moduledoc """ + San Marino IBAN parsing rules + + ## Examples + + iex> %IbanEx.Iban{country_code: "SM", check_digits: "86", bank_code: "03225", branch_code: "09800", national_check: "U", account_number: "000000270100"} + iex> |> IbanEx.Country.SM.to_string() + "SM 86 U 03225 09800 000000270100" + + """ + + @size 27 + @rule ~r/^(?[A-Z]{1})(?[0-9]{5})(?[0-9]{5})(?[0-9A-Z]{12})$/i + + use IbanEx.Country.Template + + @impl IbanEx.Country.Template + @spec to_string(Iban.t()) :: binary() + @spec to_string(Iban.t(), binary()) :: binary() + def to_string( + %Iban{ + country_code: country_code, + check_digits: check_digits, + bank_code: bank_code, + branch_code: branch_code, + national_check: national_check, + account_number: account_number + } = _iban, + joiner \\ " " + ) do + [country_code, check_digits, national_check, bank_code, branch_code, account_number] + |> Enum.join(joiner) + end +end diff --git a/lib/iban_ex/country/ua.ex b/lib/iban_ex/country/ua.ex index f09a508..c763292 100644 --- a/lib/iban_ex/country/ua.ex +++ b/lib/iban_ex/country/ua.ex @@ -1,10 +1,16 @@ defmodule IbanEx.Country.UA do @moduledoc """ Ukrainian IBAN parsing rules + + ## Examples + + iex> %IbanEx.Iban{country_code: "UA", check_digits: "21", bank_code: "322313", branch_code: nil, national_check: nil, account_number: "0000026007233566001"} + iex> |> IbanEx.Country.UA.to_string() + "UA 21 322313 0000026007233566001" + """ @size 29 @rule ~r/^(?[0-9]{6})(?[0-9A-Z]{19})$/i - use IbanEx.Country.Template end diff --git a/lib/iban_ex/country/va.ex b/lib/iban_ex/country/va.ex new file mode 100644 index 0000000..70d7ec8 --- /dev/null +++ b/lib/iban_ex/country/va.ex @@ -0,0 +1,17 @@ +defmodule IbanEx.Country.VA do + @moduledoc """ + Vatican IBAN parsing rules + + ## Examples + + iex> %IbanEx.Iban{country_code: "VA", check_digits: "59", bank_code: "001", branch_code: nil, national_check: nil, account_number: "123000012345678"} + iex> |> IbanEx.Country.VA.to_string() + "VA 59 001 123000012345678" + + """ + + @size 22 + @rule ~r/^(?[0-9]{3})(?[0-9]{15})$/i + + use IbanEx.Country.Template +end diff --git a/mix.exs b/mix.exs index 106f456..5a3ee06 100644 --- a/mix.exs +++ b/mix.exs @@ -2,7 +2,7 @@ defmodule IbanEx.MixProject do use Mix.Project @source_url "https://g.tulz.dev/opensource/iban-ex" - @version "0.1.1" + @version "0.1.2" def project do [ diff --git a/test/iban_ex_test.exs b/test/iban_ex_test.exs index 85f2337..c4cf468 100644 --- a/test/iban_ex_test.exs +++ b/test/iban_ex_test.exs @@ -1,8 +1,129 @@ defmodule IbanExTest do - use ExUnit.Case - doctest IbanEx + alias IbanEx.{Country, Iban, Parser} + use ExUnit.Case, async: true + doctest IbanEx.Country.AT + doctest IbanEx.Country.BE + doctest IbanEx.Country.BG + doctest IbanEx.Country.CH + doctest IbanEx.Country.CY + doctest IbanEx.Country.CZ + doctest IbanEx.Country.DE + doctest IbanEx.Country.DK + doctest IbanEx.Country.EE + doctest IbanEx.Country.ES + doctest IbanEx.Country.FI + doctest IbanEx.Country.FR + doctest IbanEx.Country.GB + doctest IbanEx.Country.GI + doctest IbanEx.Country.GR + doctest IbanEx.Country.HR + doctest IbanEx.Country.HU + doctest IbanEx.Country.IE + doctest IbanEx.Country.IT + doctest IbanEx.Country.LI + doctest IbanEx.Country.LT + doctest IbanEx.Country.LU + doctest IbanEx.Country.LV + doctest IbanEx.Country.MC + doctest IbanEx.Country.MT + doctest IbanEx.Country.NL + doctest IbanEx.Country.NO + doctest IbanEx.Country.PL + doctest IbanEx.Country.PT + doctest IbanEx.Country.RO + doctest IbanEx.Country.SE + doctest IbanEx.Country.SM + doctest IbanEx.Country.SI + doctest IbanEx.Country.SK + doctest IbanEx.Country.UA + doctest IbanEx.Country.VA - test "greets the world" do - assert IbanEx.hello() == :world + @ibans [ + "AL47212110090000000235698741", + "AD1200012030200359100100", + "AT611904300234573201", + "AZ21NABZ00000000137010001944", + "BH67BMAG00001299123456", + "BE68539007547034", + "BA391290079401028494", + "BR1800360305000010009795493C1", + "BG80BNBG96611020345678", + "CR05015202001026284066", + "HR1210010051863000160", + "CY17002001280000001200527600", + "CZ6508000000192000145399", + "DK5000400440116243", + "DO28BAGR00000001212453611324", + "EG380019000500000000263180002", + "SV62CENR00000000000000700025", + "EE382200221020145685", + "FO6264600001631634", + "FI2112345600000785", + "FR1420041010050500013M02606", + "GE29NB0000000101904917", + "DE89370400440532013000", + "GI75NWBK000000007099453", + "GR1601101250000000012300695", + "GL8964710001000206", + "GT82TRAJ01020000001210029690", + "HU42117730161111101800000000", + "IS140159260076545510730339", + "IE29AIBK93115212345678", + "IL620108000000099999999", + "IT60X0542811101000000123456", + "JO94CBJO0010000000000131000302", + "KZ86125KZT5004100100", + "XK051212012345678906", + "KW81CBKU0000000000001234560101", + "LV80BANK0000435195001", + "LB62099900000001001901229114", + "LI21088100002324013AA", + "LT121000011101001000", + "LU280019400644750000", + "MK07250120000058984", + "MT84MALT011000012345MTLCAST001S", + "MR1300020001010000123456753", + "MC5811222000010123456789030", + "ME25505000012345678951", + "NL91ABNA0417164300", + "NO9386011117947", + "PK36SCBL0000001123456702", + "PL61109010140000071219812874", + "PT50000201231234567890154", + "QA58DOHB00001234567890ABCDEFG", + "MD24AG000225100013104168", + "RO49AAAA1B31007593840000", + "SM86U0322509800000000270100", + "SA0380000000608010167519", + "RS35260005601001611379", + "SK3112000000198742637541", + "SI56263300012039086", + "ES9121000418450200051332", + "SE4550000000058398257466", + "CH9300762011623852957", + "TL380080012345678910157", + "TR330006100519786457841326", + "UA213223130000026007233566001", + "AE070331234567890123456", + "GB29NWBK60161331926819", + "VA59001123000012345678", + "VG96VPVG0000012345678901" + ] + + test "parsing valid IBANs from available countries returns {:ok, %IbanEx.Iban{}}" do + assert Enum.all?(@ibans, fn iban -> + iban_country = iban |> String.upcase() |> String.slice(0..1) + + case {Country.is_country_code_supported?(iban_country), Parser.parse(iban)} do + {true, {:ok, %Iban{}}} -> + true + + {false, {:error, :unsupported_country_code}} -> + true + + _ -> + false + end + end) end end