Current section

Files

Jump to
money lib money.ex
Raw

lib/money.ex

defmodule Money do
@type t :: %__MODULE__{
amount: integer,
currency: atom
}
defstruct [amount: 0, currency: :USD]
@spec new(integer, atom) :: t
def new(%Money{} = num),
do: num
def new(int, currency) when is_integer(int) do
cond do
currency_exist?(currency) ->
%Money{amount: int, currency: currency}
end
end
def new(bitstr, currency) when is_bitstring(bitstr) do
case Integer.parse(bitstr) do
:error -> raise ArgumentError
{x, _} -> %Money{amount: x, currency: currency}
end
end
def currency_name(%Money{currency: cur1}) do
currency_name(cur1)
end
def currency_name(currency) do
case currency_exist?(currency) do
true ->
get_currency(currency) |> Dict.get(:name)
_ -> nil
end
end
def currency_symbol(%Money{currency: cur1}) do
currency_symbol(cur1)
end
def currency_symbol(currency) do
case currency_exist?(currency) do
true ->
get_currency(currency) |> Dict.get(:symbol)
_ -> nil
end
end
def currency_all() do
%{
:AED => %{:name => "UAE Dirham", :symbol => " "},
:AFN => %{:name => "Afghani", :symbol => "؋"},
:ALL => %{:name => "Lek", :symbol => "Lek"},
:AMD => %{:name => "Armenian Dram", :symbol => " "},
:ANG => %{:name => "Netherlands Antillian Guilder", :symbol => "ƒ"},
:AOA => %{:name => "Kwanza", :symbol => " "},
:ARS => %{:name => "Argentine Peso", :symbol => "$"},
:AUD => %{:name => "Australian Dollar", :symbol => "$"},
:AWG => %{:name => "Aruban Guilder", :symbol => "ƒ"},
:AZN => %{:name => "Azerbaijanian Manat", :symbol => "ман"},
:BAM => %{:name => "Convertible Marks", :symbol => "KM"},
:BBD => %{:name => "Barbados Dollar", :symbol => "$"},
:BDT => %{:name => "Taka", :symbol => " "},
:BGN => %{:name => "Bulgarian Lev", :symbol => "лв"},
:BHD => %{:name => "Bahraini Dinar", :symbol => " "},
:BIF => %{:name => "Burundi Franc", :symbol => " "},
:BMD => %{:name => "Bermudian Dollar (customarily known as Bermuda Dollar)", :symbol => "$"},
:BND => %{:name => "Brunei Dollar", :symbol => "$"},
:BOB => %{:name => "Boliviano Mvdol", :symbol => "$b"},
:BOV => %{:name => "Boliviano Mvdol", :symbol => "$b"},
:BRL => %{:name => "Brazilian Real", :symbol => "R$"},
:BSD => %{:name => "Bahamian Dollar", :symbol => "$"},
:BWP => %{:name => "Pula", :symbol => "P"},
:BYR => %{:name => "Belarussian Ruble", :symbol => "p."},
:BZD => %{:name => "Belize Dollar", :symbol => "BZ$"},
:CAD => %{:name => "Canadian Dollar", :symbol => "$"},
:CDF => %{:name => "Congolese Franc", :symbol => " "},
:CHF => %{:name => "Swiss Franc", :symbol => "CHF"},
:CLF => %{:name => "Chilean Peso Unidades de fomento", :symbol => "$"},
:CLP => %{:name => "Chilean Peso Unidades de fomento", :symbol => "$"},
:CNY => %{:name => "Yuan Renminbi", :symbol => "¥"},
:COP => %{:name => "Colombian Peso Unidad de Valor Real", :symbol => "$"},
:COU => %{:name => "Colombian Peso Unidad de Valor Real", :symbol => "$"},
:CRC => %{:name => "Costa Rican Colon", :symbol => "₡"},
:CUP => %{:name => "Cuban Peso Peso Convertible", :symbol => "₱"},
:CUC => %{:name => "Cuban Peso Peso Convertible", :symbol => "₱"},
:CVE => %{:name => "Cape Verde Escudo", :symbol => " "},
:CZK => %{:name => "Czech Koruna", :symbol => "Kč"},
:DJF => %{:name => "Djibouti Franc", :symbol => " "},
:DKK => %{:name => "Danish Krone", :symbol => "kr"},
:DOP => %{:name => "Dominican Peso", :symbol => "RD$"},
:DZD => %{:name => "Algerian Dinar", :symbol => " "},
:EEK => %{:name => "Kroon", :symbol => " "},
:EGP => %{:name => "Egyptian Pound", :symbol => "£"},
:ERN => %{:name => "Nakfa", :symbol => " "},
:ETB => %{:name => "Ethiopian Birr", :symbol => " "},
:EUR => %{:name => "Euro", :symbol => "€"},
:FJD => %{:name => "Fiji Dollar", :symbol => "$"},
:FKP => %{:name => "Falkland Islands Pound", :symbol => "£"},
:GBP => %{:name => "Pound Sterling", :symbol => "£"},
:GEL => %{:name => "Lari", :symbol => " "},
:GHS => %{:name => "Cedi", :symbol => " "},
:GIP => %{:name => "Gibraltar Pound", :symbol => "£"},
:GMD => %{:name => "Dalasi", :symbol => " "},
:GNF => %{:name => "Guinea Franc", :symbol => " "},
:GTQ => %{:name => "Quetzal", :symbol => "Q"},
:GYD => %{:name => "Guyana Dollar", :symbol => "$"},
:HKD => %{:name => "Hong Kong Dollar", :symbol => "$"},
:HNL => %{:name => "Lempira", :symbol => "L"},
:HRK => %{:name => "Croatian Kuna", :symbol => "kn"},
:HTG => %{:name => "Gourde US Dollar", :symbol => " "},
:HUF => %{:name => "Forint", :symbol => "Ft"},
:IDR => %{:name => "Rupiah", :symbol => "Rp"},
:ILS => %{:name => "New Israeli Sheqel", :symbol => "₪"},
:INR => %{:name => "Indian Rupee", :symbol => " "},
:INR => %{:name => "Indian Rupee Ngultrum", :symbol => " "},
:BTN => %{:name => "Indian Rupee Ngultrum", :symbol => " "},
:IQD => %{:name => "Iraqi Dinar", :symbol => " "},
:IRR => %{:name => "Iranian Rial", :symbol => "﷼"},
:ISK => %{:name => "Iceland Krona", :symbol => "kr"},
:JMD => %{:name => "Jamaican Dollar", :symbol => "J$"},
:JOD => %{:name => "Jordanian Dinar", :symbol => " "},
:JPY => %{:name => "Yen", :symbol => "¥"},
:KES => %{:name => "Kenyan Shilling", :symbol => " "},
:KGS => %{:name => "Som", :symbol => "лв"},
:KHR => %{:name => "Riel", :symbol => "៛"},
:KMF => %{:name => "Comoro Franc", :symbol => " "},
:KPW => %{:name => "North Korean Won", :symbol => "₩"},
:KRW => %{:name => "Won", :symbol => "₩"},
:KWD => %{:name => "Kuwaiti Dinar", :symbol => " "},
:KYD => %{:name => "Cayman Islands Dollar", :symbol => "$"},
:KZT => %{:name => "Tenge", :symbol => "лв"},
:LAK => %{:name => "Kip", :symbol => "₭"},
:LBP => %{:name => "Lebanese Pound", :symbol => "£"},
:LKR => %{:name => "Sri Lanka Rupee", :symbol => "₨"},
:LRD => %{:name => "Liberian Dollar", :symbol => "$"},
:LTL => %{:name => "Lithuanian Litas", :symbol => "Lt"},
:LVL => %{:name => "Latvian Lats", :symbol => "Ls"},
:LYD => %{:name => "Libyan Dinar", :symbol => " "},
:MAD => %{:name => "Moroccan Dirham", :symbol => " "},
:MDL => %{:name => "Moldovan Leu", :symbol => " "},
:MGA => %{:name => "Malagasy Ariary", :symbol => " "},
:MKD => %{:name => "Denar", :symbol => "ден"},
:MMK => %{:name => "Kyat", :symbol => " "},
:MNT => %{:name => "Tugrik", :symbol => "₮"},
:MOP => %{:name => "Pataca", :symbol => " "},
:MRO => %{:name => "Ouguiya", :symbol => " "},
:MUR => %{:name => "Mauritius Rupee", :symbol => "₨"},
:MVR => %{:name => "Rufiyaa", :symbol => " "},
:MWK => %{:name => "Kwacha", :symbol => " "},
:MXN => %{:name => "Mexican Peso Mexican Unidad de Inversion (UDI)", :symbol => "$"},
:MXV => %{:name => "Mexican Peso Mexican Unidad de Inversion (UDI)", :symbol => "$"},
:MYR => %{:name => "Malaysian Ringgit", :symbol => "RM"},
:MZN => %{:name => "Metical", :symbol => "MT"},
:NGN => %{:name => "Naira", :symbol => "₦"},
:NIO => %{:name => "Cordoba Oro", :symbol => "C$"},
:NOK => %{:name => "Norwegian Krone", :symbol => "kr"},
:NPR => %{:name => "Nepalese Rupee", :symbol => "₨"},
:NZD => %{:name => "New Zealand Dollar", :symbol => "$"},
:OMR => %{:name => "Rial Omani", :symbol => "﷼"},
:PAB => %{:name => "Balboa US Dollar", :symbol => "B/."},
:PEN => %{:name => "Nuevo Sol", :symbol => "S/."},
:PGK => %{:name => "Kina", :symbol => " "},
:PHP => %{:name => "Philippine Peso", :symbol => "Php"},
:PKR => %{:name => "Pakistan Rupee", :symbol => "₨"},
:PLN => %{:name => "Zloty", :symbol => "zł"},
:PYG => %{:name => "Guarani", :symbol => "Gs"},
:QAR => %{:name => "Qatari Rial", :symbol => "﷼"},
:RON => %{:name => "New Leu", :symbol => "lei"},
:RSD => %{:name => "Serbian Dinar", :symbol => "Дин."},
:RUB => %{:name => "Russian Ruble", :symbol => "руб"},
:RWF => %{:name => "Rwanda Franc", :symbol => " "},
:SAR => %{:name => "Saudi Riyal", :symbol => "﷼"},
:SBD => %{:name => "Solomon Islands Dollar", :symbol => "$"},
:SCR => %{:name => "Seychelles Rupee", :symbol => "₨"},
:SDG => %{:name => "Sudanese Pound", :symbol => " "},
:SEK => %{:name => "Swedish Krona", :symbol => "kr"},
:SGD => %{:name => "Singapore Dollar", :symbol => "$"},
:SHP => %{:name => "Saint Helena Pound", :symbol => "£"},
:SLL => %{:name => "Leone", :symbol => " "},
:SOS => %{:name => "Somali Shilling", :symbol => "S"},
:SRD => %{:name => "Surinam Dollar", :symbol => "$"},
:STD => %{:name => "Dobra", :symbol => " "},
:SVC => %{:name => "El Salvador Colon US Dollar", :symbol => "$"},
:SYP => %{:name => "Syrian Pound", :symbol => "£"},
:SZL => %{:name => "Lilangeni", :symbol => " "},
:THB => %{:name => "Baht", :symbol => "฿"},
:TJS => %{:name => "Somoni", :symbol => " "},
:TMT => %{:name => "Manat", :symbol => " "},
:TND => %{:name => "Tunisian Dinar", :symbol => " "},
:TOP => %{:name => "Pa'anga", :symbol => " "},
:TRY => %{:name => "Turkish Lira", :symbol => "TL"},
:TTD => %{:name => "Trinidad and Tobago Dollar", :symbol => "TT$"},
:TWD => %{:name => "New Taiwan Dollar", :symbol => "NT$"},
:TZS => %{:name => "Tanzanian Shilling", :symbol => " "},
:UAH => %{:name => "Hryvnia", :symbol => "₴"},
:UGX => %{:name => "Uganda Shilling", :symbol => " "},
:USD => %{:name => "US Dollar", :symbol => "$"},
:UYU => %{:name => "Peso Uruguayo Uruguay Peso en Unidades Indexadas", :symbol => "$U"},
:UYI => %{:name => "Peso Uruguayo Uruguay Peso en Unidades Indexadas", :symbol => "$U"},
:UZS => %{:name => "Uzbekistan Sum", :symbol => "лв"},
:VEF => %{:name => "Bolivar Fuerte", :symbol => "Bs"},
:VND => %{:name => "Dong", :symbol => "₫"},
:VUV => %{:name => "Vatu", :symbol => " "},
:WST => %{:name => "Tala", :symbol => " "},
:XAF => %{:name => "CFA Franc BEAC", :symbol => " "},
:XAG => %{:name => "Silver", :symbol => " "},
:XAU => %{:name => "Gold", :symbol => " "},
:XBA => %{:name => "Bond Markets Units European Composite Unit (EURCO)", :symbol => " "},
:XBB => %{:name => "European Monetary Unit (E.M.U.-6)", :symbol => " "},
:XBC => %{:name => "European Unit of Account 9(E.U.A.-9)", :symbol => " "},
:XBD => %{:name => "European Unit of Account 17(E.U.A.-17)", :symbol => " "},
:XCD => %{:name => "East Caribbean Dollar", :symbol => "$"},
:XDR => %{:name => "SDR", :symbol => " "},
:XFU => %{:name => "UIC-Franc", :symbol => " "},
:XOF => %{:name => "CFA Franc BCEAO", :symbol => " "},
:XPD => %{:name => "Palladium", :symbol => " "},
:XPF => %{:name => "CFP Franc", :symbol => " "},
:XPT => %{:name => "Platinum", :symbol => " "},
:XTS => %{:name => "Codes specifically reserved for testing purposes", :symbol => " "},
:YER => %{:name => "Yemeni Rial", :symbol => "﷼"},
:ZAR => %{:name => "Rand", :symbol => "R"},
:ZAR => %{:name => "Rand Loti", :symbol => " "},
:LSL => %{:name => "Rand Loti", :symbol => " "},
:ZAR => %{:name => "Rand Namibia Dollar", :symbol => " "},
:NAD => %{:name => "Rand Namibia Dollar", :symbol => " "},
:ZMK => %{:name => "Zambian Kwacha", :symbol => " "},
:ZWL => %{:name => "Zimbabwe Dollar", :symbol => " "}
}
end
[:AED, :AFN, :ALL, :AMD, :ANG, :AOA, :ARS, :AUD, :AWG, :AZN, :BAM, :BBD, :BDT, :BGN, :BHD, :BIF, :BMD, :BND, :BOB, :BOV, :BRL, :BSD, :BWP, :BYR, :BZD, :CAD, :CDF, :CHF, :CLF, :CLP, :CNY, :COP, :COU, :CRC, :CUP, :CUC, :CVE, :CZK, :DJF, :DKK, :DOP, :DZD, :EEK, :EGP, :ERN, :ETB, :EUR, :FJD, :FKP, :GBP, :GEL, :GHS, :GIP, :GMD, :GNF, :GTQ, :GYD, :HKD, :HNL, :HRK, :HTG, :HUF, :IDR, :ILS, :INR, :INR, :BTN, :IQD, :IRR, :ISK, :JMD, :JOD, :JPY, :KES, :KGS, :KHR, :KMF, :KPW, :KRW, :KWD, :KYD, :KZT, :LAK, :LBP, :LKR, :LRD, :LTL, :LVL, :LYD, :MAD, :MDL, :MGA, :MKD, :MMK, :MNT, :MOP, :MRO, :MUR, :MVR, :MWK, :MXN, :MXV, :MYR, :MZN, :NGN, :NIO, :NOK, :NPR, :NZD, :OMR, :PAB, :PEN, :PGK, :PHP, :PKR, :PLN, :PYG, :QAR, :RON, :RSD, :RUB, :RWF, :SAR, :SBD, :SCR, :SDG, :SEK, :SGD, :SHP, :SLL, :SOS, :SRD, :STD, :SVC, :SYP, :SZL, :THB, :TJS, :TMT, :TND, :TOP, :TRY, :TTD, :TWD, :TZS, :UAH, :UGX, :USD, :UYU, :UYI, :UZS, :VEF, :VND, :VUV, :WST, :XAF, :XAG, :XAU, :XBA, :XBB, :XBC, :XBD, :XCD, :XDR, :XFU, :XOF, :XPD, :XPF, :XPT, :XTS, :YER, :ZAR, :ZAR, :LSL, :ZAR, :NAD, :ZMK, :ZWL] |> Enum.each fn name ->
currency = to_string(name) |> String.Unicode.downcase
def unquote(:"#{currency}")(amount) do
new(amount, unquote(name))
end
end
defp currency_exist?(currency) do
currency_all
|> Dict.has_key?(currency)
end
def get_currency(currency) do
currency_all
|> Dict.get(currency)
end
@spec compare(t, t) :: t
def compare(%Money{currency: cur1} = a, %Money{currency: cur1} = b) do
case a.amount - b.amount do
x when x>0 -> 1
x when x<0 -> -1
x when x==0 -> 0
end
end
def compare(a, b) do
raise fail_currencies_must_be_equal(a,b)
end
@spec zero?(t) :: boolean
def zero?(a) do
a.amount == 0
end
@spec positive?(t) :: boolean
def positive?(a) do
a.amount > 0
end
@spec negative?(t) :: boolean
def negative?(a) do
a.amount < 0
end
@spec equals?(t, t) :: boolean
def equals?(a, b) do
compare(a, b) == 0
end
@spec add(t, t|integer) :: t
def add(%Money{currency: cur1} = a, %Money{currency: cur1} = b) do
x = a.amount + b.amount
Money.new(x, cur1)
end
def add(%Money{currency: cur1} = a, addend) when is_integer(addend) do
x = a.amount + addend
Money.new(x, cur1)
end
def add(a, b) do
fail_currencies_must_be_equal(a, b)
end
@spec subtract(t, t|integer) :: t
def subtract(%Money{currency: cur1} = a, %Money{currency: cur1} = b) do
x = a.amount - b.amount
Money.new(x, cur1)
end
def subtract(%Money{currency: cur1} = a, subtrahend) when is_integer(subtrahend) do
x = a.amount - subtrahend
Money.new(x, cur1)
end
def subtract(a, b) do
fail_currencies_must_be_equal(a, b)
end
@spec multiply(t, t|integer) :: t
def multiply(%Money{currency: cur1} = a, %Money{currency: cur1} = b) do
x = a.amount * b.amount
Money.new(x, cur1)
end
def multiply(%Money{currency: cur1} = a, multiplier) when is_integer(multiplier) do
x = a.amount * multiplier
Money.new(x, cur1)
end
def multiply(a, b) do
fail_currencies_must_be_equal(a, b)
end
@spec divide(t, t|integer) :: t
def divide(%Money{currency: cur1} = a, %Money{currency: cur1} = b) do
x = round(a.amount / b.amount)
Money.new(x, cur1)
end
def divide(%Money{currency: cur1} = a, divisor) when is_integer(divisor) do
x = round(a.amount / divisor)
Money.new(x, cur1)
end
def divide(a, b) do
fail_currencies_must_be_equal(a, b)
end
@spec to_string(t) :: String.t
def to_string(%Money{} = m) do
decimal_amount = decimal_amount(m)
symbol = currency_symbol(m)
"#{symbol} #{decimal_amount}"
end
def decimal_amount(%Money{amount: money_amount} = money) do
Float.round(money_amount/100 ,2)
end
defp fail_currencies_must_be_equal(a, b) do
raise ArgumentError, message: "Currency of #{a.currency} must be the same as #{b.currency}"
end
end