From 3dab71fdbf946afdb0991015c89933bb68f07448 Mon Sep 17 00:00:00 2001 From: Juerd Waalboer Date: Mon, 25 Dec 2023 00:33:46 +0100 Subject: [PATCH] support simple arithmetic (only + and -) for monetary amounts --- lib/RevBank/Global.pm | 21 +++++++++++++++- revbank | 2 +- t/calc.t | 56 +++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 77 insertions(+), 2 deletions(-) create mode 100644 t/calc.t diff --git a/lib/RevBank/Global.pm b/lib/RevBank/Global.pm index a3ce975..e3b3c7c 100644 --- a/lib/RevBank/Global.pm +++ b/lib/RevBank/Global.pm @@ -29,7 +29,26 @@ sub import { defined $amount or return undef; length $amount or return undef; - $amount = RevBank::Amount->parse_string($amount) // return undef; + my @split = grep /\S/, split /([+-])/, $amount; + + my $posneg = 1; + $amount = RevBank::Amount->new(0); + for my $token (@split) { + if ($token eq '-') { + $posneg = $posneg == -1 ? 1 : -1; + } elsif ($token eq '+') { + next if $posneg == -1; # -+ + $posneg ||= 1; + next; + } else { + $posneg or return undef; # two terms in a row + my $term = RevBank::Amount->parse_string($token) // return undef; + $amount += $posneg * $term; + $posneg = 0; + } + } + $posneg and return undef; # last token must be term + if ($amount->cents < 0) { die "For our sanity, no negative amounts, please :).\n"; } diff --git a/revbank b/revbank index ca23a1c..1a8f2dd 100755 --- a/revbank +++ b/revbank @@ -17,7 +17,7 @@ use RevBank::Global; use RevBank::Messages; use RevBank::Cart; -our $VERSION = "4.2.4"; +our $VERSION = "4.3.0"; our %HELP1 = ( "abort" => "Abort the current transaction", ); diff --git a/t/calc.t b/t/calc.t new file mode 100644 index 0000000..0de002a --- /dev/null +++ b/t/calc.t @@ -0,0 +1,56 @@ +use v5.32; + +use Test::More; +use Test::Exception; +use Test::Warnings ":all"; + +BEGIN { use_ok('RevBank::Global'); } + +dies_ok sub { parse_amount("-1") }; +dies_ok sub { parse_amount("0-42") }; +dies_ok sub { parse_amount("999999") }; + +is parse_amount("0.123"), undef; +is parse_amount("42.000"), undef; +is parse_amount("a"), undef; +is parse_amount("(1+1)"), undef; + +is parse_amount("42")->cents, 4200; +is parse_amount("42.0")->cents, 4200; +is parse_amount("42.00")->cents, 4200; +is parse_amount("1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1")->cents, 4200; + +is parse_amount("-42+42")->cents, 0; +is parse_amount("+42")->cents, 4200; +is parse_amount("--42")->cents, 4200; +is parse_amount("+42-42")->cents, 0; +is parse_amount("0--42")->cents, 4200; +is parse_amount("0++42")->cents, 4200; +is parse_amount("42+-42")->cents, 0; +is parse_amount("42-+42")->cents, 0; +is parse_amount("0+42")->cents, 4200; +is parse_amount("42-42")->cents, 0; + +is parse_amount(" - 42 + 42")->cents, 0; +is parse_amount(" + 42 ")->cents, 4200; +is parse_amount(" - - 42 ")->cents, 4200; +is parse_amount(" + 42 - 42 ")->cents, 0; +is parse_amount(" 0 - - 42 ")->cents, 4200; +is parse_amount(" 0 + + 42 ")->cents, 4200; +is parse_amount(" 42 + - 42 ")->cents, 0; +is parse_amount(" 42 - + 42 ")->cents, 0; +is parse_amount(" 0 + 42 ")->cents, 4200; +is parse_amount(" 42 - 42 ")->cents, 0; + +is parse_amount("-4.20+4.20")->cents, 0; +is parse_amount("+4.20")->cents, 420; +is parse_amount("--4.20")->cents, 420; +is parse_amount("+4.20-4.20")->cents, 0; +is parse_amount("0--4.20")->cents, 420; +is parse_amount("0++4.20")->cents, 420; +is parse_amount("4.20+-4.20")->cents, 0; +is parse_amount("4.20-+4.20")->cents, 0; +is parse_amount("0+4.20")->cents, 420; +is parse_amount("4.20-4.20")->cents, 0; + +done_testing;