mirror of
https://github.com/maybe-finance/maybe.git
synced 2025-08-02 20:15:22 +02:00
New Design System + Codebase Refresh (#1823)
Since the very first 0.1.0-alpha.1 release, we've been moving quickly to add new features to the Maybe app. In doing so, some parts of the codebase have become outdated, unnecessary, or overly-complex as a natural result of this feature prioritization. Now that "core" Maybe is complete, we're moving into a second phase of development where we'll be working hard to improve the accuracy of existing features and build additional features on top of "core". This PR is a quick overhaul of the existing codebase aimed to: - Establish the brand new and simplified dashboard view (pictured above) - Establish and move towards the conventions introduced in Cursor rules and project design overview #1788 - Consolidate layouts and improve the performance of layout queries - Organize the core models of the Maybe domain (i.e. Account::Entry, Account::Transaction, etc.) and break out specific traits of each model into dedicated concerns for better readability - Remove stale / dead code from codebase - Remove overly complex code paths in favor of simpler ones
This commit is contained in:
parent
8539ac7dec
commit
d75be2282b
278 changed files with 3428 additions and 4354 deletions
95
app/models/balance_sheet.rb
Normal file
95
app/models/balance_sheet.rb
Normal file
|
@ -0,0 +1,95 @@
|
|||
class BalanceSheet
|
||||
include Monetizable
|
||||
|
||||
monetize :total_assets, :total_liabilities, :net_worth
|
||||
|
||||
attr_reader :family
|
||||
|
||||
def initialize(family)
|
||||
@family = family
|
||||
end
|
||||
|
||||
def total_assets
|
||||
totals_query.filter { |t| t.classification == "asset" }.sum(&:converted_balance)
|
||||
end
|
||||
|
||||
def total_liabilities
|
||||
totals_query.filter { |t| t.classification == "liability" }.sum(&:converted_balance)
|
||||
end
|
||||
|
||||
def net_worth
|
||||
total_assets - total_liabilities
|
||||
end
|
||||
|
||||
def classification_groups
|
||||
[
|
||||
ClassificationGroup.new(
|
||||
key: "asset",
|
||||
display_name: "Assets",
|
||||
icon: "blocks",
|
||||
account_groups: account_groups("asset")
|
||||
),
|
||||
ClassificationGroup.new(
|
||||
key: "liability",
|
||||
display_name: "Debts",
|
||||
icon: "scale",
|
||||
account_groups: account_groups("liability")
|
||||
)
|
||||
]
|
||||
end
|
||||
|
||||
def account_groups(classification = nil)
|
||||
classification_accounts = classification ? totals_query.filter { |t| t.classification == classification } : totals_query
|
||||
classification_total = classification_accounts.sum(&:converted_balance)
|
||||
account_groups = classification_accounts.group_by(&:accountable_type).transform_keys { |k| Accountable.from_type(k) }
|
||||
|
||||
account_groups.map do |accountable, accounts|
|
||||
group_total = accounts.sum(&:converted_balance)
|
||||
|
||||
AccountGroup.new(
|
||||
key: accountable.model_name.param_key,
|
||||
name: accountable.display_name,
|
||||
classification: accountable.classification,
|
||||
total: group_total,
|
||||
total_money: Money.new(group_total, currency),
|
||||
weight: classification_total.zero? ? 0 : group_total / classification_total.to_d * 100,
|
||||
missing_rates?: accounts.any? { |a| a.missing_rates? },
|
||||
color: accountable.color,
|
||||
accounts: accounts.map do |account|
|
||||
account.define_singleton_method(:weight) do
|
||||
classification_total.zero? ? 0 : account.converted_balance / classification_total.to_d * 100
|
||||
end
|
||||
account
|
||||
end.sort_by(&:weight).reverse
|
||||
)
|
||||
end.sort_by(&:weight).reverse
|
||||
end
|
||||
|
||||
def net_worth_series(period: Period.last_30_days)
|
||||
active_accounts.balance_series(currency: currency, period: period, favorable_direction: "up")
|
||||
end
|
||||
|
||||
def currency
|
||||
family.currency
|
||||
end
|
||||
|
||||
private
|
||||
ClassificationGroup = Struct.new(:key, :display_name, :icon, :account_groups, keyword_init: true)
|
||||
AccountGroup = Struct.new(:key, :name, :accountable_type, :classification, :total, :total_money, :weight, :accounts, :color, :missing_rates?, keyword_init: true)
|
||||
|
||||
def active_accounts
|
||||
family.accounts.active.with_attached_logo
|
||||
end
|
||||
|
||||
def totals_query
|
||||
@totals_query ||= active_accounts
|
||||
.joins(ActiveRecord::Base.sanitize_sql_array([ "LEFT JOIN exchange_rates ON exchange_rates.date = CURRENT_DATE AND accounts.currency = exchange_rates.from_currency AND exchange_rates.to_currency = ?", currency ]))
|
||||
.select(
|
||||
"accounts.*",
|
||||
"SUM(accounts.balance * COALESCE(exchange_rates.rate, 1)) as converted_balance",
|
||||
ActiveRecord::Base.sanitize_sql_array([ "COUNT(CASE WHEN accounts.currency <> ? AND exchange_rates.rate IS NULL THEN 1 END) as missing_rates", currency ])
|
||||
)
|
||||
.group(:classification, :accountable_type, :id)
|
||||
.to_a
|
||||
end
|
||||
end
|
Loading…
Add table
Add a link
Reference in a new issue