#!perl HELP "*, x, x, *" => "Set quantity of previous/next product"; HELP "-, +" => "Decrease/increase quantity of previous product"; my $err_stacked = "Stacked repetition is not supported."; my $err_pfand = "Plugins 'pfand' and 'repeat' cannot be combined."; my $err_nope = "Entry does not support repetition."; my $err_postfix = "Addition/substraction is only supported the other way around."; my $limit = 200; my $err_limit = "Repetition is limited at $limit items."; sub command($self, $cart, $command, @) { return ABORT, $err_pfand if $cart->entries('is_pfand'); my ($lhs, $op, $rhs) = $command =~ /^(\d+)?([x*+-])(\d+)?$/ or return NEXT; my $last = ($cart->entries)[-1]; return NEXT if $lhs and $rhs; # 123x123 -> invalid syntax if ($rhs) { return ABORT, "Can't modify an empty transaction." if not $cart->size; return REJECT, $err_nope if $last->attribute('no_repeat'); return REJECT, $err_limit if $rhs > $limit; if ($op eq '+') { my $new = $last->quantity + $rhs; return REJECT, $err_limit if $new > $limit; $last->quantity($new); return ACCEPT; } if ($op eq '-') { my $new = $last->quantity - $rhs; if ($new > 0) { $last->quantity($new); } else { $cart->delete($last); print "Deleted.\n"; } return ACCEPT; } # $op is not + or -, so it must be * (or x). return REJECT, $err_stacked if $last->multiplied; $last->quantity($rhs); return ACCEPT; } if (not $lhs and not $rhs) { # Lone operator. Convert withdrawal into repetition. return ABORT, "Can't modify an empty transaction." if not $cart->size; if ($op eq '+' or $op eq '-') { $self->{op} = $op; return "$op how many?", \&plusminus; } if ($last->has_attribute('is_withdrawal')) { $lhs = $last->{amount}->abs->float; $lhs == int $lhs or return REJECT, "Repeat only works on integers."; $cart->delete($last); } } if ($lhs) { return REJECT, $err_postfix if $op eq '+' or $op eq '-'; $lhs = abs $lhs; # withdrawal is negative return REJECT, $err_limit if $lhs > $limit; $cart ->add(0, "? (The next thing you add will be multiplied.)", { _repeat => 1, refuse_checkout => 1 }) ->quantity($lhs); return ACCEPT; } return REJECT, $err_stacked if $last->multiplied; return REJECT, $err_nope if $last->attribute('no_repeat'); return "Multiply previous product by", \&repeat; } sub repeat($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 plusminus($self, $cart, $arg, @) { $arg =~ /^\d+$/ and $arg > 0 or return REJECT, "Invalid value."; my $last = ($cart->entries)[-1]; my $new = $last->quantity; $new += $arg if $self->{op} eq '+'; $new -= $arg if $self->{op} eq '-'; return REJECT, $err_limit if $new > $limit; if ($new < 0) { $cart->delete($last); print "Deleted.\n"; } else { ($cart->entries)[-1]->quantity($new); } return ACCEPT; } sub hook_added_entry($class, $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; if ($entries[-1]->attribute('no_repeat')) { print $err_nope, "\n"; $num = 1; } $cart->delete($planned[0]); $entries[-1]->quantity($num); }