revbank/plugins/repeat
Juerd Waalboer f4eb91a22b Increase maximum multiplication factor (repeat limit)
The limit was mostly imposed because of the actually repeated
lines, which would scroll off the screen. Now that the quantity
is just displayed as a number, I don't really see any technical
reason for a low limit; maybe 200 is still too low.
2019-11-06 03:25:38 +01:00

89 lines
2.5 KiB
Perl

#!perl
HELP "*<N>, x<N>, <N>x, <N>*" => "Repeat previous/next product N times";
my $err_stacked = "Stacked repetition is not supported.";
my $err_pfand = "Plugins 'pfand' and 'repeat' cannot be combined.";
my $limit = 200;
my $err_limit = "Repetition is limited at $limit items.";
sub command {
my ($self, $cart, $command) = @_;
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_limit if $post > $limit;
return ABORT, "Can't repeat an empty transaction." if not $cart->size;
return REJECT, $err_stacked if $last->multiplied;
$last->quantity($post);
return ACCEPT;
}
if (not $pre and not $post) {
# Lone operator. Convert withdrawal into repetition.
if ($last->has_attribute('is_withdrawal')) {
$pre = abs $last->{amount};
$pre == int $pre or return REJECT, "Repeat only works on integers.";
$cart->delete($last);
} elsif (not $cart->size) {
return ABORT, "Can't repeat an empty transaction.";
}
}
if ($pre) {
$pre = abs $pre; # withdrawal is negative
return REJECT, $err_limit if $pre > $limit;
$cart
->add(0, "? (The next thing you add will be multiplied.)", { _repeat => 1 })
->quantity($pre);
return ACCEPT;
}
return REJECT, $err_stacked if $last->multiplied;
return "Multiply previous product by", \&repeat;
}
sub repeat {
my ($self, $cart, $arg) = @_;
$arg =~ /^\d+$/ and $arg > 0
or return REJECT, "Invalid value.";
return REJECT, $err_limit if $arg > $limit;
($cart->entries)[-1]->quantity($arg);
return ACCEPT;
}
sub hook_added_entry {
my ($self, $cart, $entry) = @_;
$cart->size >= 2 or return;
my @entries = $cart->entries;
my @planned = $cart->entries('_repeat');
return if not @planned;
return ABORT, "Multiple repeats queued; I'm confused." if @planned > 1;
return ABORT, $err_pfand if $cart->entries('is_pfand');
return if $planned[0] == $entries[-1];
return ABORT, "Queued repeat is not the penultimate item; I'm confused"
if $entries[-2] != $planned[0];
my $num = $planned[0]->quantity;
$cart->delete($planned[0]);
$entries[-1]->quantity($num);
}