mirror of
https://github.com/maybe-finance/maybe.git
synced 2025-07-25 08:09:38 +02:00
Budgeting V1 (#1609)
* Budgeting V1 * Basic UI template * Fully scaffolded budgeting v1 * Basic working budget * Finalize donut chart for budgets * Allow categorization of loan payments for budget * Include loan payments in incomes_and_expenses scope * Add budget allocations progress * Empty states * Clean up budget methods * Category aggregation queries * Handle overage scenarios in form * Finalize budget donut chart controller * Passing tests * Fix allocation naming * Add income category migration * Native support for uncategorized budget category * Formatting * Fix subcategory sort order, padding * Fix calculation for category rollups in budget
This commit is contained in:
parent
413ec6cbed
commit
195ec85d96
61 changed files with 2044 additions and 140 deletions
|
@ -42,34 +42,34 @@ class Transfer < ApplicationRecord
|
|||
end
|
||||
|
||||
def auto_match_for_account(account)
|
||||
matches = account.entries.account_transactions.joins("
|
||||
JOIN account_entries ae2 ON
|
||||
account_entries.amount = -ae2.amount AND
|
||||
account_entries.currency = ae2.currency AND
|
||||
account_entries.account_id <> ae2.account_id AND
|
||||
ABS(account_entries.date - ae2.date) <= 4
|
||||
").select(
|
||||
"account_entries.id",
|
||||
"account_entries.entryable_id AS e1_entryable_id",
|
||||
"ae2.entryable_id AS e2_entryable_id",
|
||||
"account_entries.amount AS e1_amount",
|
||||
"ae2.amount AS e2_amount"
|
||||
)
|
||||
matches = Account::Entry.from("account_entries inflow_candidates")
|
||||
.joins("
|
||||
JOIN account_entries outflow_candidates ON (
|
||||
inflow_candidates.amount < 0 AND
|
||||
outflow_candidates.amount > 0 AND
|
||||
inflow_candidates.amount = -outflow_candidates.amount AND
|
||||
inflow_candidates.currency = outflow_candidates.currency AND
|
||||
inflow_candidates.account_id <> outflow_candidates.account_id AND
|
||||
inflow_candidates.date BETWEEN outflow_candidates.date - 4 AND outflow_candidates.date + 4 AND
|
||||
inflow_candidates.date >= outflow_candidates.date
|
||||
)
|
||||
").joins("
|
||||
LEFT JOIN transfers existing_transfers ON (
|
||||
(existing_transfers.inflow_transaction_id = inflow_candidates.entryable_id AND
|
||||
existing_transfers.outflow_transaction_id = outflow_candidates.entryable_id) OR
|
||||
(existing_transfers.inflow_transaction_id = inflow_candidates.entryable_id) OR
|
||||
(existing_transfers.outflow_transaction_id = outflow_candidates.entryable_id)
|
||||
)
|
||||
")
|
||||
.where(existing_transfers: { id: nil })
|
||||
.where("inflow_candidates.account_id = ? AND outflow_candidates.account_id = ?", account.id, account.id)
|
||||
.pluck(:inflow_transaction_id, :outflow_transaction_id)
|
||||
|
||||
Transfer.transaction do
|
||||
matches.each do |match|
|
||||
inflow = match.e1_amount.negative? ? match.e1_entryable_id : match.e2_entryable_id
|
||||
outflow = match.e1_amount.negative? ? match.e2_entryable_id : match.e1_entryable_id
|
||||
|
||||
# Skip all rejected, or already matched transfers
|
||||
next if Transfer.exists?(
|
||||
inflow_transaction_id: inflow,
|
||||
outflow_transaction_id: outflow
|
||||
)
|
||||
|
||||
matches.each do |inflow_transaction_id, outflow_transaction_id|
|
||||
Transfer.create!(
|
||||
inflow_transaction_id: inflow,
|
||||
outflow_transaction_id: outflow
|
||||
inflow_transaction_id: inflow_transaction_id,
|
||||
outflow_transaction_id: outflow_transaction_id,
|
||||
)
|
||||
end
|
||||
end
|
||||
|
@ -109,6 +109,10 @@ class Transfer < ApplicationRecord
|
|||
to_account.liability?
|
||||
end
|
||||
|
||||
def categorizable?
|
||||
to_account.accountable_type == "Loan"
|
||||
end
|
||||
|
||||
private
|
||||
def transfer_has_different_accounts
|
||||
return unless inflow_transaction.present? && outflow_transaction.present?
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue