#!perl HELP "*, x, x, *" => "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 = 24; my $err_limit = "Repetition is limited at $limit items."; sub _do_repeat { my ($cart, $item, $num) = @_; $item->{_repeated} = 1; # Strongly dependent on the implementation of RevBank::Cart and the 'add' # method. Bad idea, but meh. $cart->add( @{ $item }{qw/user amount description/}, $item ) for 2..$num; } 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; } my $item_replaced; 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); $item_replaced = 1; } 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, "Next product repeated $pre times", { _repeat => abs $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'); my @repeated = grep $_->multiplied, $cart->entries; return ABORT, "Multiple repeats queued; I'm confused." if @planned > 1; return if not @planned; return ABORT, $err_pfand if $cart->entries('is_pfand'); my $num = $planned[0]->attribute('_repeat'); $cart->delete($planned[0]); $entries[-1]->quantity($num); }