diff --git a/.github/workflows/build-actions.yml b/.github/workflows/build-actions.yml new file mode 100644 index 0000000..a8b8644 --- /dev/null +++ b/.github/workflows/build-actions.yml @@ -0,0 +1,51 @@ +name: Unit tests and checkstyle +on: [push] +jobs: + phpunit: + runs-on: ${{ matrix.operating-system }} + strategy: + matrix: + operating-system: ['ubuntu-latest'] + php-versions: ['8.2', '8.3'] + phpunit-versions: ['latest'] + include: + - operating-system: 'ubuntu-latest' + php-versions: '8.2' + phpunit-versions: 10 + steps: + - name: Checkout + uses: actions/checkout@v4 + + - name: Setup PHP + uses: shivammathur/setup-php@v2 + with: + php-version: ${{ matrix.php-versions }} + extensions: mbstring + coverage: xdebug + tools: composer:v2, php-cs-fixer, phpunit:${{ matrix.phpunit-versions }} + + - name: Get composer cache directory + id: composer-cache + run: echo "dir=$(composer config cache-files-dir)" >> $GITHUB_OUTPUT + + - name: Cache dependencies + uses: actions/cache@v3 + with: + path: ${{ steps.composer-cache.outputs.dir }} + key: ${{ runner.os }}-composer-${{ hashFiles('**/composer.lock') }} + restore-keys: ${{ runner.os }}-composer- + + - name: Install dependencies + run: composer install --prefer-dist + + - name: Run PHPCS + run: ./vendor/bin/phpcs src tests -v --standard=PSR2 + + - name: Run Psalm + run: ./vendor/bin/psalm --show-info=true + + - name: Run PHPStan + run: ./vendor/bin/phpstan analyse --level=5 src tests + + - name: Run PHPUnit + run: ./vendor/bin/phpunit --coverage-text --colors diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..cd23d83 --- /dev/null +++ b/.gitignore @@ -0,0 +1,11 @@ +# IDE +/.idea/ + +# PHP Unit +.phpunit.cache +.phpunit.result.cache + +# Composer +composer.lock +composer.phar +/vendor/ diff --git a/README.md b/README.md new file mode 100644 index 0000000..8b16544 --- /dev/null +++ b/README.md @@ -0,0 +1,6 @@ +## Requirements +[![PHP Version Require](http://poser.pugx.org/inserve/also-cloud-marketplace-api-php/require/php)](https://packagist.org/packages/inserve/also-cloud-marketplace-api-php) + +## Installation +`composer require inserve/also-cloud-marketplace-api-php` + diff --git a/composer.json b/composer.json new file mode 100644 index 0000000..d143aba --- /dev/null +++ b/composer.json @@ -0,0 +1,37 @@ +{ + "name": "inserve/also-cloud-marketplace-api-php", + "description": "A PHP wrapper ALSO Cloud Marketplace", + "license": "MIT", + "type": "library", + "require": { + "php": "^8.2", + "guzzlehttp/guzzle": "^7.7", + "symfony/serializer": "^6.3|^7", + "symfony/property-access": "^6.3|^7", + "psr/log": "^3.0", + "phpdocumentor/reflection-docblock": "^5.3" + }, + "require-dev": { + "phpunit/phpunit": "^10.2", + "squizlabs/php_codesniffer": "^3.7", + "phpstan/phpstan": "^1.10", + "vimeo/psalm": "^5.22" + }, + "autoload": { + "psr-4": { + "Inserve\\ALSOCloudMarketplaceAPI\\": "src/" + } + }, + "autoload-dev": { + "psr-4": { + "Inserve\\ALSOCloudMarketplaceAPI\\Tests\\": "tests/" + } + }, + "authors": [ + { + "name": "Inserve", + "email": "dev@inserve.nl" + } + ], + "minimum-stability": "stable" +} diff --git a/phpunit.xml b/phpunit.xml new file mode 100644 index 0000000..0fe1e4a --- /dev/null +++ b/phpunit.xml @@ -0,0 +1,25 @@ + + + + + tests + + + + + + src + + + diff --git a/psalm.xml b/psalm.xml new file mode 100644 index 0000000..a9624f0 --- /dev/null +++ b/psalm.xml @@ -0,0 +1,18 @@ + + + + + + + + + + diff --git a/src/API/AbstractAPIClient.php b/src/API/AbstractAPIClient.php new file mode 100644 index 0000000..749c0d7 --- /dev/null +++ b/src/API/AbstractAPIClient.php @@ -0,0 +1,18 @@ +apiClient->call( + '/GetCompany', + json_encode(compact('accountId')) + ); + + return $this->apiClient->denormalize($response, Company::class); + } + + /** + * @param int $parentAccountId + * + * @return Company[] + * + * @throws MarketplaceAPIException|ExceptionInterface + */ + public function list(int $parentAccountId): array + { + $response = $this->apiClient->call( + '/GetCompanies', + json_encode(compact('parentAccountId')) + ); + + $companies = []; + foreach ($response as $item) { + $companies[] = $this->apiClient->denormalize($item, Company::class); + } + + return $companies; + } +} diff --git a/src/API/SubscriptionsAPI.php b/src/API/SubscriptionsAPI.php new file mode 100644 index 0000000..86568e5 --- /dev/null +++ b/src/API/SubscriptionsAPI.php @@ -0,0 +1,53 @@ +apiClient->call( + '/GetSubscription', + json_encode(compact('accountId')) + ); + + return $this->apiClient->denormalize($response, Subscription::class); + } + + /** + * @param int $parentAccountId + * @param bool $excludeUserLevel + * + * @return Subscription[] + * + * @throws MarketplaceAPIException|ExceptionInterface + */ + public function list(int $parentAccountId, bool $excludeUserLevel = false): array + { + $response = $this->apiClient->call( + '/GetSubscriptions', + json_encode(compact('parentAccountId', 'excludeUserLevel')) + ); + + $subscriptions = []; + foreach ($response as $item) { + $subscriptions[] = $this->apiClient->denormalize($item, Subscription::class); + } + + return $subscriptions; + } +} diff --git a/src/Client/APIClient.php b/src/Client/APIClient.php new file mode 100644 index 0000000..8f84245 --- /dev/null +++ b/src/Client/APIClient.php @@ -0,0 +1,185 @@ +normalizer = new ObjectNormalizer( + classMetadataFactory: $classMetadataFactory, + nameConverter: $nameConverter, + propertyTypeExtractor: $extractor, + defaultContext: [AbstractObjectNormalizer::SKIP_NULL_VALUES => true] + ); + + $this->serializer = new Serializer( + [$this->normalizer, new ArrayDenormalizer()], + [new JsonEncoder(), new XmlEncoder()] + ); + } + + /** + * @return ClientInterface + */ + public function getClient(): ClientInterface + { + return $this->client; + } + + /** + * @param string $sessionToken + * + * @return void + */ + public function setSessionToken(#[\SensitiveParameter] string $sessionToken): void + { + $this->sessionToken = $sessionToken; + } + + /** + * @return string|null + */ + public function getSessionToken(): ?string + { + return $this->sessionToken; + } + + /** + * @param array $response + * @param string $class + * + * @return mixed + * + * @throws ExceptionInterface + */ + public function denormalize(array $response, string $class): mixed + { + try { + return $this->normalizer->denormalize($response, $class); + } catch (Exception $exception) { + $this->logError(sprintf('(%s): %s', __FUNCTION__, $exception->getMessage())); + + return null; + } + } + + /** + * @param string $url + * @param string|null $body + * + * @return mixed + * + * @throws MarketplaceAPIException + */ + public function call(string $url, ?string $body = null): mixed + { + try { + $request = new Request( + 'POST', + $this->getAPIUrl($url), + $this->getDefaultHeaders(), + $body + ); + $response = $this->client->send($request); + + return json_decode((string) $response->getBody(), true); + } catch (GuzzleException|BadResponseException $exception) { + $errorMessage = $exception->getMessage(); + + if ($exception instanceof RequestException) { + $errorResponse = $this->serializer->decode((string) $exception->getResponse()?->getBody(), 'xml'); + $errorMessage = $errorResponse['Reason']['Text']['#'] ?? 'Invalid API call'; + } + + throw new MarketplaceAPIException( + sprintf('%s: %s', $url, $errorMessage), + $exception->getCode() + ); + } + } + + /** + * @return string[] + */ + protected function getDefaultHeaders(): array + { + $headers = [ + 'Content-Type' => 'application/json', + ]; + + if ($this->sessionToken !== null) { + $headers['Authenticate'] = $this->sessionToken; + } + + return $headers; + } + + /** + * @param string $url + * + * @return string + */ + protected function getAPIUrl(string $url): string + { + return sprintf('/SimpleAPI/SimpleAPIService.svc/rest/%s', $url); + } + + /** + * @param string $message + * + * @return void + */ + private function logError(string $message): void + { + if (!$this->logger) { + return; + } + + $this->logger->error($message); + } +} diff --git a/src/Exception/MarketplaceAPIException.php b/src/Exception/MarketplaceAPIException.php new file mode 100644 index 0000000..9a7c414 --- /dev/null +++ b/src/Exception/MarketplaceAPIException.php @@ -0,0 +1,12 @@ +apiClient = new APIClient($this->client, $this->logger); + } + + /** + * @param string $name + * @param array $arguments + * + * @return mixed + */ + public function __call(string $name, array $arguments): mixed + { + return $this->__get($name); + } + + /** + * @param string $name + * + * @return mixed + */ + public function __get(string $name): mixed + { + $fqdnClass = sprintf('%s\\API\\%sAPI', __NAMESPACE__, ucfirst($name)); + + if (class_exists($fqdnClass)) { + return new $fqdnClass($this->apiClient); + } + + return null; + } + + /** + * @param string $username + * @param string $password + * + * @return string + * + * @throws MarketplaceAPIException + */ + public function authenticate(string $username, #[\SensitiveParameter] string $password): string + { + $loginData = json_encode(compact('username', 'password')); + $sessionToken = $this->apiClient->call('GetSessionToken', $loginData); + $this->apiClient->setSessionToken($sessionToken); + + return $sessionToken; + } +} diff --git a/src/Model/Company.php b/src/Model/Company.php new file mode 100644 index 0000000..291f55c --- /dev/null +++ b/src/Model/Company.php @@ -0,0 +1,575 @@ +parentAccountId; + } + + /** + * @return int|null + */ + public function getAccountId(): ?int + { + return $this->accountId; + } + + /** + * @return string|null + */ + public function getAccountState(): ?string + { + return $this->accountState; + } + + /** + * @return string|null + */ + public function getCompanyName(): ?string + { + return $this->companyName; + } + + /** + * @return string|null + */ + public function getVatId(): ?string + { + return $this->vatId; + } + + /** + * @return string[]|null + */ + public function getDomain(): ?array + { + return $this->domain; + } + + /** + * @return string|null + */ + public function getBillingStartDate(): ?string + { + return $this->billingStartDate; + } + + /** + * @return string|null + */ + public function getContractId(): ?string + { + return $this->contractId; + } + + /** + * @return string|null + */ + public function getCurrency(): ?string + { + return $this->currency; + } + + /** + * @return string|null + */ + public function getAddress(): ?string + { + return $this->address; + } + + /** + * @return string|null + */ + public function getCity(): ?string + { + return $this->city; + } + + /** + * @return string|null + */ + public function getCountry(): ?string + { + return $this->country; + } + + /** + * @return string|null + */ + public function getZip(): ?string + { + return $this->zip; + } + + /** + * @return string|null + */ + public function getEmail(): ?string + { + return $this->email; + } + + /** + * @return int|null + */ + public function getMarketplace(): ?int + { + return $this->marketplace; + } + + /** + * @return int[]|null + */ + public function getMarketplaces(): ?array + { + return $this->marketplaces; + } + + /** + * @return string|null + */ + public function getVat(): ?string + { + return $this->vat; + } + + /** + * @return string|null + */ + public function getAccountType(): ?string + { + return $this->accountType; + } + + /** + * @return string|null + */ + public function getNumericId(): ?string + { + return $this->numericId; + } + + /** + * @return string|null + */ + public function getLanguage(): ?string + { + return $this->language; + } + + /** + * @return bool|null + */ + public function getOnlineBillSplitByEndCustomer(): ?bool + { + return $this->onlineBillSplitByEndCustomer; + } + + /** + * @param int|null $parentAccountId + * + * @return $this + */ + public function setParentAccountId(?int $parentAccountId): self + { + $this->parentAccountId = $parentAccountId; + + return $this; + } + + /** + * @param int|null $accountId + * + * @return $this + */ + public function setAccountId(?int $accountId): self + { + $this->accountId = $accountId; + + return $this; + } + + /** + * @param string|null $accountState + * + * @return $this + */ + public function setAccountState(?string $accountState): self + { + $this->accountState = $accountState; + + return $this; + } + + /** + * @param string|null $companyName + * + * @return $this + */ + public function setCompanyName(?string $companyName): self + { + $this->companyName = $companyName; + + return $this; + } + + /** + * @param string|null $vatId + * + * @return $this + */ + public function setVatid(?string $vatId): self + { + $this->vatId = $vatId; + + return $this; + } + + /** + * @param string[]|null $domain + */ + public function setDomain(?array $domain): self + { + $this->domain = $domain; + + return $this; + } + + /** + * @param string|null $billingStartDate + * + * @return $this + */ + public function setBillingStartDate(?string $billingStartDate): self + { + $this->billingStartDate = $billingStartDate; + + return $this; + } + + /** + * @param string|null $contractId + * + * @return $this + */ + public function setContractId(?string $contractId): self + { + $this->contractId = $contractId; + + return $this; + } + + /** + * @param string|null $currency + * + * @return $this + */ + public function setCurrency(?string $currency): self + { + $this->currency = $currency; + + return $this; + } + + /** + * @param string|null $address + * + * @return $this + */ + public function setAddress(?string $address): self + { + $this->address = $address; + + return $this; + } + + /** + * @param string|null $city + * + * @return $this + */ + public function setCity(?string $city): self + { + $this->city = $city; + + return $this; + } + + /** + * @param string|null $country + * + * @return $this + */ + public function setCountry(?string $country): self + { + $this->country = $country; + + return $this; + } + + /** + * @param string|null $zip + * + * @return $this + */ + public function setZip(?string $zip): self + { + $this->zip = $zip; + + return $this; + } + + /** + * @param string|null $email + * + * @return $this + */ + public function setEmail(?string $email): self + { + $this->email = $email; + + return $this; + } + + /** + * @param int|null $marketplace + * + * @return $this + */ + public function setMarketplace(?int $marketplace): self + { + $this->marketplace = $marketplace; + + return $this; + } + + /** + * @param int[]|null $marketplaces + */ + public function setMarketplaces(?array $marketplaces): self + { + $this->marketplaces = $marketplaces; + + return $this; + } + + /** + * @param string|null $vat + * + * @return $this + */ + public function setVat(?string $vat): self + { + $this->vat = $vat; + + return $this; + } + + /** + * @param string|null $accountType + * + * @return $this + */ + public function setAccountType(?string $accountType): self + { + $this->accountType = $accountType; + + return $this; + } + + /** + * @param string|null $numericId + * + * @return $this + */ + public function setNumericId(?string $numericId): self + { + $this->numericId = $numericId; + + return $this; + } + + /** + * @param string|null $language + * + * @return $this + */ + public function setLanguage(?string $language): self + { + $this->language = $language; + + return $this; + } + + /** + * @param bool|null $onlineBillSplitByEndCustomer + * + * @return $this + */ + public function setOnlineBillSplitByEndCustomer(?bool $onlineBillSplitByEndCustomer): self + { + $this->onlineBillSplitByEndCustomer = $onlineBillSplitByEndCustomer; + + return $this; + } + + /** + * @return string|null + */ + public function getPurchaseOrderNumber(): ?string + { + return $this->purchaseOrderNumber; + } + + /** + * @param string|null $purchaseOrderNumber + * + * @return $this + */ + public function setPurchaseOrderNumber(?string $purchaseOrderNumber): self + { + $this->purchaseOrderNumber = $purchaseOrderNumber; + + return $this; + } + + /** + * @return string|null + */ + public function getCustomerId(): ?string + { + return $this->customerId; + } + + /** + * @param string|null $customerId + * + * @return $this + */ + public function setCustomerId(?string $customerId): self + { + $this->customerId = $customerId; + + return $this; + } + + /** + * @return string|null + */ + public function getTechnicalEmail(): ?string + { + return $this->technicalEmail; + } + + /** + * @param string|null $technicalEmail + * + * @return $this + */ + public function setTechnicalEmail(?string $technicalEmail): self + { + $this->technicalEmail = $technicalEmail; + + return $this; + } + + /** + * @return string|null + */ + public function getSalesMan(): ?string + { + return $this->salesMan; + } + + /** + * @param string|null $salesMan + * + * @return $this + */ + public function setSalesMan(?string $salesMan): self + { + $this->salesMan = $salesMan; + + return $this; + } + + /** + * @return string|null + */ + public function getCrefoNumber(): ?string + { + return $this->crefoNumber; + } + + /** + * @param string|null $crefoNumber + * + * @return $this + */ + public function setCrefoNumber(?string $crefoNumber): self + { + $this->crefoNumber = $crefoNumber; + + return $this; + } + + /** + * @return string|null + */ + public function getMpnId(): ?string + { + return $this->mpnId; + } + + /** + * @param string|null $mpnId + * + * @return $this + */ + public function setMpnId(?string $mpnId): self + { + $this->mpnId = $mpnId; + + return $this; + } +} diff --git a/src/Model/Field.php b/src/Model/Field.php new file mode 100644 index 0000000..f0dbdea --- /dev/null +++ b/src/Model/Field.php @@ -0,0 +1,73 @@ +name; + } + + /** + * @return string|null + */ + public function getDisplayName(): ?string + { + return $this->displayName; + } + + /** + * @return mixed + */ + public function getValue(): mixed + { + return $this->value; + } + + /** + * @param string|null $name + * + * @return $this + */ + public function setName(?string $name): self + { + $this->name = $name; + + return $this; + } + + /** + * @param string|null $displayName + * + * @return $this + */ + public function setDisplayName(?string $displayName): self + { + $this->displayName = $displayName; + + return $this; + } + + /** + * @param mixed $value + * + * @return $this + */ + public function setValue(mixed $value): self + { + $this->value = $value; + + return $this; + } +} diff --git a/src/Model/PriceableItem.php b/src/Model/PriceableItem.php new file mode 100644 index 0000000..6dd04e5 --- /dev/null +++ b/src/Model/PriceableItem.php @@ -0,0 +1,241 @@ +chargeType; + } + + /** + * @return string|null + */ + public function getPriceableItemDescription(): ?string + { + return $this->priceableItemDescription; + } + + /** + * @return bool|null + */ + public function getIsUdrcField(): ?bool + { + return $this->isUdrcField; + } + + /** + * @return int|float|null + */ + public function getPurchasePrice(): int|float|null + { + return $this->purchasePrice; + } + + /** + * @return int|float|null + */ + public function getSalesPrice(): int|float|null + { + return $this->salesPrice; + } + + /** + * @return int|float|null + */ + public function getSuggestedRetailPrice(): int|float|null + { + return $this->suggestedRetailPrice; + } + + /** + * @return string|null + */ + public function getCurrency(): ?string + { + return $this->currency; + } + + /** + * @return int|null + */ + public function getPriceableItemId(): ?int + { + return $this->priceableItemId; + } + + /** + * @param string|null $chargeType + * + * @return $this + */ + public function setChargeType(?string $chargeType): self + { + $this->chargeType = $chargeType; + + return $this; + } + + /** + * @param string|null $priceableItemDescription + * + * @return $this + */ + public function setPriceableItemDescription(?string $priceableItemDescription): self + { + $this->priceableItemDescription = $priceableItemDescription; + + return $this; + } + + /** + * @param bool|null $isUdrcField + * + * @return $this + */ + public function setIsUdrcField(?bool $isUdrcField): self + { + $this->isUdrcField = $isUdrcField; + + return $this; + } + + /** + * @param int|float|null $purchasePrice + * + * @return $this + */ + public function setPurchasePrice(int|float|null $purchasePrice): self + { + $this->purchasePrice = $purchasePrice; + + return $this; + } + + /** + * @param int|float|null $salesPrice + * + * @return $this + */ + public function setSalesPrice(int|float|null $salesPrice): self + { + $this->salesPrice = $salesPrice; + + return $this; + } + + /** + * @param int|float|null $suggestedRetailPrice + * + * @return $this + */ + public function setSuggestedRetailPrice(int|float|null $suggestedRetailPrice): self + { + $this->suggestedRetailPrice = $suggestedRetailPrice; + + return $this; + } + + /** + * @param string|null $currency + * + * @return $this + */ + public function setCurrency(?string $currency): self + { + $this->currency = $currency; + + return $this; + } + + /** + * @param int|null $priceableItemId + * + * @return $this + */ + public function setPriceableItemId(?int $priceableItemId): self + { + $this->priceableItemId = $priceableItemId; + + return $this; + } + + /** + * @return string|null + */ + public function getMaterialNumber(): ?string + { + return $this->materialNumber; + } + + /** + * @param string|null $materialNumber + * + * @return $this + */ + public function setMaterialNumber(?string $materialNumber): self + { + $this->materialNumber = $materialNumber; + + return $this; + } + + /** + * @return string|null + */ + public function getFieldName(): ?string + { + return $this->fieldName; + } + + /** + * @param string|null $fieldName + * + * @return $this + */ + public function setFieldName(?string $fieldName): self + { + $this->fieldName = $fieldName; + + return $this; + } + + /** + * @return string|null + */ + public function getProductNumber(): ?string + { + return $this->productNumber; + } + + /** + * @param string|null $productNumber + * + * @return $this + */ + public function setProductNumber(?string $productNumber): self + { + $this->productNumber = $productNumber; + + return $this; + } +} diff --git a/src/Model/Subscription.php b/src/Model/Subscription.php new file mode 100644 index 0000000..3ca6960 --- /dev/null +++ b/src/Model/Subscription.php @@ -0,0 +1,537 @@ +parentAccountId; + } + + /** + * @return int|null + */ + public function getCompanyAccountId(): ?int + { + return $this->companyAccountId; + } + + /** + * @return string|null + */ + public function getParentType(): ?string + { + return $this->parentType; + } + + /** + * @return int|null + */ + public function getAccountId(): ?int + { + return $this->accountId; + } + + /** + * @return string|null + */ + public function getAccountState(): ?string + { + return $this->accountState; + } + + /** + * @return string|null + */ + public function getServiceName(): ?string + { + return $this->serviceName; + } + + /** + * @return string|null + */ + public function getServiceDisplayName(): ?string + { + return $this->serviceDisplayName; + } + + /** + * @return string|null + */ + public function getContractId(): ?string + { + return $this->contractId; + } + + /** + * @return string|null + */ + public function getProvisioningStatus(): ?string + { + return $this->provisioningStatus; + } + + /** + * @return string|null + */ + public function getErrorDetails(): ?string + { + return $this->errorDetails; + } + + /** + * @return string|null + */ + public function getVendorReferenceId(): ?string + { + return $this->vendorReferenceId; + } + + /** + * @return bool|null + */ + public function getHasRenewActionValuesConfigured(): ?bool + { + return $this->hasRenewActionValuesConfigured; + } + + /** + * @return Field[]|null + */ + public function getFields(): ?array + { + return $this->fields; + } + + /** + * @return PriceableItem[]|null + */ + public function getPriceableItems(): ?array + { + return $this->priceableItems; + } + + /** + * @param int|null $parentAccountId + * + * @return $this + */ + public function setParentAccountId(?int $parentAccountId): self + { + $this->parentAccountId = $parentAccountId; + + return $this; + } + + /** + * @param int|null $companyAccountId + * + * @return $this + */ + public function setCompanyAccountId(?int $companyAccountId): self + { + $this->companyAccountId = $companyAccountId; + + return $this; + } + + /** + * @param string|null $parentType + * + * @return $this + */ + public function setParentType(?string $parentType): self + { + $this->parentType = $parentType; + + return $this; + } + + /** + * @param int|null $accountId + * + * @return $this + */ + public function setAccountId(?int $accountId): self + { + $this->accountId = $accountId; + + return $this; + } + + /** + * @param string|null $accountState + * + * @return $this + */ + public function setAccountState(?string $accountState): self + { + $this->accountState = $accountState; + + return $this; + } + + /** + * @param string|null $serviceName + * + * @return $this + */ + public function setServiceName(?string $serviceName): self + { + $this->serviceName = $serviceName; + + return $this; + } + + /** + * @param string|null $serviceDisplayName + * + * @return $this + */ + public function setServiceDisplayName(?string $serviceDisplayName): self + { + $this->serviceDisplayName = $serviceDisplayName; + + return $this; + } + + /** + * @param string|null $contractId + * + * @return $this + */ + public function setContractId(?string $contractId): self + { + $this->contractId = $contractId; + + return $this; + } + + /** + * @param string|null $provisioningStatus + * + * @return $this + */ + public function setProvisioningStatus(?string $provisioningStatus): self + { + $this->provisioningStatus = $provisioningStatus; + + return $this; + } + + /** + * @param string|null $errorDetails + * + * @return $this + */ + public function setErrorDetails(?string $errorDetails): self + { + $this->errorDetails = $errorDetails; + + return $this; + } + + /** + * @param string|null $vendorReferenceId + * + * @return $this + */ + public function setVendorReferenceId(?string $vendorReferenceId): self + { + $this->vendorReferenceId = $vendorReferenceId; + + return $this; + } + + /** + * @param bool|null $hasRenewActionValuesConfigured + * + * @return $this + */ + public function setHasRenewActionValuesConfigured(?bool $hasRenewActionValuesConfigured): self + { + $this->hasRenewActionValuesConfigured = $hasRenewActionValuesConfigured; + + return $this; + } + + /** + * @param Field[]|null $fields + */ + public function setFields(?array $fields): self + { + $this->fields = $fields; + + return $this; + } + + /** + * @param PriceableItem[]|null $priceableItems + */ + public function setPriceableItems(?array $priceableItems): self + { + $this->priceableItems = $priceableItems; + + return $this; + } + + /** + * @return int|null + */ + public function getDependencyAccountId(): ?int + { + return $this->dependencyAccountId; + } + + /** + * @param int|null $dependencyAccountId + * + * @return $this + */ + public function setDependencyAccountId(?int $dependencyAccountId): self + { + $this->dependencyAccountId = $dependencyAccountId; + + return $this; + } + + /** + * @return string|null + */ + public function getDependencyServiceName(): ?string + { + return $this->dependencyServiceName; + } + + /** + * @param string|null $dependencyServiceName + * + * @return $this + */ + public function setDependencyServiceName(?string $dependencyServiceName): self + { + $this->dependencyServiceName = $dependencyServiceName; + + return $this; + } + + /** + * @return string|null + */ + public function getSecondVendorReferenceId(): ?string + { + return $this->secondVendorReferenceId; + } + + /** + * @param string|null $secondVendorReferenceId + * + * @return $this + */ + public function setSecondVendorReferenceId(?string $secondVendorReferenceId): self + { + $this->secondVendorReferenceId = $secondVendorReferenceId; + + return $this; + } + + /** + * @return string|null + */ + public function getProductName(): ?string + { + return $this->productName; + } + + /** + * @param string|null $productName + * + * @return $this + */ + public function setProductName(?string $productName): self + { + $this->productName = $productName; + + return $this; + } + + /** + * @return string|null + */ + public function getContractEndDate(): ?string + { + return $this->contractEndDate; + } + + /** + * @param string|null $contractEndDate + * + * @return $this + */ + public function setContractEndDate(?string $contractEndDate): self + { + $this->contractEndDate = $contractEndDate; + + return $this; + } + + /** + * @return string|null + */ + public function getPriceProtectionEndDate(): ?string + { + return $this->priceProtectionEndDate; + } + + /** + * @param string|null $priceProtectionEndDate + * + * @return $this + */ + public function setPriceProtectionEndDate(?string $priceProtectionEndDate): self + { + $this->priceProtectionEndDate = $priceProtectionEndDate; + + return $this; + } + + /** + * @return string|null + */ + public function getScheduledTerminationDate(): ?string + { + return $this->scheduledTerminationDate; + } + + /** + * @param string|null $scheduledTerminationDate + * + * @return $this + */ + public function setScheduledTerminationDate(?string $scheduledTerminationDate): self + { + $this->scheduledTerminationDate = $scheduledTerminationDate; + + return $this; + } + + /** + * @return int|null + */ + public function getRemainingCreditLimit(): ?int + { + return $this->remainingCreditLimit; + } + + /** + * @param int|null $remainingCreditLimit + * + * @return $this + */ + public function setRemainingCreditLimit(?int $remainingCreditLimit): self + { + $this->remainingCreditLimit = $remainingCreditLimit; + + return $this; + } + + /** + * @return string|null + */ + public function getPurchaseOrderNumber(): ?string + { + return $this->purchaseOrderNumber; + } + + /** + * @param string|null $purchaseOrderNumber + * + * @return $this + */ + public function setPurchaseOrderNumber(?string $purchaseOrderNumber): self + { + $this->purchaseOrderNumber = $purchaseOrderNumber; + + return $this; + } + + /** + * @return string|null + */ + public function getAdvancePeriodEndDate(): ?string + { + return $this->advancePeriodEndDate; + } + + /** + * @param string|null $advancePeriodEndDate + * + * @return $this + */ + public function setAdvancePeriodEndDate(?string $advancePeriodEndDate): self + { + $this->advancePeriodEndDate = $advancePeriodEndDate; + + return $this; + } + + /** + * @return Field[]|null + */ + public function getRenewFields(): ?array + { + return $this->renewFields; + } + + /** + * @param array|null $renewFields + * + * @return $this + */ + public function setRenewFields(?array $renewFields): self + { + $this->renewFields = $renewFields; + + return $this; + } +} diff --git a/tests/MarketplaceAPITest.php b/tests/MarketplaceAPITest.php new file mode 100644 index 0000000..9adc41f --- /dev/null +++ b/tests/MarketplaceAPITest.php @@ -0,0 +1,99 @@ +setExpectedResponses([ + new BadResponseException( + '', + new Request('POST', '/SimpleAPI/SimpleAPIService.svc/rest/GetSessionToken'), + new Response(body: $this->getErrorResponse('Invalid login!')) + ), + ]); + + $this->expectExceptionMessage('GetSessionToken: Invalid login!'); + $this->expectException(MarketplaceAPIException::class); + $this->marketplaceAPI->authenticate('invalid', 'password'); + } + + /** + * @return void + * + * @throws MarketplaceAPIException + */ + public function testAuthenticate(): void + { + $this->setExpectedResponses([ + new Response(200, [], json_encode('sessionToken')), + ]); + + self::assertSame( + 'sessionToken', + $this->marketplaceAPI->authenticate('unit', 'test') + ); + } + + /** + * @param array $responses + * + * @return void + */ + protected function setExpectedResponses(array $responses): void + { + $mockHandler = new MockHandler($responses); + $handlerStack = HandlerStack::create($mockHandler); + + $this->httpClient = new Client(['handler' => $handlerStack]); + $this->marketplaceAPI = new MarketplaceAPI($this->httpClient); + } + + /** + * @param string $message + * + * @return string + */ + protected function getErrorResponse(string $message): string + { + // phpcs:disable + return sprintf(' + + Sender + + + %s + + + + false + + %s + + +', $message, $message); + } +}