Defaults to enabled; use C<--no-commodities> to disable.
+=head2 --budget
+
+Enables budget transactions.
+
+Budget transactions are only supported by the Ledger format (for now). This option is silently
+ignored otherwise.
+
+Defaults to enabled; use C<--no-budget> to disable.
+
=head2 --opening-date DATE
Specify the opening date for the "opening balances" transaction. This transaction is created (if
=for :list
* I didn't intend to make this a releasable robust product, so it's lacking tests.
-* Budgets and scheduled transactions are not (yet) converted.
+* Scheduled transactions are not (yet) converted.
* There are some minor formatting tweaks I will make (e.g. consolidate transaction tags and payees)
=cut
my $transactions = $homebank->sorted_transactions;
my $accounts = $homebank->accounts;
my $categories = $homebank->categories;
+ my @budget;
# determine full Ledger account names
for my $account (@$accounts) {
my $type = $category->{flags}{income} ? 'Income' : 'Expenses';
my $full_name = $homebank->full_category_name($category->{key});
$category->{ledger_name} = "${type}:${full_name}";
+
+ if ($opts->{budget} && $category->{flags}{budget}) {
+ for my $month_num ($category->{flags}{custom} ? (1 .. 12) : 0) {
+ my $amount = $category->{budget_amounts}[$month_num] || 0;
+ next if !$amount && !$category->{flags}{forced};
+
+ $budget[$month_num]{$category->{ledger_name}} = $amount;
+ }
+ }
}
# handle renaming and marking excluded accounts
$ledger->add_commodities($commodity) if $opts->{commodities};
}
+ my $first_date;
if ($has_initial_balance) {
# transactions are sorted, so the first transaction is the oldest
- my $first_date = $opts->{opening_date} || $transactions->[0]{date};
+ $first_date = $opts->{opening_date} || $transactions->[0]{date};
if ($first_date !~ /^\d{4}-\d{2}-\d{2}$/) {
die "Opening date must be in the form YYYY-MM-DD.\n";
}
});
}
+ if ($opts->{budget}) {
+ my ($first_year) = $first_date =~ /^(\d{4})/;
+
+ for my $month_num (0 .. 12) {
+ next if !$budget[$month_num];
+
+ my $payee = 'Monthly';
+ if (0 < $month_num) {
+ my $year = $first_year;
+ $year += 1 if sprintf('%04d-%02d-99', $first_year, $month_num) lt $first_date;
+ my $date = sprintf('%04d-%02d', $year, $month_num);
+ $payee = "Every 12 months from ${date}";
+ }
+ # my @MONTHS = qw(ALL Jan Feb Mar Apr May Jun Jul Aug Sep Oct Nov Dec);
+ # $payee = "Monthly this $MONTHS[$month_num]" if 0 < $month_num;
+
+ my @postings;
+
+ for my $account (sort keys %{$budget[$month_num]}) {
+ my $amount = $budget[$month_num]{$account};
+ push @postings, {
+ account => $account,
+ amount => -$amount,
+ commodity => $commodities{$homebank->base_currency},
+ }
+ }
+ push @postings, {
+ account => 'Assets',
+ };
+
+ $ledger->add_transactions({
+ date => '~',
+ payee => $payee,
+ postings => \@postings,
+ });
+ }
+ }
+
my %seen;
TRANSACTION:
payees => 1,
tags => 1,
commodities => 1,
+ budget => 1,
opening_date => '',
rename_accounts => {},
exclude_accounts => [],
'payees!' => \$opts{payees},
'tags!' => \$opts{tags},
'commodities!' => \$opts{commodities},
+ 'budget!' => \$opts{budget},
'opening-date=s' => \$opts{opening_date},
'rename-account|r=s' => \%{$opts{rename_accounts}},
'exclude-account|x=s' => \@{$opts{exclude_accounts}},
) or pod2usage(-exitval => 1, -verbose => 99, -sections => [qw(SYNOPSIS OPTIONS)]);
- $opts{input} = shift @args if !$opts{input};
+ $opts{input} = shift @args if !$opts{input};
+ $opts{budget} = 0 if lc($opts{format}) ne 'ledger';
return \%opts;
}