v9.0.0: rename 'user' to 'account' where appropriate
This commit is contained in:
parent
996159a2ad
commit
4c90277fa9
33 changed files with 249 additions and 172 deletions
51
UPGRADING.md
51
UPGRADING.md
|
@ -19,6 +19,57 @@ supports Perl versions down to 5.32 (2020), which is in Debian 11 "bullseye"
|
|||
and 12 "bookworm" becomes the new oldstable, RevBank will begin to require Perl
|
||||
5.36 (2022).
|
||||
|
||||
# (2025-04-10) RevBank 9.0.0
|
||||
|
||||
In many places, the term 'user' has been replaced with the term 'account', to
|
||||
more accurately describe the current state of RevBank, which has non-user
|
||||
accounts in addition to user accounts.
|
||||
|
||||
The term 'account' is now the generic term (visible and hidden accounts), but
|
||||
'user' or 'username' is still used where only user accounts (visible accounts)
|
||||
are valid.
|
||||
|
||||
## Renamed hooks
|
||||
|
||||
| Old name | New name |
|
||||
|---------------------|------------------------|
|
||||
| `hook_user_created` | `hook_account_created` |
|
||||
| `hook_user_balance` | `hook_account_balance` |
|
||||
|
||||
The new hooks are added in addition to the old ones.
|
||||
|
||||
The old hooks will be removed in a future version, after 2027-05-01.
|
||||
|
||||
## Renamed global identifiers
|
||||
|
||||
| Old name | New name |
|
||||
|-------------------------------|-------------------------------------|
|
||||
| `RevBank::Users::assert_user` | `RevBank::Accounts::assert_account` |
|
||||
| `RevBank::Users` | `RevBank::Accounts` |
|
||||
| `$contra->{user}` | `$contra->{account}` |
|
||||
| `$entry->user` | `$entry->account` |
|
||||
|
||||
Custom plugins might be affected by this change, but most won't.
|
||||
|
||||
`->{user}` was kept for read-only use, and will be removed after 2027-05-01.
|
||||
|
||||
The old functions/method names are aliases for the new ones, and will be
|
||||
removed after 2027-05-01.
|
||||
|
||||
## Not renamed
|
||||
|
||||
The following remain unchanged, as they only or mostly pertain to visible
|
||||
accounts, which are primarily intended as user accounts:
|
||||
|
||||
- `parse_user()` function
|
||||
- `hook_user_info`
|
||||
- `adduser` command
|
||||
- `users` plugin
|
||||
|
||||
The following remain unchanged (for now) because external scripts might break
|
||||
if these were changed:
|
||||
- `NEWUSER` in the log file
|
||||
|
||||
# (2024-12-26) RevBank 8.0.0
|
||||
|
||||
Another breaking change, another major version upgrade due to semantic versioning!
|
||||
|
|
|
@ -10,7 +10,7 @@ Since version 2, RevBank is loosely modeled after C<qpsmtpd>, which is an SMTP s
|
|||
|
||||
RevBank is interactive and stateful. Global state is provided in the form of a "shopping cart", a L<RevBank::Cart> object, which represents the ongoing, unfinished, transaction. The terms "cart", "unfinished transaction", and "current transaction" generally all refer to the same thing in the context of RevBank.
|
||||
|
||||
In addition, RevBank provides the concept of accounts through L<RevBank::Users>. There are user accounts and internal accounts; internal accounts are used as contra accounts for I<double-entry bookkeeping>, and are hidden from the user interface. Accounts only have a name, a balance, and some timestamps; things like transaction histories are provided by plugins.
|
||||
In addition, RevBank provides the concept of accounts through L<RevBank::Accounts>. There are user accounts and hidden accounts; hidden accounts are used as contra accounts for I<double-entry bookkeeping>, and are hidden from the user interface. Accounts only have a name, a balance, and some timestamps; things like transaction histories are provided by plugins.
|
||||
|
||||
Notably, the RevBank core does B<not> have any notion of "products". Support for buying products through RevBank is provided by plugins, like the included C<products> and C<market> plugins. It is easy to add another source of products by writing another plugin. A plugin contains arbitrary code and can do anything, including querying external resources.
|
||||
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
package RevBank::Users;
|
||||
package RevBank::Accounts;
|
||||
|
||||
use v5.32;
|
||||
use warnings;
|
||||
|
@ -12,7 +12,7 @@ use List::Util ();
|
|||
my $filename = "revbank.accounts";
|
||||
|
||||
sub _read() {
|
||||
my @users;
|
||||
my @accounts;
|
||||
for my $line (slurp $filename) {
|
||||
$line =~ /\S/ or next;
|
||||
# Not using RevBank::Prompt::split_input to keep parsing by external
|
||||
|
@ -25,23 +25,23 @@ sub _read() {
|
|||
@split = split " ", $line, 2;
|
||||
}
|
||||
|
||||
push @users, \@split;
|
||||
push @accounts, \@split;
|
||||
}
|
||||
|
||||
my %users;
|
||||
for (@users) {
|
||||
my %accounts;
|
||||
for (@accounts) {
|
||||
my $name = lc $_->[0];
|
||||
|
||||
exists $users{$name} and die "$filename: duplicate entry '$name'\n";
|
||||
$users{$name} = $_;
|
||||
exists $accounts{$name} and die "$filename: duplicate entry '$name'\n";
|
||||
$accounts{$name} = $_;
|
||||
|
||||
if ($name =~ s/^\*//) {
|
||||
# user-accessible special account: support without * prefix
|
||||
exists $users{$name} and die "$filename: duplicate entry '$name'\n";
|
||||
$users{$name} = $_;
|
||||
exists $accounts{$name} and die "$filename: duplicate entry '$name'\n";
|
||||
$accounts{$name} = $_;
|
||||
}
|
||||
}
|
||||
return \%users;
|
||||
return \%accounts;
|
||||
}
|
||||
|
||||
sub names() {
|
||||
|
@ -50,25 +50,26 @@ sub names() {
|
|||
return List::Util::uniqstr map $_->[0], values %{ _read() };
|
||||
}
|
||||
|
||||
sub balance($username) {
|
||||
return RevBank::Amount->parse_string( _read()->{ lc $username }->[1] );
|
||||
sub balance($account) {
|
||||
return RevBank::Amount->parse_string( _read()->{ lc $account }->[1] );
|
||||
}
|
||||
|
||||
sub since($username) {
|
||||
return _read()->{ lc $username }->[3];
|
||||
sub since($account) {
|
||||
return _read()->{ lc $account }->[3];
|
||||
}
|
||||
|
||||
sub create($username) {
|
||||
die "Account already exists" if exists _read()->{ lc $username };
|
||||
sub create($account) {
|
||||
die "Account already exists" if exists _read()->{ lc $account };
|
||||
|
||||
my $now = now();
|
||||
append $filename, "$username 0.00 $now\n";
|
||||
RevBank::Plugins::call_hooks("user_created", $username);
|
||||
return $username;
|
||||
append $filename, "$account 0.00 $now\n";
|
||||
RevBank::Plugins::call_hooks("user_created", $account); # until 2027-05-01
|
||||
RevBank::Plugins::call_hooks("account_created", $account);
|
||||
return $account;
|
||||
}
|
||||
|
||||
sub update($username, $delta, $transaction_id) {
|
||||
my $account = assert_user($username) or die "No such user ($username)";
|
||||
sub update($account, $delta, $transaction_id) {
|
||||
$account = assert_account($account);
|
||||
|
||||
my $old = RevBank::Amount->new(0);
|
||||
my $new = RevBank::Amount->new(0);
|
||||
|
@ -99,24 +100,28 @@ sub update($username, $delta, $transaction_id) {
|
|||
};
|
||||
|
||||
RevBank::Plugins::call_hooks(
|
||||
# Backwards compatibility until 2027-05-01
|
||||
"user_balance", $account, $old, $delta, $new, $transaction_id
|
||||
);
|
||||
RevBank::Plugins::call_hooks(
|
||||
"account_balance", $account, $old, $delta, $new, $transaction_id
|
||||
);
|
||||
}
|
||||
|
||||
sub is_hidden($username) {
|
||||
return $username =~ /^[-+]/;
|
||||
sub is_hidden($account) {
|
||||
return $account =~ /^[-+]/;
|
||||
}
|
||||
|
||||
sub is_special($username) {
|
||||
return $username =~ /^[-+*]/;
|
||||
sub is_special($account) {
|
||||
return $account =~ /^[-+*]/;
|
||||
}
|
||||
|
||||
sub parse_user($username, $allow_invalid = 0) {
|
||||
return undef if is_hidden($username);
|
||||
|
||||
my $users = _read();
|
||||
my $accounts = _read();
|
||||
|
||||
my $user = $users->{ lc $username } or return undef;
|
||||
my $user = $accounts->{ lc $username } or return undef;
|
||||
|
||||
if ($user->[1] =~ /^!(.*)/) {
|
||||
warn "$username: Invalid account ($1).\n";
|
||||
|
@ -128,21 +133,32 @@ sub parse_user($username, $allow_invalid = 0) {
|
|||
return $user->[0];
|
||||
}
|
||||
|
||||
sub assert_user($username) {
|
||||
my $users = _read();
|
||||
sub assert_account($account) {
|
||||
my $accounts = _read();
|
||||
|
||||
my $user = $users->{ lc $username };
|
||||
my $account_info = $accounts->{ lc $account };
|
||||
|
||||
if ($user) {
|
||||
Carp::croak("Account $username can't be used") if not defined balance $username;
|
||||
return $user->[0];
|
||||
if ($account) {
|
||||
Carp::croak("Account $account can't be used") if not defined balance $account;
|
||||
return $account_info->[0];
|
||||
}
|
||||
|
||||
return create $username if is_hidden $username;
|
||||
return create $account if is_hidden $account;
|
||||
|
||||
Carp::croak("No such user ($username)")
|
||||
Carp::croak("No such user ($account)");
|
||||
}
|
||||
|
||||
# Backwards compatibility until 2027-05-01
|
||||
*RevBank::Users::names = \&RevBank::Accounts::names;
|
||||
*RevBank::Users::balance = \&RevBank::Accounts::balance;
|
||||
*RevBank::Users::since = \&RevBank::Accounts::since;
|
||||
*RevBank::Users::create = \&RevBank::Accounts::create;
|
||||
*RevBank::Users::update = \&RevBank::Accounts::update;
|
||||
*RevBank::Users::is_hidden = \&RevBank::Accounts::is_hidden;
|
||||
*RevBank::Users::is_special = \&RevBank::Accounts::is_special;
|
||||
*RevBank::Users::parse_user = \&RevBank::Accounts::parse_user;
|
||||
*RevBank::Users::assert_user = \&RevBank::Accounts::assert_account;
|
||||
|
||||
1;
|
||||
|
||||
|
|
@ -1,10 +1,10 @@
|
|||
=head1 NAME
|
||||
|
||||
RevBank::Users - Banking and bookkeeping accounts
|
||||
RevBank::Accounts - Banking and bookkeeping accounts
|
||||
|
||||
=head1 DESCRIPTION
|
||||
|
||||
This package handles all accounts in RevBank. Accounts are called "users" because originally, RevBank only had user accounts. Today, RevBank does doubly-entry bookkeeping and has multiple account types to accommodate that.
|
||||
This package handles all accounts in RevBank. RevBank does doubly-entry bookkeeping and has multiple account types to accommodate that.
|
||||
|
||||
This package is where manipulation of C<revbank.accounts> happens.
|
||||
|
||||
|
@ -16,6 +16,10 @@ This package is where manipulation of C<revbank.accounts> happens.
|
|||
|
||||
User accounts are typically made with the C<adduser> command, and almost all interactions with RevBank will involve only user accounts, from the perspective of the user.
|
||||
|
||||
The name of a user account is called a I<username> within RevBank.
|
||||
|
||||
Any account that does not begin with one of the characters C<->, C<+>, or C<*>, is a user account.
|
||||
|
||||
=item * Hidden accounts
|
||||
|
||||
The name of a hidden account begins with a C<-> or C<+> sign. These accounts are created automatically by plugins to provide the I<double> part in I<doubly-entry bookkeeping>.
|
||||
|
@ -100,9 +104,9 @@ Only the first two columns are mandatory. This makes migrating to RevBank very s
|
|||
|
||||
=head2 Functions
|
||||
|
||||
Usernames are case preserving, but case insensitive. Account name arguments to functions are case insensitive, but return values use the canonical capitalization.
|
||||
Account names are case preserving, but case insensitive. Account name arguments to functions are case insensitive, but return values use the canonical capitalization.
|
||||
|
||||
Anything that outputs a username should always run it through C<parse_user> or C<assert_user>.
|
||||
Anything that outputs a username should always run it through C<parse_user> or C<assert_account>.
|
||||
|
||||
=head3 names
|
||||
|
||||
|
@ -120,13 +124,13 @@ Returns the last used datetime of the account.
|
|||
|
||||
Creates an account with that name and a balance of zero. The name must not already exist.
|
||||
|
||||
After updating the file, calls the C<user_created> hook with the account name.
|
||||
After updating the file, calls the C<account_created> hook with the account name.
|
||||
|
||||
=head3 update($name, $delta, $transaction_id)
|
||||
|
||||
Given the relative change (C<$delta>), updates the user balance for an account.
|
||||
|
||||
After updating the file, calls the C<user_balance> hook with the account name, the old balance, the given delta, the new balance, and the transaction_id.
|
||||
After updating the file, calls the C<account_balance> hook with the account name, the old balance, the given delta, the new balance, and the transaction_id.
|
||||
|
||||
This function should not be used directly; instead, create a transaction via C<RevBank::Cart> and use C<checkout> to ensure a balanced booking for proper double-entry bookkeeping.
|
||||
|
||||
|
@ -140,17 +144,19 @@ Returns true if the account is hidden (begins with C<+> or C<->), or user-access
|
|||
|
||||
=head3 parse_user($username)
|
||||
|
||||
Returns the canonical account name if the user account exists, or undef if it does not exist.
|
||||
Returns the canonical account name if the account exists and is not a hidden account, or undef otherwise.
|
||||
|
||||
=head3 assert_user($name)
|
||||
=head3 assert_account($name)
|
||||
|
||||
For a hidden account, returns the canonical account name, creating the account if it did not already exist.
|
||||
|
||||
For a non-hidden account, works like parse_user.
|
||||
For a non-hidden account, returns the canonical account name if the account exists, or throws an exception if it does not exist.
|
||||
|
||||
=head1 CAVEATS
|
||||
=head1 HISTORY
|
||||
|
||||
The identifiers can be confusing and most instances of C<user> should probably be renamed to C<account>.
|
||||
Originally, RevBank had only user accounts, and the package was called C<RevBank::Users>. When hidden (internal) accouns were added, account names were still always in variables called C<$user> or C<$username> even if they were hidden accounts and thus not accessible to users. In current RevBank, the term I<account> is used as the generic thing, or I<user> only in places where only user accounts (non-hidden accounts) are supported.
|
||||
|
||||
This change took place in 2025, and some backwards compatibility will be kept until at least 2027-05-01. See UPGRADING.md for more information.
|
||||
|
||||
=head1 AUTHOR
|
||||
|
|
@ -7,7 +7,7 @@ use experimental 'signatures'; # stable since v5.36
|
|||
use Carp ();
|
||||
use List::Util ();
|
||||
use RevBank::Global;
|
||||
use RevBank::Users;
|
||||
use RevBank::Accounts;
|
||||
use RevBank::FileIO;
|
||||
use RevBank::Cart::Entry;
|
||||
|
||||
|
@ -84,11 +84,11 @@ sub prohibit_checkout($self, $bool, $reason) {
|
|||
}
|
||||
}
|
||||
|
||||
sub deltas($self, $user) {
|
||||
my %deltas = ($user => RevBank::Amount->new(0));
|
||||
sub deltas($self, $account) {
|
||||
my %deltas = ($account => RevBank::Amount->new(0));
|
||||
|
||||
for my $entry (@{ $self->{entries} }) {
|
||||
$deltas{$_->{user}} += $_->{amount} * $entry->quantity
|
||||
$deltas{$_->{account}} += $_->{amount} * $entry->quantity
|
||||
for $entry, $entry->contras;
|
||||
}
|
||||
|
||||
|
@ -96,7 +96,7 @@ sub deltas($self, $user) {
|
|||
}
|
||||
|
||||
|
||||
sub checkout($self, $user) {
|
||||
sub checkout($self, $account) {
|
||||
if ($self->{prohibited}) {
|
||||
die RevBank::Cart::CheckoutProhibited->new(
|
||||
"Cannot complete transaction: $self->{prohibited}"
|
||||
|
@ -108,13 +108,13 @@ sub checkout($self, $user) {
|
|||
die "Refusing to finalize deficient transaction";
|
||||
}
|
||||
|
||||
$user = RevBank::Users::assert_user($user);
|
||||
$account = RevBank::Accounts::assert_account($account);
|
||||
|
||||
my $entries = $self->{entries};
|
||||
|
||||
for my $entry (@$entries) {
|
||||
$entry->sanity_check;
|
||||
$entry->user($user);
|
||||
$entry->account($account);
|
||||
}
|
||||
|
||||
RevBank::FileIO::with_lock {
|
||||
|
@ -133,28 +133,28 @@ sub checkout($self, $user) {
|
|||
$transaction_id = time() - 1300000000;
|
||||
}
|
||||
|
||||
RevBank::Plugins::call_hooks("checkout_prepare", $self, $user, $transaction_id)
|
||||
RevBank::Plugins::call_hooks("checkout_prepare", $self, $account, $transaction_id)
|
||||
or die "Refusing to finalize after failed checkout_prepare";
|
||||
|
||||
for my $entry (@$entries) {
|
||||
$entry->sanity_check;
|
||||
$entry->user($user) if not $entry->user;
|
||||
$entry->account($account) if not $entry->account;
|
||||
}
|
||||
|
||||
RevBank::FileIO::spurt($fn, ++(my $next_id = $transaction_id)) unless $legacy_id;
|
||||
|
||||
RevBank::Plugins::call_hooks("checkout", $self, $user, $transaction_id);
|
||||
RevBank::Plugins::call_hooks("checkout", $self, $account, $transaction_id);
|
||||
|
||||
my $deltas = $self->deltas($user);
|
||||
my $deltas = $self->deltas($account);
|
||||
|
||||
for my $account (reverse sort keys %$deltas) {
|
||||
# The reverse sort is a lazy way to make the "-" accounts come last,
|
||||
# which looks nicer with the "cash" plugin.
|
||||
RevBank::Users::update($account, $deltas->{$account}, $transaction_id)
|
||||
RevBank::Accounts::update($account, $deltas->{$account}, $transaction_id)
|
||||
if $deltas->{$account} != 0;
|
||||
}
|
||||
|
||||
RevBank::Plugins::call_hooks("checkout_done", $self, $user, $transaction_id);
|
||||
RevBank::Plugins::call_hooks("checkout_done", $self, $account, $transaction_id);
|
||||
|
||||
sleep 1; # look busy
|
||||
|
||||
|
|
|
@ -5,7 +5,7 @@ use warnings;
|
|||
use experimental 'signatures'; # stable since v5.36
|
||||
|
||||
use Carp qw(carp croak);
|
||||
use RevBank::Users;
|
||||
use RevBank::Accounts;
|
||||
use List::Util ();
|
||||
use Scalar::Util ();
|
||||
|
||||
|
@ -24,7 +24,7 @@ sub new($class, $amount, $description, $attributes = {}) {
|
|||
amount => $amount, # negative = pay, positive = add money
|
||||
description => $description,
|
||||
attributes => { %$attributes },
|
||||
user => undef,
|
||||
account => undef,
|
||||
contras => [],
|
||||
caller => List::Util::first(sub { !/^RevBank::Cart/ }, map { (caller $_)[3] } 1..10)
|
||||
|| (caller 1)[3],
|
||||
|
@ -34,20 +34,21 @@ sub new($class, $amount, $description, $attributes = {}) {
|
|||
return bless $self, $class;
|
||||
}
|
||||
|
||||
sub add_contra($self, $user, $amount, $description, $display = undef) {
|
||||
sub add_contra($self, $account, $amount, $description, $display = undef) {
|
||||
# $display should be given for either ALL or NONE of the contras,
|
||||
# with the exception of contras with $amount == 0.00;
|
||||
|
||||
$amount = RevBank::Amount->parse_string($amount) if not ref $amount;
|
||||
$user = RevBank::Users::assert_user($user);
|
||||
$account = RevBank::Accounts::assert_account($account);
|
||||
|
||||
$description =~ s/\$you/$self->{user}/g if defined $self->{user};
|
||||
$description =~ s/\$you/$self->{account}/g if defined $self->{account};
|
||||
|
||||
push @{ $self->{contras} }, {
|
||||
user => $user,
|
||||
amount => $amount, # should usually have opposite sign (+/-)
|
||||
description => $description, # contra user's perspective
|
||||
display => $display, # interactive user's perspective
|
||||
account => $account,
|
||||
user => $account, # backwards compatibility until 2027-05-01
|
||||
amount => $amount, # should usually have opposite sign (+/-)
|
||||
description => $description, # contra account's perspective
|
||||
display => $display, # interactive user's perspective
|
||||
highlight => 1,
|
||||
};
|
||||
|
||||
|
@ -133,9 +134,9 @@ sub as_printable($self) {
|
|||
for my $c (@{ $self->{contras} }) {
|
||||
my $description;
|
||||
my $amount = $self->{amount};
|
||||
my $hidden = RevBank::Users::is_hidden($c->{user});
|
||||
my $hidden = RevBank::Accounts::is_hidden($c->{account});
|
||||
my $fromto = $c->{amount}->cents < 0 ? "<-" : "->";
|
||||
$fromto .= " $c->{user}";
|
||||
$fromto .= " $c->{account}";
|
||||
|
||||
if ($c->{display}) {
|
||||
$description =
|
||||
|
@ -165,7 +166,7 @@ sub as_printable($self) {
|
|||
}
|
||||
|
||||
sub as_loggable($self) {
|
||||
croak "Loggable called before set_user" if not defined $self->{user};
|
||||
croak "Loggable called before set_account" if not defined $self->{account};
|
||||
|
||||
my $quantity = $self->{quantity};
|
||||
|
||||
|
@ -180,7 +181,7 @@ sub as_loggable($self) {
|
|||
|
||||
push @s, sprintf(
|
||||
"%-12s %4s %3d %6s # %s",
|
||||
$_->{user},
|
||||
$_->{account},
|
||||
($total->cents > 0 ? 'GAIN' : $total->cents < 0 ? 'LOSE' : '===='),
|
||||
$quantity,
|
||||
$total->abs,
|
||||
|
@ -191,17 +192,20 @@ sub as_loggable($self) {
|
|||
return @s;
|
||||
}
|
||||
|
||||
sub user($self, $new = undef) {
|
||||
sub account($self, $new = undef) {
|
||||
if (defined $new) {
|
||||
croak "User can only be set once" if defined $self->{user};
|
||||
croak "User can only be set once" if defined $self->{account};
|
||||
|
||||
$self->{user} = $new;
|
||||
$self->{account} = $new;
|
||||
$self->{user} = $new; # backwards compatibility until 2027-05-01
|
||||
$_->{description} =~ s/\$you/$new/g for $self, @{ $self->{contras} };
|
||||
}
|
||||
|
||||
return $self->{user};
|
||||
return $self->{account};
|
||||
}
|
||||
|
||||
*user = \&account; # backwards compatibility until 2027-05-01
|
||||
|
||||
sub sanity_check($self) {
|
||||
my @contras = $self->contras;
|
||||
|
||||
|
|
|
@ -16,7 +16,7 @@ use RevBank::FileIO;
|
|||
|
||||
sub import {
|
||||
require RevBank::Plugins;
|
||||
require RevBank::Users;
|
||||
require RevBank::Accounts;
|
||||
no strict 'refs';
|
||||
my $caller = caller;
|
||||
*{"$caller\::ACCEPT"} = sub () { \1 };
|
||||
|
@ -30,7 +30,7 @@ sub import {
|
|||
*{"$caller\::rewrite"} = \&RevBank::FileIO::rewrite;
|
||||
*{"$caller\::append"} = \&RevBank::FileIO::append;
|
||||
*{"$caller\::with_lock"} = \&RevBank::FileIO::with_lock;
|
||||
*{"$caller\::parse_user"} = \&RevBank::Users::parse_user;
|
||||
*{"$caller\::parse_user"} = \&RevBank::Accounts::parse_user;
|
||||
*{"$caller\::parse_amount"} = sub ($amount) {
|
||||
defined $amount or return undef;
|
||||
length $amount or return undef;
|
||||
|
|
|
@ -32,10 +32,10 @@ Commas are changed to periods so C<3,50> and C<3.50> both result in C<3.5>.
|
|||
|
||||
=head2 parse_user($username)
|
||||
|
||||
See C<parse_user> in L<RevBank::Users>.
|
||||
|
||||
Returns the canonical username, or undef if the account does not exist.
|
||||
|
||||
See C<parse_user> in L<RevBank::Accounts> for the gory details.
|
||||
|
||||
=head1 AUTHOR
|
||||
|
||||
Juerd Waalboer <#####@juerd.nl>
|
||||
|
|
|
@ -12,7 +12,7 @@ use base 'RevBank::Plugin';
|
|||
|
||||
BEGIN {
|
||||
RevBank::Plugins::register("RevBank::Messages");
|
||||
*hidden = \&RevBank::Users::is_hidden;
|
||||
*hidden = \&RevBank::Accounts::is_hidden;
|
||||
}
|
||||
|
||||
|
||||
|
@ -41,7 +41,7 @@ sub hook_cart_changed($class, $cart, @) {
|
|||
}
|
||||
}
|
||||
|
||||
sub hook_checkout($class, $cart, $user, $transaction_id, @) {
|
||||
sub hook_checkout($class, $cart, $account, $transaction_id, @) {
|
||||
if ($cart->changed) {
|
||||
say "Done:";
|
||||
$cart->display;
|
||||
|
@ -66,8 +66,8 @@ sub hook_reject($class, $plugin, $reason, $abort, @) {
|
|||
say $abort ? $reason : "$reason Enter 'abort' to abort.";
|
||||
}
|
||||
|
||||
sub hook_user_balance($class, $username, $old, $delta, $new, @) {
|
||||
return if hidden $username and not $ENV{REVBANK_DEBUG};
|
||||
sub hook_account_balance($class, $account, $old, $delta, $new, @) {
|
||||
return if hidden $account and not $ENV{REVBANK_DEBUG};
|
||||
|
||||
my $sign = $delta->cents >= 0 ? '+' : '-';
|
||||
my $rood = $new->cents < 0 ? '31;' : '';
|
||||
|
@ -75,13 +75,13 @@ sub hook_user_balance($class, $username, $old, $delta, $new, @) {
|
|||
my $warn = $new->cents < -2300 ? " \e[5;1m(!!)\e[0m" : "";
|
||||
|
||||
$_ = $_->string("+") for $old, $new;
|
||||
printf "New balance for $username: $old $sign $abs = \e[${rood}1m$new\e[0m$warn\n",
|
||||
printf "New balance for $account: $old $sign $abs = \e[${rood}1m$new\e[0m$warn\n",
|
||||
}
|
||||
|
||||
sub hook_user_created($class, $username, @) {
|
||||
return if hidden $username and not $ENV{REVBANK_DEBUG};
|
||||
sub hook_account_created($class, $account, @) {
|
||||
return if hidden $account and not $ENV{REVBANK_DEBUG};
|
||||
|
||||
say "New account '$username' created.";
|
||||
say "New account '$account' created.";
|
||||
}
|
||||
|
||||
1;
|
||||
|
|
|
@ -33,8 +33,8 @@ sub Tab($self, $method) {
|
|||
}
|
||||
|
||||
if (delete $completions{USERS}) {
|
||||
for my $name (RevBank::Users::names()) {
|
||||
next if RevBank::Users::is_hidden($name);
|
||||
for my $name (RevBank::Accounts::names()) {
|
||||
next if RevBank::Accounts::is_hidden($name);
|
||||
|
||||
$completions{ $name }++;
|
||||
$completions{ $1 }++ if $name =~ /^\*(.*)/;
|
||||
|
|
|
@ -145,10 +145,10 @@ Called when user input was given. C<$split_input> is a boolean that is true
|
|||
if the input will be split on whitespace, rather than treated as a whole.
|
||||
The input MAY be altered by the plugin.
|
||||
|
||||
=item hook_add($class, $cart, $user, $item, @)
|
||||
=item hook_add($class, $cart, $account, $item, @)
|
||||
|
||||
Called when something is added to the cart. Of course, like in C<< $cart->add
|
||||
>>, C<$user> will be undef if the product is added for the current user.
|
||||
>>, C<$account> will be undef if the product is added for the current user.
|
||||
|
||||
C<$item> is a reference to a hash with the keys C<amount>, C<description> and
|
||||
the metadata given in the C<add> call. Changing the values changes the actual
|
||||
|
@ -156,15 +156,15 @@ item going into the cart!
|
|||
|
||||
Be careful to avoid infinite loops if you add new stuff.
|
||||
|
||||
=item hook_checkout_prepare($class, $cart, $user, $transaction_id, @)
|
||||
=item hook_checkout_prepare($class, $cart, $account, $transaction_id, @)
|
||||
|
||||
Called when the transaction is about to be processed. In this phase, the cart and its entries can still be manipulated. If the hook throws an exception, the transaction is aborted.
|
||||
|
||||
=item hook_checkout($class, $cart, $user, $transaction_id, @)
|
||||
=item hook_checkout($class, $cart, $account, $transaction_id, @)
|
||||
|
||||
Called when the transaction is finalized, before accounts are updated. The cart and cart entries must not be changed.
|
||||
|
||||
=item hook_checkout_done($class, $cart, $user, $transaction_id, @)
|
||||
=item hook_checkout_done($class, $cart, $account, $transaction_id, @)
|
||||
|
||||
Called when the transaction is finalized, after accounts were updated.
|
||||
|
||||
|
@ -181,13 +181,13 @@ Called when input was not recognised by any of the plugins.
|
|||
|
||||
Called when a plugin fails.
|
||||
|
||||
=item hook_user_created($class, $username, @)
|
||||
=item hook_account_created($class, $account, @)
|
||||
|
||||
Called when a new user account was created.
|
||||
Called when a new account was created.
|
||||
|
||||
=item hook_user_balance($class, $username, $old, $delta, $new, $transaction_id, @)
|
||||
=item hook_account_balance($class, $account, $old, $delta, $new, $transaction_id, @)
|
||||
|
||||
Called when a user account is updated.
|
||||
Called when an account is updated.
|
||||
|
||||
=item hook_products_changed($class, $changes, $mtime, @)
|
||||
|
||||
|
|
|
@ -34,7 +34,7 @@ sub username($self, $cart, $name, @) {
|
|||
if any sub { $_ eq $name }, $plugin->Tab('command');
|
||||
}
|
||||
|
||||
RevBank::Users::create( $name );
|
||||
RevBank::Accounts::create( $name );
|
||||
|
||||
return ACCEPT;
|
||||
}
|
||||
|
|
10
plugins/cash
10
plugins/cash
|
@ -31,13 +31,13 @@ sub command :Tab(cash) ($self, $cart, $command, @) {
|
|||
|
||||
sub hook_cash($class, @) {
|
||||
printf "There should currently be (at least) %s in the cash box.\n",
|
||||
-RevBank::Users::balance("-cash") || "0.00";
|
||||
-RevBank::Accounts::balance("-cash") || "0.00";
|
||||
}
|
||||
|
||||
our $suppress = 0;
|
||||
|
||||
sub hook_user_balance($class, $username, $old, $delta, $new, @) {
|
||||
return if $username ne '-cash' or $delta->cents == 0;
|
||||
sub hook_account_balance($class, $account, $old, $delta, $new, @) {
|
||||
return if $account ne '-cash' or $delta->cents == 0;
|
||||
return if $suppress;
|
||||
|
||||
# "-" accounts need to be inverted to display the intuitive value.
|
||||
|
@ -55,7 +55,7 @@ sub hook_user_balance($class, $username, $old, $delta, $new, @) {
|
|||
my $confirm_prompt = "Type 'fix pls' to apply a permanent correction, or 'abort' to abort";
|
||||
|
||||
sub check($self, $cart, $arg, @) {
|
||||
my $should = -RevBank::Users::balance("-cash") || parse_amount(0);
|
||||
my $should = -RevBank::Accounts::balance("-cash") || parse_amount(0);
|
||||
my $have = parse_amount($arg);
|
||||
return REJECT, "Invalid amount" if not defined $have;
|
||||
|
||||
|
@ -94,7 +94,7 @@ sub confirm($self, $cart, $arg, @) {
|
|||
$cart->checkout('-expenses/discrepancies');
|
||||
|
||||
printf "\nDiscrepancy recorded; corrected cash box amount is %s.\n",
|
||||
-RevBank::Users::balance("-cash") || "0.00";
|
||||
-RevBank::Accounts::balance("-cash") || "0.00";
|
||||
|
||||
return ACCEPT;
|
||||
}
|
||||
|
|
|
@ -15,8 +15,8 @@ sub hook_cash {
|
|||
open_drawer();
|
||||
}
|
||||
|
||||
sub hook_checkout($class, $cart, $user, $transaction_id, @) {
|
||||
$user eq '-cash' or return;
|
||||
sub hook_checkout($class, $cart, $account, $transaction_id, @) {
|
||||
$account eq '-cash' or return;
|
||||
|
||||
open_drawer();
|
||||
}
|
||||
|
|
|
@ -23,7 +23,7 @@ use List::Util qw(sum);
|
|||
my $iban = "NL99ABCD1234567890";
|
||||
my $beneficiary = "Account Name";
|
||||
|
||||
sub hook_checkout($class, $cart, $user, $transaction_id, @) {
|
||||
sub hook_checkout($class, $cart, $account, $transaction_id, @) {
|
||||
my @entries = $cart->entries("is_deposit");
|
||||
|
||||
my $amount = sum map $_->{amount}, grep $_->attribute('method') eq 'iban', @entries;
|
||||
|
@ -41,7 +41,7 @@ sub hook_checkout($class, $cart, $user, $transaction_id, @) {
|
|||
"EUR" . $amount, # Amount
|
||||
"",
|
||||
"",
|
||||
"rb $user",
|
||||
"rb $account",
|
||||
"",
|
||||
);
|
||||
close $in;
|
||||
|
|
|
@ -5,7 +5,7 @@ HELP "dinnerbonus" => "Add fee for cooking supplies";
|
|||
my $bonus = 1.00;
|
||||
|
||||
sub command :Tab(kookbonus,dinnerbonus) ($self, $cart, $command, @) {
|
||||
my @users = map $_->{user}, map $_->contras, $cart->entries('is_take');
|
||||
my @users = map $_->{account}, map $_->contras, $cart->entries('is_take');
|
||||
|
||||
(@users and $command eq 'kookpotje') # common mistake promoted to feature
|
||||
or $command eq 'kookbonus'
|
||||
|
|
|
@ -9,8 +9,8 @@ sub command :Tab(grandtotal) ($self, $cart, $command, @) {
|
|||
my $neg = 0;
|
||||
|
||||
for my $line (slurp 'revbank.accounts') {
|
||||
my ($username, $balance) = split " ", $line;
|
||||
next if RevBank::Users::is_special($username);
|
||||
my ($account, $balance) = split " ", $line;
|
||||
next if RevBank::Accounts::is_special($account);
|
||||
|
||||
my $credit = RevBank::Amount->parse_string($balance) or next;
|
||||
$neg += $credit if $credit < 0;
|
||||
|
|
12
plugins/json
12
plugins/json
|
@ -75,17 +75,17 @@ sub hook_retry($class, $plugin, $reason, $abort, @) {
|
|||
_log({ _ => "RETRY", plugin => $plugin, reason => $reason, abort => $abort });
|
||||
}
|
||||
|
||||
sub hook_user_created($class, $username, @) {
|
||||
_log({ _ => "NEWUSER", account => $username });
|
||||
sub hook_account_created($class, $account, @) {
|
||||
_log({ _ => "NEWUSER", account => $account });
|
||||
}
|
||||
|
||||
# NB: stringify transaction_id because future ids might not be numeric.
|
||||
|
||||
sub hook_user_balance($class, $user, $old, $delta, $new, $transaction_id, @) {
|
||||
_log({ _ => "BALANCE", account => $user, old => $old, delta => $delta, new => $new, transaction_id => "$transaction_id" });
|
||||
sub hook_account_balance($class, $account, $old, $delta, $new, $transaction_id, @) {
|
||||
_log({ _ => "BALANCE", account => $account, old => $old, delta => $delta, new => $new, transaction_id => "$transaction_id" });
|
||||
}
|
||||
|
||||
sub hook_checkout($class, $cart, $username, $transaction_id, @) {
|
||||
_log({ _ => "CHECKOUT", account => $username, transaction_id => "$transaction_id" });
|
||||
sub hook_checkout($class, $cart, $account, $transaction_id, @) {
|
||||
_log({ _ => "CHECKOUT", account => $account, transaction_id => "$transaction_id" });
|
||||
}
|
||||
|
||||
|
|
10
plugins/log
10
plugins/log
|
@ -30,18 +30,18 @@ sub hook_retry($class, $plugin, $reason, $abort, @) {
|
|||
_log(RETRY => "[$plugin] $reason");
|
||||
}
|
||||
|
||||
sub hook_user_created($class, $username, @) {
|
||||
_log(NEWUSER => "$username");
|
||||
sub hook_account_created($class, $account, @) {
|
||||
_log(NEWUSER => "$account");
|
||||
}
|
||||
|
||||
sub hook_user_balance($class, $user, $old, $delta, $new, $transaction_id, @) {
|
||||
sub hook_account_balance($class, $account, $old, $delta, $new, $transaction_id, @) {
|
||||
my $lost = $delta < 0 ? "lost" : "got";
|
||||
$delta = $delta->abs;
|
||||
$_ = $_->string("+") for $old, $new;
|
||||
_log(BALANCE => "$transaction_id $user had $old, $lost $delta, now has $new");
|
||||
_log(BALANCE => "$transaction_id $account had $old, $lost $delta, now has $new");
|
||||
}
|
||||
|
||||
sub hook_checkout($class, $cart, $username, $transaction_id, @) {
|
||||
sub hook_checkout($class, $cart, $account, $transaction_id, @) {
|
||||
_log(CHECKOUT => "$transaction_id $_") for map $_->as_loggable, $cart->entries;
|
||||
}
|
||||
|
||||
|
|
|
@ -35,7 +35,7 @@ sub _inform($unresolved, $username, $skip_print = 0) {
|
|||
my $broke_users = $entry->attribute('nomoney_users');
|
||||
|
||||
for my $account (sort keys %$broke_users) {
|
||||
my $balance = RevBank::Users::balance($account);
|
||||
my $balance = RevBank::Accounts::balance($account);
|
||||
|
||||
my $m = sprintf(
|
||||
"%s have %s",
|
||||
|
@ -60,9 +60,9 @@ sub hook_checkout_prepare($class, $cart, $username, $transaction_id, @) {
|
|||
|
||||
for my $account (keys %$deltas) {
|
||||
next if $deltas->{$account} > 0;
|
||||
next if RevBank::Users::is_special($account);
|
||||
next if RevBank::Accounts::is_special($account);
|
||||
|
||||
my $old = $balances{$account} = RevBank::Users::balance($account);
|
||||
my $old = $balances{$account} = RevBank::Accounts::balance($account);
|
||||
my $new = $old + $deltas->{$account};
|
||||
|
||||
next if $new >= 0 or $new > $old;
|
||||
|
@ -73,14 +73,14 @@ sub hook_checkout_prepare($class, $cart, $username, $transaction_id, @) {
|
|||
next if none { $plugin eq $_ } @deny_plugins;
|
||||
|
||||
my @contra_users = uniqstr sort grep {
|
||||
not RevBank::Users::is_special($_)
|
||||
not RevBank::Accounts::is_special($_)
|
||||
and $_ ne $username
|
||||
} map {
|
||||
$_->{user}
|
||||
$_->{account}
|
||||
} $entry->contras;
|
||||
|
||||
next if $allow_multi_user and @contra_users > 1;
|
||||
next if none { $account eq $_ } $entry->user // $username, @contra_users;
|
||||
next if none { $account eq $_ } $entry->account // $username, @contra_users;
|
||||
|
||||
$unresolved->add_entry($entry);
|
||||
}
|
||||
|
@ -112,7 +112,7 @@ sub hook_checkout_prepare($class, $cart, $username, $transaction_id, @) {
|
|||
$entry->attribute('nomoney_users', \%broke_users);
|
||||
|
||||
for my $account (keys %$trial_deltas) {
|
||||
next if RevBank::Users::is_special($account);
|
||||
next if RevBank::Accounts::is_special($account);
|
||||
next if $trial_deltas->{$account} > 0;
|
||||
|
||||
my $trial_balance = $resolved_balances{$account} + $trial_deltas->{$account};
|
||||
|
@ -144,11 +144,11 @@ sub hook_abort($class, $cart, @) {
|
|||
return;
|
||||
}
|
||||
|
||||
sub hook_checkout_done($class, $cart, $username, $transaction_id, @) {
|
||||
sub hook_checkout_done($class, $cart, $account, $transaction_id, @) {
|
||||
my $n = $unresolved{$cart}->size or return;
|
||||
print "\n";
|
||||
|
||||
_inform($unresolved{$cart}, $username);
|
||||
_inform($unresolved{$cart}, $account);
|
||||
delete $unresolved{$cart};
|
||||
|
||||
my $message = $n == 1 ? "THIS ENTRY WAS IGNORED" : "THESE ENTRIES WERE IGNORED";
|
||||
|
|
|
@ -35,7 +35,7 @@ sub data($self, $cart, $input, @) {
|
|||
return ACCEPT;
|
||||
}
|
||||
|
||||
sub hook_checkout($class, $cart, $username, $transaction_id, @) {
|
||||
sub hook_checkout($class, $cart, $account, $transaction_id, @) {
|
||||
my @barcodes;
|
||||
for my $entry ($cart->entries('is_barcode')) {
|
||||
push @barcodes, ($entry->attribute('barcode_data')) x $entry->quantity;
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
#!perl
|
||||
|
||||
sub hook_user_balance($class, $username, $old, $delta, $new, $transaction_id, @) {
|
||||
my $msg = "$transaction_id ($username)";
|
||||
sub hook_account_balance($class, $account, $old, $delta, $new, $transaction_id, @) {
|
||||
my $msg = "$transaction_id ($account)";
|
||||
$msg =~ s/[^\x20-\x7E]//g;
|
||||
$msg =~ s/'//g;
|
||||
|
||||
|
|
|
@ -57,7 +57,7 @@ sub hook_abort($class, $cart, $reason, @) {
|
|||
for @ids;
|
||||
}
|
||||
|
||||
sub hook_checkout($class, $cart, $user, $transaction_id, @) {
|
||||
sub hook_checkout($class, $cart, $account, $transaction_id, @) {
|
||||
# Opportunistic; ignore failures. Can't do anything about it anyway.
|
||||
|
||||
my @ids = map $_->attribute('mollie_id'), $cart->entries('mollie_id');
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
|
||||
use Net::MQTT::Simple "mosquitto.space.revspace.nl";
|
||||
|
||||
sub hook_checkout($class, $cart, $user, $transaction_id, @) {
|
||||
sub hook_checkout($class, $cart, $account, $transaction_id, @) {
|
||||
my $filename = "revbank.sales";
|
||||
my @entries = $cart->entries('product_id') or return;
|
||||
my %already_retained;
|
||||
|
|
|
@ -10,16 +10,16 @@ sub _box(@lines) {
|
|||
);
|
||||
}
|
||||
|
||||
sub hook_checkout_done($class, $cart, $user, $transaction_id, @) {
|
||||
defined $user or return; # hacks like 'undo' don't have an acting user
|
||||
RevBank::Users::is_hidden($user) and return;
|
||||
sub hook_checkout_done($class, $cart, $account, $transaction_id, @) {
|
||||
defined $account or return; # hacks like 'undo' don't have an acting user
|
||||
RevBank::Accounts::is_hidden($account) and return;
|
||||
|
||||
my $balance = RevBank::Users::balance($user) or return;
|
||||
my $since = RevBank::Users::since($user);
|
||||
my $balance = RevBank::Accounts::balance($account) or return;
|
||||
my $since = RevBank::Accounts::since($account);
|
||||
|
||||
if ($balance < -22.00) {
|
||||
_box(
|
||||
"Hoi $user,",
|
||||
"Hoi $account,",
|
||||
"",
|
||||
"Je saldo is $balance en dus lager dan toegestaan. Graag meteen aanvullen!",
|
||||
"Zodra je een positief saldo hebt, mag je weer producten kopen.",
|
||||
|
@ -33,7 +33,7 @@ sub hook_checkout_done($class, $cart, $user, $transaction_id, @) {
|
|||
and $1 lt strftime('%Y-%m-%d_%H:%M:%S', localtime(time() - 14 * 86400))
|
||||
) {
|
||||
_box(
|
||||
"Hoi $user,",
|
||||
"Hoi $account,",
|
||||
"",
|
||||
"Je staat al sinds $1 negatief, dus meer dan 2 weken. Deelnemers",
|
||||
"mogen rood staan, maar niet langdurig. Wil je je saldo even aanvullen?",
|
||||
|
|
|
@ -125,7 +125,7 @@ sub hook_undo($class, $cart) {
|
|||
# Undo deposit refund: prohibit
|
||||
for my $contra ($entry->contras) {
|
||||
next if $contra->{amount} < 0;
|
||||
next if List::Util::none { $contra->{user} eq $_ } _addon_accounts;
|
||||
next if List::Util::none { $contra->{account} eq $_ } _addon_accounts;
|
||||
|
||||
return ABORT, "Sorry, deposit refunds cannot be undone.";
|
||||
}
|
||||
|
@ -151,14 +151,14 @@ sub _handle_undo($cart) {
|
|||
}
|
||||
}
|
||||
|
||||
sub hook_checkout_prepare($class, $cart, $username, $transaction_id, @) {
|
||||
if ($username eq '-undo') {
|
||||
sub hook_checkout_prepare($class, $cart, $account, $transaction_id, @) {
|
||||
if ($account eq '-undo') {
|
||||
_handle_undo($cart);
|
||||
return;
|
||||
}
|
||||
|
||||
# Read data
|
||||
my $tokens_by_type = _read->{lc $username};
|
||||
my $tokens_by_type = _read->{lc $account};
|
||||
my $is_new = !defined $tokens_by_type;
|
||||
$tokens_by_type = {} if $is_new;
|
||||
my $time_is_reliable = _time_is_reliable;
|
||||
|
@ -235,15 +235,15 @@ sub hook_checkout_prepare($class, $cart, $username, $transaction_id, @) {
|
|||
# Store data
|
||||
call_hooks(
|
||||
"log_info",
|
||||
"statiegeld_tokens: ${\scalar @created } created for $username: @created"
|
||||
"statiegeld_tokens: ${\scalar @created } created for $account: @created"
|
||||
) if @created;
|
||||
|
||||
call_hooks(
|
||||
"log_info",
|
||||
"statiegeld_tokens: ${\scalar @used } used by $username: @used"
|
||||
"statiegeld_tokens: ${\scalar @used } used by $account: @used"
|
||||
) if @used;
|
||||
|
||||
_write $username, $tokens_by_type, $is_new if $tokens_changed;
|
||||
_write $account, $tokens_by_type, $is_new if $tokens_changed;
|
||||
|
||||
return ABORT if %warnings_by_type and not $cart->size;
|
||||
|
||||
|
|
|
@ -21,7 +21,7 @@
|
|||
}
|
||||
}
|
||||
|
||||
sub hook_checkout($class, $cart, $user, $transaction_id, @) {
|
||||
sub hook_checkout($class, $cart, $account, $transaction_id, @) {
|
||||
# Hack42 for some reason used the dutch word in their revbank1 hack.
|
||||
my $filename = -e("revbank.voorraad")
|
||||
? "revbank.voorraad"
|
||||
|
|
|
@ -15,7 +15,7 @@ sub command :Tab(tail) ($self, $cart, $command, @) {
|
|||
|
||||
my ($dt, $c, $t_id, $u, $dir, $qty, $amount, undef, $desc) = split " ", $_, 9;
|
||||
$c eq 'CHECKOUT' or next; # real check after expensive split
|
||||
RevBank::Users::is_hidden($u) and next;
|
||||
RevBank::Accounts::is_hidden($u) and next;
|
||||
|
||||
shift @lines if @lines == $n;
|
||||
|
||||
|
|
|
@ -12,7 +12,7 @@ sub command :Tab(undeposit) ($self, $cart, $command, @) {
|
|||
warn "\n\n\n";
|
||||
warn "Enter 'abort' to abort.\n";
|
||||
|
||||
@TAB = grep /^[-+]deposit/, RevBank::Users::names
|
||||
@TAB = grep /^[-+]deposit/, RevBank::Accounts::names
|
||||
or return REJECT, "No contras available.";
|
||||
print "Available contras:\n", map " $_\n", sort(@TAB);
|
||||
|
||||
|
|
18
plugins/undo
18
plugins/undo
|
@ -13,11 +13,11 @@ sub command :Tab(undo) ($self, $cart, $command, @) {
|
|||
|
||||
my @log;
|
||||
for my $line (slurp $filename) {
|
||||
my ($tid, $user, $delta, $dt) = split " ", $line;
|
||||
my ($tid, $account, $delta, $dt) = split " ", $line;
|
||||
if (@log and $log[-1]{tid} eq $tid) {
|
||||
push @{ $log[-1]{deltas} }, [ $user, $delta ];
|
||||
push @{ $log[-1]{deltas} }, [ $account, $delta ];
|
||||
} else {
|
||||
push @log, { tid => $tid, dt => $dt, deltas => [ [ $user, $delta ] ] };
|
||||
push @log, { tid => $tid, dt => $dt, deltas => [ [ $account, $delta ] ] };
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -49,11 +49,11 @@ sub undo :Tab(&tab) ($self, $cart, $tid, @) {
|
|||
return with_lock {
|
||||
for my $line (slurp $filename) {
|
||||
if ($line =~ /^\Q$tid\E\s/) {
|
||||
my (undef, $user, $delta) = split " ", $line;
|
||||
my (undef, $account, $delta) = split " ", $line;
|
||||
|
||||
$entry ||= $cart->add(0, $description, { undo_transaction_id => $tid });
|
||||
|
||||
$entry->add_contra($user, $delta, "Undo $tid");
|
||||
$entry->add_contra($account, $delta, "Undo $tid");
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -68,8 +68,8 @@ sub undo :Tab(&tab) ($self, $cart, $tid, @) {
|
|||
};
|
||||
}
|
||||
|
||||
sub hook_checkout_prepare($class, $cart, $username, $transaction_id, @) {
|
||||
$username eq '-undo' or return;
|
||||
sub hook_checkout_prepare($class, $cart, $account, $transaction_id, @) {
|
||||
$account eq '-undo' or return;
|
||||
|
||||
for my $entry ($cart->entries) {
|
||||
my $undo_tid = $entry->attribute('undo_transaction_id')
|
||||
|
@ -85,8 +85,8 @@ sub hook_checkout_prepare($class, $cart, $username, $transaction_id, @) {
|
|||
}
|
||||
}
|
||||
|
||||
sub hook_user_balance($class, $username, $old, $delta, $new, $transaction_id, @) {
|
||||
sub hook_account_balance($class, $account, $old, $delta, $new, $transaction_id, @) {
|
||||
return if $doing_undo; # don't allow undoing undos
|
||||
|
||||
append $filename, join(" ", $transaction_id, $username, -$delta, now()), "\n";
|
||||
append $filename, join(" ", $transaction_id, $account, -$delta, now()), "\n";
|
||||
}
|
||||
|
|
|
@ -91,7 +91,7 @@ sub _recent($n, $u) {
|
|||
sub balance($self, $u) {
|
||||
_recent(10, $u);
|
||||
call_hooks("user_info", $u);
|
||||
my $balance = RevBank::Users::balance($u);
|
||||
my $balance = RevBank::Accounts::balance($u);
|
||||
my $red = $balance->cents < 0 ? "31;" : "";
|
||||
printf "Balance for $u is \e[%s1m%s\e[0m\n", $red, $balance->string("+");
|
||||
say "NB: Products/amounts/commands FIRST, username LAST.";
|
||||
|
|
12
plugins/vat
12
plugins/vat
|
@ -2,26 +2,26 @@ sub _read_vat {
|
|||
my %vat;
|
||||
for my $line (slurp "revbank.vat") {
|
||||
my ($match, $vataccount, $pct) = split " ", $line;
|
||||
$vat{lc $match} = { user => $vataccount, pct => $pct };
|
||||
$vat{lc $match} = { account => $vataccount, pct => $pct };
|
||||
}
|
||||
return \%vat;
|
||||
}
|
||||
|
||||
sub hook_checkout_prepare($class, $cart, $username, $transaction_id, @) {
|
||||
sub hook_checkout_prepare($class, $cart, $account, $transaction_id, @) {
|
||||
my $config = _read_vat;
|
||||
|
||||
for my $entry ($cart->entries) {
|
||||
for my $contra ($entry->contras) {
|
||||
my $vat = $config->{ lc $contra->{user} } or next;
|
||||
my $vat = $config->{ lc $contra->{account} } or next;
|
||||
|
||||
my $amount = RevBank::Amount->new(
|
||||
$contra->{amount}->cents * $vat->{pct} / (100 + $vat->{pct})
|
||||
);
|
||||
|
||||
my $desc = "VAT ($vat->{pct}% * $contra->{amount})";
|
||||
my $display = RevBank::Users::is_hidden($contra->{user}) ? undef : $desc;
|
||||
$entry->add_contra($contra->{user}, -$amount, $desc, $display);
|
||||
$entry->add_contra($vat->{user}, +$amount, $desc);
|
||||
my $display = RevBank::Accounts::is_hidden($contra->{account}) ? undef : $desc;
|
||||
$entry->add_contra($contra->{account}, -$amount, $desc, $display);
|
||||
$entry->add_contra($vat->{account}, +$amount, $desc);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
2
revbank
2
revbank
|
@ -17,7 +17,7 @@ use RevBank::Messages;
|
|||
use RevBank::Cart;
|
||||
use RevBank::Prompt;
|
||||
|
||||
our $VERSION = "8.3.1";
|
||||
our $VERSION = "9.0.0";
|
||||
|
||||
our %HELP1 = (
|
||||
"abort" => "Abort the current transaction",
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue