mirror of
https://github.com/maybe-finance/maybe.git
synced 2025-08-09 23:45:21 +02:00
feature: money abbreviate formatting
This commit is contained in:
parent
210b89cd17
commit
a352b3b2d1
3 changed files with 83 additions and 5 deletions
|
@ -3,7 +3,7 @@
|
|||
<div class="space-y-4">
|
||||
<% balance_sheet.classification_groups.each do |classification_group| %>
|
||||
<div class="bg-container shadow-border-xs rounded-xl space-y-4 p-4">
|
||||
<h2 class="text-lg font-medium"><%= classification_group.display_name %></h2>
|
||||
<h2 class="text-lg font-medium"><%= classification_group.display_name %> · <span class="text-secondary"><%= classification_group.key == "asset" ? format_money(balance_sheet.total_assets, abbreviate: true) : format_money(balance_sheet.total_liabilities, abbreviate: true) %></span></h2>
|
||||
|
||||
<% if classification_group.account_groups.any? %>
|
||||
<div class="space-y-4">
|
||||
|
|
|
@ -5,7 +5,11 @@ module Money::Formatting
|
|||
locale = options[:locale] || I18n.locale
|
||||
default_opts = format_options(locale)
|
||||
|
||||
number_to_currency(amount, default_opts.merge(options))
|
||||
if options[:abbreviate]
|
||||
format_abbreviated(default_opts.merge(options))
|
||||
else
|
||||
number_to_currency(amount, default_opts.merge(options))
|
||||
end
|
||||
end
|
||||
alias_method :to_s, :format
|
||||
|
||||
|
@ -22,6 +26,39 @@ module Money::Formatting
|
|||
end
|
||||
|
||||
private
|
||||
def format_abbreviated(options)
|
||||
threshold = options[:abbreviate_threshold] || 1000
|
||||
abs_amount = amount.abs
|
||||
|
||||
return number_to_currency(amount, options) if abs_amount < threshold
|
||||
|
||||
suffixes = options[:unit_suffixes]
|
||||
|
||||
if abs_amount >= 1_000_000_000
|
||||
unit_suffix = suffixes[:billion]
|
||||
value = abs_amount / 1_000_000_000.0
|
||||
elsif abs_amount >= 1_000_000
|
||||
unit_suffix = suffixes[:million]
|
||||
value = abs_amount / 1_000_000.0
|
||||
else
|
||||
unit_suffix = suffixes[:thousand]
|
||||
value = abs_amount / 1000.0
|
||||
end
|
||||
|
||||
# Always use period as decimal separator for abbreviations and don't round up
|
||||
abbrev_options = options.merge(precision: 1, separator: ".", round_mode: :down)
|
||||
value_formatted = number_to_rounded(value, abbrev_options)
|
||||
abbreviated_num = "#{value_formatted}#{unit_suffix}"
|
||||
|
||||
if options[:format].to_s.include?("%u %n")
|
||||
formatted = "#{options[:unit]} #{abbreviated_num}"
|
||||
else
|
||||
formatted = "#{options[:unit]}#{abbreviated_num}"
|
||||
end
|
||||
|
||||
amount.negative? ? "-#{formatted}" : formatted
|
||||
end
|
||||
|
||||
def get_symbol
|
||||
if currency.symbol == "$" && currency.iso_code != "USD"
|
||||
[ currency.iso_code.first(2), currency.symbol ].join
|
||||
|
@ -33,11 +70,20 @@ module Money::Formatting
|
|||
def locale_options(locale)
|
||||
case [ currency.iso_code, locale.to_sym ]
|
||||
when [ "EUR", :nl ], [ "EUR", :pt ]
|
||||
{ delimiter: ".", separator: ",", format: "%u %n" }
|
||||
{
|
||||
delimiter: ".",
|
||||
separator: ",",
|
||||
format: "%u %n",
|
||||
unit_suffixes: { thousand: "K", million: "M", billion: "B" }
|
||||
}
|
||||
when [ "EUR", :en ], [ "EUR", :en_IE ]
|
||||
{ delimiter: ",", separator: "." }
|
||||
{
|
||||
delimiter: ",",
|
||||
separator: ".",
|
||||
unit_suffixes: { thousand: "K", million: "M", billion: "B" }
|
||||
}
|
||||
else
|
||||
{}
|
||||
{ unit_suffixes: { thousand: "K", million: "M", billion: "B" } }
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
@ -90,6 +90,38 @@ class MoneyTest < ActiveSupport::TestCase
|
|||
assert_equal "€ 1.000,12", Money.new(1000.12, :eur).format(locale: :nl)
|
||||
end
|
||||
|
||||
test "can format with abbreviation" do
|
||||
# Values below 1000 should be formatted normally
|
||||
assert_equal "$500.00", Money.new(500).format(abbreviate: true)
|
||||
assert_equal "$999.99", Money.new(999.99).format(abbreviate: true)
|
||||
assert_equal "-$500.00", Money.new(-500).format(abbreviate: true)
|
||||
|
||||
assert_equal "$1.0K", Money.new(1000).format(abbreviate: true)
|
||||
assert_equal "$1.5K", Money.new(1500).format(abbreviate: true)
|
||||
assert_equal "$999.9K", Money.new(999900).format(abbreviate: true)
|
||||
assert_equal "-$1.5K", Money.new(-1500).format(abbreviate: true)
|
||||
|
||||
assert_equal "$1.0M", Money.new(1_000_000).format(abbreviate: true)
|
||||
assert_equal "$1.5M", Money.new(1_500_000).format(abbreviate: true)
|
||||
assert_equal "$999.9M", Money.new(999_900_000).format(abbreviate: true)
|
||||
assert_equal "-$1.5M", Money.new(-1_500_000).format(abbreviate: true)
|
||||
|
||||
assert_equal "$1.0B", Money.new(1_000_000_000).format(abbreviate: true)
|
||||
assert_equal "$1.5B", Money.new(1_500_000_000).format(abbreviate: true)
|
||||
assert_equal "$999.9B", Money.new(999_900_000_000).format(abbreviate: true)
|
||||
assert_equal "-$1.5B", Money.new(-1_500_000_000).format(abbreviate: true)
|
||||
|
||||
assert_equal "€1.5M", Money.new(1_500_000, :EUR).format(abbreviate: true)
|
||||
assert_equal "£1.5M", Money.new(1_500_000, :GBP).format(abbreviate: true)
|
||||
assert_equal "CA$1.5M", Money.new(1_500_000, :CAD).format(abbreviate: true)
|
||||
|
||||
assert_equal "$900.00", Money.new(900).format(abbreviate: true, abbreviate_threshold: 1000)
|
||||
assert_equal "$0.9K", Money.new(900).format(abbreviate: true, abbreviate_threshold: 500)
|
||||
assert_equal "$0.1K", Money.new(100).format(abbreviate: true, abbreviate_threshold: 50)
|
||||
|
||||
assert_equal "€ 1.5M", Money.new(1_500_000, :EUR).format(abbreviate: true, locale: :nl)
|
||||
end
|
||||
|
||||
test "converts currency when rate available" do
|
||||
ExchangeRate.expects(:find_or_fetch_rate).returns(OpenStruct.new(rate: 1.2))
|
||||
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue