From ff1bb89cd48a36fda82370bd9637ff35a3c82a3f Mon Sep 17 00:00:00 2001 From: "Paul M. Jones" Date: Tue, 16 Mar 2021 12:12:59 -0500 Subject: [PATCH 01/17] introduce Teller class fixes #629 --- doc/features/teller.rst | 66 +++++ doc/index.rst | 1 + src/Teller.php | 521 ++++++++++++++++++++++++++++++++++++++++ tests/TellerTest.php | 417 ++++++++++++++++++++++++++++++++ 4 files changed, 1005 insertions(+) create mode 100644 doc/features/teller.rst create mode 100644 src/Teller.php create mode 100644 tests/TellerTest.php diff --git a/doc/features/teller.rst b/doc/features/teller.rst new file mode 100644 index 000000000..267504539 --- /dev/null +++ b/doc/features/teller.rst @@ -0,0 +1,66 @@ +.. _teller: + +Teller +====== + +Legacy codebases often use float math for monetary calculations, which leads to problems with fractions-of-pennies in monetary amounts. The proper solution is to introduce a Money object, and use Money objects in place of float math. However, doing so can be quite an onerous task, especially when the float values need to be moved to and from database storage; intercepting and coercing the float values (often represented by strings) can be very difficult and time-consuming. + +To help ease the transition from float math to Money objects, use a Teller instance to replace float math for monetary calculations in place: + +.. code-block:: php + + // before + $price = 234.56; + $discount = 0.05; + $discountAmount = $price * $discount; // 11.728 + + // after + $teller = \Money\Teller::USD(); + $discountAmount = $teller->multiply($amount, $discount); // '11.73' + +The main drawback is that you cannot use two different currencies with the Teller; you can use only one. + +The Teller offers these methods: + +* operation + + * ``absolute($amount) : string`` Returns an absoute monetary amount. + * ``add($amount, $other, ...$others) : string`` Adds one or more monetary amounts to a monetary amount. + * ``divide($amount, $divisor) : string`` Divides a monetary amount by a divisor. + * ``mod($amount, $divisor)`` Retuns the mod of one amount by another. + * ``multiply($amount, $multiplier) : string`` Multiplies a monetary amount by a multiplier. + * ``negative($amount) : string`` Negates a monetary amount. + * ``ratioOf($amount, $other)`` Determines the ratio of one monetary amount to another. + * ``subtract($amount, $other, ...$others) : string`` Subracts one or more monetary amounts from a monetary amount. + +* comparison + + * ``compare($amount, $other) : int`` Compares one monetary amount to the other; -1 is less than, 0 is equals, 1 is greater than. + * ``equals($amount, $other) : bool`` Are two monetary amounts equal? + * ``greaterThan($amount, $other) : bool`` Is one monetary amount greater than the other? + * ``greaterThanOrEqual($amount, $other) : bool`` Is one monetary amount greater than or equal to the other? + * ``isNegative($amount) : bool`` Is a monetary amount less than zero? + * ``isPositive($amount) : bool`` Is a monetary amount greater than zero? + * ``isZero($amount) : bool`` Is a monetary amount equal to zero? + * ``lessThan($amount, $other) : bool`` Is one monetary amount less than the other? + * ``lessThanOrEqual($amount, $other) : bool`` Is one monetary amount less than or equal to the other? + +* allocation + + * ``allocate($amount, array $ratios) : string[]`` Allocates a monetary amount according to an array of ratios. + * ``allocateTo($amount, $n) : string[]`` Allocates a monetary amount among N targets. + +* aggregation + + * ``avg($amount, ...$amounts) : string`` Averages a series of monetary amounts. + * ``sum($amount, ...$amounts) : string`` Sums a series of monetary amounts. + * ``max($amount, ...$amounts) : string`` Finds the highest of a series of monetary amounts. + * ``min($amount, ...$amounts) : string`` Finds the lowest of a series of monetary amounts. + +* conversion + + * ``convertToMoney($amount) : Money`` Converts a monetary amount to a Money object. + * ``convertToMoneyArray(array $amounts) : Money`` Converts an array of monetary amounts to an array of Money objects. + * ``convertToString($amount) : string`` Converts a monetary amount to a string. + * ``convertToStringArray($amount) : string`` Converts an array of monetary amounts to an array of strings. + * ``zero() : string`` Returns a zero monetary amount (``'0.00'``). diff --git a/doc/index.rst b/doc/index.rst index b5af8c342..b1aa7ae6d 100644 --- a/doc/index.rst +++ b/doc/index.rst @@ -48,6 +48,7 @@ subtle intricacies of handling money. features/parsing features/formatting features/aggregation + features/teller .. toctree:: :hidden: diff --git a/src/Teller.php b/src/Teller.php new file mode 100644 index 000000000..d2a0eda80 --- /dev/null +++ b/src/Teller.php @@ -0,0 +1,521 @@ + + * $teller = Teller::USD(); + * + * + * @param string $method + * + * @param array $arguments + * + * @return Money + * + */ + public static function __callStatic($method, $arguments) + { + $class = get_called_class(); + $currency = new Currency($method); + $currencies = new ISOCurrencies(); + $parser = new DecimalMoneyParser($currencies); + $formatter = new DecimalMoneyFormatter($currencies); + $roundingMode = empty($arguments) + ? Money::ROUND_HALF_UP + : array_unshift($arguments); + + return new $class( + $currency, + $parser, + $formatter, + $roundingMode + ); + } + + /** @var ISOCurrencies */ + private $currencies; + + /** @var Currency */ + private $currency; + + /** @var MoneyFormatter */ + private $formatter; + + /** @var MoneyParser */ + private $parser; + + /** @var int Rounding mode for multiply/divide */ + private $roundingMode; + + /** + * Constructor. + * + * @param Currency $currency + * @param MoneyParser $parser + * @param MoneyFormatter $formatter + * @param int $roundingMode + */ + public function __construct( + Currency $currency, + MoneyParser $parser, + MoneyFormatter $formatter, + $roundingMode = Money::ROUND_HALF_UP + ) { + $this->currency = $currency; + $this->parser = $parser; + $this->formatter = $formatter; + $this->roundingMode = $roundingMode; + } + + /** + * Are two monetary amounts equal to each other? + * + * @param mixed $amount A monetary amount. + * @param mixed $other Another monetary amount. + * + * @return bool + */ + public function equals($amount, $other) + { + return $this->convertToMoney($amount)->equals( + $this->convertToMoney($other) + ); + } + + /** + * Returns an integer less than, equal to, or greater than zero if a + * monetary amount is respectively less than, equal to, or greater than + * another. + * + * @param mixed $amount A monetary amount. + * @param mixed $other Another monetary amount. + * + * @return int + */ + public function compare($amount, $other) + { + return $this->convertToMoney($amount)->compare( + $this->convertToMoney($other) + ); + } + + /** + * Is one monetary amount greater than another? + * + * @param mixed $amount A monetary amount. + * @param mixed $other Another monetary amount. + * + * @return bool + */ + public function greaterThan($amount, $other) + { + return $this->convertToMoney($amount)->greaterThan( + $this->convertToMoney($other) + ); + } + + /** + * Is one monetary amount greater than or equal to another? + * + * @param mixed $amount A monetary amount. + * @param mixed $other Another monetary amount. + * + * @return bool + */ + public function greaterThanOrEqual($amount, $other) + { + return $this->convertToMoney($amount)->greaterThanOrEqual( + $this->convertToMoney($other) + ); + } + + /** + * Is one monetary amount less than another? + * + * @param mixed $amount A monetary amount. + * @param mixed $other Another monetary amount. + * + * @return bool + */ + public function lessThan($amount, $other) + { + return $this->convertToMoney($amount)->lessThan( + $this->convertToMoney($other) + ); + } + + /** + * Is one monetary amount less than or equal to another? + * + * @param mixed $amount A monetary amount. + * @param mixed $other Another monetary amount. + * + * @return bool + */ + public function lessThanOrEqual($amount, $other) + { + return $this->convertToMoney($amount)->lessThanOrEqual( + $this->convertToMoney($other) + ); + } + + /** + * Adds a series of monetary amounts to each other in sequence. + * + * @param mixed $amount A monetary amount. + * @param mixed $other Another monetary amount. + * @param mixed[] $others Subsequent other monetary amounts. + * + * @return string The calculated monetary amount. + */ + public function add($amount, $other, ...$others) + { + return $this->convertToString( + $this->convertToMoney($amount)->add( + $this->convertToMoney($other), + ...$this->convertToMoneyArray($others) + ) + ); + } + + /** + * Subtracts a series of monetary amounts from each other in sequence. + * + * @param mixed $amount A monetary amount. + * @param mixed $other Another monetary amount. + * @param mixed[] $others Subsequent monetary amounts. + * + * @return string The calculated monetary amount. + */ + public function subtract($amount, $other, ...$others) + { + return $this->convertToString( + $this->convertToMoney($amount)->subtract( + $this->convertToMoney($other), + ...$this->convertToMoneyArray($others) + ) + ); + } + + /** + * Multiplies a monetary amount by a factor. + * + * @param mixed $amount A monetary amount. + * @param int|float|string $multiplier The multiplier. + * + * @return string The calculated monetary amount. + */ + public function multiply($amount, $multiplier) + { + return $this->convertToString( + $this->convertToMoney($amount)->multiply( + $multiplier, $this->roundingMode + ) + ); + } + + /** + * Divides a monetary amount by a divisor. + * + * @param mixed $amount A monetary amount. + * @param int|float|string $divisor The divisor. + * + * @return string The calculated monetary amount. + */ + public function divide($amount, $divisor) + { + return $this->convertToString( + $this->convertToMoney($amount)->divide( + $divisor, $this->roundingMode + ) + ); + } + + /** + * Mods a monetary amount by a divisor. + * + * @param mixed $amount A monetary amount. + * @param int|float|string $divisor The divisor. + * + * @return string The calculated monetary amount. + */ + public function mod($amount, $divisor) + { + return $this->convertToString( + $this->convertToMoney($amount)->mod( + $this->convertToMoney($divisor) + ) + ); + } + + /** + * Allocates a monetary amount according to an array of ratios. + * + * @param mixed $amount A monetary amount. + * @param array $ratios An array of ratios. + * + * @return string[] The calculated monetary amounts. + */ + public function allocate($amount, array $ratios) + { + return $this->convertToStringArray( + $this->convertToMoney($amount)->allocate($ratios) + ); + } + + /** + * Allocates a monetary amount among N targets. + * + * @param mixed $amount A monetary amount. + * @param int $n The number of targets. + * + * @return string[] The calculated monetary amounts. + */ + public function allocateTo($amount, $n) + { + return $this->convertToStringArray( + $this->convertToMoney($amount)->allocateTo($n) + ); + } + + /** + * Determines the ratio of one monetary amount to another. + * + * @param mixed $amount A monetary amount. + * @param array $other Another monetary amount. + * + * @return string The calculated monetary amount. + */ + public function ratioOf($amount, $other) + { + return $this->convertToString( + $this->convertToMoney($amount)->ratioOf( + $this->convertToMoney($other) + ) + ); + } + + /** + * Returns an absolute monetary amount. + * + * @param mixed $amount A monetary amount. + * + * @return string The absolute monetary amount. + */ + public function absolute($amount) + { + return $this->convertToString( + $this->convertToMoney($amount)->absolute() + ); + } + + /** + * Returns the negative of an amount; note that this will convert negative + * amounts to positive ones. + * + * @param mixed $amount A monetary amount. + * + * @return string The negative monetary amount. + */ + public function negative($amount) + { + return $this->convertToString( + $this->convertToMoney($amount)->negative() + ); + } + + /** + * Is the monetary amount equal to zero? + * + * @param mixed $amount The monetary amount. + * + * @return bool + */ + public function isZero($amount) + { + return $this->convertToMoney($amount)->isZero(); + } + + /** + * Is the monetary amount greater than zero? + * + * @param mixed $amount The monetary amount. + * + * @return bool + */ + public function isPositive($amount) + { + return $this->convertToMoney($amount)->isPositive(); + } + + /** + * Is the monetary amount less than zero? + * + * @param mixed $amount The monetary amount. + * + * @return bool + */ + public function isNegative($amount) + { + return $this->convertToMoney($amount)->isNegative(); + } + + /** + * Returns the lowest of a series of monetary values. + * + * @param mixed $amount A monetary amount. + * @param mixed ...$amounts Additional monetary amounts. + * + * @return string + */ + public function min($amount, ...$amounts) + { + return $this->convertToString( + Money::min( + $this->convertToMoney($amount), + ...$this->convertToMoneyArray($amounts) + ) + ); + } + + /** + * Returns the highest of a series of monetary values. + * + * @param mixed $amount A monetary amount. + * @param mixed ...$amounts Additional monetary amounts. + * + * @return string + */ + public function max($amount, ...$amounts) + { + return $this->convertToString( + Money::max( + $this->convertToMoney($amount), + ...$this->convertToMoneyArray($amounts) + ) + ); + } + + /** + * Returns the sum of a series of monetary values. + * + * @param mixed $amount A monetary amount. + * @param mixed ...$amounts Additional monetary amounts. + * + * @return string + */ + public function sum($amount, ...$amounts) + { + return $this->convertToString( + Money::sum( + $this->convertToMoney($amount), + ...$this->convertToMoneyArray($amounts) + ) + ); + } + + /** + * Returns the average of a series of monetary values. + * + * @param mixed $amount A monetary amount. + * @param mixed ...$amounts Additional monetary amounts. + * + * @return string + */ + public function avg($amount, ...$amounts) + { + return $this->convertToString( + Money::avg( + $this->convertToMoney($amount), + ...$this->convertToMoneyArray($amounts) + ) + ); + } + + /** + * Converts a monetary amount to a Money object. + * + * @param mixed $amount A monetary amount. + * + * @return Money + */ + public function convertToMoney($amount) + { + return $this->parser->parse((string) $amount, $this->currency); + } + + /** + * Converts an array of monetary amounts to an array of Money objects. + * + * @param array $amounts An array of monetary amounts. + * + * @return Money[] + */ + public function convertToMoneyArray(array $amounts) + { + foreach ($amounts as $key => $amount) { + $amounts[$key] = $this->convertToMoney($amount); + } + + return $amounts; + } + + /** + * Converts a monetary amount into a Money object, then into a string. + * + * @param mixed $amount Typically a Money object, int, float, or string + * representing a monetary amount. + * + * @return string + */ + public function convertToString($amount) + { + if (! $amount instanceof Money) { + $amount = $this->convertToMoney($amount); + } + + return $this->formatter->format($amount); + } + + /** + * Converts an array of monetary amounts into Money objects, then into + * strings. + * + * @param mixed $amount Typically a Money object, int, float, or string + * representing a monetary amount. + * + * @return array + */ + public function convertToStringArray(array $amounts) + { + foreach ($amounts as $key => $amount) { + $amounts[$key] = $this->convertToString($amount); + } + + return $amounts; + } + + /** + * Returns a "zero" monetary amount. + * + * @return string + */ + public function zero() + { + return '0.00'; + } +} diff --git a/tests/TellerTest.php b/tests/TellerTest.php new file mode 100644 index 000000000..5ca2ac498 --- /dev/null +++ b/tests/TellerTest.php @@ -0,0 +1,417 @@ +teller = Teller::USD(); + } + + public function it_demonstrates_the_pennies_problem() + { + $amount1 = 1.23; + $amount2 = 4.56; + + // this illustrates the problem with doing float + // math on monetary values; among other things, + // we end up with tenths of pennies. + $actual = $amount1 * $amount2; + $expect = 5.6088; + $this->assertSame($expect, $actual); + + // instead, use the Teller to do monetary math. + $actual = $this->teller->multiply($amount1, $amount2); + $expect = '5.61'; + $this->assertSame($expect, $actual); + } + + /** + * @test + */ + public function it_compares_equal_amounts() + { + $this->assertTrue($this->teller->equals('7.00', 7.00)); + $this->assertTrue($this->teller->equals('7', 7.00)); + $this->assertTrue($this->teller->equals(7, 7.00)); + } + + /** + * @test + */ + public function it_compares_two_amounts() + { + $amount = 1.23; + $other = 4.56; + + $this->assertSame(-1, $this->teller->compare($amount, $other)); + $this->assertSame(0, $this->teller->compare($amount, $amount)); + $this->assertSame(+1, $this->teller->compare($other, $amount)); + } + + /** + * @test + */ + public function it_compares_greater_than_amounts() + { + $this->assertTrue($this->teller->greaterThan('45.67', '9.01')); + } + + /** + * @test + */ + public function it_compares_greater_than_or_equal_amounts() + { + $this->assertTrue($this->teller->greaterThanOrEqual('45.67', '9.01')); + $this->assertTrue($this->teller->greaterThanOrEqual('7.00', 7.00)); + $this->assertTrue($this->teller->greaterThanOrEqual('7', 7.00)); + $this->assertTrue($this->teller->greaterThanOrEqual(7, 7.00)); + $this->assertFalse($this->teller->greaterThanOrEqual(7, 7.01)); + } + + /** + * @test + */ + public function it_compares_less_than_amounts() + { + $this->assertTrue($this->teller->lessThan('9.01', '45.67')); + } + + /** + * @test + */ + public function it_compares_less_than_or_equal_amounts() + { + $this->assertTrue($this->teller->lessThanOrEqual('9.01', '45.67')); + $this->assertTrue($this->teller->lessThanOrEqual('7.00', 7.00)); + $this->assertTrue($this->teller->lessThanOrEqual('7', 7.00)); + $this->assertTrue($this->teller->lessThanOrEqual(7, 7.00)); + $this->assertFalse($this->teller->lessThanOrEqual(7, 6.99)); + } + + /** + * @test + */ + public function it_adds_amounts() + { + $actual = $this->teller->add(1.1, '2.2', 3, 4.44, '5.55'); + $expect = '16.29'; + $this->assertSame($expect, $actual); + } + + /** + * @test + */ + public function it_subtracts_amounts() + { + $actual = $this->teller->subtract(1.1, '2.2', 3, 4.44, '5.55'); + $expect = '-14.09'; + $this->assertSame($expect, $actual); + } + + /** + * @test + */ + public function it_multiplies_amounts() + { + $amount = 1.23; + $multiplier = 4.56; + + $actual = $this->teller->multiply($amount, $multiplier); + $expect = '5.61'; + $this->assertSame($expect, $actual); + } + + /** + * @test + */ + public function it_multiplies_negative_amounts() + { + $amount = '-0.09'; + $multiplier = '0.01'; + $actual = $this->teller->multiply($amount, $multiplier); + $expect = '-0.00'; + $this->assertSame($expect, $actual); + + $amount = '-100.00'; + $multiplier = '0.01'; + $actual = $this->teller->multiply($amount, $multiplier); + $expect = '-1.00'; + $this->assertSame($expect, $actual); + + $amount = '100.00'; + $multiplier = '-0.01'; + $actual = $this->teller->multiply($amount, $multiplier); + $expect = '-1.00'; + $this->assertSame($expect, $actual); + + $amount = '141950.00'; + $multiplier = '-0.01'; + $actual = $this->teller->multiply($amount, $multiplier); + $expect = '-1419.50'; + $this->assertSame($expect, $actual); + + $amount = '141950.00'; + $multiplier = '-0.01056710109193'; + $actual = $this->teller->multiply($amount, $multiplier); + $expect = '-1500.00'; + $this->assertSame($expect, $actual); + + $amount = '141950.00'; + $multiplier = '-0.0001056710109193'; + $actual = $this->teller->multiply($amount, $multiplier); + $expect = '-15.00'; + $this->assertSame($expect, $actual); + } + + /** + * @test + */ + public function it_divides_amounts() + { + $amount = 1.23; + $divisor = 4.56; + + $actual = $this->teller->divide($amount, $divisor); + $expect = '0.27'; + $this->assertSame($expect, $actual); + } + + /** + * @test + */ + public function it_divides_negative_amounts() + { + $amount = '-0.09'; + $divisor = '100'; + $actual = $this->teller->divide($amount, $divisor); + $expect = '-0.00'; + $this->assertSame($expect, $actual); + + $amount = '-100.00'; + $divisor = '0.01'; + $actual = $this->teller->divide($amount, $divisor); + $expect = '-10000.00'; + $this->assertSame($expect, $actual); + + $amount = '100.00'; + $divisor = '-0.01'; + $actual = $this->teller->divide($amount, $divisor); + $expect = '-10000.00'; + $this->assertSame($expect, $actual); + + $amount = '141950.00'; + $divisor = '-0.01056710109193'; + $actual = $this->teller->divide($amount, $divisor); + $expect = '-13433201.67'; + $this->assertSame($expect, $actual); + + $amount = '141950.00'; + $divisor = '-0.0001056710109193'; + $actual = $this->teller->divide($amount, $divisor); + $expect = '-1343320166.67'; + $this->assertSame($expect, $actual); + } + + /** + * @test + */ + public function it_mods_amounts() + { + $amount = '10'; + $divisor = '3'; + $actual = $this->teller->mod($amount, $divisor); + $expect = '1.00'; + $this->assertSame($expect, $actual); + } + + /** + * @test + */ + public function it_allocates_amounts_across_ratios() + { + $amount = '100.00'; + $ratios = [1/2, 1/3, 1/6]; + $actual = $this->teller->allocate($amount, $ratios); + $expect = [ + '50.00', + '33.33', + '16.67', + ]; + $this->assertSame($expect, $actual); + } + + /** + * @test + */ + public function it_allocates_amounts_among_targets() + { + $amount = '100.00'; + $n = 3; + $actual = $this->teller->allocateTo($amount, $n); + $expect = [ + '33.34', + '33.33', + '33.33', + ]; + $this->assertSame($expect, $actual); + } + + /** + * @test + */ + public function it_calculates_ratios_of_amounts() + { + $amount = '100.00'; + $other = '30'; + $actual = $this->teller->ratioOf($amount, $other); + $expect = '3.33'; + $this->assertSame($expect, $actual); + } + + /** + * @test + */ + public function it_calculates_absolute_amount() + { + $this->assertSame('7.00', $this->teller->absolute(-7)); + $this->assertSame('7.00', $this->teller->absolute(7.0)); + } + + /** + * @test + */ + public function it_calculates_negative_amount() + { + $this->assertSame('-7.00', $this->teller->negative(7)); + $this->assertSame('7.00', $this->teller->negative(-7)); + } + + /** + * @test + */ + public function it_compares_an_amount_to_zero() + { + $this->assertTrue($this->teller->isZero(0.00)); + $this->assertFalse($this->teller->isZero(0.01)); + } + + /** + * @test + */ + public function it_tells_if_an_amount_is_positive() + { + $this->assertTrue($this->teller->isPositive(1)); + $this->assertFalse($this->teller->isPositive(0)); + $this->assertFalse($this->teller->isPositive(-1)); + } + + /** + * @test + */ + public function it_tells_if_an_amount_is_negative() + { + $this->assertFalse($this->teller->isNegative(1)); + $this->assertFalse($this->teller->isNegative(0)); + $this->assertTrue($this->teller->isNegative(-1)); + } + + /** + * @test + */ + public function it_finds_the_minimum_amount() + { + $amounts = [ + '1.23', + '4.56', + '7.89', + '0.12', + ]; + + $actual = $this->teller->min(...$amounts); + $expect = '0.12'; + $this->assertSame($expect, $actual); + } + + /** + * @test + */ + public function it_finds_the_maximum_amount() + { + $amounts = [ + '1.23', + '4.56', + '7.89', + '0.12', + ]; + + $actual = $this->teller->max(...$amounts); + $expect = '7.89'; + $this->assertSame($expect, $actual); + } + + /** + * @test + */ + public function it_sums_amounts() + { + $amounts = [ + '1.23', + '4.56', + '7.89', + '0.12', + ]; + + $actual = $this->teller->sum(...$amounts); + $expect = '13.80'; + $this->assertSame($expect, $actual); + } + + /** + * @test + */ + public function it_averages_amounts() + { + $amounts = [ + '1.23', + '4.56', + '7.89', + '0.12', + ]; + + $actual = $this->teller->avg(...$amounts); + $expect = '3.45'; + $this->assertSame($expect, $actual); + } + + /** + * @test + */ + public function it_returns_a_zero_string() + { + $this->assertSame('0.00', $this->teller->zero()); + } + + /** + * @test + */ + public function it_converts_monetary_amounts() + { + $money = $this->teller->convertToMoney('1.23'); + $this->assertInstanceOf(Money::CLASS, $money); + $this->assertSame('123', $money->getAmount()); + $this->assertSame('USD', $money->getCurrency()->getCode()); + + $value = $this->teller->convertToString($money); + $this->assertSame('1.23', $value); + } +} From 0abe8e33d5feb44330a460064980627c46b99f7c Mon Sep 17 00:00:00 2001 From: "Paul M. Jones" Date: Tue, 16 Mar 2021 12:20:15 -0500 Subject: [PATCH 02/17] fix doc typo --- doc/features/teller.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/doc/features/teller.rst b/doc/features/teller.rst index 267504539..b94335c87 100644 --- a/doc/features/teller.rst +++ b/doc/features/teller.rst @@ -16,7 +16,7 @@ To help ease the transition from float math to Money objects, use a Teller insta // after $teller = \Money\Teller::USD(); - $discountAmount = $teller->multiply($amount, $discount); // '11.73' + $discountAmount = $teller->multiply($price, $discount); // '11.73' The main drawback is that you cannot use two different currencies with the Teller; you can use only one. From 15ec88a7dffbbd41540d8e2e74a5e61ca7d96a72 Mon Sep 17 00:00:00 2001 From: "Paul M. Jones" Date: Tue, 16 Mar 2021 12:22:00 -0500 Subject: [PATCH 03/17] bugfix --- src/Teller.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Teller.php b/src/Teller.php index d2a0eda80..9f5799dd2 100644 --- a/src/Teller.php +++ b/src/Teller.php @@ -36,7 +36,7 @@ public static function __callStatic($method, $arguments) $formatter = new DecimalMoneyFormatter($currencies); $roundingMode = empty($arguments) ? Money::ROUND_HALF_UP - : array_unshift($arguments); + : array_shift($arguments); return new $class( $currency, From b33b583341cf5a674a1abab0e43c8bcf3a6b3986 Mon Sep 17 00:00:00 2001 From: "Paul M. Jones" Date: Tue, 16 Mar 2021 12:23:28 -0500 Subject: [PATCH 04/17] fix docblock --- src/Teller.php | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/Teller.php b/src/Teller.php index 9f5799dd2..7183a6a57 100644 --- a/src/Teller.php +++ b/src/Teller.php @@ -495,8 +495,7 @@ public function convertToString($amount) * Converts an array of monetary amounts into Money objects, then into * strings. * - * @param mixed $amount Typically a Money object, int, float, or string - * representing a monetary amount. + * @param array $amounts An array of monetary amounts. * * @return array */ From 452ce4f54f76206dc34a798f61cf447dccc3564a Mon Sep 17 00:00:00 2001 From: "Paul M. Jones" Date: Tue, 16 Mar 2021 12:24:51 -0500 Subject: [PATCH 05/17] fix docblock --- src/Teller.php | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/src/Teller.php b/src/Teller.php index 7183a6a57..18813cfe9 100644 --- a/src/Teller.php +++ b/src/Teller.php @@ -21,11 +21,9 @@ class Teller * * * @param string $method - * * @param array $arguments * - * @return Money - * + * @return Teller */ public static function __callStatic($method, $arguments) { From 2abccce7e31d8aec54578a849796b6ce9263faf8 Mon Sep 17 00:00:00 2001 From: "Paul M. Jones" Date: Tue, 16 Mar 2021 12:33:37 -0500 Subject: [PATCH 06/17] soothe php-cs-fixer --- src/Teller.php | 112 +++++++++++++++++++++---------------------- tests/TellerTest.php | 8 ++-- 2 files changed, 60 insertions(+), 60 deletions(-) diff --git a/src/Teller.php b/src/Teller.php index 18813cfe9..cffcbb414 100644 --- a/src/Teller.php +++ b/src/Teller.php @@ -82,8 +82,8 @@ public function __construct( /** * Are two monetary amounts equal to each other? * - * @param mixed $amount A monetary amount. - * @param mixed $other Another monetary amount. + * @param mixed $amount a monetary amount + * @param mixed $other another monetary amount * * @return bool */ @@ -99,8 +99,8 @@ public function equals($amount, $other) * monetary amount is respectively less than, equal to, or greater than * another. * - * @param mixed $amount A monetary amount. - * @param mixed $other Another monetary amount. + * @param mixed $amount a monetary amount + * @param mixed $other another monetary amount * * @return int */ @@ -114,8 +114,8 @@ public function compare($amount, $other) /** * Is one monetary amount greater than another? * - * @param mixed $amount A monetary amount. - * @param mixed $other Another monetary amount. + * @param mixed $amount a monetary amount + * @param mixed $other another monetary amount * * @return bool */ @@ -129,8 +129,8 @@ public function greaterThan($amount, $other) /** * Is one monetary amount greater than or equal to another? * - * @param mixed $amount A monetary amount. - * @param mixed $other Another monetary amount. + * @param mixed $amount a monetary amount + * @param mixed $other another monetary amount * * @return bool */ @@ -144,8 +144,8 @@ public function greaterThanOrEqual($amount, $other) /** * Is one monetary amount less than another? * - * @param mixed $amount A monetary amount. - * @param mixed $other Another monetary amount. + * @param mixed $amount a monetary amount + * @param mixed $other another monetary amount * * @return bool */ @@ -159,8 +159,8 @@ public function lessThan($amount, $other) /** * Is one monetary amount less than or equal to another? * - * @param mixed $amount A monetary amount. - * @param mixed $other Another monetary amount. + * @param mixed $amount a monetary amount + * @param mixed $other another monetary amount * * @return bool */ @@ -174,9 +174,9 @@ public function lessThanOrEqual($amount, $other) /** * Adds a series of monetary amounts to each other in sequence. * - * @param mixed $amount A monetary amount. - * @param mixed $other Another monetary amount. - * @param mixed[] $others Subsequent other monetary amounts. + * @param mixed $amount a monetary amount + * @param mixed $other another monetary amount + * @param mixed[] $others subsequent other monetary amounts * * @return string The calculated monetary amount. */ @@ -193,9 +193,9 @@ public function add($amount, $other, ...$others) /** * Subtracts a series of monetary amounts from each other in sequence. * - * @param mixed $amount A monetary amount. - * @param mixed $other Another monetary amount. - * @param mixed[] $others Subsequent monetary amounts. + * @param mixed $amount a monetary amount + * @param mixed $other another monetary amount + * @param mixed[] $others subsequent monetary amounts * * @return string The calculated monetary amount. */ @@ -212,8 +212,8 @@ public function subtract($amount, $other, ...$others) /** * Multiplies a monetary amount by a factor. * - * @param mixed $amount A monetary amount. - * @param int|float|string $multiplier The multiplier. + * @param mixed $amount a monetary amount + * @param int|float|string $multiplier the multiplier * * @return string The calculated monetary amount. */ @@ -229,8 +229,8 @@ public function multiply($amount, $multiplier) /** * Divides a monetary amount by a divisor. * - * @param mixed $amount A monetary amount. - * @param int|float|string $divisor The divisor. + * @param mixed $amount a monetary amount + * @param int|float|string $divisor the divisor * * @return string The calculated monetary amount. */ @@ -246,8 +246,8 @@ public function divide($amount, $divisor) /** * Mods a monetary amount by a divisor. * - * @param mixed $amount A monetary amount. - * @param int|float|string $divisor The divisor. + * @param mixed $amount a monetary amount + * @param int|float|string $divisor the divisor * * @return string The calculated monetary amount. */ @@ -263,8 +263,8 @@ public function mod($amount, $divisor) /** * Allocates a monetary amount according to an array of ratios. * - * @param mixed $amount A monetary amount. - * @param array $ratios An array of ratios. + * @param mixed $amount a monetary amount + * @param array $ratios an array of ratios * * @return string[] The calculated monetary amounts. */ @@ -278,8 +278,8 @@ public function allocate($amount, array $ratios) /** * Allocates a monetary amount among N targets. * - * @param mixed $amount A monetary amount. - * @param int $n The number of targets. + * @param mixed $amount a monetary amount + * @param int $n the number of targets * * @return string[] The calculated monetary amounts. */ @@ -293,8 +293,8 @@ public function allocateTo($amount, $n) /** * Determines the ratio of one monetary amount to another. * - * @param mixed $amount A monetary amount. - * @param array $other Another monetary amount. + * @param mixed $amount a monetary amount + * @param array $other another monetary amount * * @return string The calculated monetary amount. */ @@ -310,7 +310,7 @@ public function ratioOf($amount, $other) /** * Returns an absolute monetary amount. * - * @param mixed $amount A monetary amount. + * @param mixed $amount a monetary amount * * @return string The absolute monetary amount. */ @@ -325,7 +325,7 @@ public function absolute($amount) * Returns the negative of an amount; note that this will convert negative * amounts to positive ones. * - * @param mixed $amount A monetary amount. + * @param mixed $amount a monetary amount * * @return string The negative monetary amount. */ @@ -337,9 +337,9 @@ public function negative($amount) } /** - * Is the monetary amount equal to zero? + * Is a monetary amount equal to zero? * - * @param mixed $amount The monetary amount. + * @param mixed $amount a monetary amount * * @return bool */ @@ -349,9 +349,9 @@ public function isZero($amount) } /** - * Is the monetary amount greater than zero? + * Is a monetary amount greater than zero? * - * @param mixed $amount The monetary amount. + * @param mixed $amount a monetary amount * * @return bool */ @@ -361,9 +361,9 @@ public function isPositive($amount) } /** - * Is the monetary amount less than zero? + * Is a monetary amount less than zero? * - * @param mixed $amount The monetary amount. + * @param mixed $amount a monetary amount * * @return bool */ @@ -373,10 +373,10 @@ public function isNegative($amount) } /** - * Returns the lowest of a series of monetary values. + * Returns the lowest of a series of monetary amounts. * - * @param mixed $amount A monetary amount. - * @param mixed ...$amounts Additional monetary amounts. + * @param mixed $amount a monetary amount + * @param mixed ...$amounts additional monetary amounts * * @return string */ @@ -391,10 +391,10 @@ public function min($amount, ...$amounts) } /** - * Returns the highest of a series of monetary values. + * Returns the highest of a series of monetary amounts. * - * @param mixed $amount A monetary amount. - * @param mixed ...$amounts Additional monetary amounts. + * @param mixed $amount a monetary amount + * @param mixed ...$amounts additional monetary amounts * * @return string */ @@ -409,10 +409,10 @@ public function max($amount, ...$amounts) } /** - * Returns the sum of a series of monetary values. + * Returns the sum of a series of monetary amounts. * - * @param mixed $amount A monetary amount. - * @param mixed ...$amounts Additional monetary amounts. + * @param mixed $amount a monetary amount + * @param mixed ...$amounts additional monetary amounts * * @return string */ @@ -427,10 +427,10 @@ public function sum($amount, ...$amounts) } /** - * Returns the average of a series of monetary values. + * Returns the average of a series of monetary amounts. * - * @param mixed $amount A monetary amount. - * @param mixed ...$amounts Additional monetary amounts. + * @param mixed $amount a monetary amount + * @param mixed ...$amounts additional monetary amounts * * @return string */ @@ -447,7 +447,7 @@ public function avg($amount, ...$amounts) /** * Converts a monetary amount to a Money object. * - * @param mixed $amount A monetary amount. + * @param mixed $amount a monetary amount * * @return Money */ @@ -459,7 +459,7 @@ public function convertToMoney($amount) /** * Converts an array of monetary amounts to an array of Money objects. * - * @param array $amounts An array of monetary amounts. + * @param array $amounts an array of monetary amounts * * @return Money[] */ @@ -475,14 +475,14 @@ public function convertToMoneyArray(array $amounts) /** * Converts a monetary amount into a Money object, then into a string. * - * @param mixed $amount Typically a Money object, int, float, or string - * representing a monetary amount. + * @param mixed $amount typically a Money object, int, float, or string + * representing a monetary amount * * @return string */ public function convertToString($amount) { - if (! $amount instanceof Money) { + if (!$amount instanceof Money) { $amount = $this->convertToMoney($amount); } @@ -493,7 +493,7 @@ public function convertToString($amount) * Converts an array of monetary amounts into Money objects, then into * strings. * - * @param array $amounts An array of monetary amounts. + * @param array $amounts an array of monetary amounts * * @return array */ diff --git a/tests/TellerTest.php b/tests/TellerTest.php index 5ca2ac498..303c19ce4 100644 --- a/tests/TellerTest.php +++ b/tests/TellerTest.php @@ -2,13 +2,13 @@ namespace Tests\Money; -use Money\Money; use Money\Calculator\PhpCalculator; +use Money\Money; use Money\Teller; class TellerTest extends \PHPUnit\Framework\TestCase { - protected function setUp() : void + protected function setUp() { // this overrides the GmpCalculator, which has multiply/divide problems // with negative values @@ -240,7 +240,7 @@ public function it_mods_amounts() public function it_allocates_amounts_across_ratios() { $amount = '100.00'; - $ratios = [1/2, 1/3, 1/6]; + $ratios = [1 / 2, 1 / 3, 1 / 6]; $actual = $this->teller->allocate($amount, $ratios); $expect = [ '50.00', @@ -407,7 +407,7 @@ public function it_returns_a_zero_string() public function it_converts_monetary_amounts() { $money = $this->teller->convertToMoney('1.23'); - $this->assertInstanceOf(Money::CLASS, $money); + $this->assertInstanceOf(Money::class, $money); $this->assertSame('123', $money->getAmount()); $this->assertSame('USD', $money->getCurrency()->getCode()); From b550dc96577893f26b0eac2de957f2a6dbecc779 Mon Sep 17 00:00:00 2001 From: "Paul M. Jones" Date: Tue, 16 Mar 2021 12:38:25 -0500 Subject: [PATCH 07/17] soothe PrettyCI --- src/Teller.php | 51 +++++++++++++++++++++++--------------------------- 1 file changed, 23 insertions(+), 28 deletions(-) diff --git a/src/Teller.php b/src/Teller.php index cffcbb414..2b99d92e1 100644 --- a/src/Teller.php +++ b/src/Teller.php @@ -2,13 +2,8 @@ namespace Money; -use InvalidArgumentException; use Money\Currencies\ISOCurrencies; -use Money\Currency; use Money\Formatter\DecimalMoneyFormatter; -use Money\Money; -use Money\MoneyFormatter; -use Money\MoneyParser; use Money\Parser\DecimalMoneyParser; class Teller @@ -21,7 +16,7 @@ class Teller * * * @param string $method - * @param array $arguments + * @param array $arguments * * @return Teller */ @@ -62,10 +57,10 @@ public static function __callStatic($method, $arguments) /** * Constructor. * - * @param Currency $currency - * @param MoneyParser $parser + * @param Currency $currency + * @param MoneyParser $parser * @param MoneyFormatter $formatter - * @param int $roundingMode + * @param int $roundingMode */ public function __construct( Currency $currency, @@ -83,7 +78,7 @@ public function __construct( * Are two monetary amounts equal to each other? * * @param mixed $amount a monetary amount - * @param mixed $other another monetary amount + * @param mixed $other another monetary amount * * @return bool */ @@ -100,7 +95,7 @@ public function equals($amount, $other) * another. * * @param mixed $amount a monetary amount - * @param mixed $other another monetary amount + * @param mixed $other another monetary amount * * @return int */ @@ -115,7 +110,7 @@ public function compare($amount, $other) * Is one monetary amount greater than another? * * @param mixed $amount a monetary amount - * @param mixed $other another monetary amount + * @param mixed $other another monetary amount * * @return bool */ @@ -130,7 +125,7 @@ public function greaterThan($amount, $other) * Is one monetary amount greater than or equal to another? * * @param mixed $amount a monetary amount - * @param mixed $other another monetary amount + * @param mixed $other another monetary amount * * @return bool */ @@ -145,7 +140,7 @@ public function greaterThanOrEqual($amount, $other) * Is one monetary amount less than another? * * @param mixed $amount a monetary amount - * @param mixed $other another monetary amount + * @param mixed $other another monetary amount * * @return bool */ @@ -160,7 +155,7 @@ public function lessThan($amount, $other) * Is one monetary amount less than or equal to another? * * @param mixed $amount a monetary amount - * @param mixed $other another monetary amount + * @param mixed $other another monetary amount * * @return bool */ @@ -174,8 +169,8 @@ public function lessThanOrEqual($amount, $other) /** * Adds a series of monetary amounts to each other in sequence. * - * @param mixed $amount a monetary amount - * @param mixed $other another monetary amount + * @param mixed $amount a monetary amount + * @param mixed $other another monetary amount * @param mixed[] $others subsequent other monetary amounts * * @return string The calculated monetary amount. @@ -193,8 +188,8 @@ public function add($amount, $other, ...$others) /** * Subtracts a series of monetary amounts from each other in sequence. * - * @param mixed $amount a monetary amount - * @param mixed $other another monetary amount + * @param mixed $amount a monetary amount + * @param mixed $other another monetary amount * @param mixed[] $others subsequent monetary amounts * * @return string The calculated monetary amount. @@ -212,7 +207,7 @@ public function subtract($amount, $other, ...$others) /** * Multiplies a monetary amount by a factor. * - * @param mixed $amount a monetary amount + * @param mixed $amount a monetary amount * @param int|float|string $multiplier the multiplier * * @return string The calculated monetary amount. @@ -229,7 +224,7 @@ public function multiply($amount, $multiplier) /** * Divides a monetary amount by a divisor. * - * @param mixed $amount a monetary amount + * @param mixed $amount a monetary amount * @param int|float|string $divisor the divisor * * @return string The calculated monetary amount. @@ -246,7 +241,7 @@ public function divide($amount, $divisor) /** * Mods a monetary amount by a divisor. * - * @param mixed $amount a monetary amount + * @param mixed $amount a monetary amount * @param int|float|string $divisor the divisor * * @return string The calculated monetary amount. @@ -279,7 +274,7 @@ public function allocate($amount, array $ratios) * Allocates a monetary amount among N targets. * * @param mixed $amount a monetary amount - * @param int $n the number of targets + * @param int $n the number of targets * * @return string[] The calculated monetary amounts. */ @@ -294,7 +289,7 @@ public function allocateTo($amount, $n) * Determines the ratio of one monetary amount to another. * * @param mixed $amount a monetary amount - * @param array $other another monetary amount + * @param array $other another monetary amount * * @return string The calculated monetary amount. */ @@ -375,7 +370,7 @@ public function isNegative($amount) /** * Returns the lowest of a series of monetary amounts. * - * @param mixed $amount a monetary amount + * @param mixed $amount a monetary amount * @param mixed ...$amounts additional monetary amounts * * @return string @@ -393,7 +388,7 @@ public function min($amount, ...$amounts) /** * Returns the highest of a series of monetary amounts. * - * @param mixed $amount a monetary amount + * @param mixed $amount a monetary amount * @param mixed ...$amounts additional monetary amounts * * @return string @@ -411,7 +406,7 @@ public function max($amount, ...$amounts) /** * Returns the sum of a series of monetary amounts. * - * @param mixed $amount a monetary amount + * @param mixed $amount a monetary amount * @param mixed ...$amounts additional monetary amounts * * @return string @@ -429,7 +424,7 @@ public function sum($amount, ...$amounts) /** * Returns the average of a series of monetary amounts. * - * @param mixed $amount a monetary amount + * @param mixed $amount a monetary amount * @param mixed ...$amounts additional monetary amounts * * @return string From 15a63cfa197b64c2116c869760c506ea3734786a Mon Sep 17 00:00:00 2001 From: "Paul M. Jones" Date: Tue, 16 Mar 2021 12:47:06 -0500 Subject: [PATCH 08/17] soothe cs fixers --- src/Teller.php | 15 ++++++--------- 1 file changed, 6 insertions(+), 9 deletions(-) diff --git a/src/Teller.php b/src/Teller.php index 2b99d92e1..e85573e50 100644 --- a/src/Teller.php +++ b/src/Teller.php @@ -57,9 +57,6 @@ public static function __callStatic($method, $arguments) /** * Constructor. * - * @param Currency $currency - * @param MoneyParser $parser - * @param MoneyFormatter $formatter * @param int $roundingMode */ public function __construct( @@ -173,7 +170,7 @@ public function lessThanOrEqual($amount, $other) * @param mixed $other another monetary amount * @param mixed[] $others subsequent other monetary amounts * - * @return string The calculated monetary amount. + * @return string the calculated monetary amount */ public function add($amount, $other, ...$others) { @@ -192,7 +189,7 @@ public function add($amount, $other, ...$others) * @param mixed $other another monetary amount * @param mixed[] $others subsequent monetary amounts * - * @return string The calculated monetary amount. + * @return string the calculated monetary amount */ public function subtract($amount, $other, ...$others) { @@ -210,7 +207,7 @@ public function subtract($amount, $other, ...$others) * @param mixed $amount a monetary amount * @param int|float|string $multiplier the multiplier * - * @return string The calculated monetary amount. + * @return string the calculated monetary amount */ public function multiply($amount, $multiplier) { @@ -227,7 +224,7 @@ public function multiply($amount, $multiplier) * @param mixed $amount a monetary amount * @param int|float|string $divisor the divisor * - * @return string The calculated monetary amount. + * @return string the calculated monetary amount */ public function divide($amount, $divisor) { @@ -244,7 +241,7 @@ public function divide($amount, $divisor) * @param mixed $amount a monetary amount * @param int|float|string $divisor the divisor * - * @return string The calculated monetary amount. + * @return string the calculated monetary amount */ public function mod($amount, $divisor) { @@ -291,7 +288,7 @@ public function allocateTo($amount, $n) * @param mixed $amount a monetary amount * @param array $other another monetary amount * - * @return string The calculated monetary amount. + * @return string the calculated monetary amount */ public function ratioOf($amount, $other) { From 45d5f02001e698f9b1530e23eb050b94eeffa3e6 Mon Sep 17 00:00:00 2001 From: "Paul M. Jones" Date: Tue, 16 Mar 2021 12:51:11 -0500 Subject: [PATCH 09/17] soothe cs fixers --- src/Teller.php | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/Teller.php b/src/Teller.php index e85573e50..7a8ab0053 100644 --- a/src/Teller.php +++ b/src/Teller.php @@ -57,7 +57,7 @@ public static function __callStatic($method, $arguments) /** * Constructor. * - * @param int $roundingMode + * @param int $roundingMode */ public function __construct( Currency $currency, @@ -258,7 +258,7 @@ public function mod($amount, $divisor) * @param mixed $amount a monetary amount * @param array $ratios an array of ratios * - * @return string[] The calculated monetary amounts. + * @return string[] the calculated monetary amounts */ public function allocate($amount, array $ratios) { @@ -273,7 +273,7 @@ public function allocate($amount, array $ratios) * @param mixed $amount a monetary amount * @param int $n the number of targets * - * @return string[] The calculated monetary amounts. + * @return string[] the calculated monetary amounts */ public function allocateTo($amount, $n) { @@ -304,7 +304,7 @@ public function ratioOf($amount, $other) * * @param mixed $amount a monetary amount * - * @return string The absolute monetary amount. + * @return string the absolute monetary amount */ public function absolute($amount) { @@ -319,7 +319,7 @@ public function absolute($amount) * * @param mixed $amount a monetary amount * - * @return string The negative monetary amount. + * @return string the negative monetary amount */ public function negative($amount) { From 2e72f9c4a7ffdacaf96fb9c23e1ef7ea9cdb1da7 Mon Sep 17 00:00:00 2001 From: "Paul M. Jones" Date: Wed, 7 Jun 2023 14:43:55 -0500 Subject: [PATCH 10/17] use non-signed zero values also, PhpCalculator is gone, so use default calculator --- tests/TellerTest.php | 9 ++------- 1 file changed, 2 insertions(+), 7 deletions(-) diff --git a/tests/TellerTest.php b/tests/TellerTest.php index 303c19ce4..700ed67fb 100644 --- a/tests/TellerTest.php +++ b/tests/TellerTest.php @@ -2,7 +2,6 @@ namespace Tests\Money; -use Money\Calculator\PhpCalculator; use Money\Money; use Money\Teller; @@ -10,10 +9,6 @@ class TellerTest extends \PHPUnit\Framework\TestCase { protected function setUp() { - // this overrides the GmpCalculator, which has multiply/divide problems - // with negative values - Money::registerCalculator(PhpCalculator::class); - $this->teller = Teller::USD(); } @@ -139,7 +134,7 @@ public function it_multiplies_negative_amounts() $amount = '-0.09'; $multiplier = '0.01'; $actual = $this->teller->multiply($amount, $multiplier); - $expect = '-0.00'; + $expect = '0.00'; $this->assertSame($expect, $actual); $amount = '-100.00'; @@ -194,7 +189,7 @@ public function it_divides_negative_amounts() $amount = '-0.09'; $divisor = '100'; $actual = $this->teller->divide($amount, $divisor); - $expect = '-0.00'; + $expect = '0.00'; $this->assertSame($expect, $actual); $amount = '-100.00'; From 13232dcd6d7b3c41b5c7010f727c448543e7253b Mon Sep 17 00:00:00 2001 From: "Paul M. Jones" Date: Tue, 13 Jun 2023 11:30:14 -0500 Subject: [PATCH 11/17] respond to review, and soothe psalm --- src/Teller.php | 168 +++++++++++++++---------------------------- tests/TellerTest.php | 65 +++++++++-------- 2 files changed, 94 insertions(+), 139 deletions(-) diff --git a/src/Teller.php b/src/Teller.php index 7a8ab0053..d5e7c6bf2 100644 --- a/src/Teller.php +++ b/src/Teller.php @@ -15,12 +15,11 @@ class Teller * $teller = Teller::USD(); * * - * @param string $method - * @param array $arguments + * @param non-empty-string $method * * @return Teller */ - public static function __callStatic($method, $arguments) + public static function __callStatic(string $method, array $arguments) { $class = get_called_class(); $currency = new Currency($method); @@ -29,7 +28,7 @@ public static function __callStatic($method, $arguments) $formatter = new DecimalMoneyFormatter($currencies); $roundingMode = empty($arguments) ? Money::ROUND_HALF_UP - : array_shift($arguments); + : (int) array_shift($arguments); return new $class( $currency, @@ -39,20 +38,13 @@ public static function __callStatic($method, $arguments) ); } - /** @var ISOCurrencies */ - private $currencies; + private Currency $currency; - /** @var Currency */ - private $currency; + private MoneyFormatter $formatter; - /** @var MoneyFormatter */ - private $formatter; + private MoneyParser $parser; - /** @var MoneyParser */ - private $parser; - - /** @var int Rounding mode for multiply/divide */ - private $roundingMode; + private int $roundingMode = Money::ROUND_HALF_UP; /** * Constructor. @@ -63,7 +55,7 @@ public function __construct( Currency $currency, MoneyParser $parser, MoneyFormatter $formatter, - $roundingMode = Money::ROUND_HALF_UP + int $roundingMode = Money::ROUND_HALF_UP ) { $this->currency = $currency; $this->parser = $parser; @@ -76,10 +68,8 @@ public function __construct( * * @param mixed $amount a monetary amount * @param mixed $other another monetary amount - * - * @return bool */ - public function equals($amount, $other) + public function equals($amount, $other): bool { return $this->convertToMoney($amount)->equals( $this->convertToMoney($other) @@ -93,10 +83,8 @@ public function equals($amount, $other) * * @param mixed $amount a monetary amount * @param mixed $other another monetary amount - * - * @return int */ - public function compare($amount, $other) + public function compare($amount, $other): int { return $this->convertToMoney($amount)->compare( $this->convertToMoney($other) @@ -108,10 +96,8 @@ public function compare($amount, $other) * * @param mixed $amount a monetary amount * @param mixed $other another monetary amount - * - * @return bool */ - public function greaterThan($amount, $other) + public function greaterThan($amount, $other): bool { return $this->convertToMoney($amount)->greaterThan( $this->convertToMoney($other) @@ -123,10 +109,8 @@ public function greaterThan($amount, $other) * * @param mixed $amount a monetary amount * @param mixed $other another monetary amount - * - * @return bool */ - public function greaterThanOrEqual($amount, $other) + public function greaterThanOrEqual($amount, $other): bool { return $this->convertToMoney($amount)->greaterThanOrEqual( $this->convertToMoney($other) @@ -138,10 +122,8 @@ public function greaterThanOrEqual($amount, $other) * * @param mixed $amount a monetary amount * @param mixed $other another monetary amount - * - * @return bool */ - public function lessThan($amount, $other) + public function lessThan($amount, $other): bool { return $this->convertToMoney($amount)->lessThan( $this->convertToMoney($other) @@ -153,10 +135,8 @@ public function lessThan($amount, $other) * * @param mixed $amount a monetary amount * @param mixed $other another monetary amount - * - * @return bool */ - public function lessThanOrEqual($amount, $other) + public function lessThanOrEqual($amount, $other): bool { return $this->convertToMoney($amount)->lessThanOrEqual( $this->convertToMoney($other) @@ -172,7 +152,7 @@ public function lessThanOrEqual($amount, $other) * * @return string the calculated monetary amount */ - public function add($amount, $other, ...$others) + public function add($amount, $other, ...$others): string { return $this->convertToString( $this->convertToMoney($amount)->add( @@ -188,10 +168,8 @@ public function add($amount, $other, ...$others) * @param mixed $amount a monetary amount * @param mixed $other another monetary amount * @param mixed[] $others subsequent monetary amounts - * - * @return string the calculated monetary amount */ - public function subtract($amount, $other, ...$others) + public function subtract($amount, $other, ...$others): string { return $this->convertToString( $this->convertToMoney($amount)->subtract( @@ -204,16 +182,14 @@ public function subtract($amount, $other, ...$others) /** * Multiplies a monetary amount by a factor. * - * @param mixed $amount a monetary amount - * @param int|float|string $multiplier the multiplier - * - * @return string the calculated monetary amount + * @param mixed $amount a monetary amount + * @param int|float|numeric-string $multiplier the multiplier */ - public function multiply($amount, $multiplier) + public function multiply($amount, int|float|string $multiplier): string { return $this->convertToString( $this->convertToMoney($amount)->multiply( - $multiplier, $this->roundingMode + (string) $multiplier, $this->roundingMode ) ); } @@ -221,16 +197,14 @@ public function multiply($amount, $multiplier) /** * Divides a monetary amount by a divisor. * - * @param mixed $amount a monetary amount - * @param int|float|string $divisor the divisor - * - * @return string the calculated monetary amount + * @param mixed $amount a monetary amount + * @param int|float|numeric-string $divisor the divisor */ - public function divide($amount, $divisor) + public function divide($amount, int|float|string $divisor): string { return $this->convertToString( $this->convertToMoney($amount)->divide( - $divisor, $this->roundingMode + (string) $divisor, $this->roundingMode ) ); } @@ -238,16 +212,14 @@ public function divide($amount, $divisor) /** * Mods a monetary amount by a divisor. * - * @param mixed $amount a monetary amount - * @param int|float|string $divisor the divisor - * - * @return string the calculated monetary amount + * @param mixed $amount a monetary amount + * @param int|float|numeric-string $divisor the divisor */ - public function mod($amount, $divisor) + public function mod($amount, int|float|string $divisor): string { return $this->convertToString( $this->convertToMoney($amount)->mod( - $this->convertToMoney($divisor) + $this->convertToMoney((string) $divisor) ) ); } @@ -255,12 +227,12 @@ public function mod($amount, $divisor) /** * Allocates a monetary amount according to an array of ratios. * - * @param mixed $amount a monetary amount - * @param array $ratios an array of ratios + * @param mixed $amount a monetary amount + * @param non-empty-array $ratios an array of ratios * * @return string[] the calculated monetary amounts */ - public function allocate($amount, array $ratios) + public function allocate($amount, array $ratios): array { return $this->convertToStringArray( $this->convertToMoney($amount)->allocate($ratios) @@ -270,12 +242,12 @@ public function allocate($amount, array $ratios) /** * Allocates a monetary amount among N targets. * - * @param mixed $amount a monetary amount - * @param int $n the number of targets + * @param mixed $amount a monetary amount + * @param int<1, max> $n the number of targets * * @return string[] the calculated monetary amounts */ - public function allocateTo($amount, $n) + public function allocateTo($amount, int $n): array { return $this->convertToStringArray( $this->convertToMoney($amount)->allocateTo($n) @@ -286,11 +258,9 @@ public function allocateTo($amount, $n) * Determines the ratio of one monetary amount to another. * * @param mixed $amount a monetary amount - * @param array $other another monetary amount - * - * @return string the calculated monetary amount + * @param mixed $other another monetary amount */ - public function ratioOf($amount, $other) + public function ratioOf($amount, $other): string { return $this->convertToString( $this->convertToMoney($amount)->ratioOf( @@ -303,10 +273,8 @@ public function ratioOf($amount, $other) * Returns an absolute monetary amount. * * @param mixed $amount a monetary amount - * - * @return string the absolute monetary amount */ - public function absolute($amount) + public function absolute($amount): string { return $this->convertToString( $this->convertToMoney($amount)->absolute() @@ -318,10 +286,8 @@ public function absolute($amount) * amounts to positive ones. * * @param mixed $amount a monetary amount - * - * @return string the negative monetary amount */ - public function negative($amount) + public function negative($amount): string { return $this->convertToString( $this->convertToMoney($amount)->negative() @@ -332,10 +298,8 @@ public function negative($amount) * Is a monetary amount equal to zero? * * @param mixed $amount a monetary amount - * - * @return bool */ - public function isZero($amount) + public function isZero($amount): bool { return $this->convertToMoney($amount)->isZero(); } @@ -344,10 +308,8 @@ public function isZero($amount) * Is a monetary amount greater than zero? * * @param mixed $amount a monetary amount - * - * @return bool */ - public function isPositive($amount) + public function isPositive($amount): bool { return $this->convertToMoney($amount)->isPositive(); } @@ -356,10 +318,8 @@ public function isPositive($amount) * Is a monetary amount less than zero? * * @param mixed $amount a monetary amount - * - * @return bool */ - public function isNegative($amount) + public function isNegative($amount): bool { return $this->convertToMoney($amount)->isNegative(); } @@ -369,10 +329,8 @@ public function isNegative($amount) * * @param mixed $amount a monetary amount * @param mixed ...$amounts additional monetary amounts - * - * @return string */ - public function min($amount, ...$amounts) + public function min($amount, ...$amounts): string { return $this->convertToString( Money::min( @@ -387,10 +345,8 @@ public function min($amount, ...$amounts) * * @param mixed $amount a monetary amount * @param mixed ...$amounts additional monetary amounts - * - * @return string */ - public function max($amount, ...$amounts) + public function max($amount, ...$amounts): string { return $this->convertToString( Money::max( @@ -405,10 +361,8 @@ public function max($amount, ...$amounts) * * @param mixed $amount a monetary amount * @param mixed ...$amounts additional monetary amounts - * - * @return string */ - public function sum($amount, ...$amounts) + public function sum($amount, ...$amounts): string { return $this->convertToString( Money::sum( @@ -423,10 +377,8 @@ public function sum($amount, ...$amounts) * * @param mixed $amount a monetary amount * @param mixed ...$amounts additional monetary amounts - * - * @return string */ - public function avg($amount, ...$amounts) + public function avg($amount, ...$amounts): string { return $this->convertToString( Money::avg( @@ -440,10 +392,8 @@ public function avg($amount, ...$amounts) * Converts a monetary amount to a Money object. * * @param mixed $amount a monetary amount - * - * @return Money */ - public function convertToMoney($amount) + public function convertToMoney($amount): Money { return $this->parser->parse((string) $amount, $this->currency); } @@ -455,13 +405,15 @@ public function convertToMoney($amount) * * @return Money[] */ - public function convertToMoneyArray(array $amounts) + public function convertToMoneyArray(array $amounts): array { + $converted = []; + foreach ($amounts as $key => $amount) { - $amounts[$key] = $this->convertToMoney($amount); + $converted[$key] = $this->convertToMoney($amount); } - return $amounts; + return $converted; } /** @@ -469,10 +421,8 @@ public function convertToMoneyArray(array $amounts) * * @param mixed $amount typically a Money object, int, float, or string * representing a monetary amount - * - * @return string */ - public function convertToString($amount) + public function convertToString($amount): string { if (!$amount instanceof Money) { $amount = $this->convertToMoney($amount); @@ -487,23 +437,23 @@ public function convertToString($amount) * * @param array $amounts an array of monetary amounts * - * @return array + * @return string[] */ - public function convertToStringArray(array $amounts) + public function convertToStringArray(array $amounts): array { + $converted = []; + foreach ($amounts as $key => $amount) { - $amounts[$key] = $this->convertToString($amount); + $converted[$key] = $this->convertToString($amount); } - return $amounts; + return $converted; } /** * Returns a "zero" monetary amount. - * - * @return string */ - public function zero() + public function zero(): string { return '0.00'; } diff --git a/tests/TellerTest.php b/tests/TellerTest.php index 700ed67fb..4d3da6203 100644 --- a/tests/TellerTest.php +++ b/tests/TellerTest.php @@ -5,14 +5,19 @@ use Money\Money; use Money\Teller; -class TellerTest extends \PHPUnit\Framework\TestCase +final class TellerTest extends \PHPUnit\Framework\TestCase { - protected function setUp() + protected Teller $teller; + + protected function setUp(): void { $this->teller = Teller::USD(); } - public function it_demonstrates_the_pennies_problem() + /** + * @test + */ + public function it_demonstrates_the_pennies_problem(): void { $amount1 = 1.23; $amount2 = 4.56; @@ -33,7 +38,7 @@ public function it_demonstrates_the_pennies_problem() /** * @test */ - public function it_compares_equal_amounts() + public function it_compares_equal_amounts(): void { $this->assertTrue($this->teller->equals('7.00', 7.00)); $this->assertTrue($this->teller->equals('7', 7.00)); @@ -43,7 +48,7 @@ public function it_compares_equal_amounts() /** * @test */ - public function it_compares_two_amounts() + public function it_compares_two_amounts(): void { $amount = 1.23; $other = 4.56; @@ -56,7 +61,7 @@ public function it_compares_two_amounts() /** * @test */ - public function it_compares_greater_than_amounts() + public function it_compares_greater_than_amounts(): void { $this->assertTrue($this->teller->greaterThan('45.67', '9.01')); } @@ -64,7 +69,7 @@ public function it_compares_greater_than_amounts() /** * @test */ - public function it_compares_greater_than_or_equal_amounts() + public function it_compares_greater_than_or_equal_amounts(): void { $this->assertTrue($this->teller->greaterThanOrEqual('45.67', '9.01')); $this->assertTrue($this->teller->greaterThanOrEqual('7.00', 7.00)); @@ -76,7 +81,7 @@ public function it_compares_greater_than_or_equal_amounts() /** * @test */ - public function it_compares_less_than_amounts() + public function it_compares_less_than_amounts(): void { $this->assertTrue($this->teller->lessThan('9.01', '45.67')); } @@ -84,7 +89,7 @@ public function it_compares_less_than_amounts() /** * @test */ - public function it_compares_less_than_or_equal_amounts() + public function it_compares_less_than_or_equal_amounts(): void { $this->assertTrue($this->teller->lessThanOrEqual('9.01', '45.67')); $this->assertTrue($this->teller->lessThanOrEqual('7.00', 7.00)); @@ -96,7 +101,7 @@ public function it_compares_less_than_or_equal_amounts() /** * @test */ - public function it_adds_amounts() + public function it_adds_amounts(): void { $actual = $this->teller->add(1.1, '2.2', 3, 4.44, '5.55'); $expect = '16.29'; @@ -106,7 +111,7 @@ public function it_adds_amounts() /** * @test */ - public function it_subtracts_amounts() + public function it_subtracts_amounts(): void { $actual = $this->teller->subtract(1.1, '2.2', 3, 4.44, '5.55'); $expect = '-14.09'; @@ -116,7 +121,7 @@ public function it_subtracts_amounts() /** * @test */ - public function it_multiplies_amounts() + public function it_multiplies_amounts(): void { $amount = 1.23; $multiplier = 4.56; @@ -129,7 +134,7 @@ public function it_multiplies_amounts() /** * @test */ - public function it_multiplies_negative_amounts() + public function it_multiplies_negative_amounts(): void { $amount = '-0.09'; $multiplier = '0.01'; @@ -171,7 +176,7 @@ public function it_multiplies_negative_amounts() /** * @test */ - public function it_divides_amounts() + public function it_divides_amounts(): void { $amount = 1.23; $divisor = 4.56; @@ -184,7 +189,7 @@ public function it_divides_amounts() /** * @test */ - public function it_divides_negative_amounts() + public function it_divides_negative_amounts(): void { $amount = '-0.09'; $divisor = '100'; @@ -220,7 +225,7 @@ public function it_divides_negative_amounts() /** * @test */ - public function it_mods_amounts() + public function it_mods_amounts(): void { $amount = '10'; $divisor = '3'; @@ -232,7 +237,7 @@ public function it_mods_amounts() /** * @test */ - public function it_allocates_amounts_across_ratios() + public function it_allocates_amounts_across_ratios(): void { $amount = '100.00'; $ratios = [1 / 2, 1 / 3, 1 / 6]; @@ -248,7 +253,7 @@ public function it_allocates_amounts_across_ratios() /** * @test */ - public function it_allocates_amounts_among_targets() + public function it_allocates_amounts_among_targets(): void { $amount = '100.00'; $n = 3; @@ -264,7 +269,7 @@ public function it_allocates_amounts_among_targets() /** * @test */ - public function it_calculates_ratios_of_amounts() + public function it_calculates_ratios_of_amounts(): void { $amount = '100.00'; $other = '30'; @@ -276,7 +281,7 @@ public function it_calculates_ratios_of_amounts() /** * @test */ - public function it_calculates_absolute_amount() + public function it_calculates_absolute_amount(): void { $this->assertSame('7.00', $this->teller->absolute(-7)); $this->assertSame('7.00', $this->teller->absolute(7.0)); @@ -285,7 +290,7 @@ public function it_calculates_absolute_amount() /** * @test */ - public function it_calculates_negative_amount() + public function it_calculates_negative_amount(): void { $this->assertSame('-7.00', $this->teller->negative(7)); $this->assertSame('7.00', $this->teller->negative(-7)); @@ -294,7 +299,7 @@ public function it_calculates_negative_amount() /** * @test */ - public function it_compares_an_amount_to_zero() + public function it_compares_an_amount_to_zero(): void { $this->assertTrue($this->teller->isZero(0.00)); $this->assertFalse($this->teller->isZero(0.01)); @@ -303,7 +308,7 @@ public function it_compares_an_amount_to_zero() /** * @test */ - public function it_tells_if_an_amount_is_positive() + public function it_tells_if_an_amount_is_positive(): void { $this->assertTrue($this->teller->isPositive(1)); $this->assertFalse($this->teller->isPositive(0)); @@ -313,7 +318,7 @@ public function it_tells_if_an_amount_is_positive() /** * @test */ - public function it_tells_if_an_amount_is_negative() + public function it_tells_if_an_amount_is_negative(): void { $this->assertFalse($this->teller->isNegative(1)); $this->assertFalse($this->teller->isNegative(0)); @@ -323,7 +328,7 @@ public function it_tells_if_an_amount_is_negative() /** * @test */ - public function it_finds_the_minimum_amount() + public function it_finds_the_minimum_amount(): void { $amounts = [ '1.23', @@ -340,7 +345,7 @@ public function it_finds_the_minimum_amount() /** * @test */ - public function it_finds_the_maximum_amount() + public function it_finds_the_maximum_amount(): void { $amounts = [ '1.23', @@ -357,7 +362,7 @@ public function it_finds_the_maximum_amount() /** * @test */ - public function it_sums_amounts() + public function it_sums_amounts(): void { $amounts = [ '1.23', @@ -374,7 +379,7 @@ public function it_sums_amounts() /** * @test */ - public function it_averages_amounts() + public function it_averages_amounts(): void { $amounts = [ '1.23', @@ -391,7 +396,7 @@ public function it_averages_amounts() /** * @test */ - public function it_returns_a_zero_string() + public function it_returns_a_zero_string(): void { $this->assertSame('0.00', $this->teller->zero()); } @@ -399,7 +404,7 @@ public function it_returns_a_zero_string() /** * @test */ - public function it_converts_monetary_amounts() + public function it_converts_monetary_amounts(): void { $money = $this->teller->convertToMoney('1.23'); $this->assertInstanceOf(Money::class, $money); From ff94be06776bde0cb9c07e300dc11b8230aaad99 Mon Sep 17 00:00:00 2001 From: "Paul M. Jones" Date: Tue, 13 Jun 2023 11:35:58 -0500 Subject: [PATCH 12/17] convert test method names to conform with other tests --- tests/TellerTest.php | 56 ++++++++++++++++++++++---------------------- 1 file changed, 28 insertions(+), 28 deletions(-) diff --git a/tests/TellerTest.php b/tests/TellerTest.php index 4d3da6203..c1b1e0a52 100644 --- a/tests/TellerTest.php +++ b/tests/TellerTest.php @@ -17,7 +17,7 @@ protected function setUp(): void /** * @test */ - public function it_demonstrates_the_pennies_problem(): void + public function itDemonstratesThePenniesProblem(): void { $amount1 = 1.23; $amount2 = 4.56; @@ -38,7 +38,7 @@ public function it_demonstrates_the_pennies_problem(): void /** * @test */ - public function it_compares_equal_amounts(): void + public function itComparesEqualAmounts(): void { $this->assertTrue($this->teller->equals('7.00', 7.00)); $this->assertTrue($this->teller->equals('7', 7.00)); @@ -48,7 +48,7 @@ public function it_compares_equal_amounts(): void /** * @test */ - public function it_compares_two_amounts(): void + public function itComparesTwoAmounts(): void { $amount = 1.23; $other = 4.56; @@ -61,7 +61,7 @@ public function it_compares_two_amounts(): void /** * @test */ - public function it_compares_greater_than_amounts(): void + public function itComparesGreaterThanAmounts(): void { $this->assertTrue($this->teller->greaterThan('45.67', '9.01')); } @@ -69,7 +69,7 @@ public function it_compares_greater_than_amounts(): void /** * @test */ - public function it_compares_greater_than_or_equal_amounts(): void + public function itComparesGreaterThanOrEqualAmounts(): void { $this->assertTrue($this->teller->greaterThanOrEqual('45.67', '9.01')); $this->assertTrue($this->teller->greaterThanOrEqual('7.00', 7.00)); @@ -81,7 +81,7 @@ public function it_compares_greater_than_or_equal_amounts(): void /** * @test */ - public function it_compares_less_than_amounts(): void + public function itComparesLessThanAmounts(): void { $this->assertTrue($this->teller->lessThan('9.01', '45.67')); } @@ -89,7 +89,7 @@ public function it_compares_less_than_amounts(): void /** * @test */ - public function it_compares_less_than_or_equal_amounts(): void + public function itComparesLessThanOrEqualAmounts(): void { $this->assertTrue($this->teller->lessThanOrEqual('9.01', '45.67')); $this->assertTrue($this->teller->lessThanOrEqual('7.00', 7.00)); @@ -101,7 +101,7 @@ public function it_compares_less_than_or_equal_amounts(): void /** * @test */ - public function it_adds_amounts(): void + public function itAddsAmounts(): void { $actual = $this->teller->add(1.1, '2.2', 3, 4.44, '5.55'); $expect = '16.29'; @@ -111,7 +111,7 @@ public function it_adds_amounts(): void /** * @test */ - public function it_subtracts_amounts(): void + public function itSubtractsAmounts(): void { $actual = $this->teller->subtract(1.1, '2.2', 3, 4.44, '5.55'); $expect = '-14.09'; @@ -121,7 +121,7 @@ public function it_subtracts_amounts(): void /** * @test */ - public function it_multiplies_amounts(): void + public function itMultipliesAmounts(): void { $amount = 1.23; $multiplier = 4.56; @@ -134,7 +134,7 @@ public function it_multiplies_amounts(): void /** * @test */ - public function it_multiplies_negative_amounts(): void + public function itMultipliesNegativeAmounts(): void { $amount = '-0.09'; $multiplier = '0.01'; @@ -176,7 +176,7 @@ public function it_multiplies_negative_amounts(): void /** * @test */ - public function it_divides_amounts(): void + public function itDividesAmounts(): void { $amount = 1.23; $divisor = 4.56; @@ -189,7 +189,7 @@ public function it_divides_amounts(): void /** * @test */ - public function it_divides_negative_amounts(): void + public function itDividesNegativeAmounts(): void { $amount = '-0.09'; $divisor = '100'; @@ -225,7 +225,7 @@ public function it_divides_negative_amounts(): void /** * @test */ - public function it_mods_amounts(): void + public function itModsAmounts(): void { $amount = '10'; $divisor = '3'; @@ -237,7 +237,7 @@ public function it_mods_amounts(): void /** * @test */ - public function it_allocates_amounts_across_ratios(): void + public function itAllocatesAmountsAcrossRatios(): void { $amount = '100.00'; $ratios = [1 / 2, 1 / 3, 1 / 6]; @@ -253,7 +253,7 @@ public function it_allocates_amounts_across_ratios(): void /** * @test */ - public function it_allocates_amounts_among_targets(): void + public function itAllocatesAmountsAmongTargets(): void { $amount = '100.00'; $n = 3; @@ -269,7 +269,7 @@ public function it_allocates_amounts_among_targets(): void /** * @test */ - public function it_calculates_ratios_of_amounts(): void + public function itCalculatesRatiosOfAmounts(): void { $amount = '100.00'; $other = '30'; @@ -281,7 +281,7 @@ public function it_calculates_ratios_of_amounts(): void /** * @test */ - public function it_calculates_absolute_amount(): void + public function itCalculatesAbsoluteAmount(): void { $this->assertSame('7.00', $this->teller->absolute(-7)); $this->assertSame('7.00', $this->teller->absolute(7.0)); @@ -290,7 +290,7 @@ public function it_calculates_absolute_amount(): void /** * @test */ - public function it_calculates_negative_amount(): void + public function itCalculatesNegativeAmount(): void { $this->assertSame('-7.00', $this->teller->negative(7)); $this->assertSame('7.00', $this->teller->negative(-7)); @@ -299,7 +299,7 @@ public function it_calculates_negative_amount(): void /** * @test */ - public function it_compares_an_amount_to_zero(): void + public function itComparesAnAmountToZero(): void { $this->assertTrue($this->teller->isZero(0.00)); $this->assertFalse($this->teller->isZero(0.01)); @@ -308,7 +308,7 @@ public function it_compares_an_amount_to_zero(): void /** * @test */ - public function it_tells_if_an_amount_is_positive(): void + public function itTellsIfAnAmountIsPositive(): void { $this->assertTrue($this->teller->isPositive(1)); $this->assertFalse($this->teller->isPositive(0)); @@ -318,7 +318,7 @@ public function it_tells_if_an_amount_is_positive(): void /** * @test */ - public function it_tells_if_an_amount_is_negative(): void + public function itTellsIfAnAmountIsNegative(): void { $this->assertFalse($this->teller->isNegative(1)); $this->assertFalse($this->teller->isNegative(0)); @@ -328,7 +328,7 @@ public function it_tells_if_an_amount_is_negative(): void /** * @test */ - public function it_finds_the_minimum_amount(): void + public function itFindsTheMinimumAmount(): void { $amounts = [ '1.23', @@ -345,7 +345,7 @@ public function it_finds_the_minimum_amount(): void /** * @test */ - public function it_finds_the_maximum_amount(): void + public function itFindsTheMaximumAmount(): void { $amounts = [ '1.23', @@ -362,7 +362,7 @@ public function it_finds_the_maximum_amount(): void /** * @test */ - public function it_sums_amounts(): void + public function itSumsAmounts(): void { $amounts = [ '1.23', @@ -379,7 +379,7 @@ public function it_sums_amounts(): void /** * @test */ - public function it_averages_amounts(): void + public function itAveragesAmounts(): void { $amounts = [ '1.23', @@ -396,7 +396,7 @@ public function it_averages_amounts(): void /** * @test */ - public function it_returns_a_zero_string(): void + public function itReturnsAZeroString(): void { $this->assertSame('0.00', $this->teller->zero()); } @@ -404,7 +404,7 @@ public function it_returns_a_zero_string(): void /** * @test */ - public function it_converts_monetary_amounts(): void + public function itConvertsMonetaryAmounts(): void { $money = $this->teller->convertToMoney('1.23'); $this->assertInstanceOf(Money::class, $money); From 7ff2e409fc3cefc41bc113e547e012cb179a274f Mon Sep 17 00:00:00 2001 From: Frederik Bosch Date: Wed, 14 Jun 2023 16:16:12 +0200 Subject: [PATCH 13/17] first convert divisor and multiplier to Number, then divide/multiply/mod --- src/Teller.php | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/src/Teller.php b/src/Teller.php index d5e7c6bf2..999e1c63a 100644 --- a/src/Teller.php +++ b/src/Teller.php @@ -187,6 +187,8 @@ public function subtract($amount, $other, ...$others): string */ public function multiply($amount, int|float|string $multiplier): string { + $multiplier = \is_float($multiplier) ? Number::fromFloat($multiplier) : Number::fromNumber($multiplier); + return $this->convertToString( $this->convertToMoney($amount)->multiply( (string) $multiplier, $this->roundingMode @@ -202,6 +204,8 @@ public function multiply($amount, int|float|string $multiplier): string */ public function divide($amount, int|float|string $divisor): string { + $divisor = \is_float($divisor) ? Number::fromFloat($divisor) : Number::fromNumber($divisor); + return $this->convertToString( $this->convertToMoney($amount)->divide( (string) $divisor, $this->roundingMode @@ -217,6 +221,8 @@ public function divide($amount, int|float|string $divisor): string */ public function mod($amount, int|float|string $divisor): string { + $divisor = \is_float($divisor) ? Number::fromFloat($divisor) : Number::fromNumber($divisor); + return $this->convertToString( $this->convertToMoney($amount)->mod( $this->convertToMoney((string) $divisor) From a27372e6a4c3377aeb71c97c7f490833cfeb8454 Mon Sep 17 00:00:00 2001 From: Frederik Bosch Date: Wed, 14 Jun 2023 16:17:51 +0200 Subject: [PATCH 14/17] stable constructor --- src/Teller.php | 10 ++-------- 1 file changed, 2 insertions(+), 8 deletions(-) diff --git a/src/Teller.php b/src/Teller.php index 999e1c63a..2d08301d3 100644 --- a/src/Teller.php +++ b/src/Teller.php @@ -6,7 +6,7 @@ use Money\Formatter\DecimalMoneyFormatter; use Money\Parser\DecimalMoneyParser; -class Teller +final class Teller { /** * Convenience factory method for a Teller object. @@ -21,7 +21,6 @@ class Teller */ public static function __callStatic(string $method, array $arguments) { - $class = get_called_class(); $currency = new Currency($method); $currencies = new ISOCurrencies(); $parser = new DecimalMoneyParser($currencies); @@ -30,7 +29,7 @@ public static function __callStatic(string $method, array $arguments) ? Money::ROUND_HALF_UP : (int) array_shift($arguments); - return new $class( + return new static( $currency, $parser, $formatter, @@ -46,11 +45,6 @@ public static function __callStatic(string $method, array $arguments) private int $roundingMode = Money::ROUND_HALF_UP; - /** - * Constructor. - * - * @param int $roundingMode - */ public function __construct( Currency $currency, MoneyParser $parser, From 41733f19440679870824c5620965b4019377132c Mon Sep 17 00:00:00 2001 From: Frederik Bosch Date: Wed, 14 Jun 2023 16:28:43 +0200 Subject: [PATCH 15/17] fix psalm --- src/Teller.php | 6 +++++- tests/TellerTest.php | 6 ++++++ 2 files changed, 11 insertions(+), 1 deletion(-) diff --git a/src/Teller.php b/src/Teller.php index 2d08301d3..cb18d4f5f 100644 --- a/src/Teller.php +++ b/src/Teller.php @@ -1,5 +1,7 @@ $amounts an array of monetary amounts * * @return Money[] */ @@ -409,6 +411,7 @@ public function convertToMoneyArray(array $amounts): array { $converted = []; + /** @var mixed $amount */ foreach ($amounts as $key => $amount) { $converted[$key] = $this->convertToMoney($amount); } @@ -443,6 +446,7 @@ public function convertToStringArray(array $amounts): array { $converted = []; + /** @var mixed $amount */ foreach ($amounts as $key => $amount) { $converted[$key] = $this->convertToString($amount); } diff --git a/tests/TellerTest.php b/tests/TellerTest.php index c1b1e0a52..52684d2c3 100644 --- a/tests/TellerTest.php +++ b/tests/TellerTest.php @@ -1,5 +1,7 @@ assertSame($expect, $actual); // instead, use the Teller to do monetary math. From b7855e794a8dc6b2844b011222ec78a173d6c51b Mon Sep 17 00:00:00 2001 From: Frederik Bosch Date: Wed, 14 Jun 2023 16:38:30 +0200 Subject: [PATCH 16/17] fix code style --- src/Teller.php | 92 +++++++++++++++++++++++--------------------- tests/TellerTest.php | 85 ++++++++++++++++++++-------------------- 2 files changed, 92 insertions(+), 85 deletions(-) diff --git a/src/Teller.php b/src/Teller.php index cb18d4f5f..197515e96 100644 --- a/src/Teller.php +++ b/src/Teller.php @@ -8,6 +8,9 @@ use Money\Formatter\DecimalMoneyFormatter; use Money\Parser\DecimalMoneyParser; +use function array_shift; +use function is_float; + final class Teller { /** @@ -18,20 +21,21 @@ final class Teller * * * @param non-empty-string $method + * @param array{0?: int} $arguments * * @return Teller */ - public static function __callStatic(string $method, array $arguments) + public static function __callStatic(string $method, array $arguments): self { - $currency = new Currency($method); - $currencies = new ISOCurrencies(); - $parser = new DecimalMoneyParser($currencies); - $formatter = new DecimalMoneyFormatter($currencies); + $currency = new Currency($method); + $currencies = new ISOCurrencies(); + $parser = new DecimalMoneyParser($currencies); + $formatter = new DecimalMoneyFormatter($currencies); $roundingMode = empty($arguments) ? Money::ROUND_HALF_UP : (int) array_shift($arguments); - return new static( + return new self( $currency, $parser, $formatter, @@ -53,9 +57,9 @@ public function __construct( MoneyFormatter $formatter, int $roundingMode = Money::ROUND_HALF_UP ) { - $this->currency = $currency; - $this->parser = $parser; - $this->formatter = $formatter; + $this->currency = $currency; + $this->parser = $parser; + $this->formatter = $formatter; $this->roundingMode = $roundingMode; } @@ -65,7 +69,7 @@ public function __construct( * @param mixed $amount a monetary amount * @param mixed $other another monetary amount */ - public function equals($amount, $other): bool + public function equals(mixed $amount, mixed $other): bool { return $this->convertToMoney($amount)->equals( $this->convertToMoney($other) @@ -80,7 +84,7 @@ public function equals($amount, $other): bool * @param mixed $amount a monetary amount * @param mixed $other another monetary amount */ - public function compare($amount, $other): int + public function compare(mixed $amount, mixed $other): int { return $this->convertToMoney($amount)->compare( $this->convertToMoney($other) @@ -93,7 +97,7 @@ public function compare($amount, $other): int * @param mixed $amount a monetary amount * @param mixed $other another monetary amount */ - public function greaterThan($amount, $other): bool + public function greaterThan(mixed $amount, mixed $other): bool { return $this->convertToMoney($amount)->greaterThan( $this->convertToMoney($other) @@ -106,7 +110,7 @@ public function greaterThan($amount, $other): bool * @param mixed $amount a monetary amount * @param mixed $other another monetary amount */ - public function greaterThanOrEqual($amount, $other): bool + public function greaterThanOrEqual(mixed $amount, mixed $other): bool { return $this->convertToMoney($amount)->greaterThanOrEqual( $this->convertToMoney($other) @@ -119,7 +123,7 @@ public function greaterThanOrEqual($amount, $other): bool * @param mixed $amount a monetary amount * @param mixed $other another monetary amount */ - public function lessThan($amount, $other): bool + public function lessThan(mixed $amount, mixed $other): bool { return $this->convertToMoney($amount)->lessThan( $this->convertToMoney($other) @@ -132,7 +136,7 @@ public function lessThan($amount, $other): bool * @param mixed $amount a monetary amount * @param mixed $other another monetary amount */ - public function lessThanOrEqual($amount, $other): bool + public function lessThanOrEqual(mixed $amount, mixed $other): bool { return $this->convertToMoney($amount)->lessThanOrEqual( $this->convertToMoney($other) @@ -148,7 +152,7 @@ public function lessThanOrEqual($amount, $other): bool * * @return string the calculated monetary amount */ - public function add($amount, $other, ...$others): string + public function add(mixed $amount, mixed $other, mixed ...$others): string { return $this->convertToString( $this->convertToMoney($amount)->add( @@ -165,7 +169,7 @@ public function add($amount, $other, ...$others): string * @param mixed $other another monetary amount * @param mixed[] $others subsequent monetary amounts */ - public function subtract($amount, $other, ...$others): string + public function subtract(mixed $amount, mixed $other, mixed ...$others): string { return $this->convertToString( $this->convertToMoney($amount)->subtract( @@ -181,13 +185,14 @@ public function subtract($amount, $other, ...$others): string * @param mixed $amount a monetary amount * @param int|float|numeric-string $multiplier the multiplier */ - public function multiply($amount, int|float|string $multiplier): string + public function multiply(mixed $amount, int|float|string $multiplier): string { - $multiplier = \is_float($multiplier) ? Number::fromFloat($multiplier) : Number::fromNumber($multiplier); + $multiplier = is_float($multiplier) ? Number::fromFloat($multiplier) : Number::fromNumber($multiplier); return $this->convertToString( $this->convertToMoney($amount)->multiply( - (string) $multiplier, $this->roundingMode + (string) $multiplier, + $this->roundingMode ) ); } @@ -198,13 +203,14 @@ public function multiply($amount, int|float|string $multiplier): string * @param mixed $amount a monetary amount * @param int|float|numeric-string $divisor the divisor */ - public function divide($amount, int|float|string $divisor): string + public function divide(mixed $amount, int|float|string $divisor): string { - $divisor = \is_float($divisor) ? Number::fromFloat($divisor) : Number::fromNumber($divisor); + $divisor = is_float($divisor) ? Number::fromFloat($divisor) : Number::fromNumber($divisor); return $this->convertToString( $this->convertToMoney($amount)->divide( - (string) $divisor, $this->roundingMode + (string) $divisor, + $this->roundingMode ) ); } @@ -215,9 +221,9 @@ public function divide($amount, int|float|string $divisor): string * @param mixed $amount a monetary amount * @param int|float|numeric-string $divisor the divisor */ - public function mod($amount, int|float|string $divisor): string + public function mod(mixed $amount, int|float|string $divisor): string { - $divisor = \is_float($divisor) ? Number::fromFloat($divisor) : Number::fromNumber($divisor); + $divisor = is_float($divisor) ? Number::fromFloat($divisor) : Number::fromNumber($divisor); return $this->convertToString( $this->convertToMoney($amount)->mod( @@ -234,7 +240,7 @@ public function mod($amount, int|float|string $divisor): string * * @return string[] the calculated monetary amounts */ - public function allocate($amount, array $ratios): array + public function allocate(mixed $amount, array $ratios): array { return $this->convertToStringArray( $this->convertToMoney($amount)->allocate($ratios) @@ -244,12 +250,12 @@ public function allocate($amount, array $ratios): array /** * Allocates a monetary amount among N targets. * - * @param mixed $amount a monetary amount - * @param int<1, max> $n the number of targets + * @param mixed $amount a monetary amount + * @param int<1, max> $n the number of targets * * @return string[] the calculated monetary amounts */ - public function allocateTo($amount, int $n): array + public function allocateTo(mixed $amount, int $n): array { return $this->convertToStringArray( $this->convertToMoney($amount)->allocateTo($n) @@ -262,7 +268,7 @@ public function allocateTo($amount, int $n): array * @param mixed $amount a monetary amount * @param mixed $other another monetary amount */ - public function ratioOf($amount, $other): string + public function ratioOf(mixed $amount, mixed $other): string { return $this->convertToString( $this->convertToMoney($amount)->ratioOf( @@ -276,7 +282,7 @@ public function ratioOf($amount, $other): string * * @param mixed $amount a monetary amount */ - public function absolute($amount): string + public function absolute(mixed $amount): string { return $this->convertToString( $this->convertToMoney($amount)->absolute() @@ -289,7 +295,7 @@ public function absolute($amount): string * * @param mixed $amount a monetary amount */ - public function negative($amount): string + public function negative(mixed $amount): string { return $this->convertToString( $this->convertToMoney($amount)->negative() @@ -301,7 +307,7 @@ public function negative($amount): string * * @param mixed $amount a monetary amount */ - public function isZero($amount): bool + public function isZero(mixed $amount): bool { return $this->convertToMoney($amount)->isZero(); } @@ -311,7 +317,7 @@ public function isZero($amount): bool * * @param mixed $amount a monetary amount */ - public function isPositive($amount): bool + public function isPositive(mixed $amount): bool { return $this->convertToMoney($amount)->isPositive(); } @@ -321,7 +327,7 @@ public function isPositive($amount): bool * * @param mixed $amount a monetary amount */ - public function isNegative($amount): bool + public function isNegative(mixed $amount): bool { return $this->convertToMoney($amount)->isNegative(); } @@ -332,7 +338,7 @@ public function isNegative($amount): bool * @param mixed $amount a monetary amount * @param mixed ...$amounts additional monetary amounts */ - public function min($amount, ...$amounts): string + public function min(mixed $amount, mixed ...$amounts): string { return $this->convertToString( Money::min( @@ -348,7 +354,7 @@ public function min($amount, ...$amounts): string * @param mixed $amount a monetary amount * @param mixed ...$amounts additional monetary amounts */ - public function max($amount, ...$amounts): string + public function max(mixed $amount, mixed ...$amounts): string { return $this->convertToString( Money::max( @@ -364,7 +370,7 @@ public function max($amount, ...$amounts): string * @param mixed $amount a monetary amount * @param mixed ...$amounts additional monetary amounts */ - public function sum($amount, ...$amounts): string + public function sum(mixed $amount, mixed ...$amounts): string { return $this->convertToString( Money::sum( @@ -380,7 +386,7 @@ public function sum($amount, ...$amounts): string * @param mixed $amount a monetary amount * @param mixed ...$amounts additional monetary amounts */ - public function avg($amount, ...$amounts): string + public function avg(mixed $amount, mixed ...$amounts): string { return $this->convertToString( Money::avg( @@ -395,7 +401,7 @@ public function avg($amount, ...$amounts): string * * @param mixed $amount a monetary amount */ - public function convertToMoney($amount): Money + public function convertToMoney(mixed $amount): Money { return $this->parser->parse((string) $amount, $this->currency); } @@ -425,9 +431,9 @@ public function convertToMoneyArray(array $amounts): array * @param mixed $amount typically a Money object, int, float, or string * representing a monetary amount */ - public function convertToString($amount): string + public function convertToString(mixed $amount): string { - if (!$amount instanceof Money) { + if ($amount instanceof Money === false) { $amount = $this->convertToMoney($amount); } @@ -438,7 +444,7 @@ public function convertToString($amount): string * Converts an array of monetary amounts into Money objects, then into * strings. * - * @param array $amounts an array of monetary amounts + * @param array $amounts an array of monetary amounts * * @return string[] */ diff --git a/tests/TellerTest.php b/tests/TellerTest.php index 52684d2c3..2725a2840 100644 --- a/tests/TellerTest.php +++ b/tests/TellerTest.php @@ -6,8 +6,9 @@ use Money\Money; use Money\Teller; +use PHPUnit\Framework\TestCase; -final class TellerTest extends \PHPUnit\Framework\TestCase +final class TellerTest extends TestCase { protected Teller $teller; @@ -57,7 +58,7 @@ public function itComparesEqualAmounts(): void public function itComparesTwoAmounts(): void { $amount = 1.23; - $other = 4.56; + $other = 4.56; $this->assertSame(-1, $this->teller->compare($amount, $other)); $this->assertSame(0, $this->teller->compare($amount, $amount)); @@ -129,7 +130,7 @@ public function itSubtractsAmounts(): void */ public function itMultipliesAmounts(): void { - $amount = 1.23; + $amount = 1.23; $multiplier = 4.56; $actual = $this->teller->multiply($amount, $multiplier); @@ -142,40 +143,40 @@ public function itMultipliesAmounts(): void */ public function itMultipliesNegativeAmounts(): void { - $amount = '-0.09'; + $amount = '-0.09'; $multiplier = '0.01'; - $actual = $this->teller->multiply($amount, $multiplier); - $expect = '0.00'; + $actual = $this->teller->multiply($amount, $multiplier); + $expect = '0.00'; $this->assertSame($expect, $actual); - $amount = '-100.00'; + $amount = '-100.00'; $multiplier = '0.01'; - $actual = $this->teller->multiply($amount, $multiplier); - $expect = '-1.00'; + $actual = $this->teller->multiply($amount, $multiplier); + $expect = '-1.00'; $this->assertSame($expect, $actual); - $amount = '100.00'; + $amount = '100.00'; $multiplier = '-0.01'; - $actual = $this->teller->multiply($amount, $multiplier); - $expect = '-1.00'; + $actual = $this->teller->multiply($amount, $multiplier); + $expect = '-1.00'; $this->assertSame($expect, $actual); - $amount = '141950.00'; + $amount = '141950.00'; $multiplier = '-0.01'; - $actual = $this->teller->multiply($amount, $multiplier); - $expect = '-1419.50'; + $actual = $this->teller->multiply($amount, $multiplier); + $expect = '-1419.50'; $this->assertSame($expect, $actual); - $amount = '141950.00'; + $amount = '141950.00'; $multiplier = '-0.01056710109193'; - $actual = $this->teller->multiply($amount, $multiplier); - $expect = '-1500.00'; + $actual = $this->teller->multiply($amount, $multiplier); + $expect = '-1500.00'; $this->assertSame($expect, $actual); - $amount = '141950.00'; + $amount = '141950.00'; $multiplier = '-0.0001056710109193'; - $actual = $this->teller->multiply($amount, $multiplier); - $expect = '-15.00'; + $actual = $this->teller->multiply($amount, $multiplier); + $expect = '-15.00'; $this->assertSame($expect, $actual); } @@ -184,7 +185,7 @@ public function itMultipliesNegativeAmounts(): void */ public function itDividesAmounts(): void { - $amount = 1.23; + $amount = 1.23; $divisor = 4.56; $actual = $this->teller->divide($amount, $divisor); @@ -197,34 +198,34 @@ public function itDividesAmounts(): void */ public function itDividesNegativeAmounts(): void { - $amount = '-0.09'; + $amount = '-0.09'; $divisor = '100'; - $actual = $this->teller->divide($amount, $divisor); - $expect = '0.00'; + $actual = $this->teller->divide($amount, $divisor); + $expect = '0.00'; $this->assertSame($expect, $actual); - $amount = '-100.00'; + $amount = '-100.00'; $divisor = '0.01'; - $actual = $this->teller->divide($amount, $divisor); - $expect = '-10000.00'; + $actual = $this->teller->divide($amount, $divisor); + $expect = '-10000.00'; $this->assertSame($expect, $actual); - $amount = '100.00'; + $amount = '100.00'; $divisor = '-0.01'; - $actual = $this->teller->divide($amount, $divisor); - $expect = '-10000.00'; + $actual = $this->teller->divide($amount, $divisor); + $expect = '-10000.00'; $this->assertSame($expect, $actual); - $amount = '141950.00'; + $amount = '141950.00'; $divisor = '-0.01056710109193'; - $actual = $this->teller->divide($amount, $divisor); - $expect = '-13433201.67'; + $actual = $this->teller->divide($amount, $divisor); + $expect = '-13433201.67'; $this->assertSame($expect, $actual); - $amount = '141950.00'; + $amount = '141950.00'; $divisor = '-0.0001056710109193'; - $actual = $this->teller->divide($amount, $divisor); - $expect = '-1343320166.67'; + $actual = $this->teller->divide($amount, $divisor); + $expect = '-1343320166.67'; $this->assertSame($expect, $actual); } @@ -233,10 +234,10 @@ public function itDividesNegativeAmounts(): void */ public function itModsAmounts(): void { - $amount = '10'; + $amount = '10'; $divisor = '3'; - $actual = $this->teller->mod($amount, $divisor); - $expect = '1.00'; + $actual = $this->teller->mod($amount, $divisor); + $expect = '1.00'; $this->assertSame($expect, $actual); } @@ -262,7 +263,7 @@ public function itAllocatesAmountsAcrossRatios(): void public function itAllocatesAmountsAmongTargets(): void { $amount = '100.00'; - $n = 3; + $n = 3; $actual = $this->teller->allocateTo($amount, $n); $expect = [ '33.34', @@ -278,7 +279,7 @@ public function itAllocatesAmountsAmongTargets(): void public function itCalculatesRatiosOfAmounts(): void { $amount = '100.00'; - $other = '30'; + $other = '30'; $actual = $this->teller->ratioOf($amount, $other); $expect = '3.33'; $this->assertSame($expect, $actual); From a552ba8c5471e7432e8bfa0c8a18fb53883bdb0d Mon Sep 17 00:00:00 2001 From: Frederik Bosch Date: Wed, 14 Jun 2023 16:55:46 +0200 Subject: [PATCH 17/17] fix code style --- src/Teller.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/Teller.php b/src/Teller.php index 197515e96..22121285b 100644 --- a/src/Teller.php +++ b/src/Teller.php @@ -250,8 +250,8 @@ public function allocate(mixed $amount, array $ratios): array /** * Allocates a monetary amount among N targets. * - * @param mixed $amount a monetary amount - * @param int<1, max> $n the number of targets + * @param mixed $amount a monetary amount + * @psalm-param positive-int $n the number of targets * * @return string[] the calculated monetary amounts */