Account

NAME

App::Moneymoor::Gateway::Account - SQL gateway for accounts, and the owner of the credit-card payment-category invariant.

SYNOPSIS


use App::Moneymoor::Gateway::Account;

my $gw = App::Moneymoor::Gateway::Account.new(:$db);

my $current = $gw.create(App::Moneymoor::Model::Account.new(
    name => 'Current Account', type => 'cash',
));

# Creating a credit account also creates its payment envelope, in the
# same SQL transaction — there is no window in which one exists
# without the other.
my $visa = $gw.create(App::Moneymoor::Model::Account.new(
    name => 'Visa', type => 'credit',
));
my $envelope = $gw.payment-category-for($visa.id);
say $envelope.name;                     # Visa

my @open = $gw.find-all;                # closed accounts excluded
my @all  = $gw.find-all(:include-closed);

$gw.close($visa.id);                    # soft retire, history intact
$gw.reopen($visa.id);

my $dup = $gw.create(App::Moneymoor::Model::Account.new(name => 'Visa'));
say $dup ~~ Failure;                    # True — names are unique
$dup.so;

DESCRIPTION

Accounts are the one entity whose creation has a side effect, and it is a load-bearing one: every credit account owns exactly one payment category, created with it and deleted with it. The budget derivation relies on that — a credit account with no payment envelope has nowhere to reserve the cash its spending commits, so Service::Budget refuses to let its transactions reach the budget at all (and says so in warnings). Doing the two inserts inside one run-txn is what makes the invariant true rather than usually true.

The payment envelope is named after its account and lives in the system Credit Card Payments group, which the migrations seed. If that group has somehow been deleted, create recreates it rather than failing: an ungrouped payment category is a display problem, a missing one is a correctness problem.

VALIDATION AND FAILURE

Every method validates before opening a transaction and returns a Failure (via fail) for anything it will not do — duplicate name, empty name, unknown type, unknown id. A Failure returned from inside a transaction would be a silent commit of a half-applied change, so the rule is: validate first, then write.

my $r = $gw.create($account);
    if $r ~~ Failure { note $r.exception.message; $r.so }

WHAT UPDATE WILL NOT DO

update changes name, note, closed and sort-order. It refuses to change type, and that is deliberate: every type transition has a different correct behaviour (cash → credit must mint a payment envelope; credit → cash must retire one that may already hold money and be referenced by splits; anything → tracking must pull existing transactions back out of the budget). Silently picking one of those would corrupt history. Delete the account and re-create it, or wait for a version that offers explicit conversions.

DELETION

delete is a hard delete and it takes the account's transactions (and their splits) with it, plus the payment category and any money assigned to it. It is refused when the payment category is referenced by splits belonging to other accounts' transactions — that would rewrite those transactions' history — with a message naming the problem. Prefer close for anything you still want to see.

ATTRIBUTES

  • db — required App::Moneymoor::DB.

METHODS

  • find-all(Bool :$include-closed = False -- Array)>

  • find-by-id(Int:D $id -- Model::Account)> — type object when absent.

  • find-by-name(Str:D $name -- Model::Account)>

  • create(Model::Account:D $account -- Model::Account)>

  • update(Model::Account:D $account)

  • close(Int:D $id) / reopen(Int:D $id)

  • delete(Int:D $id)

  • payment-category-for(Int:D $account-id -- Model::Category)>

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.