shopify-money 3.2.3 → 3.2.4

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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 36ae50865f51d78857ad4aadffe1a9acc8976fd248ba736d3e99b69487b5ba8a
4
- data.tar.gz: 4c8365727256cc699e4f0429e45e85b458234c98a2509773a9c19bae303e9af4
3
+ metadata.gz: 22d6b7f34e2df9d08722a1b5a3c4297bb95d68557b7e82c448476478336cf339
4
+ data.tar.gz: c267cac812901641a799ddc08afd446051f808c632d75ef62c8c80ad4237bf72
5
5
  SHA512:
6
- metadata.gz: cbc2bac8bffd0456c62d2722108fd0c869a716018b43e99636f161efe72b7bbd000753b256d843d97d29bca34263e514d0f26f6d989b9898339c04fdfed724ee
7
- data.tar.gz: 0eb55e57aeb3309adae9de14fc6cedad266708fa738809002c4d627751d699c7382062a81703e93476e34b40a5d045ca653c5e9f0761f5acb2f10f0277982bf7
6
+ metadata.gz: 4da3c3318564210997ae4e3a56c99e46d4702de1c19d258f61948f7aee0b978c7ccaea8f9be13d270216af9ad23d52d25e48a44e514e154014bd179ca217403f
7
+ data.tar.gz: e1378b9689d6e7a22cf4d9892a4802e09ecdca0e67b4bb3bc5a5c7c924fa06c3fdf0bea6ab5b4f65db206cd06c4becd5f23b0f46381ad425350aa4925d4b9e8b
data/Gemfile.lock CHANGED
@@ -1,7 +1,7 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- shopify-money (3.2.3)
4
+ shopify-money (3.2.4)
5
5
  bigdecimal (>= 3.0)
6
6
 
7
7
  GEM
@@ -81,7 +81,7 @@ GEM
81
81
  ast (2.4.3)
82
82
  base64 (0.2.0)
83
83
  benchmark (0.4.0)
84
- bigdecimal (3.1.9)
84
+ bigdecimal (3.2.2)
85
85
  builder (3.3.0)
86
86
  byebug (12.0.0)
87
87
  coderay (1.1.3)
data/lib/money/version.rb CHANGED
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  class Money
4
- VERSION = "3.2.3"
4
+ VERSION = "3.2.4"
5
5
  end
@@ -1,7 +1,9 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module MoneyColumn
4
- class CurrencyReadOnlyError < StandardError; end
4
+ class Error < StandardError; end
5
+ class CurrencyReadOnlyError < Error; end
6
+ class CurrencyMismatchError < Error; end
5
7
 
6
8
  module ActiveRecordHooks
7
9
  def self.included(base)
@@ -52,33 +54,63 @@ module MoneyColumn
52
54
  return self[column] = nil
53
55
  end
54
56
 
55
- unless money.is_a?(Money)
56
- return self[column] = Money::Helpers.value_to_decimal(money)
57
+ if money.is_a?(Money)
58
+ write_currency(column, money, options)
59
+ end
60
+
61
+ self[column] = Money::Helpers.value_to_decimal(money)
62
+ end
63
+
64
+ def write_currency(column, money, options)
65
+ currency_column = options[:currency_column]
66
+
67
+ if options[:currency]
68
+ validate_hardcoded_currency_compatibility!(column, money, options[:currency])
69
+ return
57
70
  end
58
71
 
59
72
  if options[:currency_read_only]
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"
62
- if Money::Config.current.legacy_deprecations
63
- Money.deprecate(msg)
64
- else
65
- raise MoneyColumn::CurrencyReadOnlyError, msg
66
- end
67
- end
68
- else
69
- self[options[:currency_column]] = money.currency.to_s unless money.no_currency?
73
+ validate_currency_compatibility!(column, money, currency_column)
74
+ return
70
75
  end
71
76
 
72
- self[column] = money.value
77
+ if currency_column && !money.no_currency?
78
+ self[currency_column] = money.currency.to_s
79
+ end
73
80
  end
74
81
 
