diff --git a/src/ApiPlatform/Resources/Manufacturer/BulkManufacturers.php b/src/ApiPlatform/Resources/Manufacturer/BulkManufacturers.php new file mode 100644 index 00000000..9c9a2f8d --- /dev/null +++ b/src/ApiPlatform/Resources/Manufacturer/BulkManufacturers.php @@ -0,0 +1,62 @@ + + * @copyright Since 2007 PrestaShop SA and Contributors + * @license https://opensource.org/licenses/AFL-3.0 Academic Free License version 3.0 + */ + +declare(strict_types=1); + +namespace PrestaShop\Module\APIResources\ApiPlatform\Resources\Manufacturer; + +use ApiPlatform\Metadata\ApiProperty; +use ApiPlatform\Metadata\ApiResource; +use PrestaShop\PrestaShop\Core\Domain\Manufacturer\Command\BulkDeleteManufacturerCommand; +use PrestaShop\PrestaShop\Core\Domain\Manufacturer\Exception\DeleteManufacturerException; +use PrestaShop\PrestaShop\Core\Domain\Manufacturer\Exception\ManufacturerException; +use PrestaShop\PrestaShop\Core\Domain\Manufacturer\Exception\ManufacturerNotFoundException; +use PrestaShopBundle\ApiPlatform\Metadata\CQRSUpdate; +use Symfony\Component\HttpFoundation\Response; +use Symfony\Component\Validator\Constraints as Assert; + +#[ApiResource( + operations: [ + new CQRSUpdate( + uriTemplate: '/manufacturers/delete', + // No output 204 code + output: false, + CQRSCommand: BulkDeleteManufacturerCommand::class, + scopes: [ + 'manufacturer_write', + ], + ), + ], + exceptionToStatus: [ + ManufacturerNotFoundException::class => Response::HTTP_NOT_FOUND, + DeleteManufacturerException::class => Response::HTTP_INTERNAL_SERVER_ERROR, + ManufacturerException::class => Response::HTTP_INTERNAL_SERVER_ERROR, + ], +)] +class BulkManufacturers +{ + /** + * @var int[] + */ + #[ApiProperty(openapiContext: ['type' => 'array', 'items' => ['type' => 'integer'], 'example' => [1, 3]])] + #[Assert\NotBlank] + public array $manufacturerIds; +} diff --git a/src/ApiPlatform/Resources/Manufacturer/Manufacturer.php b/src/ApiPlatform/Resources/Manufacturer/Manufacturer.php new file mode 100644 index 00000000..59b7d20a --- /dev/null +++ b/src/ApiPlatform/Resources/Manufacturer/Manufacturer.php @@ -0,0 +1,188 @@ + + * @copyright Since 2007 PrestaShop SA and Contributors + * @license https://opensource.org/licenses/AFL-3.0 Academic Free License version 3.0 + */ + +declare(strict_types=1); + +namespace PrestaShop\Module\APIResources\ApiPlatform\Resources\Manufacturer; + +use ApiPlatform\Metadata\ApiProperty; +use ApiPlatform\Metadata\ApiResource; +use PrestaShop\Module\APIResources\Validation\IframeValidationGroupsResolver; +use PrestaShop\PrestaShop\Core\ConstraintValidator\Constraints\DefaultLanguage; +use PrestaShop\PrestaShop\Core\ConstraintValidator\Constraints\TypedRegex; +use PrestaShop\PrestaShop\Core\Domain\Manufacturer\Command\AddManufacturerCommand; +use PrestaShop\PrestaShop\Core\Domain\Manufacturer\Command\DeleteManufacturerCommand; +use PrestaShop\PrestaShop\Core\Domain\Manufacturer\Command\EditManufacturerCommand; +use PrestaShop\PrestaShop\Core\Domain\Manufacturer\Exception\ManufacturerConstraintException; +use PrestaShop\PrestaShop\Core\Domain\Manufacturer\Exception\ManufacturerException; +use PrestaShop\PrestaShop\Core\Domain\Manufacturer\Exception\ManufacturerNotFoundException; +use PrestaShop\PrestaShop\Core\Domain\Manufacturer\Query\GetManufacturerForEditing; +use PrestaShopBundle\ApiPlatform\Metadata\CQRSCreate; +use PrestaShopBundle\ApiPlatform\Metadata\CQRSDelete; +use PrestaShopBundle\ApiPlatform\Metadata\CQRSGet; +use PrestaShopBundle\ApiPlatform\Metadata\CQRSPartialUpdate; +use PrestaShopBundle\ApiPlatform\Metadata\LocalizedValue; +use Symfony\Component\HttpFoundation\Response; +use Symfony\Component\Validator\Constraints as Assert; + +#[ApiResource( + operations: [ + // GET /manufacturer/{manufacturerId} + new CQRSGet( + uriTemplate: '/manufacturer/{manufacturerId}', + requirements: ['manufacturerId' => '\d+'], + CQRSQuery: GetManufacturerForEditing::class, + scopes: ['manufacturer_read'], + CQRSQueryMapping: self::QUERY_MAPPING, + ), + // POST /manufacturer + new CQRSCreate( + uriTemplate: '/manufacturer', + validationContext: [IframeValidationGroupsResolver::class, 'create'], + CQRSCommand: AddManufacturerCommand::class, + CQRSQuery: GetManufacturerForEditing::class, + scopes: ['manufacturer_write'], + CQRSQueryMapping: self::QUERY_MAPPING, + CQRSCommandMapping: self::COMMAND_MAPPING, + ), + new CQRSPartialUpdate( + uriTemplate: '/manufacturer/{manufacturerId}', + validationContext: [IframeValidationGroupsResolver::class, 'create'], + requirements: ['manufacturerId' => '\d+'], + CQRSCommand: EditManufacturerCommand::class, + CQRSQuery: GetManufacturerForEditing::class, + scopes: ['manufacturer_write'], + CQRSQueryMapping: self::QUERY_MAPPING, + CQRSCommandMapping: self::COMMAND_MAPPING, + ), + new CQRSDelete( + uriTemplate: '/manufacturer/{manufacturerId}', + requirements: ['manufacturerId' => '\d+'], + CQRSCommand: DeleteManufacturerCommand::class, + scopes: ['manufacturer_write'], + ), + ], + exceptionToStatus: [ + ManufacturerNotFoundException::class => Response::HTTP_NOT_FOUND, + ManufacturerConstraintException::class => Response::HTTP_UNPROCESSABLE_ENTITY, + ManufacturerException::class => Response::HTTP_UNPROCESSABLE_ENTITY, + ], +)] +class Manufacturer +{ + #[ApiProperty(identifier: true)] + public int $manufacturerId; + + #[Assert\NotBlank(groups: ['Create'])] + #[TypedRegex(['type' => TypedRegex::TYPE_CATALOG_NAME])] + public string $name; + + #[ApiProperty( + required: false, + openapiContext: ['nullable' => true] + )] + public ?array $logoImage = null; + + #[LocalizedValue] + #[DefaultLanguage(groups: ['Create'], fieldName: 'shortDescriptions')] + #[DefaultLanguage(groups: ['Update'], fieldName: 'shortDescriptions', allowNull: true)] + #[Assert\All(constraints: [ + new TypedRegex([ + 'type' => TypedRegex::CLEAN_HTML_NO_IFRAME, + 'groups' => ['NoIframe'], + ]), + new TypedRegex([ + 'type' => TypedRegex::CLEAN_HTML_ALLOW_IFRAME, + 'groups' => ['AllowIframe'], + ]), + ])] + public array $shortDescriptions; + + #[LocalizedValue] + #[DefaultLanguage(groups: ['Create'], fieldName: 'descriptions')] + #[DefaultLanguage(groups: ['Update'], fieldName: 'descriptions', allowNull: true)] + #[Assert\All(constraints: [ + new TypedRegex([ + 'type' => TypedRegex::CLEAN_HTML_NO_IFRAME, + 'groups' => ['NoIframe'], + ]), + new TypedRegex([ + 'type' => TypedRegex::CLEAN_HTML_ALLOW_IFRAME, + 'groups' => ['AllowIframe'], + ]), + ])] + public array $descriptions; + + #[LocalizedValue] + #[DefaultLanguage(groups: ['Create'], fieldName: 'metaTitles')] + #[DefaultLanguage(groups: ['Update'], fieldName: 'metaTitles', allowNull: true)] + #[Assert\All(constraints: [ + new TypedRegex([ + 'type' => TypedRegex::TYPE_GENERIC_NAME, + ]), + ])] + public array $metaTitles; + + #[LocalizedValue] + #[DefaultLanguage(groups: ['Create'], fieldName: 'metaDescriptions')] + #[DefaultLanguage(groups: ['Update'], fieldName: 'metaDescriptions', allowNull: true)] + #[Assert\All(constraints: [ + new TypedRegex([ + 'type' => TypedRegex::TYPE_GENERIC_NAME, + ]), + ])] + public array $metaDescriptions; + + #[LocalizedValue] + public array $metaKeywords; + + #[ApiProperty(openapiContext: ['type' => 'array', 'items' => ['type' => 'integer']])] + #[Assert\NotBlank(allowNull: true)] + public array $shopIds; + + #[Assert\Type(type: 'bool')] + public bool $enabled; + + public const QUERY_MAPPING = [ + '[manufacturerId]' => '[manufacturerId]', + '[name]' => '[name]', + '[logoImage]' => '[logoImage]', + '[localizedShortDescriptions]' => '[shortDescriptions]', + '[localizedMetaTitles]' => '[metaTitles]', + '[localizedDescriptions]' => '[descriptions]', + '[localizedMetaDescriptions]' => '[metaDescriptions]', + '[localizedMetaKeywords]' => '[metaKeywords]', + '[enabled]' => '[enabled]', + '[associatedShops]' => '[shopIds]', + ]; + + public const COMMAND_MAPPING = [ + '[manufacturerId]' => '[manufacturerId]', + '[name]' => '[name]', + '[logoImage]' => '[logoImage]', + '[shortDescriptions]' => '[localizedShortDescriptions]', + '[metaTitles]' => '[localizedMetaTitles]', + '[descriptions]' => '[localizedDescriptions]', + '[metaDescriptions]' => '[localizedMetaDescriptions]', + '[enabled]' => '[enabled]', + '[shopIds]' => '[shopAssociation]', + ]; +} diff --git a/src/ApiPlatform/Resources/Manufacturer/ManufacturerDetail.php b/src/ApiPlatform/Resources/Manufacturer/ManufacturerDetail.php new file mode 100644 index 00000000..99a7a2aa --- /dev/null +++ b/src/ApiPlatform/Resources/Manufacturer/ManufacturerDetail.php @@ -0,0 +1,74 @@ + + * @copyright Since 2007 PrestaShop SA and Contributors + * @license https://opensource.org/licenses/AFL-3.0 Academic Free License version 3.0 + */ + +declare(strict_types=1); + +namespace PrestaShop\Module\APIResources\ApiPlatform\Resources\Manufacturer; + +use ApiPlatform\Metadata\ApiProperty; +use ApiPlatform\Metadata\ApiResource; +use PrestaShop\PrestaShop\Core\Domain\Manufacturer\Exception\ManufacturerConstraintException; +use PrestaShop\PrestaShop\Core\Domain\Manufacturer\Exception\ManufacturerException; +use PrestaShop\PrestaShop\Core\Domain\Manufacturer\Exception\ManufacturerNotFoundException; +use PrestaShop\PrestaShop\Core\Domain\Manufacturer\Query\GetManufacturerForViewing; +use PrestaShopBundle\ApiPlatform\Metadata\CQRSGet; +use Symfony\Component\HttpFoundation\Response; + +#[ApiResource( + operations: [ + // GET /manufacturer/{manufacturerId}/details/{languageId} + new CQRSGet( + uriTemplate: '/manufacturer/{manufacturerId}/details/{languageId}', + requirements: [ + 'manufacturerId' => '\d+', + 'languageId' => '\d+', + ], + CQRSQuery: GetManufacturerForViewing::class, + scopes: ['manufacturer_read'], + CQRSQueryMapping: self::QUERY_MAPPING, + ), + ], + exceptionToStatus: [ + ManufacturerConstraintException::class => Response::HTTP_UNPROCESSABLE_ENTITY, + ManufacturerNotFoundException::class => Response::HTTP_NOT_FOUND, + ManufacturerException::class => Response::HTTP_UNPROCESSABLE_ENTITY, + ], +)] +class ManufacturerDetail +{ + #[ApiProperty(identifier: true, readable: false)] + public int $manufacturerId = 0; + + #[ApiProperty(identifier: true, readable: false)] + public int $languageId = 0; + + public string $name; + + public array $products = []; + + public array $addresses = []; + + public const QUERY_MAPPING = [ + '[name]' => '[name]', + '[manufacturerProducts]' => '[products]', + '[manufacturerAddresses]' => '[addresses]', + ]; +} diff --git a/src/ApiPlatform/Resources/Manufacturer/ManufacturerList.php b/src/ApiPlatform/Resources/Manufacturer/ManufacturerList.php new file mode 100644 index 00000000..da900026 --- /dev/null +++ b/src/ApiPlatform/Resources/Manufacturer/ManufacturerList.php @@ -0,0 +1,76 @@ + + * @copyright Since 2007 PrestaShop SA and Contributors + * @license https://opensource.org/licenses/AFL-3.0 Academic Free License version 3.0 + */ + +declare(strict_types=1); + +namespace PrestaShop\Module\APIResources\ApiPlatform\Resources\Manufacturer; + +use ApiPlatform\Metadata\ApiProperty; +use ApiPlatform\Metadata\ApiResource; +use Doctrine\DBAL\Exception\InvalidFieldNameException; +use PrestaShop\PrestaShop\Core\Domain\Manufacturer\Exception\ManufacturerConstraintException; +use PrestaShop\PrestaShop\Core\Domain\Manufacturer\Exception\ManufacturerException; +use PrestaShopBundle\ApiPlatform\Metadata\PaginatedList; +use Symfony\Component\HttpFoundation\Response; + +#[ApiResource( + operations: [ + new PaginatedList( + uriTemplate: '/manufacturers', + scopes: [ + 'manufacturer_read', + ], + ApiResourceMapping: self::MAPPING, + gridDataFactory: 'prestashop.core.grid.data.factory.manufacturer_decorator', + filtersMapping: [ + '[manufacturerId]' => '[id_manufacturer]', + ], + ), + ], + exceptionToStatus: [ + InvalidFieldNameException::class => Response::HTTP_UNPROCESSABLE_ENTITY, + ManufacturerConstraintException::class => Response::HTTP_UNPROCESSABLE_ENTITY, + ManufacturerException::class => Response::HTTP_UNPROCESSABLE_ENTITY, + ], +)] +class ManufacturerList +{ + #[ApiProperty(identifier: true)] + public int $manufacturerId; + + public string $name; + + public ?string $logo; + + public int $productCount; + + public int|string $addressesCount; + + public bool $enabled; + + public const MAPPING = [ + '[id_manufacturer]' => '[manufacturerId]', + '[name]' => '[name]', + '[products_count]' => '[productsCount]', + '[addresses_count]' => '[addressesCount]', + '[active]' => '[enabled]', + ]; +} diff --git a/tests/Integration/ApiPlatform/ManufacturerEndpointTest.php b/tests/Integration/ApiPlatform/ManufacturerEndpointTest.php new file mode 100644 index 00000000..ff67b7ed --- /dev/null +++ b/tests/Integration/ApiPlatform/ManufacturerEndpointTest.php @@ -0,0 +1,433 @@ + + * @copyright Since 2007 PrestaShop SA and Contributors + * @license https://opensource.org/licenses/AFL-3.0 Academic Free License version 3.0 + */ + +declare(strict_types=1); + +namespace PsApiResourcesTest\Integration\ApiPlatform; + +use Symfony\Component\HttpFoundation\Response; +use Tests\Resources\DatabaseDump; +use Tests\Resources\Resetter\LanguageResetter; + +class ManufacturerEndpointTest extends ApiTestCase +{ + public static function setUpBeforeClass(): void + { + parent::setUpBeforeClass(); + // Add the fr-FR language to test multi lang values accurately + LanguageResetter::resetLanguages(); + self::addLanguageByLocale('fr-FR'); + self::resetTables(); + // Pre-create the API Client with the needed scopes, this way we reduce the number of created API Clients + self::createApiClient(['manufacturer_write', 'manufacturer_read']); + } + + public static function tearDownAfterClass(): void + { + parent::tearDownAfterClass(); + // Reset DB as it was before this test + LanguageResetter::resetLanguages(); + self::resetTables(); + } + + protected static function resetTables(): void + { + DatabaseDump::restoreTables([ + 'manufacturer', + 'manufacturer_lang', + 'manufacturer_shop', + ]); + } + + public static function getProtectedEndpoints(): iterable + { + yield 'get endpoint' => [ + 'GET', + '/manufacturer/1', + ]; + + yield 'get details endpoint' => [ + 'GET', + '/manufacturer/1/details/1', + ]; + + yield 'create endpoint' => [ + 'POST', + '/manufacturer', + ]; + + yield 'patch endpoint' => [ + 'PATCH', + '/manufacturer/1', + ]; + + yield 'bulk delete endpoint' => [ + 'PUT', + '/manufacturers/delete', + ]; + + yield 'delete endpoint' => [ + 'DELETE', + '/manufacturer/1', + ]; + } + + public function testAddManufacturer(): int + { + $itemsCount = $this->countItems('/manufacturers', ['manufacturer_read']); + $postData = [ + 'name' => 'manufacturer name', + 'shortDescriptions' => [ + 'en-US' => 'short description en', + 'fr-FR' => 'short description fr', + ], + 'descriptions' => [ + 'en-US' => 'description en', + 'fr-FR' => 'description fr', + ], + 'metaTitles' => [ + 'en-US' => 'meta title en', + 'fr-FR' => 'meta title fr', + ], + 'metaDescriptions' => [ + 'en-US' => 'meta description en', + 'fr-FR' => 'meta description fr', + ], + 'shopIds' => [1], + 'enabled' => true, + ]; + // Create an manufacturer, the POST endpoint returns the created item as JSON + $manufacturer = $this->createItem('/manufacturer', $postData, ['manufacturer_write']); + $this->assertArrayHasKey('manufacturerId', $manufacturer); + $manufacturerId = $manufacturer['manufacturerId']; + + // We assert the returned data matches what was posted (plus the ID) + $this->assertEquals( + ['manufacturerId' => $manufacturerId] + $postData, + $manufacturer + ); + + $newItemsCount = $this->countItems('/manufacturers', ['manufacturer_read']); + $this->assertEquals($itemsCount + 1, $newItemsCount); + + return $manufacturerId; + } + + /** + * @depends testAddManufacturer + * + * @param int $manufacturerId + * + * @return int + */ + public function testGetManufacturer(int $manufacturerId): int + { + $manufacturer = $this->getItem('/manufacturer/' . $manufacturerId, ['manufacturer_read']); + $this->assertEquals([ + 'manufacturerId' => $manufacturerId, + 'name' => 'manufacturer name', + 'shortDescriptions' => [ + 'en-US' => 'short description en', + 'fr-FR' => 'short description fr', + ], + 'descriptions' => [ + 'en-US' => 'description en', + 'fr-FR' => 'description fr', + ], + 'metaTitles' => [ + 'en-US' => 'meta title en', + 'fr-FR' => 'meta title fr', + ], + 'metaDescriptions' => [ + 'en-US' => 'meta description en', + 'fr-FR' => 'meta description fr', + ], + 'shopIds' => [1], + 'enabled' => true, + ], $manufacturer); + + return $manufacturerId; + } + + /** + * @depends testGetManufacturer + * + * @param int $manufacturerId + * + * @return int + */ + public function testGetManufacturerDetails(int $manufacturerId): int + { + $manufacturer = $this->getItem('/manufacturer/' . $manufacturerId . '/details/1', ['manufacturer_read']); + + $this->assertEquals([ + 'name' => 'manufacturer name', + 'products' => [], + 'addresses' => [], + ], $manufacturer); + + return $manufacturerId; + } + + /** + * @depends testGetManufacturer + * + * @param int $manufacturerId + * + * @return int + */ + public function testUpdatePartialManufacturer(int $manufacturerId): int + { + $patchData = [ + 'name' => 'updated manufacturer', + 'enabled' => true, + 'shortDescriptions' => [ + 'en-US' => 'updated short desc en', + 'fr-FR' => 'updated short desc fr', + ], + 'descriptions' => [ + 'en-US' => 'updated description en', + 'fr-FR' => 'updated description fr', + ], + 'metaTitles' => [ + 'en-US' => 'updated meta title en', + 'fr-FR' => 'updated meta title en', + ], + 'metaDescriptions' => [ + 'en-US' => 'updated meta description en', + 'fr-FR' => 'updated meta description fr', + ], + 'shopIds' => [1], + ]; + + $updatedManufacturer = $this->partialUpdateItem('/manufacturer/' . $manufacturerId, $patchData, ['manufacturer_write']); + $this->assertEquals(['manufacturerId' => $manufacturerId] + $patchData, $updatedManufacturer); + + // We check that when we GET the item it is updated as expected + $manufacturer = $this->getItem('/manufacturer/' . $manufacturerId, ['manufacturer_read']); + $this->assertEquals(['manufacturerId' => $manufacturerId] + $patchData, $manufacturer); + + // Test partial update + $partialUpdateData = [ + 'name' => 'updated manufacturer name', + 'enabled' => false, + 'shortDescriptions' => [ + 'en-US' => 'updated short description en', + 'fr-FR' => 'updated short description fr', + ], + ]; + $expectedUpdatedData = [ + 'manufacturerId' => $manufacturerId, + 'name' => 'updated manufacturer name', + 'enabled' => false, + 'shortDescriptions' => [ + 'en-US' => 'updated short description en', + 'fr-FR' => 'updated short description fr', + ], + 'descriptions' => [ + 'en-US' => 'updated description en', + 'fr-FR' => 'updated description fr', + ], + 'metaTitles' => [ + 'en-US' => 'updated meta title en', + 'fr-FR' => 'updated meta title en', + ], + 'metaDescriptions' => [ + 'en-US' => 'updated meta description en', + 'fr-FR' => 'updated meta description fr', + ], + 'shopIds' => [1], + ]; + + $updatedManufacturer = $this->partialUpdateItem('/manufacturer/' . $manufacturerId, $partialUpdateData, ['manufacturer_write']); + $this->assertEquals($expectedUpdatedData, $updatedManufacturer); + + return $manufacturerId; + } + + /** + * @depends testUpdatePartialManufacturer + * + * @param int $manufacturerId + * + * @return int + */ + public function testListManufacturers(int $manufacturerId): int + { + // List by manufacturerId in descending order so the created one comes first (and test ordering at the same time) + foreach (['manufacturerId', 'active', 'products_count', 'addresses_count', 'name'] as $orderBy) { + $paginatedManufacturers = $this->listItems('/manufacturers?orderBy=' . $orderBy . '&sortOrder=desc', ['manufacturer_read']); + $this->assertGreaterThanOrEqual(1, $paginatedManufacturers['totalItems']); + + // Check the details to make sure filters mapping is correct + $this->assertEquals($orderBy, $paginatedManufacturers['orderBy']); + } + + // Test manufacturer should be the first returned in the list + $testManufacturer = $paginatedManufacturers['items'][0]; + + $expectedManufacturer = [ + 'manufacturerId' => $manufacturerId, + 'name' => 'updated manufacturer name', + 'addressesCount' => '--', + 'enabled' => false, + ]; + $this->assertEquals($expectedManufacturer, $testManufacturer); + + $filteredManufacturers = $this->listItems('/manufacturers', ['manufacturer_read'], [ + 'manufacturerId' => $manufacturerId, + ]); + $this->assertEquals(1, $filteredManufacturers['totalItems']); + + $testManufacturer = $filteredManufacturers['items'][0]; + $this->assertEquals($expectedManufacturer, $testManufacturer); + + // Check the filters details + $this->assertEquals([ + 'manufacturerId' => $manufacturerId, + ], $filteredManufacturers['filters']); + + return $manufacturerId; + } + + /** + * @depends testListManufacturers + * + * @param int $manufacturerId + */ + public function testRemoveManufacturer(int $manufacturerId): void + { + // Delete the item + $return = $this->deleteItem('/manufacturer/' . $manufacturerId, ['manufacturer_write']); + // This endpoint return empty response and 204 HTTP code + $this->assertNull($return); + + // Getting the item should result in a 404 now + $this->getItem('/manufacturer/' . $manufacturerId, ['manufacturer_read'], Response::HTTP_NOT_FOUND); + } + + /** + * @depends testListManufacturers + * + * @param int $manufacturerId + */ + public function testBulkRemoveManufacturers(): void + { + // We create another manufacturer + $postData = [ + 'name' => 'manufacturer name', + 'shortDescriptions' => [ + 'en-US' => 'short description en', + 'fr-FR' => 'short description fr', + ], + 'descriptions' => [ + 'en-US' => 'description en', + 'fr-FR' => 'description fr', + ], + 'metaTitles' => [ + 'en-US' => 'meta title en', + 'fr-FR' => 'meta title fr', + ], + 'metaDescriptions' => [ + 'en-US' => 'meta description en', + 'fr-FR' => 'meta description fr', + ], + 'shopIds' => [1], + 'enabled' => true, + ]; + // Create an manufacturer, the POST endpoint returns the created item as JSON + $manufacturer = $this->createItem('/manufacturer', $postData, ['manufacturer_write']); + + $manufacturers = $this->listItems('/manufacturers', ['manufacturer_read']); + + // There are currently tree manufacturers + $this->assertEquals(3, $manufacturers['totalItems']); + + // We remove two manufacturers + $removeManufacturerIds = [ + $manufacturers['items'][0]['manufacturerId'], + $manufacturers['items'][2]['manufacturerId'], + ]; + + $this->updateItem('/manufacturers/delete', [ + 'manufacturerIds' => $removeManufacturerIds, + ], ['manufacturer_write'], Response::HTTP_NO_CONTENT); + + // Assert the provided manufacturers have been removed + foreach ($removeManufacturerIds as $manufacturerId) { + $this->getItem('/manufacturer/' . $manufacturerId, ['manufacturer_read'], Response::HTTP_NOT_FOUND); + } + + // Only two manufacturer remain + $this->assertEquals(1, $this->countItems('/manufacturers', ['manufacturer_read'])); + } + + public function testInvalidFilterManufacturers() + { + $orderByInvalid = 'INVALID_FILTER'; + + $this->requestApi('GET', '/manufacturers?orderBy=' . $orderByInvalid . '&sortOrder=desc', null, ['manufacturer_read'], Response::HTTP_UNPROCESSABLE_ENTITY); + } + + public function testInvalidManufacturer(): void + { + $manufacturer = $this->getItem('/manufacturer/9999', ['manufacturer_read'], Response::HTTP_NOT_FOUND); + + $manufacturerInvalidData = [ + 'name' => 'updated manufacturer name', + 'enabled' => false, + 'shortDescriptions' => [ + //