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
|
@ -19,14 +19,16 @@ sub _call_old_hooks {
|
|||
|
||||
my $data = $entry->{attributes};
|
||||
|
||||
for ($entry, $entry->contras) {
|
||||
my $item = {
|
||||
%$data,
|
||||
amount => $_->{amount},
|
||||
description => $_->{description},
|
||||
};
|
||||
for (1 .. $entry->quantity) {
|
||||
for ($entry, $entry->contras) {
|
||||
my $item = {
|
||||
%$data,
|
||||
amount => $_->{amount},
|
||||
description => $_->{description},
|
||||
};
|
||||
|
||||
RevBank::Plugins::call_hooks($hook, $self, $_->{user}, $item);
|
||||
RevBank::Plugins::call_hooks($hook, $self, $_->{user}, $item);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -118,14 +120,17 @@ sub checkout {
|
|||
my %deltas;
|
||||
for my $entry (@$entries) {
|
||||
$entry->user($user);
|
||||
$deltas{$_->{user}} += $_->{amount} for $entry, $entry->contras;
|
||||
|
||||
$deltas{$_->{user}} += $_->{amount} * $entry->quantity
|
||||
for $entry, $entry->contras;
|
||||
}
|
||||
|
||||
my $transaction_id = time() - 1300000000;
|
||||
RevBank::Plugins::call_hooks("checkout", $self, $user, $transaction_id);
|
||||
|
||||
for my $account (keys %deltas) {
|
||||
RevBank::Users::update($account, $deltas{$account}, $transaction_id);
|
||||
RevBank::Users::update($account, $deltas{$account}, $transaction_id)
|
||||
if $deltas{$account} != 0;
|
||||
}
|
||||
|
||||
RevBank::Plugins::call_hooks("checkout_done", $self, $user, $transaction_id);
|
||||
|
@ -142,24 +147,45 @@ sub select_items {
|
|||
my @matches;
|
||||
for my $entry (@{ $self->{entries} }) {
|
||||
my %attributes = %{ $entry->{attributes} };
|
||||
for my $item ($entry, $entry->contras) {
|
||||
push @matches, { %attributes, %$item }
|
||||
if @_ == 1 # No key or match given: match everything
|
||||
or @_ == 2 and $entry->has_attribute($key) # Just a key
|
||||
for (1 .. $entry->quantity) {
|
||||
for my $item ($entry, $entry->contras) {
|
||||
push @matches, { %attributes, %$item }
|
||||
if @_ == 1 # No key or match given: match everything
|
||||
or @_ == 2 and $entry->has_attribute($key) # Just a key
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return @matches;
|
||||
}
|
||||
|
||||
sub entries {
|
||||
my ($self, $attribute) = @_;
|
||||
|
||||
my @entries = @{ $self->{entries} };
|
||||
return grep $_->has_attribute($attribute), @entries if defined $attribute;
|
||||
return @entries;
|
||||
}
|
||||
|
||||
sub is_multi_user {
|
||||
Carp::carp("\$cart->is_multi_user is no longer supported, ignoring");
|
||||
}
|
||||
|
||||
sub changed {
|
||||
my ($self) = @_;
|
||||
return delete $self->{changed};
|
||||
|
||||
my $changed = 0;
|
||||
for my $entry ($self->entries('changed')) {
|
||||
$entry->attribute('changed', undef);
|
||||
$changed = 1;
|
||||
}
|
||||
$changed = 1 if delete $self->{changed};
|
||||
return $changed;
|
||||
}
|
||||
|
||||
sub sum {
|
||||
my ($self) = @_;
|
||||
return List::Util::sum(map $_->{amount} * $_->quantity, @{ $self->{entries} });
|
||||
}
|
||||
|
||||
1;
|
||||
|
||||
|
|
|
@ -34,6 +34,8 @@ sub add_contra {
|
|||
amount => $amount, # should usually have opposite sign (+/-)
|
||||
description => $description,
|
||||
};
|
||||
|
||||
$self->attribute('changed', 1);
|
||||
}
|
||||
|
||||
sub has_attribute {
|
||||
|
@ -57,12 +59,13 @@ sub quantity {
|
|||
if (defined $new) {
|
||||
$new >= 0 or croak "Quantity must be positive";
|
||||
$$ref = $new;
|
||||
$self->attribute('changed', 1);
|
||||
}
|
||||
|
||||
return $$ref;
|
||||
}
|
||||
|
||||
sub multiple {
|
||||
sub multiplied {
|
||||
my ($self) = @_;
|
||||
|
||||
return $self->{quantity} != 1;
|
||||
|
@ -81,7 +84,7 @@ sub as_printable {
|
|||
$self->sanity_check;
|
||||
|
||||
my @s;
|
||||
push @s, $self->{quantity} . "x {" if $self->multiple;
|
||||
push @s, $self->{quantity} . "x {" if $self->multiplied;
|
||||
|
||||
# Normally, the implied sign is "+", and an "-" is only added for negative
|
||||
# numbers. Here, the implied sign is "-", and a "+" is only added for
|
||||
|
@ -102,7 +105,7 @@ sub as_printable {
|
|||
|
||||
}
|
||||
|
||||
push @s, "}" if $self->multiple;
|
||||
push @s, "}" if $self->multiplied;
|
||||
|
||||
return @s;
|
||||
}
|
||||
|
@ -122,10 +125,10 @@ sub as_loggable {
|
|||
my $description =
|
||||
$quantity == 1
|
||||
? $_->{description}
|
||||
: sprintf("[%fx%.2f]", $quantity, $_->{amount});
|
||||
: sprintf("[%sx %.2f] %s", $quantity, abs($_->{amount}), $_->{description});
|
||||
|
||||
push @s, sprintf(
|
||||
"%-12s %4s EUR %5.2f %s",
|
||||
"%-12s %4s EUR %5.2f # %s",
|
||||
$_->{user},
|
||||
($total > 0 ? 'GAIN' : $total < 0 ? 'LOSE' : ''),
|
||||
abs($total),
|
||||
|
@ -143,6 +146,7 @@ sub user {
|
|||
croak "User can only be set once" if defined $self->{user};
|
||||
|
||||
$self->{user} = $new;
|
||||
$self->attribute('changed', 1);
|
||||
$_->{description} =~ s/\$you/$new/g for $self, @{ $self->{contras} };
|
||||
}
|
||||
|
||||
|
|
|
@ -24,8 +24,12 @@ sub hook_plugin_fail {
|
|||
sub hook_cart_changed {
|
||||
my ($class, $cart) = @_;
|
||||
$cart->size or return;
|
||||
say "Pending:";
|
||||
$cart->display;
|
||||
say "Enter username to pay/finish or 'abort' to abort.\n";
|
||||
|
||||
my $sum = $cart->sum;
|
||||
my $what = $sum > 0 ? "add %.2f" : "pay %.2f";
|
||||
say sprintf "Enter username to $what; type 'abort' to abort.\n", abs $sum;
|
||||
}
|
||||
|
||||
sub hook_abort {
|
||||
|
|
|
@ -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
Reference in a new issue