New feature: percentage addons (discounts etc)

This commit is contained in:
Juerd Waalboer 2023-01-05 19:10:40 +01:00
parent eb55aa0eb5
commit 7c05b3108c
2 changed files with 60 additions and 31 deletions

View file

@ -72,6 +72,17 @@ sub attribute($self, $key, $new = undef) {
return $$ref; 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) { sub quantity($self, $new = undef) {
my $ref = \$self->{quantity}; my $ref = \$self->{quantity};
if (defined $new) { if (defined $new) {

View file

@ -3,6 +3,7 @@
HELP1 "<productID>" => "Add a product to pending transaction"; HELP1 "<productID>" => "Add a product to pending transaction";
my $filename = 'revbank.products'; my $filename = 'revbank.products';
my $default_contra = '+sales/products';
sub _read_products() { sub _read_products() {
my %products; my %products;
@ -23,11 +24,20 @@ sub _read_products() {
my ($price, $contra) = split /\@/, $p, 2; my ($price, $contra) = split /\@/, $p, 2;
my $sign = $price =~ s/^-// ? -1 : 1; my $sign = $price =~ s/^-// ? -1 : 1;
my $percent = $price =~ s/%$//;
$price = eval { parse_amount($price) }; if ($percent) {
if (not defined $price) { if (grep !/^\+/, @ids) {
warn "Invalid price for '$ids[0]' at $filename line $line.\n"; warn "Percentage invalid for non-addon at $filename line $line.\n";
next; 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; my @addons;
@ -36,8 +46,9 @@ sub _read_products() {
$products{$_} = { $products{$_} = {
id => $ids[0], id => $ids[0],
price => $sign * $price, price => $sign * $price,
percent => $percent,
description => $desc, description => $desc,
contra => $contra || '+sales/products', contra => $contra || $default_contra,
addons => \@addons, addons => \@addons,
line => $line, line => $line,
} for @ids; } for @ids;
@ -64,17 +75,26 @@ sub command :Tab(&tab) ($self, $cart, $command, @) {
return ACCEPT; return ACCEPT;
} }
my $total = $price;
my $contra_desc = "\$you bought $product->{description}"; my $contra_desc = "\$you bought $product->{description}";
my @addons = @{ $product->{addons} }; my $entry = $cart->add(
my @infos = @addons ? ( -$price,
$price->cents > 0 ? ([ $price, "Product" ]) $product->{description},
: $price->cents < 0 ? ([ $price, "Reimbursement" ]) { product_id => $product->{id}, plugin => $self->id, addons => $product->{addons} }
: () # price == 0: only 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); my %ids_seen = ($product->{id} => 1);
while (my $addon_id = shift @addons) { while (my $addon_id = shift @addons) {
@ -87,33 +107,31 @@ sub command :Tab(&tab) ($self, $cart, $command, @) {
my $addon = $products->{$addon_id} my $addon = $products->{$addon_id}
or return REJECT, "Addon '$addon_id' does not exist."; 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} =~ /^[-+]/; if $addon->{contra} =~ /^[-+]/;
push @contras, [ $entry->add_contra(
$addon->{contra}, $addon->{contra},
$addon->{price}, $addon_price,
"$addon->{description} ($contra_desc)" "$addon->{description} ($contra_desc)"
]; );
push @addons, @{ $addon->{addons} }; 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; return ACCEPT;
} }