money_attribute 0.11.0 → 0.12.0
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/README.md +32 -8
- data/lib/money_attribute/migration_extensions/helper.rb +34 -28
- data/lib/money_attribute/version.rb +1 -1
- metadata +1 -1
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 306761efbc2f4f645f3e975ea830ff26901bc4ba5fac664346f5d7b5720050b8
|
|
4
|
+
data.tar.gz: 13dfc1b02f256f22ac1027700164ae57cee60bc77e1b233c28549b20988adaf7
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 3d39e999c298070baf49359ed226f9582defac099e4da3b342f3b367df81c658575e973095a0c8de4a19d8c7116af778d38160de6dbb263fd050a6a36bb3f0a9
|
|
7
|
+
data.tar.gz: 02c399705be0e9ac78c3f9dd1bbe9603055d6702df60a43e12e57fb0fa16ecfd4212d129a91294bdb4323f487030def2bc3fe52a7484552b93c4f2e81b6a71ed
|
data/README.md
CHANGED
|
@@ -91,7 +91,9 @@ The generator creates `config/initializers/money_attribute.rb`.
|
|
|
91
91
|
|
|
92
92
|
## Migration helpers
|
|
93
93
|
|
|
94
|
-
MoneyAttribute adds `add_money` / `remove_money` for existing tables and `t.money` / `t.remove_money` for `create_table` / `change_table` blocks
|
|
94
|
+
MoneyAttribute adds `add_money` / `remove_money` for existing tables and `t.money` / `t.remove_money` for `create_table` / `change_table` blocks.
|
|
95
|
+
|
|
96
|
+
By default `t.money :price` creates a `decimal(16,4)` amount column and a `string` currency column — both nullable, no default. Pass `amount: { type: :integer }` to store subunits instead, or `currency: false` to skip the currency column entirely.
|
|
95
97
|
|
|
96
98
|
```ruby
|
|
97
99
|
class CreateProducts < ActiveRecord::Migration[8.1]
|
|
@@ -101,7 +103,7 @@ class CreateProducts < ActiveRecord::Migration[8.1]
|
|
|
101
103
|
t.money :price # price (decimal) + price_currency (string)
|
|
102
104
|
t.money :price_amount # price_amount + price_currency (strips _amount suffix)
|
|
103
105
|
t.money :fee, currency: false # single column, no currency
|
|
104
|
-
t.money :tax, type: :bigint
|
|
106
|
+
t.money :tax, amount: { type: :bigint } # bigint amount + currency
|
|
105
107
|
t.timestamps
|
|
106
108
|
end
|
|
107
109
|
end
|
|
@@ -110,7 +112,7 @@ end
|
|
|
110
112
|
class AddPriceToProducts < ActiveRecord::Migration[8.1]
|
|
111
113
|
def change
|
|
112
114
|
add_money :products, :price # add price + price_currency
|
|
113
|
-
add_money :products, :discount, type: :integer
|
|
115
|
+
add_money :products, :discount, amount: { type: :integer }
|
|
114
116
|
remove_money :products, :obsolete_fee # reversible in change
|
|
115
117
|
end
|
|
116
118
|
end
|
|
@@ -123,8 +125,19 @@ end
|
|
|
123
125
|
| `t.money :price` | `price` decimal + `price_currency` string | `money_attribute :price` |
|
|
124
126
|
| `t.money :price_amount` | `price_amount` decimal + `price_currency` string | `money_attribute :price` |
|
|
125
127
|
| `t.money :price, currency: false` | `price` decimal | `money_attribute :price` |
|
|
126
|
-
| `t.money :price, type: :integer` | `price` integer + `price_currency` string | `money_attribute :price` |
|
|
127
|
-
| `t.money :price, amount: :a, currency: :c` | `a` + `c` | `money_attribute :price, mapping: { amount: :a, currency: :c }` |
|
|
128
|
+
| `t.money :price, amount: { type: :integer }` | `price` integer + `price_currency` string | `money_attribute :price` |
|
|
129
|
+
| `t.money :price, amount: { column: :a }, currency: { column: :c }` | `a` + `c` | `money_attribute :price, mapping: { amount: :a, currency: :c }` |
|
|
130
|
+
| `t.money :price, currency: { limit: 3 }` | `price` decimal + `price_currency` string(3) | `money_attribute :price` |
|
|
131
|
+
| `t.money :price, amount: { precision: 14, scale: 2, null: false }, currency: { limit: 3, default: 'USD' }` | `price` decimal(14,2) NOT NULL + `price_currency` string(3) DEFAULT 'USD' | `money_attribute :price` |
|
|
132
|
+
| `t.remove_money :price` | Removes `price` + `price_currency` | `money_attribute :price` |
|
|
133
|
+
|
|
134
|
+
Inside `change_table`:
|
|
135
|
+
|
|
136
|
+
```ruby
|
|
137
|
+
change_table :products do |t|
|
|
138
|
+
t.remove_money :obsolete_fee # removes obsolete_fee + obsolete_fee_currency
|
|
139
|
+
end
|
|
140
|
+
```
|
|
128
141
|
|
|
129
142
|
## Configuration
|
|
130
143
|
|
|
@@ -224,6 +237,8 @@ offer = Offer.new(price: '12')
|
|
|
224
237
|
offer.price.currency.code # => "USD"
|
|
225
238
|
```
|
|
226
239
|
|
|
240
|
+
Unlike fixed-currency attributes, composite mode does not enforce a specific currency — any registered currency is accepted at assignment.
|
|
241
|
+
|
|
227
242
|
## Column type detection
|
|
228
243
|
|
|
229
244
|
Declare the column as `decimal`, `integer`, or `bigint` — the gem adapts:
|
|
@@ -268,7 +283,14 @@ class Invoice < ApplicationRecord
|
|
|
268
283
|
end
|
|
269
284
|
```
|
|
270
285
|
|
|
271
|
-
The mapping keys are `:amount` and `:currency`; values are your database column names.
|
|
286
|
+
The mapping keys are `:amount` and `:currency`; values are your database column names. You can provide only one key — the other falls back to the `<name>_amount` / `<name>_currency` convention:
|
|
287
|
+
|
|
288
|
+
```ruby
|
|
289
|
+
class Invoice < ApplicationRecord
|
|
290
|
+
money_attribute :total, mapping: { amount: :total_amount }
|
|
291
|
+
# currency column inferred as `total_currency`
|
|
292
|
+
end
|
|
293
|
+
```
|
|
272
294
|
|
|
273
295
|
## Column resolution
|
|
274
296
|
|
|
@@ -279,8 +301,10 @@ When you declare `money_attribute :name`, the gem resolves which database column
|
|
|
279
301
|
| 1 | `mapping:` provided | As specified | Explicit composite |
|
|
280
302
|
| 2 | `name_currency` column exists | `name` + `name_currency` | Composite (multi-currency) |
|
|
281
303
|
| 3 | `name == 'amount'` AND `currency` column exists | `amount` + `currency` | Composite (multi-currency) |
|
|
282
|
-
| 4 | `
|
|
283
|
-
| 5 |
|
|
304
|
+
| 4 | `name` column exists (no currency partner) | `name` alone | Single-column (fixed-currency) |
|
|
305
|
+
| 5 | None of the above (name column missing) | `name_amount` + `name_currency` (convention) | Composite (multi-currency) |
|
|
306
|
+
|
|
307
|
+
Step 5 raises `ArgumentError` if the convention columns don't exist in the table.
|
|
284
308
|
|
|
285
309
|
**Example**
|
|
286
310
|
|
|
@@ -8,42 +8,48 @@ module MoneyAttribute
|
|
|
8
8
|
def parse_money_args(accessor, options = {})
|
|
9
9
|
name = accessor.to_s
|
|
10
10
|
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
11
|
+
if options.key?(:amount) && options[:amount].is_a?(Hash)
|
|
12
|
+
amount_col = options[:amount][:column]&.to_s || name
|
|
13
|
+
opts = options[:amount]
|
|
14
|
+
amount_opts = {
|
|
15
|
+
type: opts[:type],
|
|
16
|
+
null: opts[:null],
|
|
17
|
+
default: opts[:default],
|
|
18
|
+
precision: opts[:precision],
|
|
19
|
+
scale: opts[:scale]
|
|
20
|
+
}.compact
|
|
19
21
|
else
|
|
20
|
-
|
|
21
|
-
|
|
22
|
+
amount_col = name
|
|
23
|
+
amount_opts = {}
|
|
22
24
|
end
|
|
23
25
|
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
amount_opts = {}
|
|
27
|
-
amount_opts[:type] = col_type
|
|
26
|
+
amount_opts[:type] ||= :decimal
|
|
28
27
|
|
|
29
|
-
if
|
|
30
|
-
amount_opts[:null] = options[:amount][:null] if options[:amount].key?(:null)
|
|
31
|
-
amount_opts[:default] = options[:amount][:default] if options[:amount].key?(:default)
|
|
32
|
-
amount_opts[:precision] = options[:amount][:precision] if options[:amount].key?(:precision)
|
|
33
|
-
amount_opts[:scale] = options[:amount][:scale] if options[:amount].key?(:scale)
|
|
34
|
-
end
|
|
35
|
-
|
|
36
|
-
if col_type == :decimal && !amount_opts.key?(:precision) && !amount_opts.key?(:scale)
|
|
28
|
+
if amount_opts[:type] == :decimal && !amount_opts.key?(:precision) && !amount_opts.key?(:scale)
|
|
37
29
|
amount_opts[:precision] = 16
|
|
38
30
|
amount_opts[:scale] = 4
|
|
31
|
+
elsif amount_opts[:type] != :decimal
|
|
32
|
+
amount_opts.delete(:precision)
|
|
33
|
+
amount_opts.delete(:scale)
|
|
39
34
|
end
|
|
40
35
|
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
if options[:currency].is_a?(Hash)
|
|
45
|
-
|
|
46
|
-
|
|
36
|
+
stripped = name.end_with?('_amount') ? name.sub(/_amount$/, '') : name
|
|
37
|
+
default_currency_col = "#{stripped}_currency"
|
|
38
|
+
|
|
39
|
+
if options.key?(:currency) && options[:currency].is_a?(Hash)
|
|
40
|
+
currency_col = options[:currency][:column]&.to_s || default_currency_col
|
|
41
|
+
opts = options[:currency]
|
|
42
|
+
currency_opts = {
|
|
43
|
+
limit: opts[:limit],
|
|
44
|
+
null: opts[:null],
|
|
45
|
+
default: opts[:default]
|
|
46
|
+
}.compact
|
|
47
|
+
elsif options[:currency] == false
|
|
48
|
+
currency_col = nil
|
|
49
|
+
currency_opts = {}
|
|
50
|
+
else
|
|
51
|
+
currency_col = default_currency_col
|
|
52
|
+
currency_opts = {}
|
|
47
53
|
end
|
|
48
54
|
|
|
49
55
|
[amount_col, currency_col, amount_opts, currency_opts]
|