From 980db529f13798b6af431bcf96d63fcf26491d29 Mon Sep 17 00:00:00 2001 From: jordi fita mas Date: Thu, 23 Feb 2023 14:42:18 +0100 Subject: [PATCH] Fix to_price and parse_price for negative values --- deploy/parse_price.sql | 8 +++++++- deploy/to_price.sql | 7 ++++++- test/parse_price.sql | 8 +++++++- test/to_price.sql | 8 +++++++- 4 files changed, 27 insertions(+), 4 deletions(-) diff --git a/deploy/parse_price.sql b/deploy/parse_price.sql index 7cdfe8b..600635c 100644 --- a/deploy/parse_price.sql +++ b/deploy/parse_price.sql @@ -11,7 +11,13 @@ declare parts text[]; result int; frac_part text; + sign int := 1; begin + if price like '-%' Then + sign := -1; + price := substring(price from 2); + end if; + parts := string_to_array(price, '.'); if array_length(parts, 1) > 2 then raise invalid_parameter_value using message = price || ' is not a valid price representation.'; @@ -31,7 +37,7 @@ begin result := result + frac_part::integer; end if; - return result; + return sign * result; end; $$ language plpgsql diff --git a/deploy/to_price.sql b/deploy/to_price.sql index 0cc20bb..7cc5817 100644 --- a/deploy/to_price.sql +++ b/deploy/to_price.sql @@ -10,9 +10,14 @@ $$ declare result text; scale integer := 10^decimal_digits; + sign text := ''; begin + if cents < 0 then + sign := '-'; + cents = -cents; + end if; result = cents::text; - return (cents / scale)::text || '.' || to_char(mod(cents, scale), rpad('FM', decimal_digits + 2, '0')); + return sign || (cents / scale)::text || '.' || to_char(mod(cents, scale), rpad('FM', decimal_digits + 2, '0')); end; $$ language plpgsql diff --git a/test/parse_price.sql b/test/parse_price.sql index 6317eca..9c42d98 100644 --- a/test/parse_price.sql +++ b/test/parse_price.sql @@ -5,7 +5,7 @@ reset client_min_messages; begin; -select plan(36); +select plan(42); set search_path to auth, numerus, public; @@ -23,8 +23,12 @@ select is( parse_price('1.1', 2), 110 ); select is( parse_price('1.1', 3), 1100 ); select is( parse_price('0', 2), 0 ); select is( parse_price('0', 3), 0 ); +select is( parse_price('-0', 2), 0 ); +select is( parse_price('-0', 3), 0 ); select is( parse_price('0.01', 2), 1 ); select is( parse_price('0.001', 3), 1 ); +select is( parse_price('-0.01', 2), -1 ); +select is( parse_price('-0.001', 3), -1 ); select is( parse_price('0.1', 2), 10 ); select is( parse_price('0.01', 3), 10 ); select is( parse_price('1', 2), 100 ); @@ -33,6 +37,8 @@ select is( parse_price('10', 2), 1000 ); select is( parse_price('1', 3), 1000 ); select is( parse_price('23.23', 2), 2323 ); select is( parse_price('23.23', 3), 23230 ); +select is( parse_price('-23.23', 2), -2323 ); +select is( parse_price('-23.23', 3), -23230 ); select throws_ok( $$ select parse_price('234.234', 2) $$ ); select is( parse_price('234.234', 3), 234234 ); select throws_ok( $$ select parse_price('2345.2345', 2) $$ ); diff --git a/test/to_price.sql b/test/to_price.sql index 2fbf443..ef71373 100644 --- a/test/to_price.sql +++ b/test/to_price.sql @@ -5,7 +5,7 @@ reset client_min_messages; begin; -select plan(23); +select plan(29); set search_path to numerus, public; @@ -23,6 +23,8 @@ select is( to_price(0, 2), '0.00' ); select is( to_price(0, 3), '0.000' ); select is( to_price(1, 2), '0.01' ); select is( to_price(1, 3), '0.001' ); +select is( to_price(-1, 2), '-0.01' ); +select is( to_price(-1, 3), '-0.001' ); select is( to_price(10, 2), '0.10' ); select is( to_price(10, 3), '0.010' ); select is( to_price(100, 2), '1.00' ); @@ -33,6 +35,10 @@ select is( to_price(12345678, 2), '123456.78' ); select is( to_price(12345678, 3), '12345.678' ); select is( to_price(12345678, 4), '1234.5678' ); select is( to_price(12345678, 5), '123.45678' ); +select is( to_price(-12345678, 2), '-123456.78' ); +select is( to_price(-12345678, 3), '-12345.678' ); +select is( to_price(-12345678, 4), '-1234.5678' ); +select is( to_price(-12345678, 5), '-123.45678' ); select * from finish();