75
- def compatible_currency?(money, options)
76
- currency_column = options[:currency_column]
77
- currency = options[:currency]
78
- currency ||= @money_raw_new_attributes[currency_column.to_sym] if @money_raw_new_attributes
79
- currency ||= try(currency_column)
82
+ def read_currency_column(currency_column)
83
+ if @money_raw_new_attributes&.key?(currency_column.to_sym)
84
+ # currency column in the process of being updated
85
+ return @money_raw_new_attributes[currency_column.to_sym]
86
+ end
80
87
 
81
- currency.nil? || money.currency.compatible?(Money::Helpers.value_to_currency(currency))
88
+ try(currency_column)
89
+ end
90
+
91
+ def validate_hardcoded_currency_compatibility!(column, money, expected_currency)
92
+ return if money.currency.compatible?(Money::Helpers.value_to_currency(expected_currency))
93
+
94
+ msg = "Invalid #{column}: attempting to write a money object with currency '#{money.currency}' to a record with hard-coded currency '#{expected_currency}'."
95
+ if Money::Config.current.legacy_deprecations
96
+ Money.deprecate(msg)
97
+ else
98
+ raise MoneyColumn::CurrencyMismatchError, msg
99
+ end
100
+ end
101
+
102
+ def validate_currency_compatibility!(column, money, currency_column)
103
+ current_currency = read_currency_column(currency_column)
104
+ return if current_currency.nil? || money.currency.compatible?(Money::Helpers.value_to_currency(current_currency))
105
+
106
+ msg = "Invalid #{column}: attempting to write a money object with currency '#{money.currency}' to a record with currency '#{current_currency}'. " \
107
+ "If you do want to change the record's currency, either remove `currency_read_only` or update the record's currency manually"
108
+
109
+ if Money::Config.current.legacy_deprecations
110
+ Money.deprecate(msg)
111
+ else
112
+ raise MoneyColumn::CurrencyReadOnlyError, msg
113
+ end
82
114
  end
83
115
 
84
116
  def _assign_attributes(new_attributes)
@@ -6,47 +6,47 @@ class MoneyRecord < ActiveRecord::Base
6
6
  before_validation do
7
7
  self.price_usd = Money.new(self["price"] * RATE, 'USD') if self["price"]
8
8
  end
9
- money_column :price, currency_column: 'currency'
10
- money_column :prix, currency_column: :devise
9
+ money_column :price, currency_column: 'price_currency'
10
+ money_column :prix, currency_column: :prix_currency
11
11
  money_column :price_usd, currency: 'USD'
12
12
  end
13
13
 
14
14
  class MoneyWithValidation < ActiveRecord::Base
15
15
  self.table_name = 'money_records'
16
- validates :price, :currency, presence: true
17
- money_column :price, currency_column: 'currency'
16
+ validates :price, :price_currency, presence: true
17
+ money_column :price, currency_column: 'price_currency'
18
18
  end
19
19
 
20
20
  class MoneyWithReadOnlyCurrency < ActiveRecord::Base
21
21
  self.table_name = 'money_records'
22
- money_column :price, currency_column: 'currency', currency_read_only: true
22
+ money_column :price, currency_column: 'price_currency', currency_read_only: true
23
23
  end
24
24
 
25
25
  class MoneyRecordCoerceNull < ActiveRecord::Base
26
26
  self.table_name = 'money_records'
27
- money_column :price, currency_column: 'currency', coerce_null: true
27
+ money_column :price, currency_column: 'price_currency', coerce_null: true
28
28
  money_column :price_usd, currency: 'USD', coerce_null: true
29
29
  end
30
30
 
31
31
  class MoneyWithDelegatedCurrency < ActiveRecord::Base
32
32
  self.table_name = 'money_records'
33
- delegate :currency, to: :delegated_record
34
- money_column :price, currency_column: 'currency', currency_read_only: true
33
+ delegate :price_currency, to: :delegated_record
34
+ money_column :price, currency_column: 'price_currency', currency_read_only: true
35
35
  money_column :prix, currency_column: 'currency2', currency_read_only: true
36
36
  def currency2
37
- delegated_record.currency
37
+ delegated_record.price_currency
38
38
  end
39
39
 
40
40
  private
41
41
 
42
42
  def delegated_record
43
- MoneyRecord.new(currency: 'USD')
43
+ MoneyRecord.new(price_currency: 'USD')
44
44
  end
45
45
  end
46
46
 
47
47
  class MoneyWithCustomAccessors < ActiveRecord::Base
48
48
  self.table_name = 'money_records'
49
- money_column :price, currency_column: 'currency'
49
+ money_column :price, currency_column: 'price_currency'
50
50
  def price
51
51
  read_money_attribute(:price)
52
52
  end
@@ -56,7 +56,7 @@ class MoneyWithCustomAccessors < ActiveRecord::Base
56
56
  end
57
57
 
58
58
  class MoneyClassInheritance < MoneyWithCustomAccessors
59
- money_column :prix, currency_column: 'currency'
59
+ money_column :prix, currency_column: 'price_currency'
60
60
  end
61
61
 
62
62
  class MoneyClassInheritance2 < MoneyWithCustomAccessors
@@ -71,7 +71,7 @@ RSpec.describe 'MoneyColumn' do
71
71
  let(:toonie) { Money.new(2.00, 'CAD') }
72
72
  let(:subject) { MoneyRecord.new(price: money, prix: toonie) }
73
73
  let(:record) do
74
- subject.devise = 'CAD'
74
+ subject.prix_currency = 'CAD'
75
75
  subject.save
76
76
  subject.reload
77
77
  end
@@ -81,7 +81,7 @@ RSpec.describe 'MoneyColumn' do
81
81
  end
82
82
 
83
83
  it 'writes the currency to the db' do
84
- record.update(currency: nil)
84
+ record.update(price_currency: nil)
85
85
  record.update(price: Money.new(4, 'JPY'))
86
86
  record.reload
87
87
  expect(record.price.value).to eq(4)
@@ -101,10 +101,35 @@ RSpec.describe 'MoneyColumn' do
101
101
  expect(record.price_usd).to eq(Money.new(1.44, 'USD'))
102
102
  end
103
103
 
104
+ describe 'hard-coded currency (currency: "USD")' do
105
+ let(:record) { MoneyRecord.new }
106
+
107
+ it 'raises CurrencyMismatchError when assigning Money with wrong currency' do
108
+ expect {
109
+ record.price_usd = Money.new(5, 'EUR')
110
+ }.to raise_error(MoneyColumn::CurrencyMismatchError)
111
+ end
112
+
113
+ it 'allows assigning Money with the correct currency' do
114
+ record.price_usd = Money.new(8, 'USD')
115
+ expect(record.price_usd.value).to eq(8)
116
+ expect(record.price_usd.currency.to_s).to eq('USD')
117
+ end
118
+
119
+ it 'deprecates (but does not raise) under legacy_deprecations' do
120
+ configure(legacy_deprecations: true) do
121
+ expect(Money).to receive(:deprecate).once
122
+ record.price_usd = Money.new(9, 'EUR')
123
+ expect(record.price_usd.value).to eq(9)
124
+ expect(record.price_usd.currency.to_s).to eq('USD')
125
+ end
126
+ end
127
+ end
128
+
104
129
  it 'returns money with null currency when the currency in the DB is invalid' do
105
130
  configure(legacy_deprecations: true) do
106
131
  expect(Money).to receive(:deprecate).once
107
- record.update_columns(currency: 'invalid')
132
+ record.update_columns(price_currency: 'invalid')
108
133
  record.reload
109
134
  expect(record.price.currency).to be_a(Money::NullCurrency)
110
135
  expect(record.price.value).to eq(1.23)
@@ -142,15 +167,15 @@ RSpec.describe 'MoneyColumn' do
142
167
  end
143
168
 
144
169
  it 'does not overwrite a currency column with a default currency when saving zero' do
145
- expect(record.currency.to_s).to eq('EUR')
170
+ expect(record.price_currency.to_s).to eq('EUR')
146
171
  record.update(price: Money.new(0, Money::NULL_CURRENCY))
147
- expect(record.currency.to_s).to eq('EUR')
172
+ expect(record.price_currency.to_s).to eq('EUR')
148
173
  end
