Further update to new ledger-like internals
This commit is contained in:
parent
5a7a7184dd
commit
1cbc906f1e
22 changed files with 153 additions and 149 deletions
|
@ -7,23 +7,9 @@ HELP "deposit <amount>" => "Deposit into an account";
|
|||
sub command :Tab(deposit) {
|
||||
my ($self, $cart, $command) = @_;
|
||||
|
||||
if ($command eq 'deposit') {
|
||||
return "Amount to deposit into your account", \&amount;
|
||||
}
|
||||
$command eq 'deposit' or return NEXT;
|
||||
|
||||
if ($cart->select_items('is_deposit')) {
|
||||
# No other plugin recognised the input, so it must be a new user.
|
||||
$self->{new_user} = $command;
|
||||
|
||||
my $x = RevBank::Plugin::adduser->can("command")
|
||||
? "Please use \e[4madduser\e[0m instead."
|
||||
: "Please enable the \e[4madduser\e[0m plugin.";
|
||||
warn "Creating accounts with \e[4mdeposit\e[m is deprecated. $x\n";
|
||||
|
||||
return "Add new account for user '$command'?", \&create;
|
||||
}
|
||||
|
||||
return NEXT;
|
||||
return "Amount to deposit into your account", \&amount;
|
||||
}
|
||||
|
||||
sub amount :Tab(13.37,42) {
|
||||
|
@ -37,7 +23,7 @@ sub amount :Tab(13.37,42) {
|
|||
return $message . "How are we receiving this EUR $amount?", \&how
|
||||
if keys %{ $self->{deposit_methods} };
|
||||
|
||||
$cart->add(undef, +$self->{amount}, "Deposit", { is_deposit => 1 });
|
||||
$cart->add(+$self->{amount}, "Deposit", { is_deposit => 1 });
|
||||
return ACCEPT;
|
||||
}
|
||||
|
||||
|
@ -55,7 +41,7 @@ sub how :Tab(&how_tab) {
|
|||
return shift @{ $how->{prompts} }, \&how_prompt;
|
||||
}
|
||||
|
||||
$cart->add(undef, +$self->{amount}, $how->{description}, { is_deposit => 1, method => $how->{_key} });
|
||||
$cart->add(+$self->{amount}, $how->{description}, { is_deposit => 1, method => $how->{_key} });
|
||||
return ACCEPT;
|
||||
}
|
||||
|
||||
|
@ -77,19 +63,6 @@ sub how_prompt {
|
|||
|
||||
my $desc = sprintf $how->{description}, @{ $how->{answers} };
|
||||
|
||||
$cart->add(undef, +$self->{amount}, $desc, { is_deposit => 1, method => $how->{_key} });
|
||||
$cart->add(+$self->{amount}, $desc, { is_deposit => 1, method => $how->{_key} });
|
||||
return ACCEPT;
|
||||
}
|
||||
|
||||
sub create :Tab(yes,no) {
|
||||
my ($self, $cart, $yesno) = @_;
|
||||
my $user = $self->{new_user};
|
||||
|
||||
if ($yesno eq "y" or $yesno eq "yes") {
|
||||
RevBank::Users::create( $user );
|
||||
$cart->checkout( $user );
|
||||
return ACCEPT;
|
||||
}
|
||||
return ABORT;
|
||||
}
|
||||
|
||||
|
|
|
@ -28,9 +28,9 @@ sub command { NEXT }
|
|||
sub hook_checkout {
|
||||
my ($class, $cart, $user, $transaction_id) = @_;
|
||||
|
||||
my @items = $cart->select_items("is_deposit");
|
||||
my @entries = $cart->entries("is_deposit");
|
||||
|
||||
my $amount = sum map $_->{amount}, grep $_->{method} eq "iban", @items;
|
||||
my $amount = sum map $_->{amount}, grep $_->attribute('method') eq 'iban', @entries;
|
||||
|
||||
if (defined $amount && $amount > 0) {
|
||||
my $pid = open2 my $out, my $in, qw(qrencode -t ansiutf8 -m 2)
|
||||
|
|
|
@ -2,29 +2,36 @@
|
|||
|
||||
HELP "dinnerbonus" => "Add fee for cooking supplies";
|
||||
|
||||
my $bonus = 1.00;
|
||||
|
||||
sub command :Tab(kookbonus,dinnerbonus) {
|
||||
my ($self, $cart, $command) = @_;
|
||||
|
||||
my $bonus = 1.00;
|
||||
my @users = map $_->{user}, map $_->contras, $cart->entries('is_take');
|
||||
|
||||
$command eq 'kookbonus' or $command eq 'dinnerbonus'
|
||||
(@users and $command eq 'kookpotje') # common mistake promoted to feature
|
||||
or $command eq 'kookbonus'
|
||||
or $command eq 'dinnerbonus'
|
||||
or return NEXT;
|
||||
|
||||
my @users = grep !/^\$you$/, map $_->{user}, $cart->select_items
|
||||
or return REJECT, "$command requires a pending transaction.";
|
||||
|
||||
for my $user (@users) {
|
||||
$cart->add( $user, -$bonus, "Kookbonus by \$you" );
|
||||
}
|
||||
|
||||
@users or return REJECT, "$command requires a pending 'take'.";
|
||||
my $users = join '/', @users;
|
||||
|
||||
$cart->add(
|
||||
"kookpotje",
|
||||
my $target = parse_user("kookpotje")
|
||||
or return ABORT, "User 'kookpotje' does not exist";
|
||||
|
||||
my $entry = $cart->add(0, "Kookbonus");
|
||||
|
||||
$entry->add_contra(
|
||||
$target,
|
||||
scalar @users * $bonus,
|
||||
"Kookbonus from $users by \$you"
|
||||
);
|
||||
|
||||
for my $user (@users) {
|
||||
$entry->add_contra( $user, -$bonus, "Kookbonus by \$you" );
|
||||
}
|
||||
|
||||
return ACCEPT;
|
||||
}
|
||||
|
||||
|
|
|
@ -41,8 +41,10 @@ sub reason :Tab(whatevah) {
|
|||
my $user = parse_user($input);
|
||||
my $reason = $user ? "" : " ($input)";
|
||||
|
||||
$cart->add(undef, -$amount, "Given to $benificiary" . $reason);
|
||||
$cart->add($benificiary, +$amount, "Received from \$you" . $reason);
|
||||
$cart
|
||||
->add(-$amount, "Given to $benificiary" . $reason)
|
||||
->add_contra($benificiary, +$amount, "Received from \$you" . $reason);
|
||||
|
||||
$cart->checkout($user) if $user;
|
||||
|
||||
return ACCEPT;
|
||||
|
|
|
@ -49,7 +49,7 @@ sub hook_user_balance {
|
|||
|
||||
sub hook_checkout {
|
||||
my ($class, $cart, $username, $transaction_id) = @_;
|
||||
_log("CHECKOUT $transaction_id $_") for $cart->as_strings;
|
||||
_log("CHECKOUT $transaction_id $_") for map $_->as_loggable, $cart->entries;
|
||||
}
|
||||
|
||||
sub hook_register {
|
||||
|
|
|
@ -37,8 +37,9 @@ sub command :Tab(market,&tab) {
|
|||
my $space = parse_amount($product->{ space }) or return NEXT;
|
||||
my $description = $product->{description};
|
||||
|
||||
$cart->add(undef, -($seller + $space), $description,{product_id=>$command});
|
||||
$cart->add($username, 0+$seller, "\$you bought $description")
|
||||
$cart
|
||||
->add(-($seller + $space), "$description (sold by $username)", {product_id=>$command})
|
||||
->add_contra($username, 0+$seller, "\$you bought $description")
|
||||
if 0+$seller;
|
||||
return ACCEPT;
|
||||
}
|
||||
|
|
|
@ -29,7 +29,7 @@ sub product :Tab(&tab) {
|
|||
my $pfand = _read_pfand->{ $product };
|
||||
|
||||
if ($pfand) {
|
||||
$cart->add(undef, +$pfand, "Pfand zurueck", { is_return => 1 });
|
||||
$cart->add(+$pfand, "Pfand zurueck", { is_return => 1 });
|
||||
} else {
|
||||
say "$product: Kein Pfand";
|
||||
}
|
||||
|
@ -40,14 +40,15 @@ sub tab {
|
|||
return keys %{ _read_pfand() };
|
||||
}
|
||||
|
||||
sub hook_add {
|
||||
my ($class, $cart, $user, $item) = @_;
|
||||
return if defined $user;
|
||||
return if exists $item->{is_return};
|
||||
return if not exists $item->{product_id};
|
||||
sub hook_add_entry {
|
||||
my ($class, $cart, $entry) = @_;
|
||||
return if $entry->has_attribute('is_return');
|
||||
return if not $entry->has_attribute('product_id');
|
||||
|
||||
my $pfand = _read_pfand->{ $item->{product_id} } or return;
|
||||
my $pfand = _read_pfand->{ $entry->attribute('product_id') } or return;
|
||||
|
||||
$cart->add(undef, -$pfand, "Pfand", { is_pfand => 1 });
|
||||
$cart->add(-$pfand, "Pfand", { is_pfand => 1 });
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
|
|
|
@ -35,7 +35,6 @@ sub command :Tab(edit,&tab) {
|
|||
my $price = parse_amount( $product->{price} ) or return NEXT;
|
||||
|
||||
$cart->add(
|
||||
undef,
|
||||
-$price,
|
||||
$product->{description},
|
||||
{ product_id => $product->{id} }
|
||||
|
|
|
@ -3,7 +3,6 @@
|
|||
HELP "*<N>, x<N>, <N>x, <N>*" => "Repeat previous/next product N times";
|
||||
|
||||
my $err_stacked = "Stacked repetition is not supported.";
|
||||
my $err_multi = "Repetition not supported in multi-user transactions.";
|
||||
my $err_pfand = "Plugins 'pfand' and 'repeat' cannot be combined.";
|
||||
|
||||
my $limit = 24;
|
||||
|
@ -22,23 +21,21 @@ sub _do_repeat {
|
|||
sub command {
|
||||
my ($self, $cart, $command) = @_;
|
||||
|
||||
my @items = $cart->select_items;
|
||||
my $last = $items[-1];
|
||||
|
||||
return ABORT, $err_pfand if grep $_->{is_pfand}, @items;
|
||||
return ABORT, $err_pfand if $cart->entries('is_pfand');
|
||||
|
||||
my ($pre, $post) = $command =~ /^(\d+)?[x*](\d+)?$/
|
||||
or return NEXT;
|
||||
|
||||
my $last = ($cart->entries)[-1];
|
||||
|
||||
return NEXT if $pre and $post; # 123x123 -> invalid syntax
|
||||
|
||||
if ($post) {
|
||||
return REJECT, $err_multi if $cart->is_multi_user;
|
||||
return REJECT, $err_limit if $post > $limit;
|
||||
return ABORT, "Can't repeat an empty transaction." if not $cart->size;
|
||||
return REJECT, $err_stacked if $last->{_repeated};
|
||||
return REJECT, $err_stacked if $last->multiplied;
|
||||
|
||||
_do_repeat($cart, $last, $post);
|
||||
$last->quantity($post);
|
||||
return ACCEPT;
|
||||
}
|
||||
|
||||
|
@ -47,10 +44,10 @@ sub command {
|
|||
if (not $pre and not $post) {
|
||||
# Lone operator. Convert withdrawal into repetition.
|
||||
|
||||
if ($last->{is_withdrawal}) {
|
||||
if ($last->has_attribute('is_withdrawal')) {
|
||||
$pre = abs $last->{amount};
|
||||
$pre == int $pre or return REJECT, "Repeat only works on integers.";
|
||||
$cart->delete($last->{user}, -1);
|
||||
$cart->delete($last);
|
||||
$item_replaced = 1;
|
||||
} elsif (not $cart->size) {
|
||||
return ABORT, "Can't repeat an empty transaction.";
|
||||
|
@ -61,11 +58,11 @@ sub command {
|
|||
$pre = abs $pre; # withdrawal is negative
|
||||
|
||||
return REJECT, $err_limit if $pre > $limit;
|
||||
$cart->add(undef, 0, "Next product repeated $pre times", { _repeat => abs $pre });
|
||||
$cart->add(0, "Next product repeated $pre times", { _repeat => abs $pre });
|
||||
return ACCEPT;
|
||||
}
|
||||
|
||||
return REJECT, $err_stacked if $last->{_repeated};
|
||||
return REJECT, $err_stacked if $last->multiplied;
|
||||
return "Multiply previous product by", \&repeat;
|
||||
}
|
||||
|
||||
|
@ -77,39 +74,24 @@ sub repeat {
|
|||
|
||||
return REJECT, $err_limit if $arg > $limit;
|
||||
|
||||
my @items = $cart->select_items;
|
||||
my $last = $items[-1];
|
||||
|
||||
_do_repeat($cart, $last, $arg);
|
||||
($cart->entries)[-1]->quantity($arg);
|
||||
return ACCEPT;
|
||||
}
|
||||
|
||||
sub hook_added {
|
||||
my ($self, $cart, $user, $item) = @_;
|
||||
sub hook_added_entry {
|
||||
my ($self, $cart, $entry) = @_;
|
||||
$cart->size >= 2 or return;
|
||||
|
||||
my @items = $cart->select_items;
|
||||
my @planned = $cart->select_items('_repeat');
|
||||
my @repeated = $cart->select_items('_repeated');
|
||||
my @entries = $cart->entries;
|
||||
my @planned = $cart->entries('_repeat');
|
||||
my @repeated = grep $_->multiplied, $cart->entries;
|
||||
|
||||
return ABORT, $err_multi if $cart->is_multi_user and @planned || @repeated;
|
||||
return ABORT, "Multiple repeats queued; I'm confused." if @planned > 1;
|
||||
return if not @planned;
|
||||
return ABORT, $err_pfand if grep $_->{is_pfand}, @items;
|
||||
return ABORT, $err_pfand if $cart->entries('is_pfand');
|
||||
|
||||
for my $i (0 .. $#items - 1) {
|
||||
my $item = $items[$i];
|
||||
$item->{_repeat} or next;
|
||||
my $num = $planned[0]->attribute('_repeat');
|
||||
|
||||
my $next = $items[$i + 1];
|
||||
|
||||
return ABORT, $err_stacked if $next->{_repeat};
|
||||
|
||||
my $num = $item->{_repeat};
|
||||
$cart->delete($item->{user}, $i);
|
||||
|
||||
_do_repeat($cart, $next, $num);
|
||||
|
||||
return;
|
||||
}
|
||||
$cart->delete($planned[0]);
|
||||
$entries[-1]->quantity($num);
|
||||
}
|
||||
|
|
|
@ -19,7 +19,6 @@ sub data {
|
|||
my ($self, $cart, $input) = @_;
|
||||
|
||||
$cart->add(
|
||||
undef,
|
||||
-0.07,
|
||||
"Barcode <$input>",
|
||||
{ is_barcode => 1, barcode_data => $input }
|
||||
|
@ -32,15 +31,15 @@ sub hook_checkout {
|
|||
my ($class, $cart, $username, $transaction_id) = @_;
|
||||
|
||||
my @barcodes;
|
||||
for my $item ($cart->select_items('is_barcode')) {
|
||||
push @barcodes, $item->{barcode_data};
|
||||
for my $entry ($cart->entries('is_barcode')) {
|
||||
push @barcodes, ($entry->attribute('barcode_data')) x $entry->quantity;
|
||||
}
|
||||
if (@barcodes) {
|
||||
print "\nCheck the following:\n 1. label tape is 12 mm\n 2. printer is on\n 3. wifi is enabled and connected\n\nPress enter to continue.";
|
||||
readline STDIN;
|
||||
|
||||
|
||||
my $printjob = "";
|
||||
|
||||
|
||||
open my $bcgen, "-|", "/home/bar/revlabel/barcode.pl", @barcodes
|
||||
or warn "Could not open script 1";
|
||||
|
||||
|
|
|
@ -11,7 +11,7 @@ sub command :Tab(BOUNTY1,BOUNTY2,BOUNTY3,BOUNTY4) {
|
|||
my ($self, $cart, $command) = @_;
|
||||
|
||||
if ($command =~ /BOUNTY(\d+)/) {
|
||||
$cart->add(undef, +$bounties{$1}[0], $bounties{$1}[1]);
|
||||
$cart->add(+$bounties{$1}[0], $bounties{$1}[1]);
|
||||
return ACCEPT;
|
||||
}
|
||||
|
||||
|
|
|
@ -7,7 +7,7 @@ sub command { NEXT }
|
|||
sub hook_checkout {
|
||||
my ($class, $cart, $user, $transaction_id) = @_;
|
||||
my $filename = "revbank.sales";
|
||||
my @items = $cart->select_items('product_id') or return;
|
||||
my @entries = $cart->entries('product_id') or return;
|
||||
my %already_retained;
|
||||
|
||||
my %stats = do {
|
||||
|
@ -17,9 +17,9 @@ sub hook_checkout {
|
|||
: ()
|
||||
};
|
||||
|
||||
$stats{ $_->{product_id} }++ for @items;
|
||||
$stats{ $_->attribute('product_id') } += $_->quantity for @entries;
|
||||
|
||||
for (@items) {
|
||||
for (@entries) {
|
||||
my $product = $_->{product_id};
|
||||
|
||||
publish "revspace/bank/sale" => $product;
|
||||
|
|
|
@ -6,7 +6,7 @@ HELP "split <account>..." => "Split the bill with others";
|
|||
|
||||
sub _select_split {
|
||||
my ($cart) = @_;
|
||||
grep $_->{amount} < 0, grep $_->{user} eq '$you', $cart->select_items
|
||||
grep $_->{amount} < 0, $cart->entries
|
||||
}
|
||||
|
||||
sub command :Tab(take,steal,split) {
|
||||
|
@ -36,12 +36,12 @@ sub arg :Tab(USERS) {
|
|||
my $total = sprintf "%.2f", @$users * $each;
|
||||
my $desc = join " + ", map $_->{description}, _select_split($cart);
|
||||
|
||||
for my $user (@$users) {
|
||||
$cart->add( $user, -$each, "Taken by \$you (Split: $desc)" );
|
||||
}
|
||||
|
||||
my $users = join '/', @$users;
|
||||
$cart->add( undef, $total, "Taken from $users (Split: $desc)" );
|
||||
my $entry = $cart->add($total, "Taken from $users (Split: $desc)" );
|
||||
|
||||
for my $user (@$users) {
|
||||
$entry->add_contra( $user, -$each, "Taken by \$you (Split: $desc)" );
|
||||
}
|
||||
|
||||
return ACCEPT;
|
||||
}
|
||||
|
|
|
@ -21,7 +21,7 @@ sub hook_checkout {
|
|||
? "revbank.voorraad"
|
||||
: "revbank.stock";
|
||||
|
||||
my @items = $cart->select_items('product_id') or return;
|
||||
my @entries = $cart->entries('product_id') or return;
|
||||
|
||||
my %stock = do {
|
||||
my $in;
|
||||
|
@ -30,7 +30,7 @@ sub hook_checkout {
|
|||
: ()
|
||||
};
|
||||
|
||||
$stock{ $_->{product_id} }-- for @items;
|
||||
$stock{ $_->attribute('product_id') } -= $_->quantity for @entries;
|
||||
|
||||
open my $out, '>', "$filename.$$" or warn "$filename.$$: $!";
|
||||
printf {$out} "%-16s %+9d\n", $_, $stock{$_} for sort keys %stock;
|
||||
|
|
|
@ -59,12 +59,11 @@ sub reason :Tab(bbq,NOABORT) { # finish
|
|||
my $each = $self->{each};
|
||||
my $total = $self->{total};
|
||||
|
||||
for my $user (@users) {
|
||||
$cart->add( $user, -$each, "Taken by \$you ($reason)" );
|
||||
}
|
||||
|
||||
my $users = join '/', @users;
|
||||
$cart->add( undef, $total, "Taken from $users ($reason)" );
|
||||
my $entry = $cart->add($total, "Taken from $users ($reason)", { is_take => 1 });
|
||||
for my $user (@users) {
|
||||
$entry->add_contra( $user, -$each, "Taken by \$you ($reason)" );
|
||||
}
|
||||
|
||||
return ACCEPT;
|
||||
}
|
||||
|
|
12
plugins/undo
12
plugins/undo
|
@ -19,10 +19,18 @@ sub undo {
|
|||
|
||||
open my $in, '<', $filename or die "$filename: $!";
|
||||
open my $out, '>', "$filename.$$" or die "$filename.$$: $!";
|
||||
my $description = "Undo $tid";
|
||||
|
||||
my $entry;
|
||||
|
||||
while (defined(my $line = readline $in)) {
|
||||
if ($line =~ /^\Q$tid\E\s/) {
|
||||
my (undef, $user, $delta) = split " ", $line;
|
||||
$cart->add($user, $delta, "Undo $tid");
|
||||
|
||||
$entry ||= $cart->add(0, $description);
|
||||
$entry->{FORCE} = 1;
|
||||
|
||||
$entry->add_contra($user, $delta, "Undo $tid");
|
||||
} else {
|
||||
print {$out} $line;
|
||||
}
|
||||
|
@ -31,7 +39,7 @@ sub undo {
|
|||
close $out or die $!;
|
||||
if ($cart->size) {
|
||||
rename "$filename.$$", $filename or die $!;
|
||||
$cart->checkout();
|
||||
$cart->checkout('**UNDO**');
|
||||
} else {
|
||||
return ABORT, "Transaction ID '$tid' not found in undo log.";
|
||||
}
|
||||
|
|
|
@ -15,7 +15,7 @@ sub amount {
|
|||
$self->{amount} = parse_amount($arg) or return REJECT, "Invalid amount.";
|
||||
|
||||
if ($self->{command} eq 'donate') {
|
||||
$cart->add(undef, -$self->{amount}, "Donation (THANK YOU!)");
|
||||
$cart->add(-$self->{amount}, "Donation (THANK YOU!)");
|
||||
return ACCEPT;
|
||||
}
|
||||
|
||||
|
@ -24,7 +24,7 @@ sub amount {
|
|||
|
||||
sub description {
|
||||
my ($self, $cart, $desc) = @_;
|
||||
$cart->add(undef, -$self->{amount}, $desc);
|
||||
$cart->add(-$self->{amount}, $desc);
|
||||
return ACCEPT;
|
||||
}
|
||||
|
||||
|
|
|
@ -31,13 +31,12 @@ sub _read_warnings {
|
|||
|
||||
sub command { NEXT }
|
||||
|
||||
sub hook_add {
|
||||
my ($class, $cart, $user, $item) = @_;
|
||||
return if defined $user; # skip market items
|
||||
return if not exists $item->{product_id}; # skip unlisted, deposit, give, take
|
||||
sub hook_add_entry {
|
||||
my ($class, $cart, $entry) = @_;
|
||||
return if not $entry->has_attribute('product_id'); # skip unlisted, deposit, give, take
|
||||
|
||||
my @warnings = map {
|
||||
$_->( $item->{product_id}, $item->{description} )
|
||||
$_->( $entry->attribute('product_id'), $entry->{description} )
|
||||
} _read_warnings;
|
||||
|
||||
return if not @warnings;
|
||||
|
|
|
@ -8,7 +8,7 @@ sub command {
|
|||
my $amount = parse_amount($command);
|
||||
defined $amount or return NEXT;
|
||||
|
||||
$cart->add(undef, -$amount, "Withdrawal or unlisted product",
|
||||
$cart->add(-$amount, "Withdrawal or unlisted product",
|
||||
{ is_withdrawal => 1 });
|
||||
|
||||
return ACCEPT;
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue