shopify-money 3.2.0 → 3.2.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/Gemfile.lock +9 -8
- data/README.md +39 -0
- data/lib/money/config.rb +2 -1
- data/lib/money/converters/converter.rb +24 -0
- data/lib/money/converters/factory.rb +25 -0
- data/lib/money/converters/iso4217_converter.rb +12 -0
- data/lib/money/converters/legacy_dollars_converter.rb +12 -0
- data/lib/money/converters/stripe_converter.rb +37 -0
- data/lib/money/helpers.rb +0 -6
- data/lib/money/money.rb +4 -23
- data/lib/money/version.rb +1 -1
- data/lib/money.rb +8 -3
- data/lib/money_column/active_record_hooks.rb +18 -3
- data/money.gemspec +2 -0
- data/spec/converters_spec.rb +84 -0
- data/spec/money_column_spec.rb +15 -0
- data/spec/money_spec.rb +49 -0
- metadata +21 -1
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: d16632a569c75054c496e3d341e83ffb2ce08e25177b0c12a344c9b1c5fa23c2
|
4
|
+
data.tar.gz: 43d4b4e5f1c8b79c2d366dbad9077056cdd00744a86035ff58931e192b8fbff7
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: a15a1d6761fd8bed35cedf19ebec19b03aa7a8f10eb03c52004ce6fb166158feab2bba29a41f7fb005cf49339d39361f572c3636e716dd80dbd0a2a702db1476
|
7
|
+
data.tar.gz: e2b3760497b1d8c4947ae5adea3592a01e625e41d4d916a8155c0d18809358a040e63b897edd5942030ec8652e7e39487adb5b965023b991c8e100fa4f637c73
|
data/Gemfile.lock
CHANGED
@@ -1,7 +1,8 @@
|
|
1
1
|
PATH
|
2
2
|
remote: .
|
3
3
|
specs:
|
4
|
-
shopify-money (3.2.
|
4
|
+
shopify-money (3.2.1)
|
5
|
+
bigdecimal (>= 3.0)
|
5
6
|
|
6
7
|
GEM
|
7
8
|
remote: https://rubygems.org/
|
@@ -107,8 +108,8 @@ GEM
|
|
107
108
|
pp (>= 0.6.0)
|
108
109
|
rdoc (>= 4.0.0)
|
109
110
|
reline (>= 0.4.2)
|
110
|
-
json (2.
|
111
|
-
language_server-protocol (3.17.0.
|
111
|
+
json (2.12.2)
|
112
|
+
language_server-protocol (3.17.0.5)
|
112
113
|
lint_roller (1.1.0)
|
113
114
|
logger (1.7.0)
|
114
115
|
loofah (2.24.0)
|
@@ -148,8 +149,8 @@ GEM
|
|
148
149
|
nokogiri (1.18.7-x86_64-linux-gnu)
|
149
150
|
racc (~> 1.4)
|
150
151
|
ostruct (0.6.1)
|
151
|
-
parallel (1.
|
152
|
-
parser (3.3.
|
152
|
+
parallel (1.27.0)
|
153
|
+
parser (3.3.8.0)
|
153
154
|
ast (~> 2.4.1)
|
154
155
|
racc
|
155
156
|
pp (0.6.2)
|
@@ -223,7 +224,7 @@ GEM
|
|
223
224
|
diff-lcs (>= 1.2.0, < 2.0)
|
224
225
|
rspec-support (~> 3.13.0)
|
225
226
|
rspec-support (3.13.1)
|
226
|
-
rubocop (1.75.
|
227
|
+
rubocop (1.75.7)
|
227
228
|
json (~> 2.3)
|
228
229
|
language_server-protocol (~> 3.17.0.2)
|
229
230
|
lint_roller (~> 1.1.0)
|
@@ -234,14 +235,14 @@ GEM
|
|
234
235
|
rubocop-ast (>= 1.44.0, < 2.0)
|
235
236
|
ruby-progressbar (~> 1.7)
|
236
237
|
unicode-display_width (>= 2.4.0, < 4.0)
|
237
|
-
rubocop-ast (1.44.
|
238
|
+
rubocop-ast (1.44.1)
|
238
239
|
parser (>= 3.3.7.2)
|
239
240
|
prism (~> 1.4)
|
240
241
|
rubocop-performance (1.25.0)
|
241
242
|
lint_roller (~> 1.1)
|
242
243
|
rubocop (>= 1.75.0, < 2.0)
|
243
244
|
rubocop-ast (>= 1.38.0, < 2.0)
|
244
|
-
rubocop-shopify (2.
|
245
|
+
rubocop-shopify (2.17.0)
|
245
246
|
rubocop (~> 1.62)
|
246
247
|
ruby-progressbar (1.13.0)
|
247
248
|
securerandom (0.4.1)
|
data/README.md
CHANGED
@@ -165,6 +165,45 @@ Money.configure do |config|
|
|
165
165
|
end
|
166
166
|
```
|
167
167
|
|
168
|
+
### Converters
|
169
|
+
The Money gem provides a flexible converter system for handling different subunit formats. This is particularly useful when working with payment providers or APIs that have their own conventions for handling currency subunits.
|
170
|
+
|
171
|
+
#### Built-in Converters
|
172
|
+
- `:iso4217` (default) - Uses the standard ISO 4217 subunit definitions
|
173
|
+
- `:stripe` - Uses Stripe's special cases for certain currencies
|
174
|
+
- `:legacy_dollar` - Always uses 100 as the subunit_to_unit value
|
175
|
+
|
176
|
+
#### Using Converters
|
177
|
+
```ruby
|
178
|
+
# Convert to subunits using ISO4217 format (default)
|
179
|
+
Money.new(1.00, 'USD').subunits # => 100
|
180
|
+
Money.new(1.00, 'ISK').subunits # => 1
|
181
|
+
|
182
|
+
# Convert to subunits using Stripe format
|
183
|
+
Money.new(1.00, 'ISK').subunits(format: :stripe) # => 100
|
184
|
+
|
185
|
+
# Convert from subunits
|
186
|
+
Money.from_subunits(100, 'ISK', format: :stripe) # => Money.new(1.00, 'ISK')
|
187
|
+
```
|
188
|
+
|
189
|
+
#### Custom Converters
|
190
|
+
You can create your own converter by subclassing `Money::Converters::Converter`:
|
191
|
+
|
192
|
+
```ruby
|
193
|
+
class MyCustomConverter < Money::Converters::Converter
|
194
|
+
def subunit_to_unit(currency)
|
195
|
+
# Your custom logic here
|
196
|
+
1000
|
197
|
+
end
|
198
|
+
end
|
199
|
+
|
200
|
+
# Register your converter
|
201
|
+
Money::Converters.register(:my_format, MyCustomConverter)
|
202
|
+
|
203
|
+
# Use your converter
|
204
|
+
Money.new(1.00, 'USD').subunits(format: :my_format) # => 1000
|
205
|
+
```
|
206
|
+
|
168
207
|
## Money column
|
169
208
|
|
170
209
|
Since money internally uses BigDecimal it's logical to use a `decimal` column
|
data/lib/money/config.rb
CHANGED
@@ -41,7 +41,7 @@ class Money
|
|
41
41
|
end
|
42
42
|
end
|
43
43
|
|
44
|
-
attr_accessor :legacy_json_format, :legacy_deprecations, :experimental_crypto_currencies
|
44
|
+
attr_accessor :legacy_json_format, :legacy_deprecations, :experimental_crypto_currencies, :default_subunit_format
|
45
45
|
|
46
46
|
attr_reader :default_currency
|
47
47
|
alias_method :currency, :default_currency
|
@@ -80,6 +80,7 @@ class Money
|
|
80
80
|
@legacy_json_format = false
|
81
81
|
@legacy_deprecations = false
|
82
82
|
@experimental_crypto_currencies = false
|
83
|
+
@default_subunit_format = :iso4217
|
83
84
|
end
|
84
85
|
end
|
85
86
|
end
|
@@ -0,0 +1,24 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
class Money
|
4
|
+
module Converters
|
5
|
+
class Converter
|
6
|
+
def to_subunits(money)
|
7
|
+
raise ArgumentError, "money cannot be nil" if money.nil?
|
8
|
+
(money.value * subunit_to_unit(money.currency)).to_i
|
9
|
+
end
|
10
|
+
|
11
|
+
def from_subunits(subunits, currency)
|
12
|
+
currency = Helpers.value_to_currency(currency)
|
13
|
+
value = Helpers.value_to_decimal(subunits) / subunit_to_unit(currency)
|
14
|
+
Money.new(value, currency)
|
15
|
+
end
|
16
|
+
|
17
|
+
protected
|
18
|
+
|
19
|
+
def subunit_to_unit(currency)
|
20
|
+
raise NotImplementedError, "subunit_to_unit method must be implemented in subclasses"
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
@@ -0,0 +1,25 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
class Money
|
4
|
+
module Converters
|
5
|
+
class << self
|
6
|
+
def subunit_converters
|
7
|
+
@subunit_converters ||= {}
|
8
|
+
end
|
9
|
+
|
10
|
+
def register(key, klass)
|
11
|
+
subunit_converters[key.to_sym] = klass
|
12
|
+
end
|
13
|
+
|
14
|
+
def for(format)
|
15
|
+
format ||= Money::Config.current.default_subunit_format
|
16
|
+
|
17
|
+
if (klass = subunit_converters[format.to_sym])
|
18
|
+
klass.new
|
19
|
+
else
|
20
|
+
raise(ArgumentError, "unknown format: '#{format}'")
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
@@ -0,0 +1,12 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
class Money
|
4
|
+
module Converters
|
5
|
+
class Iso4217Converter < Converter
|
6
|
+
def subunit_to_unit(currency)
|
7
|
+
currency.subunit_to_unit
|
8
|
+
end
|
9
|
+
end
|
10
|
+
end
|
11
|
+
end
|
12
|
+
Money::Converters.register(:iso4217, Money::Converters::Iso4217Converter)
|
@@ -0,0 +1,12 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
class Money
|
4
|
+
module Converters
|
5
|
+
class LegacyDollarsConverter < Converter
|
6
|
+
def subunit_to_unit(currency)
|
7
|
+
100
|
8
|
+
end
|
9
|
+
end
|
10
|
+
end
|
11
|
+
end
|
12
|
+
Money::Converters.register(:legacy_dollar, Money::Converters::LegacyDollarsConverter)
|
@@ -0,0 +1,37 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
class Money
|
4
|
+
module Converters
|
5
|
+
class StripeConverter < Iso4217Converter
|
6
|
+
SUBUNIT_TO_UNIT = {
|
7
|
+
# https://docs.stripe.com/currencies#special-cases
|
8
|
+
'ISK' => 100,
|
9
|
+
'UGX' => 100,
|
10
|
+
'HUF' => 100,
|
11
|
+
'TWD' => 100,
|
12
|
+
# https://docs.stripe.com/currencies#zero-decimal
|
13
|
+
'BIF' => 1,
|
14
|
+
'CLP' => 1,
|
15
|
+
'DJF' => 1,
|
16
|
+
'GNF' => 1,
|
17
|
+
'JPY' => 1,
|
18
|
+
'KMF' => 1,
|
19
|
+
'KRW' => 1,
|
20
|
+
'MGA' => 1,
|
21
|
+
'PYG' => 1,
|
22
|
+
'RWF' => 1,
|
23
|
+
'VND' => 1,
|
24
|
+
'VUV' => 1,
|
25
|
+
'XAF' => 1,
|
26
|
+
'XOF' => 1,
|
27
|
+
'XPF' => 1,
|
28
|
+
'USDC' => 1_000_000,
|
29
|
+
}.freeze
|
30
|
+
|
31
|
+
def subunit_to_unit(currency)
|
32
|
+
SUBUNIT_TO_UNIT.fetch(currency.iso_code, super)
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|
37
|
+
Money::Converters.register(:stripe, Money::Converters::StripeConverter)
|
data/lib/money/helpers.rb
CHANGED
data/lib/money/money.rb
CHANGED
@@ -87,19 +87,8 @@ class Money
|
|
87
87
|
end
|
88
88
|
alias_method :from_amount, :new
|
89
89
|
|
90
|
-
def from_subunits(subunits, currency_iso, format:
|
91
|
-
|
92
|
-
|
93
|
-
subunit_to_unit_value = if format == :iso4217
|
94
|
-
currency.subunit_to_unit
|
95
|
-
elsif format == :stripe
|
96
|
-
Helpers::STRIPE_SUBUNIT_OVERRIDE.fetch(currency.iso_code, currency.subunit_to_unit)
|
97
|
-
else
|
98
|
-
raise ArgumentError, "unknown format #{format}"
|
99
|
-
end
|
100
|
-
|
101
|
-
value = Helpers.value_to_decimal(subunits) / subunit_to_unit_value
|
102
|
-
new(value, currency)
|
90
|
+
def from_subunits(subunits, currency_iso, format: nil)
|
91
|
+
Converters.for(format).from_subunits(subunits, currency_iso)
|
103
92
|
end
|
104
93
|
|
105
94
|
def from_json(string)
|
@@ -160,16 +149,8 @@ class Money
|
|
160
149
|
coder['currency'] = @currency.iso_code
|
161
150
|
end
|
162
151
|
|
163
|
-
def subunits(format:
|
164
|
-
|
165
|
-
@currency.subunit_to_unit
|
166
|
-
elsif format == :stripe
|
167
|
-
Helpers::STRIPE_SUBUNIT_OVERRIDE.fetch(@currency.iso_code, @currency.subunit_to_unit)
|
168
|
-
else
|
169
|
-
raise ArgumentError, "unknown format #{format}"
|
170
|
-
end
|
171
|
-
|
172
|
-
(@value * subunit_to_unit_value).to_i
|
152
|
+
def subunits(format: nil)
|
153
|
+
Converters.for(format).to_subunits(self)
|
173
154
|
end
|
174
155
|
|
175
156
|
def no_currency?
|
data/lib/money/version.rb
CHANGED
data/lib/money.rb
CHANGED
@@ -1,19 +1,24 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
3
|
require_relative 'money/version'
|
4
|
-
require_relative 'money/parser/fuzzy'
|
5
|
-
require_relative 'money/helpers'
|
6
4
|
require_relative 'money/currency'
|
7
5
|
require_relative 'money/null_currency'
|
8
6
|
require_relative 'money/allocator'
|
9
7
|
require_relative 'money/splitter'
|
10
8
|
require_relative 'money/config'
|
11
9
|
require_relative 'money/money'
|
10
|
+
require_relative 'money/converters/factory'
|
11
|
+
require_relative 'money/converters/converter'
|
12
|
+
require_relative 'money/converters/iso4217_converter'
|
13
|
+
require_relative 'money/converters/stripe_converter'
|
14
|
+
require_relative 'money/converters/legacy_dollars_converter'
|
12
15
|
require_relative 'money/errors'
|
13
16
|
require_relative 'money/deprecations'
|
17
|
+
require_relative 'money/parser/fuzzy'
|
14
18
|
require_relative 'money/parser/accounting'
|
15
|
-
require_relative 'money/parser/locale_aware'
|
16
19
|
require_relative 'money/parser/simple'
|
20
|
+
require_relative 'money/parser/locale_aware'
|
21
|
+
require_relative 'money/helpers'
|
17
22
|
require_relative 'money/core_extensions'
|
18
23
|
require_relative 'money_column' if defined?(ActiveRecord)
|
19
24
|
require_relative 'money/railtie' if defined?(Rails::Railtie)
|
@@ -57,9 +57,8 @@ module MoneyColumn
|
|
57
57
|
end
|
58
58
|
|
59
59
|
if options[:currency_read_only]
|
60
|
-
|
61
|
-
|
62
|
-
msg = "[money_column] currency mismatch between #{currency} and #{money.currency} in column #{column}."
|
60
|
+
unless compatible_currency?(money, options)
|
61
|
+
msg = "Cannot update #{column}: Attempting to write a money with currency #{money.currency} to a record with currency #{currency}. If you do want to change the currency, either remove `currency_read_only` or update the record's currency manually"
|
63
62
|
if Money::Config.current.legacy_deprecations
|
64
63
|
Money.deprecate(msg)
|
65
64
|
else
|
@@ -73,6 +72,22 @@ module MoneyColumn
|
|
73
72
|
self[column] = money.value
|
74
73
|
end
|
75
74
|
|
75
|
+
def compatible_currency?(money, options)
|
76
|
+
currency_column = options[:currency_column]
|
77
|
+
currency = options[:currency] ||
|
78
|
+
@money_raw_new_attributes[currency_column.to_sym] ||
|
79
|
+
try(currency_column)
|
80
|
+
|
81
|
+
currency.nil? || money.currency.compatible?(Money::Helpers.value_to_currency(currency))
|
82
|
+
end
|
83
|
+
|
84
|
+
def _assign_attributes(new_attributes)
|
85
|
+
@money_raw_new_attributes = new_attributes.symbolize_keys
|
86
|
+
super
|
87
|
+
ensure
|
88
|
+
@money_raw_new_attributes = nil
|
89
|
+
end
|
90
|
+
|
76
91
|
module ClassMethods
|
77
92
|
attr_reader :money_column_options
|
78
93
|
|
data/money.gemspec
CHANGED
@@ -16,6 +16,8 @@ Gem::Specification.new do |s|
|
|
16
16
|
|
17
17
|
s.metadata['allowed_push_host'] = "https://rubygems.org"
|
18
18
|
|
19
|
+
s.add_dependency("bigdecimal", ">= 3.0")
|
20
|
+
|
19
21
|
s.add_development_dependency("bundler")
|
20
22
|
s.add_development_dependency("database_cleaner", "~> 2.0")
|
21
23
|
s.add_development_dependency("ostruct")
|
@@ -0,0 +1,84 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
require 'spec_helper'
|
3
|
+
|
4
|
+
RSpec.describe Money::Converters do
|
5
|
+
let(:usd) { Money::Currency.find!('USD') }
|
6
|
+
let(:ugx) { Money::Currency.find!('UGX') }
|
7
|
+
|
8
|
+
describe '.for' do
|
9
|
+
it 'returns Iso4217Converter for :iso4217' do
|
10
|
+
expect(Money::Converters.for(:iso4217)).to be_a(Money::Converters::Iso4217Converter)
|
11
|
+
end
|
12
|
+
|
13
|
+
it 'returns StripeConverter for :stripe' do
|
14
|
+
expect(Money::Converters.for(:stripe)).to be_a(Money::Converters::StripeConverter)
|
15
|
+
end
|
16
|
+
|
17
|
+
it 'returns LegacyDollarsConverter for :legacy_dollar' do
|
18
|
+
expect(Money::Converters.for(:legacy_dollar)).to be_a(Money::Converters::LegacyDollarsConverter)
|
19
|
+
end
|
20
|
+
|
21
|
+
it 'raises ArgumentError for unknown format' do
|
22
|
+
expect { Money::Converters.for(:unknown) }.to raise_error(ArgumentError, /unknown format/)
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
26
|
+
describe 'registering a custom converter' do
|
27
|
+
class DummyConverter < Money::Converters::Converter
|
28
|
+
def subunit_to_unit(currency); 42; end
|
29
|
+
end
|
30
|
+
|
31
|
+
class InvalidConverter < Money::Converters::Converter
|
32
|
+
# Intentionally not implementing subunit_to_unit
|
33
|
+
end
|
34
|
+
|
35
|
+
after { Money::Converters.subunit_converters.delete(:dummy) }
|
36
|
+
|
37
|
+
it 'registers and uses a custom converter' do
|
38
|
+
Money::Converters.register(:dummy, DummyConverter)
|
39
|
+
converter = Money::Converters.for(:dummy)
|
40
|
+
expect(converter).to be_a(DummyConverter)
|
41
|
+
expect(converter.to_subunits(Money.new(1, 'USD'))).to eq(42)
|
42
|
+
end
|
43
|
+
|
44
|
+
it 'raises NotImplementedError when subunit_to_unit is not implemented' do
|
45
|
+
Money::Converters.register(:invalid, InvalidConverter)
|
46
|
+
converter = Money::Converters.for(:invalid)
|
47
|
+
expect { converter.to_subunits(Money.new(1, 'USD')) }.to raise_error(NotImplementedError, "subunit_to_unit method must be implemented in subclasses")
|
48
|
+
end
|
49
|
+
end
|
50
|
+
|
51
|
+
describe Money::Converters::Iso4217Converter do
|
52
|
+
let(:converter) { described_class.new }
|
53
|
+
it 'uses currency.subunit_to_unit' do
|
54
|
+
expect(converter.to_subunits(Money.new(1, usd))).to eq(100)
|
55
|
+
expect(converter.from_subunits(100, usd)).to eq(Money.new(1, usd))
|
56
|
+
end
|
57
|
+
end
|
58
|
+
|
59
|
+
describe Money::Converters::StripeConverter do
|
60
|
+
let(:converter) { described_class.new }
|
61
|
+
|
62
|
+
it 'uses Stripe special cases' do
|
63
|
+
expect(converter.to_subunits(Money.new(1, ugx))).to eq(100)
|
64
|
+
expect(converter.from_subunits(100, ugx)).to eq(Money.new(1, ugx))
|
65
|
+
expect(converter.to_subunits(Money.new(1, usd))).to eq(100)
|
66
|
+
expect(converter.from_subunits(100, usd)).to eq(Money.new(1, usd))
|
67
|
+
end
|
68
|
+
|
69
|
+
it 'handles USDC if present' do
|
70
|
+
configure(experimental_crypto_currencies: true) do
|
71
|
+
expect(converter.to_subunits(Money.new(1, "usdc"))).to eq(1_000_000)
|
72
|
+
expect(converter.from_subunits(1_000_000, "usdc")).to eq(Money.new(1, "usdc"))
|
73
|
+
end
|
74
|
+
end
|
75
|
+
end
|
76
|
+
|
77
|
+
describe Money::Converters::LegacyDollarsConverter do
|
78
|
+
let(:converter) { described_class.new }
|
79
|
+
it 'always uses 100 as subunit_to_unit' do
|
80
|
+
expect(converter.to_subunits(Money.new(1, usd))).to eq(100)
|
81
|
+
expect(converter.from_subunits(100, usd)).to eq(Money.new(1, usd))
|
82
|
+
end
|
83
|
+
end
|
84
|
+
end
|
data/spec/money_column_spec.rb
CHANGED
@@ -412,4 +412,19 @@ RSpec.describe 'MoneyColumn' do
|
|
412
412
|
expect(record.price.currency.to_s).to eq('GBP')
|
413
413
|
end
|
414
414
|
end
|
415
|
+
|
416
|
+
describe 'updating amount and currency simultaneously' do
|
417
|
+
let(:record) { MoneyWithReadOnlyCurrency.create!(currency: "CAD") }
|
418
|
+
|
419
|
+
it 'allows updating both amount and currency at the same time' do
|
420
|
+
record.update!(
|
421
|
+
price: Money.new(10, 'USD'),
|
422
|
+
currency: 'USD'
|
423
|
+
)
|
424
|
+
record.reload
|
425
|
+
expect(record.price.value).to eq(10)
|
426
|
+
expect(record.price.currency.to_s).to eq('USD')
|
427
|
+
expect(record.currency).to eq('USD')
|
428
|
+
end
|
429
|
+
end
|
415
430
|
end
|
data/spec/money_spec.rb
CHANGED
@@ -167,6 +167,13 @@ RSpec.describe "Money" do
|
|
167
167
|
expect(Money.new("999999999999999999.99", "USD").to_s).to eq("999999999999999999.99")
|
168
168
|
end
|
169
169
|
|
170
|
+
it "to_fs formats with correct decimal places" do
|
171
|
+
expect(amount_money.to_fs).to eq("1.23")
|
172
|
+
expect(non_fractional_money.to_fs).to eq("1")
|
173
|
+
expect(Money.new(1.2345, 'USD').to_fs).to eq("1.23")
|
174
|
+
expect(Money.new(1.2345, 'BHD').to_fs).to eq("1.235")
|
175
|
+
end
|
176
|
+
|
170
177
|
it "to_fs raises ArgumentError on unsupported style" do
|
171
178
|
expect{ money.to_fs(:some_weird_style) }.to raise_error(ArgumentError)
|
172
179
|
end
|
@@ -758,6 +765,12 @@ RSpec.describe "Money" do
|
|
758
765
|
expect(Money.new(1, 'UGX').subunits(format: :stripe)).to eq(100)
|
759
766
|
end
|
760
767
|
|
768
|
+
it 'overrides the subunit_to_unit amount for USDC' do
|
769
|
+
configure(experimental_crypto_currencies: true) do
|
770
|
+
expect(Money.from_subunits(500000, "USDC", format: :stripe)).to eq(Money.new(0.50, 'USDC'))
|
771
|
+
end
|
772
|
+
end
|
773
|
+
|
761
774
|
it 'fallbacks to the default subunit_to_unit amount if no override is specified' do
|
762
775
|
expect(Money.new(1, 'USD').subunits(format: :stripe)).to eq(100)
|
763
776
|
end
|
@@ -1185,4 +1198,40 @@ RSpec.describe "Money" do
|
|
1185
1198
|
expect(Money.current_currency.iso_code).to eq("USD")
|
1186
1199
|
end
|
1187
1200
|
end
|
1201
|
+
|
1202
|
+
describe 'from_subunits' do
|
1203
|
+
it 'creates money from subunits using ISO4217 format' do
|
1204
|
+
expect(Money.from_subunits(100, 'USD')).to eq(Money.new(1.00, 'USD'))
|
1205
|
+
expect(Money.from_subunits(10, 'JPY')).to eq(Money.new(10, 'JPY'))
|
1206
|
+
end
|
1207
|
+
|
1208
|
+
it 'creates money from subunits using custom format' do
|
1209
|
+
expect(Money.from_subunits(100, 'USD', format: :iso4217)).to eq(Money.new(1.00, 'USD'))
|
1210
|
+
expect(Money.from_subunits(100, 'USD', format: :stripe)).to eq(Money.new(1.00, 'USD'))
|
1211
|
+
end
|
1212
|
+
|
1213
|
+
it 'raises error for unknown format' do
|
1214
|
+
expect {
|
1215
|
+
Money.from_subunits(100, 'USD', format: :unknown)
|
1216
|
+
}.to raise_error(ArgumentError, /unknown format/)
|
1217
|
+
end
|
1218
|
+
end
|
1219
|
+
|
1220
|
+
describe 'subunits' do
|
1221
|
+
it 'converts money to subunits using ISO4217 format' do
|
1222
|
+
expect(Money.new(1.00, 'USD').subunits).to eq(100)
|
1223
|
+
expect(Money.new(10, 'JPY').subunits).to eq(10)
|
1224
|
+
end
|
1225
|
+
|
1226
|
+
it 'converts money to subunits using custom format' do
|
1227
|
+
expect(Money.new(1.00, 'USD').subunits(format: :iso4217)).to eq(100)
|
1228
|
+
expect(Money.new(1.00, 'USD').subunits(format: :stripe)).to eq(100)
|
1229
|
+
end
|
1230
|
+
|
1231
|
+
it 'raises error for unknown format' do
|
1232
|
+
expect {
|
1233
|
+
Money.new(1.00, 'USD').subunits(format: :unknown)
|
1234
|
+
}.to raise_error(ArgumentError, /unknown format/)
|
1235
|
+
end
|
1236
|
+
end
|
1188
1237
|
end
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: shopify-money
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 3.2.
|
4
|
+
version: 3.2.1
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Shopify Inc
|
@@ -9,6 +9,20 @@ bindir: bin
|
|
9
9
|
cert_chain: []
|
10
10
|
date: 1980-01-02 00:00:00.000000000 Z
|
11
11
|
dependencies:
|
12
|
+
- !ruby/object:Gem::Dependency
|
13
|
+
name: bigdecimal
|
14
|
+
requirement: !ruby/object:Gem::Requirement
|
15
|
+
requirements:
|
16
|
+
- - ">="
|
17
|
+
- !ruby/object:Gem::Version
|
18
|
+
version: '3.0'
|
19
|
+
type: :runtime
|
20
|
+
prerelease: false
|
21
|
+
version_requirements: !ruby/object:Gem::Requirement
|
22
|
+
requirements:
|
23
|
+
- - ">="
|
24
|
+
- !ruby/object:Gem::Version
|
25
|
+
version: '3.0'
|
12
26
|
- !ruby/object:Gem::Dependency
|
13
27
|
name: bundler
|
14
28
|
requirement: !ruby/object:Gem::Requirement
|
@@ -137,6 +151,11 @@ files:
|
|
137
151
|
- lib/money.rb
|
138
152
|
- lib/money/allocator.rb
|
139
153
|
- lib/money/config.rb
|
154
|
+
- lib/money/converters/converter.rb
|
155
|
+
- lib/money/converters/factory.rb
|
156
|
+
- lib/money/converters/iso4217_converter.rb
|
157
|
+
- lib/money/converters/legacy_dollars_converter.rb
|
158
|
+
- lib/money/converters/stripe_converter.rb
|
140
159
|
- lib/money/core_extensions.rb
|
141
160
|
- lib/money/currency.rb
|
142
161
|
- lib/money/currency/loader.rb
|
@@ -164,6 +183,7 @@ files:
|
|
164
183
|
- money.gemspec
|
165
184
|
- spec/allocator_spec.rb
|
166
185
|
- spec/config_spec.rb
|
186
|
+
- spec/converters_spec.rb
|
167
187
|
- spec/core_extensions_spec.rb
|
168
188
|
- spec/currency/loader_spec.rb
|
169
189
|
- spec/currency_spec.rb
|