149
174
 
150
175
  it 'does overwrite a currency' do
151
- expect(record.currency.to_s).to eq('EUR')
176
+ expect(record.price_currency.to_s).to eq('EUR')
152
177
  record.update(price: Money.new(4, 'JPY'))
153
- expect(record.currency.to_s).to eq('JPY')
178
+ expect(record.price_currency.to_s).to eq('JPY')
154
179
  end
155
180
 
156
181
  describe 'non-fractional-currencies' do
@@ -217,31 +242,31 @@ RSpec.describe 'MoneyColumn' do
217
242
 
218
243
  it 'is not allowed to be saved because `to_s` returns a blank string' do
219
244
  subject.valid?
220
- expect(subject.errors[:currency]).to include("can't be blank")
245
+ expect(subject.errors[:price_currency]).to include("can't be blank")
221
246
  end
222
247
  end
223
248
 
224
249
  describe 'read_only_currency true' do
225
250
  it 'raises CurrencyReadOnlyError when updating price with different currency' do
226
251
  record = MoneyWithReadOnlyCurrency.create
227
- record.update_columns(currency: 'USD')
252
+ record.update_columns(price_currency: 'USD')
228
253
  expect { record.update(price: Money.new(4, 'CAD')) }.to raise_error(MoneyColumn::CurrencyReadOnlyError)
229
254
  end
230
255
 
231
256
  it 'raises CurrencyReadOnlyError when assigning money with different currency' do
232
- record = MoneyWithReadOnlyCurrency.create(currency: 'USD', price: 1)
257
+ record = MoneyWithReadOnlyCurrency.create(price_currency: 'USD', price: 1)
233
258
  expect { record.price = Money.new(2, 'CAD') }.to raise_error(MoneyColumn::CurrencyReadOnlyError)
234
259
  end
235
260
 
236
261
  it 'allows updating price when currency matches existing currency' do
237
262
  record = MoneyWithReadOnlyCurrency.create
238
- record.update_columns(currency: 'USD')
263
+ record.update_columns(price_currency: 'USD')
239
264
  record.update(price: Money.new(4, 'USD'))
240
265
  expect(record.price.value).to eq(4)
241
266
  end
242
267
 
243
268
  it 'allows assigning price when currency matches existing currency' do
244
- record = MoneyWithReadOnlyCurrency.create(currency: 'CAD', price: 1)
269
+ record = MoneyWithReadOnlyCurrency.create(price_currency: 'CAD', price: 1)
245
270
  record.price = Money.new(2, 'CAD')
246
271
  expect(record.price.value).to eq(2)
247
272
  end
@@ -249,7 +274,7 @@ RSpec.describe 'MoneyColumn' do
249
274
  it 'legacy_deprecations does not write the currency to the db' do
250
275
  configure(legacy_deprecations: true) do
251
276
  record = MoneyWithReadOnlyCurrency.create
252
- record.update_columns(currency: 'USD')
277
+ record.update_columns(price_currency: 'USD')
253
278
 
254
279
  expect(Money).to receive(:deprecate).once
255
280
  record.update(price: Money.new(4, 'CAD'))
@@ -260,7 +285,7 @@ RSpec.describe 'MoneyColumn' do
260
285
 
261
286
  it 'reads the currency that is already in the db' do
262
287
  record = MoneyWithReadOnlyCurrency.create
263
- record.update_columns(currency: 'USD', price: 1)
288
+ record.update_columns(price_currency: 'USD', price: 1)
264
289
  record.reload
265
290
  expect(record.price.value).to eq(1)
266
291
  expect(record.price.currency.to_s).to eq('USD')
@@ -270,7 +295,7 @@ RSpec.describe 'MoneyColumn' do
270
295
  configure(legacy_deprecations: true) do
271
296
  expect(Money).to receive(:deprecate).once
272
297
  record = MoneyWithReadOnlyCurrency.create
273
- record.update_columns(currency: 'invalid', price: 1)
298
+ record.update_columns(price_currency: 'invalid', price: 1)
274
299
  record.reload
275
300
  expect(record.price.value).to eq(1)
276
301
  expect(record.price.currency.to_s).to eq('')
@@ -278,8 +303,8 @@ RSpec.describe 'MoneyColumn' do
278
303
  end
279
304
 
280
305
  it 'sets the currency correctly when the currency is changed' do
281
- record = MoneyWithReadOnlyCurrency.create(currency: 'CAD', price: 1)
282
- record.currency = 'USD'
306
+ record = MoneyWithReadOnlyCurrency.create(price_currency: 'CAD', price: 1)
307
+ record.price_currency = 'USD'
283
308
  expect(record.price.currency.to_s).to eq('USD')
284
309
  end
285
310
 
@@ -386,7 +411,7 @@ RSpec.describe 'MoneyColumn' do
386
411
 
387
412
  describe 'class inheritance' do
388
413
  it 'shares money columns declared on the parent class' do
389
- expect(MoneyClassInheritance.instance_variable_get(:@money_column_options).dig('price', :currency_column)).to eq('currency')
414
+ expect(MoneyClassInheritance.instance_variable_get(:@money_column_options).dig('price', :currency_column)).to eq('price_currency')
390
415
  expect(MoneyClassInheritance.instance_variable_get(:@money_column_options).dig('price', :currency)).to eq(nil)
391
416
  expect(MoneyClassInheritance.new(price: Money.new(1, 'USD')).price).to eq(Money.new(2, 'USD'))
392
417
  end
@@ -410,7 +435,7 @@ RSpec.describe 'MoneyColumn' do
410
435
  end
411
436
 
412
437
  it 'writes currency from input value to the db' do
413
- record.update(currency: nil)
438
+ record.update(price_currency: nil)
414
439
  record.update(price: Money.new(7, 'GBP'))
415
440
  record.reload
416
441
  expect(record.price.value).to eq(7)
@@ -418,13 +443,13 @@ RSpec.describe 'MoneyColumn' do
418
443
  end
419
444
 
420
445
  it 'raises missing currency error reading a value that was saved using legacy non-money object' do
421
- record.update(currency: nil, price: 3)
446
+ record.update(price_currency: nil, price: 3)
422
447
  expect { record.price }.to raise_error(ArgumentError, 'missing currency')
423
448
  end
424
449
 
425
450
  it 'handles legacy support for saving price and currency separately' do
426
- record.update(currency: nil)
427
- record.update(price: 7, currency: 'GBP')
451
+ record.update(price_currency: nil)
452
+ record.update(price: 7, price_currency: 'GBP')
428
453
  record.reload
429
454
  expect(record.price.value).to eq(7)
430
455
  expect(record.price.currency.to_s).to eq('GBP')
@@ -432,17 +457,17 @@ RSpec.describe 'MoneyColumn' do
432
457
  end
433
458
 
434
459
  describe 'updating amount and currency simultaneously' do
435
- let(:record) { MoneyWithReadOnlyCurrency.create!(currency: "CAD") }
460
+ let(:record) { MoneyWithReadOnlyCurrency.create!(price_currency: "CAD") }
436
461
 
437
462
  it 'allows updating both amount and currency at the same time' do
438
463
  record.update!(
439
464
  price: Money.new(10, 'USD'),
440
- currency: 'USD'
465
+ price_currency: 'USD'
441
466
  )
442
467
  record.reload
443
468
  expect(record.price.value).to eq(10)
444
469
  expect(record.price.currency.to_s).to eq('USD')
445
- expect(record.currency).to eq('USD')
470
+ expect(record.price_currency).to eq('USD')
446
471
  end
447
472
  end
448
473
 
@@ -451,7 +476,7 @@ RSpec.describe 'MoneyColumn' do
451
476
  record = MoneyRecord.create!(
452
477
  price: Money.new(100, 'USD'),
453
478
  prix: Money.new(200, 'EUR'),
454
- devise: 'EUR'
479
+ prix_currency: 'EUR'
455
480
  )
456
481
  record.reload
457
482
  expect(record.price.value).to eq(100)
