1

I use the Money gem to work with different currencies. I'm seeing a strange behavior with the "JPY" currency.

I have the following rates:

config.add_rate('USD', 'EUR', 0.92)
config.add_rate('USD', 'JPY', 123.0)

Trying to exchange currencies, I get strange results:

10.to_money.exchange_to('EUR')
=> #<Money fractional:920 currency:EUR>

10.to_money.exchange_to('JPY')
=> #<Money fractional:1230 currency:JPY>

The "JPY" conversion should be #<Money fractional:123000 currency:JPY>. Any ideas on what's going on?

the Tin Man
  • 158,662
  • 42
  • 215
  • 303
Artem Kalinchuk
  • 6,502
  • 7
  • 43
  • 57
  • 1
    How does `10.to_money` works? I am getting no method on Fixnum error. I have installed money gem – Wand Maker Dec 23 '15 at 20:37
  • You have to declare it in a variable. `money = Money.new(10, USD)` – Richard Hamilton Dec 23 '15 at 20:38
  • @RichardHamilton I am able to work with `Money.new`, but OP is using some kind of enhanced `Fixnum` that allows `to_money` method on number `10` - I am curious about that part – Wand Maker Dec 23 '15 at 20:39
  • Use `Money#format` method - you will see correct output. Fundamentally, it is still doing right thing. Output of `inspect` may be weird – Wand Maker Dec 23 '15 at 20:46
  • @WandMaker `format` returns a formatted string. I don't want to parse a string to get the value I need. I know it's a go-around but it won't work in my case. I don't think it's doing the right thing because `cents` returns 1230 when it should be 123000. – Artem Kalinchuk Dec 23 '15 at 20:52

1 Answers1

3

It really depends on definition of Currency. Below code shows that 10 USD is indeed equal to 1230 yen.

require "rails"
require "money-rails"

Money.add_rate('USD', 'EUR', 0.92)
Money.add_rate('USD', 'JPY', 123.0)

p 10.to_money.exchange_to('JPY') == Money.new(1230,"JPY")
#=> true

Your expectation that you should see 123000 may not be correct if you inspect the JPY currency

p Money.new(1230,"JPY").currency

#<Money::Currency id: jpy, priority: 6, symbol_first: true, thousands_separator: ,, html_entity: &#x00A5;, decimal_mark: ., name: Japanese Yen, symbol: ¥, subunit_to_unit: 1, exponent: 0.0, iso_code: JPY, iso_numeric: 392, subunit: , smallest_denomination: 1>

Important field to note in Currency definition is the value of subunit_to_unit: 1. As per documentation:

:subunit_to_unit the proportion between the unit and the subunit

This means that in case of Yen, the value displayed is in Yen, and it need not be multiplied by 100 as is the case with USD or EUR.

p 10.to_money.exchange_to('EUR')
#=> #<Money fractional:920 currency:EUR>
p 10.to_money.exchange_to('JPY')
#=> #<Money fractional:1230 currency:JPY>

Below is Currency definition for EUR

#<Money::Currency id: eur, priority: 2, symbol_first: true, thousands_separator: ., html_entity: &#x20AC;, decimal_mark: ,, name: Euro, symbol: €, subunit_to_unit: 100, exponent: 2.0, iso_code: EUR, iso_numeric: 978, subunit: Cent, smallest_denomination: 1>

In case of EUR, subunit_to_unit: 100 indicates that value is in cents (or equivalent)

Wand Maker
  • 18,476
  • 8
  • 53
  • 87
  • That explains it. Not very convenient since it messes up my calculations. – Artem Kalinchuk Dec 23 '15 at 22:20
  • I had the same issue with JPY. Yes, I confirm it's the subunit way to manage it that causes the issue. I found the good way to manage the conversion using "from_amount" constructor: `Money.from_amount(price, "JPY").exchange_to("USD")` instead of `Money.new(price, "JPY").exchange_to("USD")` – alex.bour Jun 15 '20 at 09:54