diff --git a/Classes/Domain/Model/Cart/Cart.php b/Classes/Domain/Model/Cart/Cart.php index 3fe4589f..69314128 100644 --- a/Classes/Domain/Model/Cart/Cart.php +++ b/Classes/Domain/Model/Cart/Cart.php @@ -11,8 +11,13 @@ * LICENSE file that was distributed with this source code. */ +use Extcode\Cart\Service\CurrencyTranslationServiceInterface; +use TYPO3\CMS\Core\Utility\GeneralUtility; + class Cart { + private ?CurrencyTranslationServiceInterface $currencyTranslationService = null; + protected float $net; protected float $gross; @@ -73,6 +78,8 @@ public function __construct( protected string $currencySign = '€', protected float $currencyTranslation = 1.00 ) { + $this->currencyTranslationService = GeneralUtility::makeInstance(CurrencyTranslationServiceInterface::class); + $this->net = 0.0; $this->gross = 0.0; $this->count = 0; @@ -1113,11 +1120,10 @@ public function setCurrencySign(string $currencySign): void public function translatePrice(?float $price = null): ?float { - if ($price !== null) { - $price /= $this->getCurrencyTranslation(); - return round($price * 100.0) / 100.0; + if (is_null($this->currencyTranslationService)) { + $this->currencyTranslationService = GeneralUtility::makeInstance(CurrencyTranslationServiceInterface::class); } - return null; + return $this->currencyTranslationService->translatePrice($this->getCurrencyTranslation(), $price); } } diff --git a/Classes/Service/CurrencyTranslationService.php b/Classes/Service/CurrencyTranslationService.php new file mode 100644 index 00000000..526392f6 --- /dev/null +++ b/Classes/Service/CurrencyTranslationService.php @@ -0,0 +1,24 @@ +`__ + +Description +=========== + +Currency conversion is currently very strongly linked to the cart model and the +way in which the currency conversion factor is loaded from TypoScript. + +In order to be able to obtain the conversion factor from other sources, the +calculation is carried out by the `CurrencyTranslationService`. This service is +instantiated via the `CurrencyTranslationServiceInterface` interface so that a +corresponding exchange via DI is possible. + +The implementation should only be a start and does not yet offer a stable API +because the behaviour must remain the same within the published versions. For +this reason, the `CurrencyTranslationServiceInterface` is marked as `@internal`. +Use is at your own risk! Changes to the service interface must be observed +independently in the event of updates! + +Impact +====== + +No direct impact. + +.. index:: API diff --git a/Documentation/Changelog/10.1/Index.rst b/Documentation/Changelog/10.1/Index.rst new file mode 100644 index 00000000..c74d42f7 --- /dev/null +++ b/Documentation/Changelog/10.1/Index.rst @@ -0,0 +1,20 @@ +.. include:: ../../Includes.rst.txt + +10.1 Changes +============ + +**Table of contents** + +.. contents:: + :local: + :depth: 1 + +Features +-------- + +.. toctree:: + :maxdepth: 1 + :titlesonly: + :glob: + + Feature-* diff --git a/Documentation/Changelog/Index.rst b/Documentation/Changelog/Index.rst index df6a0063..79dd8c46 100644 --- a/Documentation/Changelog/Index.rst +++ b/Documentation/Changelog/Index.rst @@ -10,6 +10,7 @@ ChangeLog :maxdepth: 5 :titlesonly: + 10.1/Index 10.0/Index 9.4/Index 9.3/Index diff --git a/Documentation/guides.xml b/Documentation/guides.xml index 39dfb9f7..651dd9cc 100644 --- a/Documentation/guides.xml +++ b/Documentation/guides.xml @@ -11,8 +11,8 @@ interlink-shortcode="extcode/cart" /> diff --git a/Tests/Unit/Domain/Model/Cart/CartCouponFixTest.php b/Tests/Unit/Domain/Model/Cart/CartCouponFixTest.php index d8c4559d..297fc959 100644 --- a/Tests/Unit/Domain/Model/Cart/CartCouponFixTest.php +++ b/Tests/Unit/Domain/Model/Cart/CartCouponFixTest.php @@ -12,8 +12,12 @@ use Extcode\Cart\Domain\Model\Cart\Cart; use Extcode\Cart\Domain\Model\Cart\CartCouponFix; use Extcode\Cart\Domain\Model\Cart\TaxClass; +use Extcode\Cart\Service\CurrencyTranslationService; +use Extcode\Cart\Service\CurrencyTranslationServiceInterface; use PHPUnit\Framework\Attributes\CoversClass; use PHPUnit\Framework\Attributes\Test; +use PHPUnit\Framework\MockObject\MockObject; +use TYPO3\CMS\Core\Utility\GeneralUtility; use TYPO3\TestingFramework\Core\Unit\UnitTestCase; #[CoversClass(CartCouponFix::class)] @@ -178,10 +182,7 @@ public function getGrossReturnsTranslatedDiscount(): void { $currencyTranslation = 2.0; - $cart = $this->getMockBuilder(Cart::class) - ->onlyMethods(['getCurrencyTranslation']) - ->setConstructorArgs([[$this->taxClass]]) - ->getMock(); + $cart = $this->createCartMock(['getGross', 'getCurrencyTranslation']); $cart->method('getCurrencyTranslation')->willReturn($currencyTranslation); $this->coupon->setCart($cart); @@ -238,10 +239,7 @@ public function isUsableReturnsTrueIfCartMinPriceIsLessToGivenPrice(): void $discount = 5.00; $cartMinPrice = 9.99; - $cart = $this->getMockBuilder(Cart::class) - ->onlyMethods(['getGross']) - ->setConstructorArgs([[$this->taxClass]]) - ->getMock(); + $cart = $this->createCartMock(); $cart->method('getGross')->willReturn($gross); $coupon = new CartCouponFix( @@ -267,10 +265,7 @@ public function isUsableReturnsTrueIfCartMinPriceIsEqualToGivenPrice(): void $discount = 5.00; $cartMinPrice = 10.00; - $cart = $this->getMockBuilder(Cart::class) - ->onlyMethods(['getGross']) - ->setConstructorArgs([[$this->taxClass]]) - ->getMock(); + $cart = $this->createCartMock(); $cart->method('getGross')->willReturn($gross); $coupon = new CartCouponFix( @@ -296,10 +291,7 @@ public function isUsableReturnsFalseIfCartMinPriceIsGreaterToGivenPrice(): void $discount = 5.00; $cartMinPrice = 10.01; - $cart = $this->getMockBuilder(Cart::class) - ->onlyMethods(['getGross']) - ->setConstructorArgs([[$this->taxClass]]) - ->getMock(); + $cart = $this->createCartMock(); $cart->method('getGross')->willReturn($gross); $coupon = new CartCouponFix( @@ -317,4 +309,17 @@ public function isUsableReturnsFalseIfCartMinPriceIsGreaterToGivenPrice(): void $coupon->isUseable() ); } + + private function createCartMock(array $methods = ['getGross']): Cart|MockObject + { + GeneralUtility::addInstance( + CurrencyTranslationServiceInterface::class, + new CurrencyTranslationService() + ); + + return $this->getMockBuilder(Cart::class) + ->onlyMethods($methods) + ->setConstructorArgs([[$this->taxClass]]) + ->getMock(); + } } diff --git a/Tests/Unit/Domain/Model/Cart/CartCouponPercentageTest.php b/Tests/Unit/Domain/Model/Cart/CartCouponPercentageTest.php index 39d8f23c..22813bd1 100644 --- a/Tests/Unit/Domain/Model/Cart/CartCouponPercentageTest.php +++ b/Tests/Unit/Domain/Model/Cart/CartCouponPercentageTest.php @@ -12,8 +12,12 @@ use Extcode\Cart\Domain\Model\Cart\Cart; use Extcode\Cart\Domain\Model\Cart\CartCouponPercentage; use Extcode\Cart\Domain\Model\Cart\TaxClass; +use Extcode\Cart\Service\CurrencyTranslationService; +use Extcode\Cart\Service\CurrencyTranslationServiceInterface; use PHPUnit\Framework\Attributes\CoversClass; use PHPUnit\Framework\Attributes\Test; +use PHPUnit\Framework\MockObject\MockObject; +use TYPO3\CMS\Core\Utility\GeneralUtility; use TYPO3\TestingFramework\Core\Unit\UnitTestCase; #[CoversClass(CartCouponPercentage::class)] @@ -151,10 +155,7 @@ public function getGrossInitiallyReturnsGrossSetDirectlyByConstructor(): void { $taxClass = new TaxClass(1, '19', 0.19, 'normal'); - $cart = $this->getMockBuilder(Cart::class) - ->onlyMethods(['getGross']) - ->setConstructorArgs([[$taxClass]]) - ->getMock(); + $cart = $this->createCartMock(); $cart->method('getGross')->willReturn(0.0); $this->coupon->setCart($cart); @@ -171,10 +172,7 @@ public function getGrossReturnsTranslatedDiscount(): void $taxClass = new TaxClass(1, '19', 0.19, 'normal'); $currencyTranslation = 1.0; - $cart = $this->getMockBuilder(Cart::class) - ->onlyMethods(['getGross', 'getCurrencyTranslation']) - ->setConstructorArgs([[$taxClass]]) - ->getMock(); + $cart = $this->createCartMock(['getGross', 'getCurrencyTranslation']); $cart->method('getGross')->willReturn(100.0); $cart->method('getCurrencyTranslation')->willReturn($currencyTranslation); @@ -191,10 +189,7 @@ public function getNetInitiallyReturnsNetSetIndirectlyByConstructor(): void { $taxClass = new TaxClass(1, '19', 0.19, 'normal'); - $cart = $this->getMockBuilder(Cart::class) - ->onlyMethods(['getGross']) - ->setConstructorArgs([[$taxClass]]) - ->getMock(); + $cart = $this->createCartMock(); $cart->method('getGross')->willReturn(0.0); $this->coupon->setCart($cart); @@ -204,10 +199,7 @@ public function getNetInitiallyReturnsNetSetIndirectlyByConstructor(): void $this->coupon->getNet() ); - $cart = $this->getMockBuilder(Cart::class) - ->onlyMethods(['getGross', 'getTaxes']) - ->setConstructorArgs([[$taxClass]]) - ->getMock(); + $cart = $this->createCartMock(['getGross', 'getTaxes']); $cart->method('getGross')->willReturn(100.0); $cart->method('getTaxes')->willReturn([$taxClass->getId() => 19.0]); @@ -242,10 +234,7 @@ public function getTaxesInitiallyReturnsTaxesSetIndirectlyByConstructor(): void { $taxClass = new TaxClass(1, '19', 0.19, 'normal'); - $cart = $this->getMockBuilder(Cart::class) - ->onlyMethods(['getGross']) - ->setConstructorArgs([[$taxClass]]) - ->getMock(); + $cart = $this->createCartMock(); $cart->method('getGross')->willReturn(0.0); $this->coupon->setCart($cart); @@ -255,10 +244,7 @@ public function getTaxesInitiallyReturnsTaxesSetIndirectlyByConstructor(): void $this->coupon->getTaxes() ); - $cart = $this->getMockBuilder(Cart::class) - ->onlyMethods(['getGross', 'getTaxes']) - ->setConstructorArgs([[$taxClass]]) - ->getMock(); + $cart = $this->createCartMock(['getGross', 'getTaxes']); $cart->method('getGross')->willReturn(100.0); $cart->method('getTaxes')->willReturn([$taxClass->getId() => 19.0]); @@ -286,10 +272,7 @@ public function isUsableReturnsTrueIfCartMinPriceIsLessToGivenPrice(): void $discount = 5.00; $cartMinPrice = 9.99; - $cart = $this->getMockBuilder(Cart::class) - ->onlyMethods(['getGross']) - ->setConstructorArgs([[$this->taxClass]]) - ->getMock(); + $cart = $this->createCartMock(); $cart->method('getGross')->willReturn($gross); $coupon = new CartCouponPercentage( @@ -314,10 +297,7 @@ public function isUsableReturnsTrueIfCartMinPriceIsEqualToGivenPrice(): void $discount = 5.00; $cartMinPrice = 10.00; - $cart = $this->getMockBuilder(Cart::class) - ->onlyMethods(['getGross']) - ->setConstructorArgs([[$this->taxClass]]) - ->getMock(); + $cart = $this->createCartMock(); $cart->method('getGross')->willReturn($gross); $coupon = new CartCouponPercentage( @@ -342,10 +322,7 @@ public function isUsableReturnsFalseIfCartMinPriceIsGreaterToGivenPrice(): void $discount = 5.00; $cartMinPrice = 10.01; - $cart = $this->getMockBuilder(Cart::class) - ->onlyMethods(['getGross']) - ->setConstructorArgs([[$this->taxClass]]) - ->getMock(); + $cart = $this->createCartMock(); $cart->method('getGross')->willReturn($gross); $coupon = new CartCouponPercentage( @@ -362,4 +339,17 @@ public function isUsableReturnsFalseIfCartMinPriceIsGreaterToGivenPrice(): void $coupon->isUseable() ); } + + private function createCartMock(array $methods = ['getGross']): Cart|MockObject + { + GeneralUtility::addInstance( + CurrencyTranslationServiceInterface::class, + new CurrencyTranslationService() + ); + + return $this->getMockBuilder(Cart::class) + ->onlyMethods($methods) + ->setConstructorArgs([[$this->taxClass]]) + ->getMock(); + } } diff --git a/Tests/Unit/Domain/Model/Cart/CartTest.php b/Tests/Unit/Domain/Model/Cart/CartTest.php index 50e3360e..8dea9f14 100644 --- a/Tests/Unit/Domain/Model/Cart/CartTest.php +++ b/Tests/Unit/Domain/Model/Cart/CartTest.php @@ -13,8 +13,11 @@ use Extcode\Cart\Domain\Model\Cart\CartCouponFix; use Extcode\Cart\Domain\Model\Cart\Product; use Extcode\Cart\Domain\Model\Cart\TaxClass; +use Extcode\Cart\Service\CurrencyTranslationService; +use Extcode\Cart\Service\CurrencyTranslationServiceInterface; use PHPUnit\Framework\Attributes\CoversClass; use PHPUnit\Framework\Attributes\Test; +use TYPO3\CMS\Core\Utility\GeneralUtility; use TYPO3\TestingFramework\Core\Unit\UnitTestCase; #[CoversClass(Cart::class)] @@ -34,7 +37,9 @@ class CartTest extends UnitTestCase public function setUp(): void { - $this->normalTaxClass = new TaxClass(1, '19', 0.19, 'Normal'); + parent::setUp(); + + $this->normalTaxClass = new TaxClass(1, '19%', 0.19, 'Normal'); $this->reducedTaxClass = new TaxClass(2, '7%', 0.07, 'Reduced'); $this->freeTaxClass = new TaxClass(3, '0%', 0.00, 'Free'); @@ -44,10 +49,8 @@ public function setUp(): void 3 => $this->freeTaxClass, ]; - $this->grossCart = new Cart($this->taxClasses, false); - $this->netCart = new Cart($this->taxClasses, true); - - parent::setUp(); + $this->grossCart = $this->createCart(false); + $this->netCart = $this->createCart(true); } public function tearDown(): void @@ -1352,6 +1355,10 @@ public function getSubtotalGrossReturnsSubtotalGross(): void $price = 100.00; $couponGross = 10.00; + GeneralUtility::addInstance( + CurrencyTranslationServiceInterface::class, + new CurrencyTranslationService() + ); $cart = $this->getMockBuilder(Cart::class) ->onlyMethods(['getCouponGross', 'getCurrencyTranslation']) ->setConstructorArgs([$this->taxClasses]) @@ -1385,6 +1392,10 @@ public function getSubtotalNetReturnsSubtotalNet(): void $couponGross = 10.00; $couponNet = $couponGross / 1.19; + GeneralUtility::addInstance( + CurrencyTranslationServiceInterface::class, + new CurrencyTranslationService() + ); $cart = $this->getMockBuilder(Cart::class) ->onlyMethods(['getCouponNet', 'getCurrencyTranslation']) ->setConstructorArgs([$this->taxClasses]) @@ -1429,7 +1440,11 @@ public function getCurrencyCodeInitiallyReturnsString(): void #[Test] public function constructorSetsCurrencyCode(): void { - $this->grossCart = new Cart( + GeneralUtility::addInstance( + CurrencyTranslationServiceInterface::class, + new CurrencyTranslationService() + ); + $cart = new Cart( $this->taxClasses, false, 'USD', @@ -1439,7 +1454,7 @@ public function constructorSetsCurrencyCode(): void self::assertSame( 'USD', - $this->grossCart->getCurrencyCode() + $cart->getCurrencyCode() ); } @@ -1478,7 +1493,11 @@ public function getCurrencySignInitiallyReturnsString(): void #[Test] public function constructorSetsCurrencySign(): void { - $this->grossCart = new Cart( + GeneralUtility::addInstance( + CurrencyTranslationServiceInterface::class, + new CurrencyTranslationService() + ); + $cart = new Cart( $this->taxClasses, false, 'USD', @@ -1488,7 +1507,7 @@ public function constructorSetsCurrencySign(): void self::assertSame( '$', - $this->grossCart->getCurrencySign() + $cart->getCurrencySign() ); } @@ -1527,6 +1546,10 @@ public function getCurrencyTranslationInitiallyReturnsFloat(): void #[Test] public function constructorSetsCurrencyTranslation(): void { + GeneralUtility::addInstance( + CurrencyTranslationServiceInterface::class, + new CurrencyTranslationService() + ); $cart = new Cart( $this->taxClasses, false, @@ -1598,4 +1621,14 @@ public function translatePriceReturnsCorrectPrice(): void $this->netCart->translatePrice(5.0) ); } + + private function createCart(bool $isNetCart): Cart + { + GeneralUtility::addInstance( + CurrencyTranslationServiceInterface::class, + new CurrencyTranslationService() + ); + + return new Cart($this->taxClasses, $isNetCart); + } } diff --git a/Tests/Unit/Domain/Model/Cart/ServiceTest.php b/Tests/Unit/Domain/Model/Cart/ServiceTest.php index 14cc2a6e..ae5c363e 100644 --- a/Tests/Unit/Domain/Model/Cart/ServiceTest.php +++ b/Tests/Unit/Domain/Model/Cart/ServiceTest.php @@ -13,8 +13,12 @@ use Extcode\Cart\Domain\Model\Cart\Product; use Extcode\Cart\Domain\Model\Cart\Service; use Extcode\Cart\Domain\Model\Cart\TaxClass; +use Extcode\Cart\Service\CurrencyTranslationService; +use Extcode\Cart\Service\CurrencyTranslationServiceInterface; use PHPUnit\Framework\Attributes\CoversClass; use PHPUnit\Framework\Attributes\Test; +use PHPUnit\Framework\MockObject\MockObject; +use TYPO3\CMS\Core\Utility\GeneralUtility; use TYPO3\TestingFramework\Core\Unit\UnitTestCase; #[CoversClass(Service::class)] @@ -36,6 +40,8 @@ class ServiceTest extends UnitTestCase public function setUp(): void { + parent::setUp(); + $this->normalTaxClass = new TaxClass(1, '19', 0.19, 'Normal'); $this->reducedTaxClass = new TaxClass(2, '7%', 0.07, 'Reduced'); $this->freeTaxClass = new TaxClass(3, '0%', 0.00, 'Free'); @@ -57,8 +63,6 @@ public function setUp(): void $this->id, $this->config ); - - parent::setUp(); } #[Test] @@ -106,30 +110,21 @@ public function isAvailableWithCartGrossInRangeReturnsTrue(): void $config ); - $cart1 = $this->getMockBuilder(Cart::class) - ->onlyMethods(['getGross']) - ->setConstructorArgs([$this->taxClasses]) - ->getMock(); + $cart1 = $this->createCartMock(); $cart1->method('getGross')->willReturn(20.00); $service->setCart($cart1); self::assertTrue( $service->isAvailable() ); - $cart2 = $this->getMockBuilder(Cart::class) - ->onlyMethods(['getGross']) - ->setConstructorArgs([$this->taxClasses]) - ->getMock(); + $cart2 = $this->createCartMock(); $cart2->method('getGross')->willReturn(50.00); $service->setCart($cart2); self::assertTrue( $service->isAvailable() ); - $cart3 = $this->getMockBuilder(Cart::class) - ->onlyMethods(['getGross']) - ->setConstructorArgs([$this->taxClasses]) - ->getMock(); + $cart3 = $this->createCartMock(); $cart3->method('getGross')->willReturn(100.00); $service->setCart($cart3); self::assertTrue( @@ -156,10 +151,7 @@ public function isAvailableWithCartGrossBelowRangeReturnsFalse(): void $config ); - $cart = $this->getMockBuilder(Cart::class) - ->onlyMethods(['getGross']) - ->setConstructorArgs([$this->taxClasses]) - ->getMock(); + $cart = $this->createCartMock(); $cart->method('getGross')->willReturn(19.99); $service->setCart($cart); @@ -188,10 +180,7 @@ public function isAvailableWithCartGrossAboveRangeReturnsFalse(): void $config ); - $cart = $this->getMockBuilder(Cart::class) - ->onlyMethods(['getGross']) - ->setConstructorArgs([$this->taxClasses]) - ->getMock(); + $cart = $this->createCartMock(); $cart->method('getGross')->willReturn(100.01); $service->setCart($cart); @@ -280,30 +269,21 @@ public function isFreeWithCartGrossInRangeReturnsTrue(): void $config ); - $cart1 = $this->getMockBuilder(Cart::class) - ->onlyMethods(['getGross']) - ->setConstructorArgs([$this->taxClasses]) - ->getMock(); + $cart1 = $this->createCartMock(); $cart1->method('getGross')->willReturn(20.00); $service->setCart($cart1); self::assertTrue( $service->isFree() ); - $cart2 = $this->getMockBuilder(Cart::class) - ->onlyMethods(['getGross']) - ->setConstructorArgs([$this->taxClasses]) - ->getMock(); + $cart2 = $this->createCartMock(); $cart2->method('getGross')->willReturn(50.00); $service->setCart($cart2); self::assertTrue( $service->isFree() ); - $cart3 = $this->getMockBuilder(Cart::class) - ->onlyMethods(['getGross']) - ->setConstructorArgs([$this->taxClasses]) - ->getMock(); + $cart3 = $this->createCartMock(); $cart3->method('getGross')->willReturn(100.00); $service->setCart($cart3); self::assertTrue( @@ -330,10 +310,7 @@ public function isFreeWithCartGrossBelowRangeReturnsFalse(): void $config ); - $cart = $this->getMockBuilder(Cart::class) - ->onlyMethods(['getGross']) - ->setConstructorArgs([$this->taxClasses]) - ->getMock(); + $cart = $this->createCartMock(); $cart->method('getGross')->willReturn(19.99); $service->setCart($cart); @@ -362,10 +339,7 @@ public function isFreeWithCartGrossAboveRangeReturnsFalse(): void $config ); - $cart = $this->getMockBuilder(Cart::class) - ->onlyMethods(['getGross']) - ->setConstructorArgs([$this->taxClasses]) - ->getMock(); + $cart = $this->createCartMock(); $cart->method('getGross')->willReturn(100.01); $service->setCart($cart); @@ -377,10 +351,7 @@ public function isFreeWithCartGrossAboveRangeReturnsFalse(): void #[Test] public function taxClassIdsGreaterZeroReturnsTaxClass(): void { - $cart = $this->getMockBuilder(Cart::class) - ->onlyMethods(['getGross']) - ->setConstructorArgs([$this->taxClasses]) - ->getMock(); + $cart = $this->createCartMock(); $cart->method('getGross')->willReturn(20.00); $config = [ @@ -431,10 +402,7 @@ public function forTaxClassIdMinusOneTheHighestUsedTaxRateWillBeUsed(): void $config ); - $cart = $this->getMockBuilder(Cart::class) - ->onlyMethods(['getGross']) - ->setConstructorArgs([$this->taxClasses]) - ->getMock(); + $cart = $this->createCartMock(); $cart->method('getGross')->willReturn(100.00); $firstCartProductPrice = 10.00; @@ -496,4 +464,17 @@ public function forTaxClassIdMinusTwoReturnsPseudoTaxClassWithIdMinusTwo(): void $service->getTaxClass()->getId() ); } + + private function createCartMock(array $methods = ['getGross']): Cart|MockObject + { + GeneralUtility::addInstance( + CurrencyTranslationServiceInterface::class, + new CurrencyTranslationService() + ); + + return $this->getMockBuilder(Cart::class) + ->onlyMethods($methods) + ->setConstructorArgs([$this->taxClasses]) + ->getMock(); + } } diff --git a/ext_emconf.php b/ext_emconf.php index b9e29680..35f8872d 100644 --- a/ext_emconf.php +++ b/ext_emconf.php @@ -4,7 +4,7 @@ 'title' => 'Cart', 'description' => 'Shopping Cart(s) for TYPO3', 'category' => 'plugin', - 'version' => '10.0.0', + 'version' => '10.1.0', 'state' => 'stable', 'author' => 'Daniel Gohlke', 'author_email' => 'ext@extco.de',