@@ -506,36 +531,36 @@ RSpec.describe 'MoneyColumn' do
506
531
  it 'clears all money column caches when currency changes' do
507
532
  record = MoneyRecord.new(
508
533
  price: Money.new(100, 'USD'),
509
- currency: 'USD'
534
+ price_currency: 'USD'
510
535
  )
511
536
 
512
537
  expect(record.price).to eq(Money.new(100, 'USD'))
513
538
 
514
539
  # Change currency should invalidate the cache
515
- record.currency = 'EUR'
540
+ record.price_currency = 'EUR'
516
541
  expect(record.price.currency.to_s).to eq('EUR')
517
542
  end
518
543
 
519
544
  it 'only defines currency setter once for shared currency columns' do
520
545
  class MoneyWithSharedCurrency < ActiveRecord::Base
521
546
  self.table_name = 'money_records'
522
- money_column :price, currency_column: 'currency'
523
- money_column :prix, currency_column: 'currency'
547
+ money_column :price, currency_column: 'price_currency'
548
+ money_column :prix, currency_column: 'price_currency'
524
549
  end
525
550
 
526
551
  record = MoneyWithSharedCurrency.new
527
- methods_count = record.methods.count { |m| m.to_s == 'currency=' }
552
+ methods_count = record.methods.count { |m| m.to_s == 'price_currency=' }
528
553
  expect(methods_count).to eq(1)
529
554
  end
530
555
  end
531
556
 
532
557
  describe 'no_currency handling' do
533
558
  it 'does not write currency when money has no_currency' do
534
- record = MoneyRecord.create!(currency: 'USD')
559
+ record = MoneyRecord.create!(price_currency: 'USD')
535
560
  record.price = Money.new(100, Money::NULL_CURRENCY)
536
561
  record.save!
537
562
  record.reload
538
- expect(record.currency).to eq('USD')
563
+ expect(record.price_currency).to eq('USD')
539
564
  end
540
565
  end
541
566
 
@@ -574,7 +599,7 @@ RSpec.describe 'MoneyColumn' do
574
599
  describe 'ActiveRecord callbacks integration' do
575
600
  class MoneyWithCallbacks < ActiveRecord::Base
576
601
  self.table_name = 'money_records'
577
- money_column :price, currency_column: 'currency'
602
+ money_column :price, currency_column: 'price_currency'
578
603
 
579
604
  before_save :double_price
580
605
 
@@ -595,7 +620,7 @@ RSpec.describe 'MoneyColumn' do
595
620
  describe 'validation integration' do
596
621
  class MoneyWithCustomValidation < ActiveRecord::Base
597
622
  self.table_name = 'money_records'
598
- money_column :price, currency_column: 'currency'
623
+ money_column :price, currency_column: 'price_currency'
599
624
 
600
625
  validate :price_must_be_positive
601
626
 
@@ -621,9 +646,9 @@ RSpec.describe 'MoneyColumn' do
621
646
  describe 'ActiveRecord query interface' do
622
647
  before do
623
648
  MoneyRecord.delete_all
624
- MoneyRecord.create!(price: Money.new(100, 'USD'), currency: 'USD')
625
- MoneyRecord.create!(price: Money.new(200, 'USD'), currency: 'USD')
626
- MoneyRecord.create!(price: Money.new(150, 'EUR'), currency: 'EUR')
649
+ MoneyRecord.create!(price: Money.new(100, 'USD'), price_currency: 'USD')
650
+ MoneyRecord.create!(price: Money.new(200, 'USD'), price_currency: 'USD')
651
+ MoneyRecord.create!(price: Money.new(150, 'EUR'), price_currency: 'EUR')
627
652
  end
628
653
 
629
654
  it 'supports where queries with money values' do
@@ -663,13 +688,13 @@ RSpec.describe 'MoneyColumn' do
663
688
 
664
689
  describe 'attribute assignment' do
665
690
  it 'handles hash assignment with string keys' do
666
- record = MoneyRecord.new('price' => 100, 'currency' => 'USD')
691
+ record = MoneyRecord.new('price' => 100, 'price_currency' => 'USD')
667
692
  expect(record.price.value).to eq(100)
