Transaction

NAME

App::Moneymoor::Model::Transaction - money entering or leaving one account on one day.

SYNOPSIS


use App::Moneymoor::Model::Transaction;

# £42.50 of groceries on the Visa (outflow: negative):
my $spend = App::Moneymoor::Model::Transaction.new(
    account-id => $visa-id,
    date       => '2026-03-14',
    payee-id   => $tesco-id,
    amount     => -4250,
);

# £1,800 of salary into the current account (inflow: positive):
my $pay = App::Moneymoor::Model::Transaction.new(
    account-id => $current-id,
    date       => '2026-03-25',
    amount     => 180000,
);

my $t = App::Moneymoor::Model::Transaction.new-from-row(%row);
say $t.is-transfer;      # True when it has a peer leg
say $t.is-outflow;       # amount < 0

DESCRIPTION

amount is integer pence, signed from the account's point of view: an inflow is positive, an outflow is negative. That single convention is what makes an account balance a plain sum, and it holds for every account type — spending Ā£42.50 on a credit card is -4250, which drives the card's balance further negative (i.e. deeper into debt).

A transaction is either categorized or a transfer:

  • Categorized: it owns one or more splits whose amounts sum to amount. A single-category transaction is just a transaction with one split — there is no separate "simple" shape to special case.

  • Transfer: transfer-peer-id points at the other leg, which is a separate transaction on the other account with the negated amount and the same date. Transfers between two on-budget accounts carry no splits at all: the money has not left the budget, so no envelope should move. (The one derived exception is a transfer involving a credit account, which moves that card's payment envelope — see App::Moneymoor::Service::Budget.) A transfer to or from a tracking account is different: money really is leaving or entering the budget, so the on-budget leg is categorized and carries splits.

cleared is the reconciliation state: uncleared (you entered it), cleared (you saw it on the statement), reconciled (locked as part of a finished reconciliation). v0.1 stores it and reports cleared / uncleared balances; the reconciliation workflow arrives with the UI.

date is YYYY-MM-DD — no timezone, no time of day. A transaction happens on a day, and a day is a calendar fact, not an instant.

It is not bucketed here. Which budget period a date falls in depends on the budget's period scheme (a calendar month, a month anchored on payday, a four-weekly pay window), and this model does not know the scheme and should not: a bucket derived from a date by a scheme-ignorant model is right only for the default scheme and silently wrong for every other one. Service::Budget asks App::Moneymoor::Util::Period the question, once, with the scheme in hand.

ATTRIBUTES

  • id — primary key; absent on a not-yet-inserted row.

  • account-id — required FK to accounts.id.

  • date — required YYYY-MM-DD.

  • payee-id — FK to payees.id; null for transfers.

  • memo — free-form, default empty string.

  • amount — required signed integer pence.

  • cleared — uncleared / cleared / reconciled.

  • transfer-peer-id — FK to the other leg's transactions.id.

  • created-at — gateway-managed timestamp.

METHODS

  • new-from-row(%row) — build from a DBIish row hash.

  • is-inflow / is-outflow — amount sign predicates (a zero amount is neither).

  • is-transfer — has a peer leg.

  • is-cleared — cleared or reconciled (the "has the bank seen it" question).

  • is-reconciled — strictly reconciled.

App::Moneymoor v0.4.2

YNAB-style envelope budgeting: a derivation engine

Authors

  • Matt Doughty

License

Artistic-2.0

Dependencies

DBIish:ver<0.6.7>:auth<zef:raku-community-modules>Notcurses::Native:ver<0.6.5+>:auth<zef:apogee>Selkie:ver<0.16.0+>:auth<zef:apogee>JSON::Fast:ver<0.19>:auth<cpan:TIMOTIMO>MacOS::NativeLib:ver<0.0.6>:auth<zef:lizmat>

Test Dependencies

Provides

  • App::Moneymoor
  • App::Moneymoor::Config
  • App::Moneymoor::DB
  • App::Moneymoor::Gateway::Account
  • App::Moneymoor::Gateway::Assignment
  • App::Moneymoor::Gateway::Category
  • App::Moneymoor::Gateway::Payee
  • App::Moneymoor::Gateway::Transaction
  • App::Moneymoor::Handlers::Boot
  • App::Moneymoor::Model::Account
  • App::Moneymoor::Model::Assignment
  • App::Moneymoor::Model::Category
  • App::Moneymoor::Model::CategoryGroup
  • App::Moneymoor::Model::Payee
  • App::Moneymoor::Model::Split
  • App::Moneymoor::Model::Transaction
  • App::Moneymoor::Screen::Accounts
  • App::Moneymoor::Screen::Budget
  • App::Moneymoor::Screen::Login
  • App::Moneymoor::Screen::Main
  • App::Moneymoor::Screen::Main::Keybinds
  • App::Moneymoor::Screen::Main::Modals
  • App::Moneymoor::Screen::Main::Subscriptions
  • App::Moneymoor::Screen::Reports
  • App::Moneymoor::Service::Budget
  • App::Moneymoor::Service::Icons
  • App::Moneymoor::Service::Target
  • App::Moneymoor::Service::Workspace
  • App::Moneymoor::StoreHandlers
  • App::Moneymoor::Theme
  • App::Moneymoor::Theme::Catppuccin
  • App::Moneymoor::Theme::Dracula
  • App::Moneymoor::Theme::Everforest
  • App::Moneymoor::Theme::Gruvbox
  • App::Moneymoor::Theme::Kanagawa
  • App::Moneymoor::Theme::Monokai
  • App::Moneymoor::Theme::Nord
  • App::Moneymoor::Theme::OneDark
  • App::Moneymoor::Theme::RosePine
  • App::Moneymoor::Theme::Solarized
  • App::Moneymoor::Theme::TokyoNight
  • App::Moneymoor::Themes
  • App::Moneymoor::UI
  • App::Moneymoor::Util::Money
  • App::Moneymoor::Util::Period
  • App::Moneymoor::View::BudgetRow
  • App::Moneymoor::View::EmptyState
  • App::Moneymoor::View::HintBar
  • App::Moneymoor::View::InspectorPane
  • App::Moneymoor::View::ModalChrome
  • App::Moneymoor::View::RegisterRow
  • App::Moneymoor::View::ReportRow
  • App::Moneymoor::Widget::BannerBar
  • App::Moneymoor::Widget::BootProgressModal

The Camelia image is copyright 2009 by Larry Wall. "Raku" is a trademark of the Yet Another Society. All rights reserved.

Built with Podlite — the markup and publishing tools behind this site.