From c947170e82725c2541a5afbc4d1a78804924bb56 Mon Sep 17 00:00:00 2001 From: Marcel Strahl Date: Wed, 18 Apr 2018 22:22:40 +0200 Subject: [PATCH 1/6] * A facade was provided for the generation of the price calculator --- src/Exceptions/PriceException.php | 13 --------- src/Facade/PriceCalculator.php | 43 ++++++++++++++++++++++++++++ tests/Facade/PriceCalculatorTest.php | 35 ++++++++++++++++++++++ 3 files changed, 78 insertions(+), 13 deletions(-) delete mode 100644 src/Exceptions/PriceException.php create mode 100644 src/Facade/PriceCalculator.php create mode 100644 tests/Facade/PriceCalculatorTest.php diff --git a/src/Exceptions/PriceException.php b/src/Exceptions/PriceException.php deleted file mode 100644 index d6fa7c2..0000000 --- a/src/Exceptions/PriceException.php +++ /dev/null @@ -1,13 +0,0 @@ - - * @package Src\Exceptions - */ -class PriceException extends \InvalidArgumentException -{ - -} diff --git a/src/Facade/PriceCalculator.php b/src/Facade/PriceCalculator.php new file mode 100644 index 0000000..9ba46f3 --- /dev/null +++ b/src/Facade/PriceCalculator.php @@ -0,0 +1,43 @@ + + * @package MarcelStrahl\PriceCalculator\Facade + */ +class PriceCalculator +{ + /** + * @var Vat + */ + private $vat; + + public function __construct() + { + $this->vat = new Vat(); + } + + /** + * @param int $vat + * @return PriceCalculatorService + */ + public static function getPriceCalculator(int $vat) + { + return (new self())->createPriceCalculator($vat); + } + + /** + * @param int $vat + * @return PriceCalculatorService + */ + private function createPriceCalculator(int $vat): PriceCalculatorService + { + $this->vat->setVat($vat); + return new PriceCalculatorService($this->vat); + } +} diff --git a/tests/Facade/PriceCalculatorTest.php b/tests/Facade/PriceCalculatorTest.php new file mode 100644 index 0000000..fac7003 --- /dev/null +++ b/tests/Facade/PriceCalculatorTest.php @@ -0,0 +1,35 @@ + + * @package MarcelStrahl\PriceCalculator\Tests\Facade + */ +class PriceCalculatorTest extends TestCase +{ + /** + * @return void + */ + public function testCanInitPriceCalculatorFacade(): void + { + $facade = new PriceCalculatorFacade(); + $this->assertInstanceOf(PriceCalculatorFacade::class, $facade); + } + + /** + * @return void + */ + public function testGetPriceCalculaltor(): void + { + $facade = new PriceCalculatorFacade(); + $priceCalculator = $facade::getPriceCalculator(19); + + $this->assertInstanceOf(PriceCalculatorInterface::class, $priceCalculator); + } +} From 11c8ff545253055b2316cd9184fc9f4143a2759e Mon Sep 17 00:00:00 2001 From: Marcel Strahl Date: Fri, 27 Apr 2018 00:02:12 +0200 Subject: [PATCH 2/6] Workover of pricecalculator class and test * Correction of a precision error in the calculation of taxes * Precision adjustment in the subPrice method --- src/PriceCalculator.php | 4 ++-- tests/PriceCalculatorTest.php | 19 +++++++++++-------- 2 files changed, 13 insertions(+), 10 deletions(-) diff --git a/src/PriceCalculator.php b/src/PriceCalculator.php index e9b1e7f..93d2b55 100644 --- a/src/PriceCalculator.php +++ b/src/PriceCalculator.php @@ -46,7 +46,7 @@ public function addPrice(float $total, float $price): float */ public function subPrice(float $total, float $price): float { - $total = (float)bcsub($total, $price); + $total = (float)bcsub($total, $price, 2); return ($total < 0) ? 0 : $total; } @@ -81,7 +81,7 @@ public function calculatePriceWithSalesTax(float $netPrice): float */ public function calculateSalesTaxFromTotalPrice(float $total) : float { - return (float)bcsub($total, round((float)bcdiv($total, $this->vat->getVatToCalculate(), 2))); + return (float)bcsub($total, round((float)bcdiv($total, $this->vat->getVatToCalculate(), 12), 2), 2); } /** diff --git a/tests/PriceCalculatorTest.php b/tests/PriceCalculatorTest.php index 655ad09..04977de 100644 --- a/tests/PriceCalculatorTest.php +++ b/tests/PriceCalculatorTest.php @@ -132,8 +132,8 @@ public function testCanCalculateSalesTaxOfTotal(float $grossPrice, float $netPri $priceCalculator->setVat(19); $vatPrice = $priceCalculator->calculateSalesTaxFromTotalPrice($grossPrice); $this->assertSame($expectedVat, $vatPrice); - $this->assertSame($netPrice, (float)bcsub($grossPrice, $vatPrice)); - $this->assertSame($grossPrice, (float)bcadd($netPrice, $vatPrice)); + $this->assertSame($netPrice, (float)bcsub($grossPrice, $vatPrice, 2)); + $this->assertSame($grossPrice, (float)bcadd($netPrice, $vatPrice, 2)); } /** @@ -143,19 +143,22 @@ public function dataProviderSalesTaxOfTotal(): array { return [ [ - 300, 252, 48, + 300.0, 252.1, 47.9, ], [ 76160, 64000, 12160 ], [ - 405, 340, 65 + 405, 340.34, 64.66 ], [ - 15, 13, 2 + 15, 12.61, 2.39 ], [ 238, 200, 38 + ], + [ + 42.1, 35.38, 6.72 ] ]; } @@ -220,16 +223,16 @@ public function dataProviderCalculateNetPriceFromGrossPrice(): array { return [ [ - 300, 252, + 300, 252.1, ], [ - 405, 340, + 405, 340.34, ], [ 238, 200, ], [ - 15, 13, + 15, 12.61, ], [ 76160, 64000, From 657744984c5e4effa2f0927986ce98927322d7f6 Mon Sep 17 00:00:00 2001 From: Marcel Strahl Date: Fri, 27 Apr 2018 11:55:51 +0200 Subject: [PATCH 3/6] Workover of pricecalculator class and test * Fix Division at zero exception in converter class, if number contains the value 0.00 * Remove number interface --- src/Helpers/Converter/ConverterInterface.php | 10 +++++++++ .../Converter/Currencies/CentToEuro.php | 13 ++++++++++++ .../Converter/Currencies/EuroToCent.php | 13 ++++++++++++ src/Helpers/Entity/Discount.php | 7 +++---- src/Helpers/Entity/Vat.php | 21 +++++++++---------- src/Helpers/Types/NumberInterface.php | 13 ------------ .../Converter/Currencies/CentToEuroTest.php | 12 +++++++++-- .../Converter/Currencies/EuroToCentTest.php | 13 +++++++++--- tests/Helpers/Entity/DiscountTest.php | 1 - tests/Helpers/Entity/VatTest.php | 2 ++ 10 files changed, 71 insertions(+), 34 deletions(-) delete mode 100644 src/Helpers/Types/NumberInterface.php diff --git a/src/Helpers/Converter/ConverterInterface.php b/src/Helpers/Converter/ConverterInterface.php index d77c4b4..16f87f3 100644 --- a/src/Helpers/Converter/ConverterInterface.php +++ b/src/Helpers/Converter/ConverterInterface.php @@ -2,6 +2,8 @@ namespace MarcelStrahl\PriceCalculator\Helpers\Converter; +use MarcelStrahl\PriceCalculator\Exceptions\ConverterException; + /** * Interface ConverterInterface * @author Marcel Strahl @@ -12,6 +14,14 @@ interface ConverterInterface /** * @param float $amount * @return float + * @throws ConverterException */ public function convert(float $amount): float; + + /** + * @param float $amount + * @return void + * @throws ConverterException + */ + public function isZeroAmount(float $amount): void; } diff --git a/src/Helpers/Converter/Currencies/CentToEuro.php b/src/Helpers/Converter/Currencies/CentToEuro.php index 006e01d..d4ea047 100644 --- a/src/Helpers/Converter/Currencies/CentToEuro.php +++ b/src/Helpers/Converter/Currencies/CentToEuro.php @@ -2,6 +2,8 @@ namespace MarcelStrahl\PriceCalculator\Helpers\Converter; +use MarcelStrahl\PriceCalculator\Exceptions\ConverterException; + /** * Class CentToEuro * @author Marcel Strahl @@ -14,6 +16,17 @@ class CentToEuro implements ConverterInterface */ public function convert(float $amount): float { + $this->isZeroAmount($amount); return (float)bcdiv($amount, 100, 2); } + + /** + * @inheritDoc + */ + public function isZeroAmount(float $amount): void + { + if (empty($amount)) { + throw ConverterException::fromZeroAmount($amount); + } + } } diff --git a/src/Helpers/Converter/Currencies/EuroToCent.php b/src/Helpers/Converter/Currencies/EuroToCent.php index 7f62211..9e62bf9 100644 --- a/src/Helpers/Converter/Currencies/EuroToCent.php +++ b/src/Helpers/Converter/Currencies/EuroToCent.php @@ -2,6 +2,8 @@ namespace MarcelStrahl\PriceCalculator\Helpers\Converter; +use MarcelStrahl\PriceCalculator\Exceptions\ConverterException; + /** * Class EuroToCent * @author Marcel Strahl @@ -14,6 +16,17 @@ class EuroToCent implements ConverterInterface */ public function convert(float $amount): float { + $this->isZeroAmount($amount); return (float)bcmul($amount, 100); } + + /** + * @inheritDoc + */ + public function isZeroAmount(float $amount): void + { + if (empty($amount)) { + throw ConverterException::fromZeroAmount($amount); + } + } } diff --git a/src/Helpers/Entity/Discount.php b/src/Helpers/Entity/Discount.php index e435ef3..027aa0b 100644 --- a/src/Helpers/Entity/Discount.php +++ b/src/Helpers/Entity/Discount.php @@ -2,21 +2,20 @@ namespace MarcelStrahl\PriceCalculator\Helpers\Entity; -use MarcelStrahl\PriceCalculator\Helpers\Types\PercentInterface; use MarcelStrahl\PriceCalculator\Helpers\Types\DiscountInterface; -use MarcelStrahl\PriceCalculator\Helpers\Types\NumberInterface; +use MarcelStrahl\PriceCalculator\Helpers\Types\PercentInterface; /** * Class Discount * @author Marcel Strahl * @package MarcelStrahl\PriceCalculator\Helpers\Entity */ -class Discount implements DiscountInterface, PercentInterface, NumberInterface +class Discount implements DiscountInterface, PercentInterface { /** * @var float */ - private $percent = 0.0; + private $percent = .0; /** * @param float $percent diff --git a/src/Helpers/Entity/Vat.php b/src/Helpers/Entity/Vat.php index 315cc91..4e361aa 100644 --- a/src/Helpers/Entity/Vat.php +++ b/src/Helpers/Entity/Vat.php @@ -3,7 +3,6 @@ namespace MarcelStrahl\PriceCalculator\Helpers\Entity; use MarcelStrahl\PriceCalculator\Helpers\Types\PercentInterface; -use MarcelStrahl\PriceCalculator\Helpers\Types\NumberInterface; use MarcelStrahl\PriceCalculator\Helpers\Types\VatInterface; /** @@ -11,33 +10,33 @@ * @author Marcel Strahl * @package MarcelStrahl\PriceCalculator\Helpers\Entity */ -class Vat implements VatInterface, PercentInterface, NumberInterface +class Vat implements VatInterface, PercentInterface { /** * @var float */ - private $vat = 0.00; + private $vat = .00; /** * @var float */ - private $vatToCalculate = 0.00; + private $vatToCalculate = .00; /** - * @param float $vat + * @return float */ - public function setVat(float $vat): void + public function getVat(): float { - $this->vat = $vat; - $this->vatToCalculate = (float)bcadd(1, bcdiv($vat, 100, 2), 2); + return $this->vat; } /** - * @return float + * @param float $vat */ - public function getVat(): float + public function setVat(float $vat): void { - return $this->vat; + $this->vat = $vat; + $this->vatToCalculate = (float)bcadd(1, bcdiv($vat, 100, 2), 2); } /** diff --git a/src/Helpers/Types/NumberInterface.php b/src/Helpers/Types/NumberInterface.php deleted file mode 100644 index 75800e4..0000000 --- a/src/Helpers/Types/NumberInterface.php +++ /dev/null @@ -1,13 +0,0 @@ - - * Interface NumberInterface - * @package MarcelStrahl\PriceCalculator\Helpers\Entity - */ -interface NumberInterface -{ - -} diff --git a/tests/Helpers/Converter/Currencies/CentToEuroTest.php b/tests/Helpers/Converter/Currencies/CentToEuroTest.php index 689e6f0..b5d58f2 100644 --- a/tests/Helpers/Converter/Currencies/CentToEuroTest.php +++ b/tests/Helpers/Converter/Currencies/CentToEuroTest.php @@ -2,6 +2,7 @@ namespace MarcelStrahl\PriceCalculator\Tests\Helpers\Converter\Currencies; +use MarcelStrahl\PriceCalculator\Exceptions\ConverterException; use MarcelStrahl\PriceCalculator\Helpers\Converter\CentToEuro; use MarcelStrahl\PriceCalculator\Helpers\Converter\ConverterInterface; use PHPUnit\Framework\TestCase; @@ -25,13 +26,19 @@ public function testImplements(): void /** * @dataProvider dataProviderConvert - * @param float $amount - * @param float $expected + * @param null|float $amount + * @param null|float $expected * @return void + * @throws ConverterException */ public function testConvert(float $amount, float $expected): void { $converter = new CentToEuro(); + + if ($amount === .00) { + $this->expectException(ConverterException::class); + } + $this->assertSame($expected, $converter->convert($amount)); } @@ -44,6 +51,7 @@ public function dataProviderConvert(): array [100.00, 1.00], [250.00, 2.50], [178, 1.78], + [.00, .00], ]; } } diff --git a/tests/Helpers/Converter/Currencies/EuroToCentTest.php b/tests/Helpers/Converter/Currencies/EuroToCentTest.php index b9e27b6..8a853f2 100644 --- a/tests/Helpers/Converter/Currencies/EuroToCentTest.php +++ b/tests/Helpers/Converter/Currencies/EuroToCentTest.php @@ -2,6 +2,7 @@ namespace MarcelStrahl\PriceCalculator\Tests\Helpers\Converter\Currencies; +use MarcelStrahl\PriceCalculator\Exceptions\ConverterException; use MarcelStrahl\PriceCalculator\Helpers\Converter\ConverterInterface; use MarcelStrahl\PriceCalculator\Helpers\Converter\EuroToCent; use PHPUnit\Framework\TestCase; @@ -25,13 +26,18 @@ public function testImplements(): void /** * @dataProvider dataProviderConvert - * @param float $amount - * @param float $expected + * @param null|float $amount + * @param null|float $expected * @return void + * @throws ConverterException */ - public function testConvert(float $amount, float $expected): void + public function testConvert(?float $amount, ?float $expected): void { $converter = new EuroToCent(); + + if ($amount === .00) { + $this->expectException(ConverterException::class); + } $this->assertSame($expected, $converter->convert($amount)); } @@ -44,6 +50,7 @@ public function dataProviderConvert(): array [1.00, 100.00], [1.15, 115.00], [116.80, 11680.00], + [.00, .00], ]; } } diff --git a/tests/Helpers/Entity/DiscountTest.php b/tests/Helpers/Entity/DiscountTest.php index 2d23cee..fe3b498 100644 --- a/tests/Helpers/Entity/DiscountTest.php +++ b/tests/Helpers/Entity/DiscountTest.php @@ -22,7 +22,6 @@ public function testCanSetDiscount(): void { $discount = new Discount($percent = 0.5); $this->assertInstanceOf(DiscountInterface::class, $discount); - $this->assertInstanceOf(NumberInterface::class, $discount); $this->assertInstanceOf(PercentInterface::class, $discount); $this->assertSame($percent, $discount->getDiscount()); } diff --git a/tests/Helpers/Entity/VatTest.php b/tests/Helpers/Entity/VatTest.php index 9d28be2..b3c2b2e 100644 --- a/tests/Helpers/Entity/VatTest.php +++ b/tests/Helpers/Entity/VatTest.php @@ -3,6 +3,7 @@ namespace MarcelStrahl\PriceCalculator\Tests\Helpers\Entity; use MarcelStrahl\PriceCalculator\Helpers\Entity\Vat; +use MarcelStrahl\PriceCalculator\Helpers\Types\PercentInterface; use MarcelStrahl\PriceCalculator\Helpers\Types\VatInterface; use PHPUnit\Framework\TestCase; @@ -21,6 +22,7 @@ public function testImplements(): void $vat = new Vat(); $this->assertInstanceOf(VatInterface::class, $vat); $this->assertInstanceOf(Vat::class, $vat); + $this->assertInstanceOf(PercentInterface::class, $vat); } /** From c8795c4b813db8634b19765d4dd1d20e3e86cc6e Mon Sep 17 00:00:00 2001 From: Marcel Strahl Date: Fri, 27 Apr 2018 12:14:11 +0200 Subject: [PATCH 4/6] Workover of pricecalculator class and test * update read me * update php version to 7.2 --- composer.json | 2 +- readme.md | 136 +++++++++++++++++++++++++++++++++++++++++++++++++- 2 files changed, 136 insertions(+), 2 deletions(-) diff --git a/composer.json b/composer.json index f055d93..e6bbc3f 100644 --- a/composer.json +++ b/composer.json @@ -12,7 +12,7 @@ } ], "require": { - "php": ">=7.1", + "php": ">=7.2", "ext-bcmath": "*" }, "require-dev": { diff --git a/readme.md b/readme.md index 207d8be..b1dc5b7 100644 --- a/readme.md +++ b/readme.md @@ -20,7 +20,141 @@ You are also welcome to use the Issue Tracker to set bugs, improvements or upgra ``` composer require marcel-strahl/price-calculator ``` -### Example +### How to use + +If you want to use our price calculator, you can instantiate an instance of the price calculator via the price calculator facade from version 2.1. + +```php +setVat(19); +$priceCalculator = new PriceCalculator($vat); +``` + +The price calculator can add prices + +```php +setVat(19); +$priceCalculator = new PriceCalculator($vat); + +// Total: 100 +$total = $priceCalculator->addPrice($total, $add); +``` + +Subtracting prices is made possible by the following method: + +```php +setVat(19); +$priceCalculator = new PriceCalculator($vat); + +// Total: 100 +$total = $priceCalculator->subPrice($total, $sub); +``` + +You can also multiply prices by a number (integer). + +```php +setVat(19); +$priceCalculator = new PriceCalculator($vat); + +// Total: 100 +$total = $priceCalculator->mulPrice($amount, 200); +``` + +With the following code you can calculate the VAT: + +```php +setVat(19); +$priceCalculator = new PriceCalculator($vat); + +$vatPrice = $priceCalculator->calculateSalesTaxFromTotalPrice($total); +``` + +The following example shows how to calculate the net price using the gross price. + +```php +setVat(19); +$priceCalculator = new PriceCalculator($vat); + +$vatPrice = $priceCalculator->calculateNetPriceFromGrossPrice($total); +``` + +Or the gross price is determined using the net price + +```php +setVat(19); +$priceCalculator = new PriceCalculator($vat); + +$vatPrice = $priceCalculator->calculatePriceWithSalesTax($netPrice); +``` +In another example you can see the functions of the price calculator. +A price is calculated, converted from cents to euros and the total sum is formatted. + ```php Date: Fri, 27 Apr 2018 12:14:58 +0200 Subject: [PATCH 5/6] Workover of pricecalculator class and test * add missing converter exception class --- src/Exceptions/ConverterException.php | 24 ++++++++++++++++++++++++ 1 file changed, 24 insertions(+) create mode 100644 src/Exceptions/ConverterException.php diff --git a/src/Exceptions/ConverterException.php b/src/Exceptions/ConverterException.php new file mode 100644 index 0000000..0f39e50 --- /dev/null +++ b/src/Exceptions/ConverterException.php @@ -0,0 +1,24 @@ + + * @package MarcelStrahl\PriceCalculator\Exceptions + */ +class ConverterException extends Exception +{ + /** + * @param float $amout + * @return ConverterException + */ + public static function fromZeroAmount(float $amout): self + { + return new self( + sprintf('Division by zero is not allowed. Please check your injection. Given amount: %f', $amout) + ); + } +} From dbcfdcf21b7acc96f1a7cfffee57028be2442c76 Mon Sep 17 00:00:00 2001 From: Marcel Strahl Date: Sat, 28 Apr 2018 00:32:20 +0200 Subject: [PATCH 6/6] Workover of pricecalculator class and test * add scale to the other price calculator methods * add unit converter facade --- src/Facade/UnitConverter.php | 38 ++++++++++++++++++++++++++++++ src/PriceCalculator.php | 4 ++-- tests/Facade/UnitConverterTest.php | 35 +++++++++++++++++++++++++++ 3 files changed, 75 insertions(+), 2 deletions(-) create mode 100644 src/Facade/UnitConverter.php create mode 100644 tests/Facade/UnitConverterTest.php diff --git a/src/Facade/UnitConverter.php b/src/Facade/UnitConverter.php new file mode 100644 index 0000000..27a75e7 --- /dev/null +++ b/src/Facade/UnitConverter.php @@ -0,0 +1,38 @@ + + * @package MarcelStrahl\PriceCalculator\Facade + */ +class UnitConverter +{ + /** + * @return UnitConverterService + */ + public static function getConverter(): UnitConverterService + { + return (new self)->createUnitConverter(); + } + + /** + * @return UnitConverterService + */ + private function createUnitConverter(): UnitConverterService + { + return new UnitConverterService($this->createFactory()); + } + + /** + * @return ConverterFactory + */ + private function createFactory(): ConverterFactory + { + return new ConverterFactory(); + } +} diff --git a/src/PriceCalculator.php b/src/PriceCalculator.php index 93d2b55..b5e54dd 100644 --- a/src/PriceCalculator.php +++ b/src/PriceCalculator.php @@ -34,7 +34,7 @@ public function __construct(VatInterface $vat) */ public function addPrice(float $total, float $price): float { - return (float)bcadd($total, $price); + return (float)bcadd($total, $price,2); } /** @@ -59,7 +59,7 @@ public function subPrice(float $total, float $price): float */ public function mulPrice(float $amount, float $price): float { - return (float)bcmul($price, $amount); + return (float)bcmul($price, $amount, 2); } /** diff --git a/tests/Facade/UnitConverterTest.php b/tests/Facade/UnitConverterTest.php new file mode 100644 index 0000000..e0eece3 --- /dev/null +++ b/tests/Facade/UnitConverterTest.php @@ -0,0 +1,35 @@ + + * @package MarcelStrahl\PriceCalculator\Tests\Facade + */ +class UnitConverterTest extends TestCase +{ + /** + * @return void + */ + public function testCanInitPriceCalculatorFacade(): void + { + $facade = new UnitConverterFacade(); + $this->assertInstanceOf(UnitConverterFacade::class, $facade); + } + + /** + * @return void + */ + public function testCanGetUnitConverter(): void + { + $facade = new UnitConverterFacade(); + $unitConverter = $facade::getConverter(); + + $this->assertInstanceOf(UnitConverterInterface::class, $unitConverter); + } +}