668
693
  expect(record.price.currency.to_s).to eq('USD')
669
694
  end
670
695
 
671
696
  it 'handles hash assignment with symbol keys' do
672
- record = MoneyRecord.new(price: 100, currency: 'USD')
697
+ record = MoneyRecord.new(price: 100, price_currency: 'USD')
673
698
  expect(record.price.value).to eq(100)
674
699
  expect(record.price.currency.to_s).to eq('USD')
675
700
  end
@@ -698,7 +723,7 @@ RSpec.describe 'MoneyColumn' do
698
723
 
699
724
  describe 'coerce_null with different scenarios' do
700
725
  it 'coerces nil to zero money with proper currency from column' do
701
- record = MoneyRecordCoerceNull.new(currency: 'EUR')
726
+ record = MoneyRecordCoerceNull.new(price_currency: 'EUR')
702
727
  expect(record.price.value).to eq(0)
703
728
  expect(record.price.currency.to_s).to eq('EUR')
704
729
  end
@@ -721,11 +746,11 @@ RSpec.describe 'MoneyColumn' do
721
746
  record.price = Money.new(100, 'USD')
722
747
  expect(record.price.value).to eq(100)
723
748
  # Currency is not written for read_only columns when not saved
724
- expect(record.currency).to be_nil
749
+ expect(record.price_currency).to be_nil
725
750
  end
726
751
 
727
752
  it 'allows setting money with compatible currency using string' do
728
- record = MoneyWithReadOnlyCurrency.create!(currency: 'USD')
753
+ record = MoneyWithReadOnlyCurrency.create!(price_currency: 'USD')
729
754
  record.price = Money.new(100, 'USD')
730
755
  expect(record.price.value).to eq(100)
731
756
  end
@@ -766,26 +791,26 @@ RSpec.describe 'MoneyColumn' do
766
791
  end
767
792
 
768
793
  it 'tracks currency changes' do
769
- record = MoneyRecord.create!(currency: 'USD', price: 100)
770
- record.currency = 'EUR'
794
+ record = MoneyRecord.create!(price_currency: 'USD', price: 100)
795
+ record.price_currency = 'EUR'
771
796
 
772
- expect(record.currency_changed?).to be true
773
- expect(record.currency_was).to eq('USD')
797
+ expect(record.price_currency_changed?).to be true
798
+ expect(record.price_currency_was).to eq('USD')
774
799
  end
775
800
  end
776
801
 
777
802
  describe 'mass assignment with currency updates' do
778
803
  it 'handles simultaneous updates of money and currency in mass assignment' do
779
- record = MoneyWithReadOnlyCurrency.create!(currency: 'USD', price: 100)
804
+ record = MoneyWithReadOnlyCurrency.create!(price_currency: 'USD', price: 100)
780
805
 
781
806
  record.assign_attributes(
782
- currency: 'EUR',
807
+ price_currency: 'EUR',
783
808
  price: Money.new(200, 'EUR')
784
809
  )
785
810
 
786
811
  expect { record.save! }.not_to raise_error
787
812
  expect(record.price.value).to eq(200)
788
- expect(record.currency).to eq('EUR')
813
+ expect(record.price_currency).to eq('EUR')
789
814
  end
790
815
  end
791
816
 
@@ -799,7 +824,7 @@ RSpec.describe 'MoneyColumn' do
799
824
 
800
825
  it 'preserves full precision for currencies with 3 decimal places' do
801
826
  # JOD has 3 minor units, so it preserves 3 decimal places
802
- record = MoneyRecord.create!(price: Money.new(123.456, 'JOD'), currency: 'JOD')
827
+ record = MoneyRecord.create!(price: Money.new(123.456, 'JOD'), price_currency: 'JOD')
803
828
  record.reload
804
829
  expect(record.price.value).to eq(123.456)
805
830
  end
@@ -807,7 +832,7 @@ RSpec.describe 'MoneyColumn' do
807
832
  it 'rounds database values beyond 3 decimal places' do
808
833
  record = MoneyRecord.new
809
834
  record['price'] = 123.4567
