mirror of
https://github.com/maybe-finance/maybe.git
synced 2025-08-04 21:15:19 +02:00
Multi-currency support: Money + Currency class improvements (#553)
* Money improvements * Replace all old money usage
This commit is contained in:
parent
e5750d1a13
commit
fe2fa0eac1
43 changed files with 2982 additions and 196 deletions
|
@ -1,5 +1,6 @@
|
|||
class Account < ApplicationRecord
|
||||
include Syncable
|
||||
include Monetizable
|
||||
|
||||
validates :family, presence: true
|
||||
|
||||
|
@ -9,6 +10,8 @@ class Account < ApplicationRecord
|
|||
has_many :valuations
|
||||
has_many :transactions
|
||||
|
||||
monetize :balance
|
||||
|
||||
enum :status, { ok: "ok", syncing: "syncing", error: "error" }, validate: true
|
||||
|
||||
scope :active, -> { where(is_active: true) }
|
||||
|
|
|
@ -6,8 +6,8 @@ class Account::BalanceCalculator
|
|||
def daily_balances(start_date = nil)
|
||||
calc_start_date = [ start_date, @account.effective_start_date ].compact.max
|
||||
|
||||
valuations = @account.valuations.where("date >= ?", calc_start_date).order(:date).select(:date, :value)
|
||||
transactions = @account.transactions.where("date > ?", calc_start_date).order(:date).select(:date, :amount)
|
||||
valuations = @account.valuations.where("date >= ?", calc_start_date).order(:date).select(:date, :value, :currency)
|
||||
transactions = @account.transactions.where("date > ?", calc_start_date).order(:date).select(:date, :amount, :currency)
|
||||
oldest_entry = [ valuations.first, transactions.first ].compact.min_by(&:date)
|
||||
|
||||
net_transaction_flows = transactions.sum(&:amount)
|
||||
|
|
|
@ -1,7 +1,9 @@
|
|||
class AccountBalance < ApplicationRecord
|
||||
belongs_to :account
|
||||
include Monetizable
|
||||
|
||||
belongs_to :account
|
||||
validates :account, :date, :balance, presence: true
|
||||
monetize :balance
|
||||
|
||||
scope :in_period, ->(period) { period.date_range.nil? ? all : where(date: period.date_range) }
|
||||
|
||||
|
|
14
app/models/concerns/monetizable.rb
Normal file
14
app/models/concerns/monetizable.rb
Normal file
|
@ -0,0 +1,14 @@
|
|||
module Monetizable
|
||||
extend ActiveSupport::Concern
|
||||
|
||||
class_methods do
|
||||
def monetize(*fields)
|
||||
fields.each do |field|
|
||||
define_method("#{field}_money") do
|
||||
value = self.send(field)
|
||||
value.nil? ? nil : Money.new(value, currency)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
|
@ -1,9 +1,13 @@
|
|||
class Family < ApplicationRecord
|
||||
include Monetizable
|
||||
|
||||
has_many :users, dependent: :destroy
|
||||
has_many :accounts, dependent: :destroy
|
||||
has_many :transactions, through: :accounts
|
||||
has_many :transaction_categories, dependent: :destroy, class_name: "Transaction::Category"
|
||||
|
||||
monetize :net_worth, :assets, :liabilities
|
||||
|
||||
def snapshot(period = Period.all)
|
||||
query = accounts.active.joins(:balances)
|
||||
.where("account_balances.currency = ?", self.currency)
|
||||
|
@ -35,7 +39,7 @@ class Family < ApplicationRecord
|
|||
end
|
||||
|
||||
def assets
|
||||
accounts.active.assets.sum(:balance)
|
||||
accounts.active.assets.sum(:balance)
|
||||
end
|
||||
|
||||
def liabilities
|
||||
|
|
|
@ -1,32 +0,0 @@
|
|||
class Money
|
||||
attr_reader :amount, :currency
|
||||
|
||||
def self.from_amount(amount, currency = "USD")
|
||||
Money.new(amount, currency)
|
||||
end
|
||||
|
||||
def initialize(amount, currency = :USD)
|
||||
@amount = amount
|
||||
@currency = currency
|
||||
end
|
||||
|
||||
def cents(precision: nil)
|
||||
_precision = precision || CURRENCY_OPTIONS[@currency.to_sym][:precision]
|
||||
return "" unless _precision.positive?
|
||||
|
||||
fractional_part = @amount.to_s.split(".")[1] || ""
|
||||
fractional_part = fractional_part[0, _precision].ljust(_precision, "0")
|
||||
end
|
||||
|
||||
def symbol
|
||||
CURRENCY_OPTIONS[@currency.to_sym][:symbol]
|
||||
end
|
||||
|
||||
def separator
|
||||
CURRENCY_OPTIONS[@currency.to_sym][:separator]
|
||||
end
|
||||
|
||||
def precision
|
||||
CURRENCY_OPTIONS[@currency.to_sym][:precision]
|
||||
end
|
||||
end
|
|
@ -14,7 +14,7 @@ class MoneySeries
|
|||
{
|
||||
raw: current,
|
||||
date: current.date,
|
||||
value: Money.from_amount(current.send(@accessor), current.currency),
|
||||
value: Money.new(current.send(@accessor), current.currency),
|
||||
trend: Trend.new(
|
||||
current: current.send(@accessor),
|
||||
previous: previous&.send(@accessor),
|
||||
|
|
|
@ -1,4 +1,6 @@
|
|||
class Transaction < ApplicationRecord
|
||||
include Monetizable
|
||||
|
||||
belongs_to :account
|
||||
belongs_to :category, optional: true
|
||||
|
||||
|
@ -6,6 +8,12 @@ class Transaction < ApplicationRecord
|
|||
|
||||
after_commit :sync_account
|
||||
|
||||
monetize :amount
|
||||
|
||||
scope :inflows, -> { where("amount > 0") }
|
||||
scope :outflows, -> { where("amount < 0") }
|
||||
scope :active, -> { where(excluded: false) }
|
||||
|
||||
def self.ransackable_attributes(auth_object = nil)
|
||||
%w[name amount date]
|
||||
end
|
||||
|
|
|
@ -1,9 +1,10 @@
|
|||
class Valuation < ApplicationRecord
|
||||
include Monetizable
|
||||
|
||||
belongs_to :account
|
||||
|
||||
validates :account, :date, :value, presence: true
|
||||
|
||||
after_commit :sync_account
|
||||
monetize :value
|
||||
|
||||
scope :in_period, ->(period) { period.date_range.nil? ? all : where(date: period.date_range) }
|
||||
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue