Files

59 lines
1.8 KiB
Ruby

# frozen_string_literal: true
require "bigdecimal"
module Hledger
# Turns contributed-capital balances into a per-commodity tree, where every
# row shows its share of that commodity's total.
#
# quantities are absolute, so a node equals the sum of its descendants and no
# negative values are shown.
module Equity
module_function
# entries: [[full_account_name, [{ "commodity" =>, "quantity" => BigDecimal, "style" => }]], ...]
def groups(entries)
equity_entries = entries.select { |name, _amounts| name.to_s.start_with?("equity:") }
rows =
AccountTree
.expand(equity_entries)
.reject { |node| node["root"] }
.map { |node| node.merge("depth" => node["depth"] - 1) }
commodities(rows).map { |commodity| build_group(rows, commodity) }
end
def commodities(rows)
rows.flat_map { |node| node["amounts"].map { |amount| amount["commodity"].to_s } }.uniq
end
def build_group(rows, commodity)
group_rows =
rows.filter_map do |node|
amount = node["amounts"].find { |candidate| candidate["commodity"].to_s == commodity }
node.merge("amounts" => [amount]) if amount
end
template = group_rows.first["amounts"].first
total =
group_rows
.select { |row| row["depth"].zero? }
.sum { |row| row["amounts"].first["quantity"] }
{
"commodity" => commodity,
"total" => template.merge("quantity" => total),
"rows" =>
group_rows.map do |row|
row.merge("percentage" => percentage(row["amounts"].first["quantity"], total))
end,
}
end
def percentage(quantity, total)
return "0.00" if total.zero?
format("%.2f", (quantity / total) * 100)
end
end
end