810
- record.currency = 'USD'
835
+ record.price_currency = 'USD'
811
836
  record.save!
812
837
  record.reload
813
838
  expect(record['price'].to_f.round(3)).to eq(123.457)
@@ -851,7 +876,7 @@ RSpec.describe 'MoneyColumn' do
851
876
  it 'allows direct writing of raw decimal value' do
852
877
  record = MoneyRecord.new
853
878
  record['price'] = 99.99
854
- record.currency = 'EUR'
879
+ record.price_currency = 'EUR'
855
880
  expect(record.price.value).to eq(99.99)
856
881
  expect(record.price.currency.to_s).to eq('EUR')
857
882
  end
@@ -900,7 +925,7 @@ RSpec.describe 'MoneyColumn' do
900
925
  describe 'error messages' do
901
926
  it 'provides clear error for missing currency when default_currency is nil' do
902
927
  configure(default_currency: nil) do
903
- record = MoneyRecord.create!(price: 100, currency: nil)
928
+ record = MoneyRecord.create!(price: 100, price_currency: nil)
904
929
  expect { record.reload.price }.to raise_error(ArgumentError, 'missing currency')
905
930
  end
906
931
  end
@@ -909,16 +934,16 @@ RSpec.describe 'MoneyColumn' do
909
934
  describe 'money column with different column names' do
910
935
  class MoneyWithCustomColumns < ActiveRecord::Base
911
936
  self.table_name = 'money_records'
912
- money_column :price, currency_column: :devise
913
- money_column :prix, currency_column: 'currency'
937
+ money_column :price, currency_column: :prix_currency
938
+ money_column :prix, currency_column: 'price_currency'
914
939
  end
915
940
 
916
941
  it 'supports both string and symbol currency column names' do
917
942
  record = MoneyWithCustomColumns.new(
918
943
  price: Money.new(100, 'EUR'),
919
- devise: 'EUR',
944
+ prix_currency: 'EUR',
920
945
  prix: Money.new(200, 'USD'),
921
- currency: 'USD'
946
+ price_currency: 'USD'
922
947
  )
923
948
 
924
949
  expect(record.price.currency.to_s).to eq('EUR')
@@ -929,14 +954,14 @@ RSpec.describe 'MoneyColumn' do
929
954
  describe 'money column array syntax' do
930
955
  class MoneyWithArrayColumns < ActiveRecord::Base
931
956
  self.table_name = 'money_records'
932
- money_column [:price, :prix], currency_column: 'currency'
957
+ money_column [:price, :prix], currency_column: 'price_currency'
933
958
  end
934
959
 
935
960
  it 'supports defining multiple columns at once' do
936
961
  record = MoneyWithArrayColumns.new(
937
962
  price: Money.new(100, 'USD'),
938
963
  prix: Money.new(200, 'USD'),
939
- currency: 'USD'
964
+ price_currency: 'USD'
940
965
  )
941
966
 
942
967
  expect(record.price).to eq(Money.new(100, 'USD'))
@@ -961,7 +986,7 @@ RSpec.describe 'MoneyColumn' do
961
986
  json = record.as_json
962
987
  # Money columns are serialized as a hash with symbol keys
963
988
  expect(json['price']).to eq({ currency: 'USD', value: '100.00' })
964
- expect(json['currency']).to eq('USD')
989
+ expect(json['price_currency']).to eq('USD')
965
990
  end
966
991
  end
967
992
 
data/spec/schema.rb CHANGED
@@ -2,9 +2,9 @@
2
2
  ActiveRecord::Schema.define do
3
3
  create_table "money_records", :force => true do |t|
4
4
  t.decimal "price", precision: 20, scale: 3, default: '0.000'
5
- t.string "currency", limit: 3
5
+ t.string "price_currency", limit: 3
6
6
  t.decimal "prix", precision: 20, scale: 3, default: '0.000'
7
- t.string "devise", limit: 3
7
+ t.string "prix_currency", limit: 3
8
8
  t.decimal "price_usd"
9
9
  end
10
10
  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.3
4
+ version: 3.2.4
5
5
  platform: ruby
6
6
  authors:
7
7
  - Shopify Inc