mirror of
https://github.com/maybe-finance/maybe.git
synced 2025-07-24 23:59:40 +02:00
Fix transfers and form currencies (#1477)
This commit is contained in:
parent
fcb95207d7
commit
81d604f3d4
11 changed files with 41 additions and 19 deletions
|
@ -5,7 +5,10 @@ class Account::TradesController < ApplicationController
|
||||||
before_action :set_entry, only: :update
|
before_action :set_entry, only: :update
|
||||||
|
|
||||||
def new
|
def new
|
||||||
@entry = @account.entries.account_trades.new(entryable_attributes: {})
|
@entry = @account.entries.account_trades.new(
|
||||||
|
currency: @account.currency,
|
||||||
|
entryable_attributes: {}
|
||||||
|
)
|
||||||
end
|
end
|
||||||
|
|
||||||
def index
|
def index
|
||||||
|
|
|
@ -16,8 +16,7 @@ class Account::TransfersController < ApplicationController
|
||||||
|
|
||||||
@transfer = Account::Transfer.build_from_accounts from_account, to_account, \
|
@transfer = Account::Transfer.build_from_accounts from_account, to_account, \
|
||||||
date: transfer_params[:date],
|
date: transfer_params[:date],
|
||||||
amount: transfer_params[:amount].to_d,
|
amount: transfer_params[:amount].to_d
|
||||||
currency: transfer_params[:currency]
|
|
||||||
|
|
||||||
if @transfer.save
|
if @transfer.save
|
||||||
@transfer.entries.each(&:sync_account_later)
|
@transfer.entries.each(&:sync_account_later)
|
||||||
|
|
|
@ -4,7 +4,10 @@ class Account::ValuationsController < ApplicationController
|
||||||
before_action :set_account
|
before_action :set_account
|
||||||
|
|
||||||
def new
|
def new
|
||||||
@entry = @account.entries.account_valuations.new(entryable_attributes: {})
|
@entry = @account.entries.account_valuations.new(
|
||||||
|
currency: @account.currency,
|
||||||
|
entryable_attributes: {}
|
||||||
|
)
|
||||||
end
|
end
|
||||||
|
|
||||||
def create
|
def create
|
||||||
|
|
|
@ -40,6 +40,7 @@ class Account::EntryBuilder
|
||||||
date: date,
|
date: date,
|
||||||
amount: amount,
|
amount: amount,
|
||||||
account: account,
|
account: account,
|
||||||
|
currency: currency,
|
||||||
transfer_account_id: transfer_account_id
|
transfer_account_id: transfer_account_id
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -3,7 +3,7 @@ class Account::TransactionBuilder
|
||||||
|
|
||||||
TYPES = %w[income expense interest transfer_in transfer_out].freeze
|
TYPES = %w[income expense interest transfer_in transfer_out].freeze
|
||||||
|
|
||||||
attr_accessor :type, :amount, :date, :account, :transfer_account_id
|
attr_accessor :type, :amount, :date, :account, :currency, :transfer_account_id
|
||||||
|
|
||||||
validates :type, :amount, :date, presence: true
|
validates :type, :amount, :date, presence: true
|
||||||
validates :type, inclusion: { in: TYPES }
|
validates :type, inclusion: { in: TYPES }
|
||||||
|
@ -45,8 +45,9 @@ class Account::TransactionBuilder
|
||||||
def build_entry(account_id, amount, marked_as_transfer: false)
|
def build_entry(account_id, amount, marked_as_transfer: false)
|
||||||
Account::Entry.new \
|
Account::Entry.new \
|
||||||
account_id: account_id,
|
account_id: account_id,
|
||||||
|
name: marked_as_transfer ? (amount < 0 ? "Deposit" : "Withdrawal") : "Interest",
|
||||||
amount: amount,
|
amount: amount,
|
||||||
currency: account.currency,
|
currency: currency,
|
||||||
date: date,
|
date: date,
|
||||||
marked_as_transfer: marked_as_transfer,
|
marked_as_transfer: marked_as_transfer,
|
||||||
entryable: Account::Transaction.new
|
entryable: Account::Transaction.new
|
||||||
|
|
|
@ -49,7 +49,7 @@ class Account::Transfer < ApplicationRecord
|
||||||
end
|
end
|
||||||
|
|
||||||
class << self
|
class << self
|
||||||
def build_from_accounts(from_account, to_account, date:, amount:, currency:)
|
def build_from_accounts(from_account, to_account, date:, amount:)
|
||||||
outflow = from_account.entries.build \
|
outflow = from_account.entries.build \
|
||||||
amount: amount.abs,
|
amount: amount.abs,
|
||||||
currency: from_account.currency,
|
currency: from_account.currency,
|
||||||
|
@ -58,9 +58,17 @@ class Account::Transfer < ApplicationRecord
|
||||||
marked_as_transfer: true,
|
marked_as_transfer: true,
|
||||||
entryable: Account::Transaction.new
|
entryable: Account::Transaction.new
|
||||||
|
|
||||||
|
# Attempt to convert the amount to the to_account's currency. If the conversion fails,
|
||||||
|
# use the original amount.
|
||||||
|
converted_amount = begin
|
||||||
|
Money.new(amount.abs, from_account.currency).exchange_to(to_account.currency)
|
||||||
|
rescue Money::ConversionError
|
||||||
|
Money.new(amount.abs, from_account.currency)
|
||||||
|
end
|
||||||
|
|
||||||
inflow = to_account.entries.build \
|
inflow = to_account.entries.build \
|
||||||
amount: amount.abs * -1,
|
amount: converted_amount.amount * -1,
|
||||||
currency: from_account.currency,
|
currency: converted_amount.currency.iso_code,
|
||||||
date: date,
|
date: date,
|
||||||
name: "Transfer from #{from_account.name}",
|
name: "Transfer from #{from_account.name}",
|
||||||
marked_as_transfer: true,
|
marked_as_transfer: true,
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
<%# locals: (entry:) %>
|
<%# locals: (entry:) %>
|
||||||
|
|
||||||
<%= styled_form_with data: { turbo_frame: "_top", controller: "trade-form" },
|
<%= styled_form_with data: { turbo_frame: "_top", controller: "trade-form" },
|
||||||
|
model: entry,
|
||||||
scope: :account_entry,
|
scope: :account_entry,
|
||||||
url: account_trades_path(entry.account) do |form| %>
|
url: account_trades_path(entry.account) do |form| %>
|
||||||
<div class="space-y-4">
|
<div class="space-y-4">
|
||||||
|
@ -15,7 +16,7 @@
|
||||||
<%= form.date_field :date, label: true, value: Date.today %>
|
<%= form.date_field :date, label: true, value: Date.today %>
|
||||||
|
|
||||||
<div data-trade-form-target="amountInput" hidden>
|
<div data-trade-form-target="amountInput" hidden>
|
||||||
<%= form.money_field :amount, label: t(".amount"), disable_currency: true %>
|
<%= form.money_field :amount, label: t(".amount") %>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div data-trade-form-target="transferAccountInput" hidden>
|
<div data-trade-form-target="transferAccountInput" hidden>
|
||||||
|
@ -27,7 +28,7 @@
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div data-trade-form-target="priceInput">
|
<div data-trade-form-target="priceInput">
|
||||||
<%= form.money_field :price, label: t(".price"), disable_currency: true %>
|
<%= form.money_field :price, label: t(".price"), currency_value_override: "USD", disable_currency: true %>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
<%= styled_form_with model: transfer, class: "space-y-4", data: { turbo_frame: "_top" } do |f| %>
|
<%= styled_form_with model: transfer, class: "space-y-4", data: { turbo_frame: "_top", controller: "transfer-form" } do |f| %>
|
||||||
<% if transfer.errors.present? %>
|
<% if transfer.errors.present? %>
|
||||||
<div class="text-red-600 flex items-center gap-2">
|
<div class="text-red-600 flex items-center gap-2">
|
||||||
<%= lucide_icon "circle-alert", class: "w-5 h-5" %>
|
<%= lucide_icon "circle-alert", class: "w-5 h-5" %>
|
||||||
|
@ -28,8 +28,8 @@
|
||||||
<section class="space-y-2">
|
<section class="space-y-2">
|
||||||
<%= f.collection_select :from_account_id, Current.family.accounts.manual.alphabetically, :id, :name, { prompt: t(".select_account"), label: t(".from") }, required: true %>
|
<%= f.collection_select :from_account_id, Current.family.accounts.manual.alphabetically, :id, :name, { prompt: t(".select_account"), label: t(".from") }, required: true %>
|
||||||
<%= f.collection_select :to_account_id, Current.family.accounts.manual.alphabetically, :id, :name, { prompt: t(".select_account"), label: t(".to") }, required: true %>
|
<%= f.collection_select :to_account_id, Current.family.accounts.manual.alphabetically, :id, :name, { prompt: t(".select_account"), label: t(".to") }, required: true %>
|
||||||
<%= f.money_field :amount, label: t(".amount"), required: true, hide_currency: true %>
|
<%= f.number_field :amount, label: t(".amount"), required: true, min: 0, placeholder: "100", step: 0.00000001 %>
|
||||||
<%= f.date_field :date, value: transfer.date, label: t(".date"), required: true, max: Date.current %>
|
<%= f.date_field :date, value: transfer.date || Date.today, label: t(".date"), required: true, max: Date.current %>
|
||||||
</section>
|
</section>
|
||||||
|
|
||||||
<section>
|
<section>
|
||||||
|
|
|
@ -6,7 +6,7 @@
|
||||||
data: { turbo: false } do |form| %>
|
data: { turbo: false } do |form| %>
|
||||||
<div class="space-y-3">
|
<div class="space-y-3">
|
||||||
<%= form.date_field :date, label: true, required: true, value: Date.today, min: Account::Entry.min_supported_date, max: Date.today %>
|
<%= form.date_field :date, label: true, required: true, value: Date.today, min: Account::Entry.min_supported_date, max: Date.today %>
|
||||||
<%= form.money_field :amount, label: t(".amount"), required: true, default_currency: Current.family.currency %>
|
<%= form.money_field :amount, label: t(".amount"), required: true %>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<%= form.submit t(".submit") %>
|
<%= form.submit t(".submit") %>
|
||||||
|
|
|
@ -1,6 +1,8 @@
|
||||||
<%# locals: (form:, amount_method:, currency_method:, **options) %>
|
<%# locals: (form:, amount_method:, currency_method:, **options) %>
|
||||||
|
|
||||||
<% currency_value = if form.object && form.object.respond_to?(currency_method)
|
<% currency_value = if options[:currency_value_override].present?
|
||||||
|
options[:currency_value_override]
|
||||||
|
elsif form.object && form.object.respond_to?(currency_method)
|
||||||
form.object.public_send(currency_method)
|
form.object.public_send(currency_method)
|
||||||
end
|
end
|
||||||
currency = Money::Currency.new(currency_value || options[:default_currency] || "USD") %>
|
currency = Money::Currency.new(currency_value || options[:default_currency] || "USD") %>
|
||||||
|
@ -44,7 +46,7 @@
|
||||||
<div>
|
<div>
|
||||||
<%= form.select currency_method,
|
<%= form.select currency_method,
|
||||||
currencies_for_select.map(&:iso_code),
|
currencies_for_select.map(&:iso_code),
|
||||||
{ inline: true },
|
{ inline: true, selected: currency_value },
|
||||||
{
|
{
|
||||||
class: "w-fit pr-5 disabled:text-gray-400 form-field__input",
|
class: "w-fit pr-5 disabled:text-gray-400 form-field__input",
|
||||||
disabled: options[:disable_currency],
|
disabled: options[:disable_currency],
|
||||||
|
|
|
@ -27,6 +27,7 @@ class Account::TradesControllerTest < ActionDispatch::IntegrationTest
|
||||||
type: "transfer_in",
|
type: "transfer_in",
|
||||||
date: Date.current,
|
date: Date.current,
|
||||||
amount: 10,
|
amount: 10,
|
||||||
|
currency: "USD",
|
||||||
transfer_account_id: from_account.id
|
transfer_account_id: from_account.id
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -46,6 +47,7 @@ class Account::TradesControllerTest < ActionDispatch::IntegrationTest
|
||||||
type: "transfer_out",
|
type: "transfer_out",
|
||||||
date: Date.current,
|
date: Date.current,
|
||||||
amount: 10,
|
amount: 10,
|
||||||
|
currency: "USD",
|
||||||
transfer_account_id: to_account.id
|
transfer_account_id: to_account.id
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -62,7 +64,8 @@ class Account::TradesControllerTest < ActionDispatch::IntegrationTest
|
||||||
account_entry: {
|
account_entry: {
|
||||||
type: "transfer_out",
|
type: "transfer_out",
|
||||||
date: Date.current,
|
date: Date.current,
|
||||||
amount: 10
|
amount: 10,
|
||||||
|
currency: "USD"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
end
|
end
|
||||||
|
@ -80,7 +83,8 @@ class Account::TradesControllerTest < ActionDispatch::IntegrationTest
|
||||||
account_entry: {
|
account_entry: {
|
||||||
type: "interest",
|
type: "interest",
|
||||||
date: Date.current,
|
date: Date.current,
|
||||||
amount: 10
|
amount: 10,
|
||||||
|
currency: "USD"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
end
|
end
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue