diff --git a/app/controllers/account/valuations_controller.rb b/app/controllers/account/valuations_controller.rb new file mode 100644 index 00000000..bdaba126 --- /dev/null +++ b/app/controllers/account/valuations_controller.rb @@ -0,0 +1,61 @@ +class Account::ValuationsController < ApplicationController + before_action :set_account + before_action :set_valuation, only: %i[ show edit update destroy ] + + def new + @valuation = @account.valuations.new + end + + def show + end + + def create + @valuation = @account.valuations.build(valuation_params) + + if @valuation.save + @valuation.sync_account_later + redirect_to account_path(@account), notice: "Valuation created" + else + # TODO: this is not an ideal way to handle errors and should eventually be improved. + # See: https://github.com/hotwired/turbo-rails/pull/367 + flash[:error] = @valuation.errors.full_messages.to_sentence + redirect_to account_path(@account) + end + end + + def edit + end + + def update + if @valuation.update(valuation_params) + @valuation.sync_account_later + redirect_to account_path(@account), notice: t(".success") + else + # TODO: this is not an ideal way to handle errors and should eventually be improved. + # See: https://github.com/hotwired/turbo-rails/pull/367 + flash[:error] = @valuation.errors.full_messages.to_sentence + redirect_to account_path(@account) + end + end + + def destroy + @valuation.destroy! + @valuation.sync_account_later + + redirect_to account_path(@account), notice: t(".success") + end + + private + + def set_account + @account = Current.family.accounts.find(params[:account_id]) + end + + def set_valuation + @valuation = @account.valuations.find(params[:id]) + end + + def valuation_params + params.require(:account_valuation).permit(:date, :value, :currency) + end +end diff --git a/app/controllers/accounts_controller.rb b/app/controllers/accounts_controller.rb index a0576b3a..4aa41e54 100644 --- a/app/controllers/accounts_controller.rb +++ b/app/controllers/accounts_controller.rb @@ -35,7 +35,6 @@ class AccountsController < ApplicationController def show @balance_series = @account.series(period: @period) - @valuation_series = @account.valuations.to_series end def edit diff --git a/app/controllers/valuations_controller.rb b/app/controllers/valuations_controller.rb deleted file mode 100644 index 1c2979ea..00000000 --- a/app/controllers/valuations_controller.rb +++ /dev/null @@ -1,70 +0,0 @@ -class ValuationsController < ApplicationController - before_action :set_valuation, only: %i[ edit update destroy ] - def create - @account = Current.family.accounts.find(params[:account_id]) - - # TODO: placeholder logic until we have a better abstraction for trends - @valuation = @account.valuations.new(valuation_params.merge(currency: @account.currency)) - if @valuation.save - @valuation.account.sync_later(@valuation.date) - - respond_to do |format| - format.html { redirect_to account_path(@account), notice: "Valuation created" } - format.turbo_stream - end - else - render :new, status: :unprocessable_entity - end - rescue ActiveRecord::RecordNotUnique - flash.now[:error] = "Valuation already exists for this date" - render :new, status: :unprocessable_entity - end - - def show - @valuation = Current.family.accounts.find(params[:account_id]).valuations.find(params[:id]) - end - - def edit - end - - def update - sync_start_date = [ @valuation.date, Date.parse(valuation_params[:date]) ].compact.min - if @valuation.update(valuation_params) - @valuation.account.sync_later(sync_start_date) - - redirect_to account_path(@valuation.account), notice: "Valuation updated" - else - render :edit, status: :unprocessable_entity - end - rescue ActiveRecord::RecordNotUnique - flash.now[:error] = "Valuation already exists for this date" - render :edit, status: :unprocessable_entity - end - - def destroy - @account = @valuation.account - sync_start_date = @account.valuations.where("date < ?", @valuation.date).order(date: :desc).first&.date - @valuation.destroy! - @account.sync_later(sync_start_date) - - respond_to do |format| - format.html { redirect_to account_path(@account), notice: "Valuation deleted" } - format.turbo_stream - end - end - - def new - @account = Current.family.accounts.find(params[:account_id]) - @valuation = @account.valuations.new - end - - private - # Use callbacks to share common setup or constraints between actions. - def set_valuation - @valuation = Valuation.find(params[:id]) - end - - def valuation_params - params.require(:valuation).permit(:date, :value) - end -end diff --git a/app/helpers/account/transfers_helper.rb b/app/helpers/account/transfers_helper.rb new file mode 100644 index 00000000..ba7a95ae --- /dev/null +++ b/app/helpers/account/transfers_helper.rb @@ -0,0 +1,2 @@ +module Account::TransfersHelper +end diff --git a/app/helpers/account/valuations_helper.rb b/app/helpers/account/valuations_helper.rb new file mode 100644 index 00000000..e1a93dde --- /dev/null +++ b/app/helpers/account/valuations_helper.rb @@ -0,0 +1,23 @@ +module Account::ValuationsHelper + def valuation_icon(valuation) + if valuation.first_of_series? + "keyboard" + elsif valuation.trend.direction.up? + "arrow-up" + elsif valuation.trend.direction.down? + "arrow-down" + else + "minus" + end + end + + def valuation_style(valuation) + color = valuation.first_of_series? ? "#D444F1" : valuation.trend.color + + <<-STYLE.strip + background-color: color-mix(in srgb, #{color} 5%, white); + border-color: color-mix(in srgb, #{color} 10%, white); + color: #{color}; + STYLE + end +end diff --git a/app/helpers/menus_helper.rb b/app/helpers/menus_helper.rb index 9576d54f..41907fa0 100644 --- a/app/helpers/menus_helper.rb +++ b/app/helpers/menus_helper.rb @@ -6,6 +6,23 @@ module MenusHelper end end + def contextual_menu_modal_action_item(label, url, icon: "pencil-line", turbo_frame: nil) + link_to url, class: "flex items-center rounded-lg text-gray-900 hover:bg-gray-50 py-2 px-3 gap-2", data: { turbo_frame: } do + concat(lucide_icon(icon, class: "shrink-0 w-5 h-5 text-gray-500")) + concat(tag.span(label, class: "text-sm")) + end + end + + def contextual_menu_destructive_item(label, url, turbo_confirm: true, turbo_frame: nil) + button_to url, + method: :delete, + class: "flex items-center w-full rounded-lg text-red-500 hover:bg-red-500/5 py-2 px-3 gap-2", + data: { turbo_confirm: turbo_confirm, turbo_frame: } do + concat(lucide_icon("trash-2", class: "shrink-0 w-5 h-5")) + concat(tag.span(label, class: "text-sm")) + end + end + private def contextual_menu_icon tag.button class: "flex hover:bg-gray-100 p-2 rounded", data: { menu_target: "button" } do diff --git a/app/helpers/transfers_helper.rb b/app/helpers/transfers_helper.rb deleted file mode 100644 index 98355baf..00000000 --- a/app/helpers/transfers_helper.rb +++ /dev/null @@ -1,2 +0,0 @@ -module TransfersHelper -end diff --git a/app/helpers/valuations_helper.rb b/app/helpers/valuations_helper.rb deleted file mode 100644 index 9fe5ad7f..00000000 --- a/app/helpers/valuations_helper.rb +++ /dev/null @@ -1,2 +0,0 @@ -module ValuationsHelper -end diff --git a/app/models/account.rb b/app/models/account.rb index dee4cae7..91b7532a 100644 --- a/app/models/account.rb +++ b/app/models/account.rb @@ -29,6 +29,10 @@ class Account < ApplicationRecord balances.where("date <= ?", date).order(date: :desc).first&.balance end + def favorable_direction + classification == "asset" ? "up" : "down" + end + # e.g. Wise, Revolut accounts that have transactions in multiple currencies def multi_currency? currencies = [ valuations.pluck(:currency), transactions.pluck(:currency) ].flatten.uniq diff --git a/app/models/account/valuation.rb b/app/models/account/valuation.rb new file mode 100644 index 00000000..ddbb519c --- /dev/null +++ b/app/models/account/valuation.rb @@ -0,0 +1,52 @@ +class Account::Valuation < ApplicationRecord + include Monetizable + + monetize :value + + belongs_to :account + + validates :account, :date, :value, presence: true + validates :date, uniqueness: { scope: :account_id } + + scope :chronological, -> { order(:date) } + scope :reverse_chronological, -> { order(date: :desc) } + + def trend + @trend ||= create_trend + end + + def first_of_series? + account.valuations.chronological.limit(1).pluck(:date).first == self.date + end + + def last_of_series? + account.valuations.reverse_chronological.limit(1).pluck(:date).first == self.date + end + + def sync_account_later + if destroyed? + sync_start_date = previous_valuation&.date + else + sync_start_date = [ date_previously_was, date ].compact.min + end + + account.sync_later(sync_start_date) + end + + private + + def previous_valuation + @previous_valuation ||= self.account + .valuations + .where("date < ?", date) + .order(date: :desc) + .first + end + + def create_trend + TimeSeries::Trend.new \ + current: self.value, + previous: previous_valuation&.value, + favorable_direction: account.favorable_direction + end +end diff --git a/app/models/time_series/trend.rb b/app/models/time_series/trend.rb index f62090fb..88fdd3a1 100644 --- a/app/models/time_series/trend.rb +++ b/app/models/time_series/trend.rb @@ -1,16 +1,15 @@ class TimeSeries::Trend include ActiveModel::Validations - attr_reader :current, :previous - - delegate :favorable_direction, to: :series + attr_reader :current, :previous, :favorable_direction validate :values_must_be_of_same_type, :values_must_be_of_known_type - def initialize(current:, previous:, series: nil) + def initialize(current:, previous:, series: nil, favorable_direction: nil) @current = current @previous = previous @series = series + @favorable_direction = get_favorable_direction(favorable_direction) validate! end @@ -25,6 +24,17 @@ class TimeSeries::Trend end.inquiry end + def color + case direction + when "up" + favorable_direction.down? ? red_hex : green_hex + when "down" + favorable_direction.down? ? green_hex : red_hex + else + gray_hex + end + end + def value if previous.nil? current.is_a?(Money) ? Money.new(0) : 0 @@ -56,8 +66,21 @@ class TimeSeries::Trend end private + attr_reader :series + def red_hex + "#F13636" # red-500 + end + + def green_hex + "#10A861" # green-600 + end + + def gray_hex + "#737373" # gray-500 + end + def values_must_be_of_same_type unless current.class == previous.class || [ previous, current ].any?(&:nil?) errors.add :current, "must be of the same type as previous" @@ -90,4 +113,9 @@ class TimeSeries::Trend obj end end + + def get_favorable_direction(favorable_direction) + direction = favorable_direction.presence || series&.favorable_direction + (direction.presence_in(TimeSeries::DIRECTIONS) || "up").inquiry + end end diff --git a/app/models/valuation.rb b/app/models/valuation.rb deleted file mode 100644 index 73a823e6..00000000 --- a/app/models/valuation.rb +++ /dev/null @@ -1,13 +0,0 @@ -class Valuation < ApplicationRecord - include Monetizable - - belongs_to :account - validates :account, :date, :value, presence: true - monetize :value - - scope :in_period, ->(period) { period.date_range.nil? ? all : where(date: period.date_range) } - - def self.to_series - TimeSeries.from_collection all, :value_money - end -end diff --git a/app/views/account/valuations/_form.html.erb b/app/views/account/valuations/_form.html.erb new file mode 100644 index 00000000..6027bcdd --- /dev/null +++ b/app/views/account/valuations/_form.html.erb @@ -0,0 +1,23 @@ +<%# locals: (valuation:) %> +<%= form_with model: valuation, + data: { turbo_frame: "_top" }, + url: valuation.new_record? ? account_valuations_path(valuation.account) : account_valuation_path(valuation.account, valuation), + builder: ActionView::Helpers::FormBuilder do |f| %> +
<%= valuation.date %>
- <%# TODO: Add descriptive name of valuation %> -Manually entered
-Find me in app/views/valuations/create.html.erb
-Find me in app/views/valuations/destroy.html.erb
-Find me in app/views/valuations/show.html.erb
-Find me in app/views/valuations/update.html.erb
-Deleting this entry will remove it from the account’s + history which will impact different parts of your account. This includes + the net worth and account graphs.
The only way you’ll be able + to add this entry back is by re-entering it manually via a new entry
" + confirm_title: Delete Entry? + delete_entry: Delete entry + edit_entry: Edit entry + no_change: No change + start_balance: Starting balance + value_update: Value update diff --git a/config/locales/views/accounts/en.yml b/config/locales/views/accounts/en.yml index eaf049f1..51b048e2 100644 --- a/config/locales/views/accounts/en.yml +++ b/config/locales/views/accounts/en.yml @@ -1,13 +1,6 @@ --- en: accounts: - account_valuation_list: - confirm_accept: Delete entry - confirm_body_html: "Deleting this entry will remove it from the account’s - history which will impact different parts of your account. This includes the - net worth and account graphs.
The only way you’ll be able to add - this entry back is by re-entering it manually via a new entry
" - confirm_title: Delete Entry? create: success: New account created successfully destroy: @@ -65,9 +58,12 @@ en: confirm_title: Delete account? edit: Edit import: Import transactions + loading_history: Loading account history... + new_entry: New entry sync_message_missing_rates: Since exchange rates haven't been synced, balance graphs may not reflect accurate values. sync_message_unknown_error: An error has occurred during the sync. + valuations: Value history summary: new: New account sync: diff --git a/config/routes.rb b/config/routes.rb index 2f57f282..12c059c6 100644 --- a/config/routes.rb +++ b/config/routes.rb @@ -80,8 +80,10 @@ Rails.application.routes.draw do post :sync end - resource :logo, only: :show, module: :account - resources :valuations, shallow: true + scope module: :account do + resource :logo, only: :show + resources :valuations + end end resources :institutions, except: %i[ index show ] diff --git a/db/migrate/20240620221801_rename_valuation_table.rb b/db/migrate/20240620221801_rename_valuation_table.rb new file mode 100644 index 00000000..d675f2cd --- /dev/null +++ b/db/migrate/20240620221801_rename_valuation_table.rb @@ -0,0 +1,5 @@ +class RenameValuationTable < ActiveRecord::Migration[7.2] + def change + rename_table :valuations, :account_valuations + end +end diff --git a/db/schema.rb b/db/schema.rb index f0f7d7d9..05378ced 100644 --- a/db/schema.rb +++ b/db/schema.rb @@ -10,7 +10,7 @@ # # It's strongly recommended that you check this file into your version control system. -ActiveRecord::Schema[7.2].define(version: 2024_06_20_125026) do +ActiveRecord::Schema[7.2].define(version: 2024_06_20_221801) do # These are extensions that must be enabled in order to support this database enable_extension "pgcrypto" enable_extension "plpgsql" @@ -37,6 +37,17 @@ ActiveRecord::Schema[7.2].define(version: 2024_06_20_125026) do t.datetime "updated_at", null: false end + create_table "account_valuations", id: :uuid, default: -> { "gen_random_uuid()" }, force: :cascade do |t| + t.uuid "account_id", null: false + t.date "date", null: false + t.decimal "value", precision: 19, scale: 4, null: false + t.string "currency", default: "USD", null: false + t.datetime "created_at", null: false + t.datetime "updated_at", null: false + t.index ["account_id", "date"], name: "index_account_valuations_on_account_id_and_date", unique: true + t.index ["account_id"], name: "index_account_valuations_on_account_id" + end + create_table "accounts", id: :uuid, default: -> { "gen_random_uuid()" }, force: :cascade do |t| t.string "subtype" t.uuid "family_id", null: false @@ -335,23 +346,13 @@ ActiveRecord::Schema[7.2].define(version: 2024_06_20_125026) do t.index ["family_id"], name: "index_users_on_family_id" end - create_table "valuations", id: :uuid, default: -> { "gen_random_uuid()" }, force: :cascade do |t| - t.uuid "account_id", null: false - t.date "date", null: false - t.decimal "value", precision: 19, scale: 4, null: false - t.string "currency", default: "USD", null: false - t.datetime "created_at", null: false - t.datetime "updated_at", null: false - t.index ["account_id", "date"], name: "index_valuations_on_account_id_and_date", unique: true - t.index ["account_id"], name: "index_valuations_on_account_id" - end - create_table "vehicles", id: :uuid, default: -> { "gen_random_uuid()" }, force: :cascade do |t| t.datetime "created_at", null: false t.datetime "updated_at", null: false end add_foreign_key "account_balances", "accounts", on_delete: :cascade + add_foreign_key "account_valuations", "accounts", on_delete: :cascade add_foreign_key "accounts", "families" add_foreign_key "accounts", "institutions" add_foreign_key "active_storage_attachments", "active_storage_blobs", column: "blob_id" @@ -367,5 +368,4 @@ ActiveRecord::Schema[7.2].define(version: 2024_06_20_125026) do add_foreign_key "transactions", "categories", on_delete: :nullify add_foreign_key "transactions", "merchants" add_foreign_key "users", "families" - add_foreign_key "valuations", "accounts", on_delete: :cascade end diff --git a/test/controllers/account/valuations_controller_test.rb b/test/controllers/account/valuations_controller_test.rb new file mode 100644 index 00000000..dee25276 --- /dev/null +++ b/test/controllers/account/valuations_controller_test.rb @@ -0,0 +1,71 @@ +require "test_helper" + +class Account::ValuationsControllerTest < ActionDispatch::IntegrationTest + setup do + sign_in @user = users(:family_admin) + @valuation = account_valuations(:savings_one) + @account = @valuation.account + end + + test "get valuations for an account" do + get account_valuations_url(@account) + assert_response :success + end + + test "new" do + get new_account_valuation_url(@account) + assert_response :success + end + + test "should create valuation" do + assert_difference("Account::Valuation.count") do + post account_valuations_url(@account), params: { + account_valuation: { + value: 19800, + date: Date.current + } + } + end + + assert_equal "Valuation created", flash[:notice] + assert_enqueued_with job: AccountSyncJob + assert_redirected_to account_path(@account) + end + + test "error when valuation already exists for date" do + assert_difference("Account::Valuation.count", 0) do + post account_valuations_url(@account), params: { + account_valuation: { + value: 19800, + date: @valuation.date + } + } + end + + assert_equal "Date has already been taken", flash[:error] + assert_redirected_to account_path(@account) + end + + test "should update valuation" do + patch account_valuation_url(@account, @valuation), params: { + account_valuation: { + value: 19550, + date: Date.current + } + } + + assert_equal "Valuation updated", flash[:notice] + assert_enqueued_with job: AccountSyncJob + assert_redirected_to account_path(@account) + end + + test "should destroy valuation" do + assert_difference("Account::Valuation.count", -1) do + delete account_valuation_url(@account, @valuation) + end + + assert_equal "Valuation deleted", flash[:notice] + assert_enqueued_with job: AccountSyncJob + assert_redirected_to account_path(@account) + end +end diff --git a/test/controllers/accounts_controller_test.rb b/test/controllers/accounts_controller_test.rb index d2393f25..d125af09 100644 --- a/test/controllers/accounts_controller_test.rb +++ b/test/controllers/accounts_controller_test.rb @@ -44,7 +44,7 @@ class AccountsControllerTest < ActionDispatch::IntegrationTest end test "should create an account" do - assert_difference [ "Account.count", "Valuation.count" ], 1 do + assert_difference [ "Account.count", "Account::Valuation.count" ], 1 do post accounts_path, params: { account: { accountable_type: "Depository", @@ -60,7 +60,7 @@ class AccountsControllerTest < ActionDispatch::IntegrationTest end test "can add optional start date and balance to an account on create" do - assert_difference -> { Account.count } => 1, -> { Valuation.count } => 2 do + assert_difference -> { Account.count } => 1, -> { Account::Valuation.count } => 2 do post accounts_path, params: { account: { accountable_type: "Depository", diff --git a/test/controllers/transactions_controller_test.rb b/test/controllers/transactions_controller_test.rb index 9e3cc9d9..fe861f64 100644 --- a/test/controllers/transactions_controller_test.rb +++ b/test/controllers/transactions_controller_test.rb @@ -75,7 +75,7 @@ class TransactionsControllerTest < ActionDispatch::IntegrationTest end assert_equal transaction_params[:amount].to_d, Transaction.order(created_at: :desc).first.amount - assert_equal flash[:notice], "New transaction created successfully" + assert_equal "New transaction created successfully", flash[:notice] assert_enqueued_with(job: AccountSyncJob) assert_redirected_to transactions_url end diff --git a/test/controllers/valuations_controller_test.rb b/test/controllers/valuations_controller_test.rb deleted file mode 100644 index bd7e476e..00000000 --- a/test/controllers/valuations_controller_test.rb +++ /dev/null @@ -1,74 +0,0 @@ -require "test_helper" - -class ValuationsControllerTest < ActionDispatch::IntegrationTest - setup do - sign_in @user = users(:family_admin) - @valuation = valuations(:savings_one) - @account = @valuation.account - end - - test "new" do - get new_account_valuation_url(@account) - assert_response :success - end - - test "should create valuation" do - assert_difference("Valuation.count") do - post account_valuations_url(@account), params: { valuation: { value: 1, date: Date.current, type: "Appraisal" } } - end - - assert_redirected_to account_path(@valuation.account) - end - - test "should create valuation with account's currency" do - foreign_account = accounts(:eur_checking) - post account_valuations_url(foreign_account), params: { valuation: { value: 1, date: Date.current, type: "Appraisal" } } - assert_equal foreign_account.currency, Valuation.order(created_at: :desc).first.currency - end - - test "create should sync account with correct start date" do - date = Date.current - 1.day - - assert_enqueued_with(job: AccountSyncJob, args: [ @account, date ]) do - post account_valuations_url(@account), params: { valuation: { value: 2, date:, type: "Appraisal" } } - end - end - - test "should update valuation" do - date = @valuation.date - patch valuation_url(@valuation), params: { valuation: { account_id: @valuation.account_id, value: 1, date:, type: "Appraisal" } } - assert_redirected_to account_path(@valuation.account) - end - - test "update should sync account with correct start date" do - new_date = @valuation.date - 1.day - assert_enqueued_with(job: AccountSyncJob, args: [ @account, new_date ]) do - patch valuation_url(@valuation), params: { valuation: { account_id: @valuation.account_id, value: @valuation.value, date: new_date, type: "Appraisal" } } - end - - new_date = @valuation.reload.date + 1.day - assert_enqueued_with(job: AccountSyncJob, args: [ @account, @valuation.date ]) do - patch valuation_url(@valuation), params: { valuation: { account_id: @valuation.account_id, value: @valuation.value, date: new_date, type: "Appraisal" } } - end - end - - test "should destroy valuation" do - assert_difference("Valuation.count", -1) do - delete valuation_url(@valuation) - end - - assert_redirected_to account_path(@account) - end - - test "destroy should sync account with correct start date" do - first, second = @account.valuations.order(:date).all - - assert_enqueued_with(job: AccountSyncJob, args: [ @account, first.date ]) do - delete valuation_url(second) - end - - assert_enqueued_with(job: AccountSyncJob, args: [ @account, nil ]) do - delete valuation_url(first) - end - end -end diff --git a/test/fixtures/valuations.yml b/test/fixtures/account/valuations.yml similarity index 100% rename from test/fixtures/valuations.yml rename to test/fixtures/account/valuations.yml diff --git a/test/models/transfer_test.rb b/test/models/account/transfer_test.rb similarity index 97% rename from test/models/transfer_test.rb rename to test/models/account/transfer_test.rb index 0ca4be91..d176dacf 100644 --- a/test/models/transfer_test.rb +++ b/test/models/account/transfer_test.rb @@ -1,6 +1,6 @@ require "test_helper" -class TransferTest < ActiveSupport::TestCase +class Account::TransferTest < ActiveSupport::TestCase setup do # Transfers can be posted on different dates @outflow = accounts(:checking).transactions.create! date: 1.day.ago.to_date, name: "Transfer to Savings", amount: 100, marked_as_transfer: true diff --git a/test/models/account/valuation_test.rb b/test/models/account/valuation_test.rb new file mode 100644 index 00000000..a7443237 --- /dev/null +++ b/test/models/account/valuation_test.rb @@ -0,0 +1,39 @@ +require "test_helper" + +class Account::ValuationTest < ActiveSupport::TestCase + setup do + @valuation = account_valuations :savings_one + @family = families :dylan_family + end + + test "one valuation per day" do + assert_equal 12.days.ago.to_date, account_valuations(:savings_one).date + invalid_valuation = Account::Valuation.new date: 12.days.ago.to_date, value: 20000 + assert invalid_valuation.invalid? + end + + test "triggers sync with correct start date when valuation is set to prior date" do + prior_date = @valuation.date - 1 + @valuation.update! date: prior_date + + @valuation.account.expects(:sync_later).with(prior_date) + @valuation.sync_account_later + end + + test "triggers sync with correct start date when valuation is set to future date" do + prior_date = @valuation.date + @valuation.update! date: @valuation.date + 1 + + @valuation.account.expects(:sync_later).with(prior_date) + @valuation.sync_account_later + end + + test "triggers sync with correct start date when valuation deleted" do + prior_valuation = account_valuations :savings_two # 25 days ago + current_valuation = account_valuations :savings_one # 12 days ago + current_valuation.destroy! + + current_valuation.account.expects(:sync_later).with(prior_valuation.date) + current_valuation.sync_account_later + end +end diff --git a/test/models/account_test.rb b/test/models/account_test.rb index 10397231..36633ff6 100644 --- a/test/models/account_test.rb +++ b/test/models/account_test.rb @@ -111,7 +111,7 @@ class AccountTest < ActiveSupport::TestCase end test "should destroy dependent valuations" do - assert_difference("Valuation.count", -@account.valuations.count) do + assert_difference("Account::Valuation.count", -@account.valuations.count) do @account.destroy end end diff --git a/test/models/time_series/trend_test.rb b/test/models/time_series/trend_test.rb index 1ad73421..b05d13ad 100644 --- a/test/models/time_series/trend_test.rb +++ b/test/models/time_series/trend_test.rb @@ -11,11 +11,13 @@ class TimeSeries::TrendTest < ActiveSupport::TestCase test "up" do trend = TimeSeries::Trend.new(current: 100, previous: 50) assert_equal "up", trend.direction + assert_equal "#10A861", trend.color end test "down" do trend = TimeSeries::Trend.new(current: 50, previous: 100) assert_equal "down", trend.direction + assert_equal "#F13636", trend.color end test "flat" do @@ -25,6 +27,7 @@ class TimeSeries::TrendTest < ActiveSupport::TestCase assert_equal "flat", trend1.direction assert_equal "flat", trend2.direction assert_equal "flat", trend3.direction + assert_equal "#737373", trend1.color end test "infinitely up" do diff --git a/test/models/valuation_test.rb b/test/models/valuation_test.rb deleted file mode 100644 index 59ba8292..00000000 --- a/test/models/valuation_test.rb +++ /dev/null @@ -1,4 +0,0 @@ -require "test_helper" - -class ValuationTest < ActiveSupport::TestCase -end