1
0
Fork 0
mirror of https://github.com/maybe-finance/maybe.git synced 2025-07-19 13:19:39 +02:00

Make balance editing easier (#976)

* Make balance editing easier

* Translations

* Fix money input option

* Fix balance sync logic

* Rework balance update flow
This commit is contained in:
Zach Gollwitzer 2024-07-12 13:47:39 -04:00 committed by GitHub
parent b002a41b35
commit 34e03c2d6a
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
9 changed files with 91 additions and 23 deletions

View file

@ -40,7 +40,9 @@ class AccountsController < ApplicationController
end
def update
@account.update! account_params.except(:accountable_type)
@account.update! account_params.except(:accountable_type, :balance)
@account.update_balance!(account_params[:balance]) if account_params[:balance]
@account.sync_later
redirect_back_or_to account_path(@account), notice: t(".success")
end

View file

@ -53,7 +53,7 @@ class ApplicationFormBuilder < ActionView::Helpers::FormBuilder
(label(method, *label_args(options)).to_s if options[:label]) +
@template.tag.div(class: "flex items-center") do
number_field(money_amount_method, merged_options.except(:label)) +
grouped_select(money_currency_method, grouped_options, { selected: selected_currency, disabled: readonly_currency }, class: "ml-auto form-field__input w-fit pr-8", data: { "money-field-target" => "currency", action: "change->money-field#handleCurrencyChange" })
grouped_select(money_currency_method, grouped_options, { selected: selected_currency }, disabled: readonly_currency, class: "ml-auto form-field__input w-fit pr-8", data: { "money-field-target" => "currency", action: "change->money-field#handleCurrencyChange" })
end
end
end

View file

@ -93,4 +93,18 @@ class Account < ApplicationRecord
rescue Money::ConversionError
TimeSeries.new([])
end
def update_balance!(balance)
valuation = entries.account_valuations.find_by(date: Date.current)
if valuation
valuation.update! amount: balance
else
entries.create! \
date: Date.current,
amount: balance,
currency: currency,
entryable: Account::Valuation.new
end
end
end

View file

@ -14,6 +14,11 @@ class Account::Balance::Syncer
Account::Balance.transaction do
upsert_balances!(daily_balances)
purge_stale_balances!
if daily_balances.any?
account.reload
account.update! balance: daily_balances.select { |db| db.currency == account.currency }.last&.balance
end
end
end
@ -53,16 +58,13 @@ class Account::Balance::Syncer
entries = account.entries.where("date >= ?", sync_start_date).to_a
prior_balance = find_prior_balance
daily_balances = (sync_start_date...Date.current).map do |date|
(sync_start_date..Date.current).map do |date|
current_balance = calculate_balance_for_date(date, entries:, prior_balance:)
prior_balance = current_balance
build_balance(date, current_balance)
end
# Last balance of series is always equal to account balance
daily_balances << build_balance(Date.current, account.balance)
end
def calculate_converted_balances(balances)

View file

@ -6,7 +6,8 @@
</header>
<%= form_with model: @account, data: { turbo_frame: "_top" } do |f| %>
<%= f.text_field :name, label: "Name" %>
<%= f.text_field :name, label: t(".name") %>
<%= f.money_field :balance_money, label: t(".balance"), readonly_currency: true %>
<div class="relative">
<%= f.collection_select :institution_id, Current.family.institutions.alphabetically, :id, :name, { include_blank: t(".ungrouped"), label: t(".institution") } %>

View file

@ -44,6 +44,7 @@
<% end %>
</div>
</div>
<%= turbo_frame_tag "sync_message" do %>
<%= render partial: "accounts/sync_message", locals: { is_syncing: @account.syncing? } %>
<% end %>
@ -55,12 +56,18 @@
<div class="bg-white shadow-xs rounded-xl border border-alpha-black-25 rounded-lg">
<div class="p-4 flex justify-between">
<div class="space-y-2">
<%= render partial: "shared/value_heading", locals: {
label: "Total Value",
period: @period,
value: @account.balance_money,
trend: @balance_series.trend
} %>
<%= tag.p t(".total_value"), class: "text-sm font-medium text-gray-500" %>
<%= tag.p format_money(@account.balance_money, precision: 0), class: "text-gray-900 text-3xl font-medium" %>
<div>
<% if @balance_series.trend.direction.flat? %>
<%= tag.span t(".no_change"), class: "text-gray-500" %>
<% else %>
<%= tag.span format_money(@balance_series.trend.value), style: "color: #{@balance_series.trend.color}" %>
<%= tag.span "(#{@balance_series.trend.percent}%)", style: "color: #{@balance_series.trend.color}" %>
<% end %>
<%= tag.span period_label(@period), class: "text-gray-500" %>
</div>
</div>
<%= form_with url: account_path(@account), method: :get, class: "flex items-center gap-4", data: { controller: "auto-submit-form" } do %>
<%= render partial: "shared/period_select", locals: { value: @period.name } %>
@ -71,11 +78,11 @@
</div>
</div>
<% selected_tab = params[:tab] || "history" %>
<% selected_tab = params[:tab] || "value" %>
<div class="flex gap-1 text-sm text-gray-900 font-medium mb-4">
<%= link_to "History", account_path(tab: "history"), class: ["p-2 rounded-lg", "bg-gray-100": selected_tab == "history"] %>
<%= link_to "Transactions", account_path(tab: "transactions"), class: ["p-2 rounded-lg", "bg-gray-100": selected_tab == "transactions"] %>
<div class="flex gap-2 text-sm text-gray-900 font-medium mb-4">
<%= link_to t(".value"), account_path(tab: "value"), class: ["px-2 py-1.5 rounded-md border border-transparent", "bg-white shadow-xs border-alpha-black-50": selected_tab == "value"] %>
<%= link_to t(".transactions"), account_path(tab: "transactions"), class: ["px-2 py-1.5 rounded-md border border-transparent", "bg-white shadow-xs border-alpha-black-50": selected_tab == "transactions"] %>
</div>
<div class="min-h-[800px]">