From 7c05b3108c37947634f6c9e55a495eb53f418db7 Mon Sep 17 00:00:00 2001 From: Juerd Waalboer Date: Thu, 5 Jan 2023 19:10:40 +0100 Subject: [PATCH] New feature: percentage addons (discounts etc) --- lib/RevBank/Cart/Entry.pm | 11 ++++++ plugins/products | 80 ++++++++++++++++++++++++--------------- 2 files changed, 60 insertions(+), 31 deletions(-) diff --git a/lib/RevBank/Cart/Entry.pm b/lib/RevBank/Cart/Entry.pm index 2f0d0a4..a1bb822 100644 --- a/lib/RevBank/Cart/Entry.pm +++ b/lib/RevBank/Cart/Entry.pm @@ -72,6 +72,17 @@ sub attribute($self, $key, $new = undef) { return $$ref; } +sub amount($self, $new = undef) { + my $ref = \$self->{amount}; + if (defined $new) { + $new = RevBank::Amount->parse_string($new) if not ref $new; + $$ref = $new; + $self->attribute('changed', 1); + } + + return $$ref; +} + sub quantity($self, $new = undef) { my $ref = \$self->{quantity}; if (defined $new) { diff --git a/plugins/products b/plugins/products index 47f37e5..2ab6256 100644 --- a/plugins/products +++ b/plugins/products @@ -3,6 +3,7 @@ HELP1 "" => "Add a product to pending transaction"; my $filename = 'revbank.products'; +my $default_contra = '+sales/products'; sub _read_products() { my %products; @@ -23,11 +24,20 @@ sub _read_products() { my ($price, $contra) = split /\@/, $p, 2; my $sign = $price =~ s/^-// ? -1 : 1; + my $percent = $price =~ s/%$//; - $price = eval { parse_amount($price) }; - if (not defined $price) { - warn "Invalid price for '$ids[0]' at $filename line $line.\n"; - next; + if ($percent) { + if (grep !/^\+/, @ids) { + warn "Percentage invalid for non-addon at $filename line $line.\n"; + next; + } + $price = 0 + $price; + } else { + $price = eval { parse_amount($price) }; + if (not defined $price) { + warn "Invalid price for '$ids[0]' at $filename line $line.\n"; + next; + } } my @addons; @@ -36,8 +46,9 @@ sub _read_products() { $products{$_} = { id => $ids[0], price => $sign * $price, + percent => $percent, description => $desc, - contra => $contra || '+sales/products', + contra => $contra || $default_contra, addons => \@addons, line => $line, } for @ids; @@ -64,17 +75,26 @@ sub command :Tab(&tab) ($self, $cart, $command, @) { return ACCEPT; } - my $total = $price; my $contra_desc = "\$you bought $product->{description}"; - my @addons = @{ $product->{addons} }; - my @infos = @addons ? ( - $price->cents > 0 ? ([ $price, "Product" ]) - : $price->cents < 0 ? ([ $price, "Reimbursement" ]) - : () # price == 0: only addons - ) : (); + my $entry = $cart->add( + -$price, + $product->{description}, + { product_id => $product->{id}, plugin => $self->id, addons => $product->{addons} } + ); + $entry->add_contra( + $product->{contra}, + +$price, + $contra_desc + ); + + my @addons = @{ $product->{addons} } + or return ACCEPT; + + + $entry->add_info($price, "Product") if $price->cents > 0; + $entry->add_info($price, "Reimbursement") if $price->cents < 0; - my @contras; my %ids_seen = ($product->{id} => 1); while (my $addon_id = shift @addons) { @@ -87,33 +107,31 @@ sub command :Tab(&tab) ($self, $cart, $command, @) { my $addon = $products->{$addon_id} or return REJECT, "Addon '$addon_id' does not exist."; - $total += $addon->{price}; + my $addon_price = $addon->{price}; + if ($addon->{percent}) { + my $sum = List::Util::sum map { + $_->{amount} + } grep { + $_->{user} eq $addon->{contra} + } $entry->contras; - push @infos, [ $addon->{price}, $addon->{description} ] + $addon_price = $addon_price / 100 * $sum; + } + + $entry->amount( $entry->amount - $addon_price ); + + $entry->add_info($addon_price, $addon->{description}) if $addon->{contra} =~ /^[-+]/; - push @contras, [ + $entry->add_contra( $addon->{contra}, - $addon->{price}, + $addon_price, "$addon->{description} ($contra_desc)" - ]; + ); push @addons, @{ $addon->{addons} }; } - my $entry = $cart->add( - -$total, - $product->{description}, - { product_id => $product->{id}, plugin => $self->id, addons => $product->{addons} } - ); - $entry->add_contra( - $product->{contra}, - +$price, - $contra_desc - ); - $entry->add_info(@$_) for @infos; - $entry->add_contra(@$_) for @contras; - return ACCEPT; }