Skip to content

Commit 0a5d9a2

Browse files
committed
Added forceToken support for pricing endpoints
1 parent adbb569 commit 0a5d9a2

11 files changed

Lines changed: 136 additions & 37 deletions

File tree

CHANGELOG.md

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,14 @@ All notable changes to this project will be documented in this file.
44

55
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
66

7+
## 4.2.0 - 2022-02-10
8+
9+
### Added
10+
11+
- support for `forceToken` parameter for `updateProductPricing` and `updateVariantPricing` methods of `Article` client
12+
- new `PriceProtectionException` thrown when API returns error with `PRICE_PROTECTION_ERROR` code, used to obtain force token using `getForceToken` method
13+
- `getBody` method to `BadResponseException`, which returns API response as an array
14+
715
## 4.1.0 - 2021-12-16
816

917
### Added

README.md

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -28,17 +28,17 @@ Client consists of one main client and multiple, separate, domain clients.
2828

2929
The main client groups all domain clients under one object, for easier implementation, but every domain client can be initialized and used by itself.
3030

31-
Every client provides an interface that SHOULD be used as parameter types in code, instead of client classes themselves (i.e., use `MpApiClientInterface $client`
31+
Every client provides an interface that SHOULD be used as parameter types in code, instead of client classes themselves (e.g., use `MpApiClientInterface $client`
3232
or `BrandsClientInterface $client` instead of `MpApiClient $client` or `BrandsClient $client`).
3333

3434
When initializing the client, you MUST provide
3535

3636
1. an authenticator implementing [AuthMiddlewareInterface](src/Common/Interfaces/AuthMiddlewareInterface.php)
3737
- currently, only [ClientIdAuthenticator](src/Common/Authenticators/ClientIdAuthenticator.php), which accepts `my-client-id`, is provided
38-
- in the future, new authenticators will be released (i.e., OAuth)
38+
- in the future, new authenticators will be released (e.g., OAuth)
3939
2. name of the app using the API
4040
- it is sent with every request to Mall API for easier request identification and debugging of reported issues
41-
- please provide a simple, yet meaningful name, i.e., `MyAppName CRM` or `MyAppName Order sync` instead of a random string
41+
- please provide a simple, yet meaningful name (e.g., `MyAppName CRM` or `MyAppName Order sync`), instead of a random string
4242

4343
### Examples
4444

@@ -131,7 +131,7 @@ List of custom Exceptions thrown in this client can be found [here](doc/Exceptio
131131

132132
## ⚠ Warning
133133

134-
- client does not include support for deprecated endpoints that will be changed, replaced or removed in the future (i.e., `/v1/deliveries` or `/v1/gifts`)
134+
- client does not include support for deprecated endpoints that will be changed, replaced or removed in the future (e.g., `/v1/deliveries` or `/v1/gifts`)
135135

136136
## ℹ Known missing or incomplete features
137137

doc/Article.md

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -317,7 +317,7 @@ Example above prints out
317317

318318
## Update product pricing
319319

320-
Method expects `product` ID and [Pricing](../src/Article/Entity/Common/Pricing.php) entity and does not return anything.
320+
Method expects `product` ID, [Pricing](../src/Article/Entity/Common/Pricing.php) entity and an optional `forceToken` and does not return anything.
321321

322322
```php
323323
/** @var MpApiClient\Common\Interfaces\ArticleClientInterface $articleClient */
@@ -638,14 +638,16 @@ Example above prints out
638638

639639
## Update variant pricing
640640

641-
Method expects `product` and `variant` IDs and [Pricing](../src/Article/Entity/Common/Pricing.php) entity and does not return anything.
641+
Method expects `product` and `variant` IDs, [Pricing](../src/Article/Entity/Common/Pricing.php) entity and an optional `forceToken` and does not return anything.
642642

643643
```php
644644
/** @var MpApiClient\Common\Interfaces\ArticleClientInterface $articleClient */
645+
/** @var MpApiClient\Exception\PriceProtectionException $e */
645646
$articleClient->updateVariantPricing(
646647
'my-product-id',
647648
'my-variant-id',
648-
new Pricing(99.9, 112.0, 80.5)
649+
new Pricing(99.9, 112.0, 80.5),
650+
$e->getForceToken()
649651
);
650652
```
651653

doc/Exception.md

Lines changed: 18 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ Client contains custom exceptions, for easier error handling in your application
44

55
All custom exceptions extend generic `MpApiException`.
66

7-
Some methods might throw other native PHP exceptions (i.e., `InvalidArgumentException`), which do not extend `MpApiException`. Such methods always have
7+
Some methods might throw other native PHP exceptions (e.g., `InvalidArgumentException`, `LogicException`), which do not extend `MpApiException`. Such methods always have
88
appropriate `@throws` tags.
99

1010
## [MpApiException](../src/Exception/MpApiException.php)
@@ -13,25 +13,36 @@ appropriate `@throws` tags.
1313

1414
## [IncorrectDataTypeException](../src/Exception/IncorrectDataTypeException.php)
1515

16+
- Extends [MpApiException](#mpapiexception)
1617
- Thrown when method called expects data of a specific type, but received a different one
1718

1819
## [BadResponseException](../src/Exception/BadResponseException.php)
1920

21+
- Extends [MpApiException](#mpapiexception)
2022
- Thrown when API responded with `4xx` or `5xx` status code that could not be translated to more specific exceptions
21-
- Usually indicates an unknown/unexpected error occurred
23+
- Usually indicates, that an unknown/unexpected error occurred
24+
25+
## [PriceProtectionException](../src/Exception/PriceProtectionException.php)
26+
27+
- Extends [BadResponseException](#badresponseexception)
28+
- Thrown when price protection mechanism is tripped during an article price update
29+
- Contains `getForceToken` method, that may be used to force the price change using a provided token
2230

2331
## [ForbiddenException](../src/Exception/ForbiddenException.php)
2432

33+
- Extends [BadResponseException](#badresponseexception)
2534
- Thrown when API returns `403` status code
2635
- Usually returned on endpoints your account does not have access to
2736

2837
## [NotFoundException](../src/Exception/NotFoundException.php)
2938

39+
- Extends [BadResponseException](#badresponseexception)
3040
- Thrown when API returns `404` status code
31-
- This exception should never be thrown for endpoints with static url (i.e., enums/lists)
41+
- This exception should never be thrown for endpoints with static url (e.g., enums/lists)
3242

3343
## [UnauthorizedException](../src/Exception/UnauthorizedException.php)
3444

45+
- Extends [BadResponseException](#badresponseexception)
3546
- Thrown when API returns `401` status code
3647
- Reasons might include
3748
- you forgot to provide authenticator middleware
@@ -40,16 +51,18 @@ appropriate `@throws` tags.
4051

4152
## [TooManyRequestsException](../src/Exception/TooManyRequestsException.php)
4253

54+
- Extends [BadResponseException](#badresponseexception)
4355
- Thrown when API returns `429` status code
4456
- In that case, you have been rate limited by the API and should slow down your request rate
45-
- API returns rate limit information as part of response headers, which you can easily check
57+
- API returns rate limit information as part of response headers, which can be easily checked
4658

4759
### Example of handling some errors
4860

4961
```php
5062
<?php declare(strict_types=1);
5163

52-
use MpApiClient\Common\Interfaces\ChecksClientInterface;use MpApiClient\Exception\BadResponseException;
64+
use MpApiClient\Common\Interfaces\ChecksClientInterface;
65+
use MpApiClient\Exception\BadResponseException;
5366
use MpApiClient\Exception\IncorrectDataTypeException;
5467
use MpApiClient\Exception\MpApiException;
5568
use MpApiClient\Exception\TooManyRequestsException;

example/Article.php

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@
1515
use MpApiClient\Article\Entity\Common\StatusEnum;
1616
use MpApiClient\Common\Authenticators\ClientIdAuthenticator;
1717
use MpApiClient\Exception\MpApiException;
18+
use MpApiClient\Exception\PriceProtectionException;
1819
use MpApiClient\Filter\Filter;
1920
use MpApiClient\Filter\FilterItem;
2021
use MpApiClient\Filter\FilterOperatorEnum;
@@ -231,6 +232,16 @@
231232
'my-product-id',
232233
new Pricing(99.9, 112.0, 80.5)
233234
);
235+
} catch (PriceProtectionException $e) {
236+
try {
237+
$client->article()->updateProductPricing(
238+
'my-product-id',
239+
new Pricing(99.9, 112.0, 80.5),
240+
$e->getForceToken()
241+
);
242+
} catch (MpApiException $e) {
243+
echo 'Unexpected error occurred during product pricing update with force token: ' . $e->getMessage();
244+
}
234245
} catch (MpApiException $e) {
235246
echo 'Unexpected error occurred during product pricing update: ' . $e->getMessage();
236247
}
@@ -429,6 +440,17 @@
429440
'my-variant-id',
430441
new Pricing(99.9, 112.0, 80.5)
431442
);
443+
} catch (PriceProtectionException $e) {
444+
try {
445+
$client->article()->updateVariantPricing(
446+
'my-product-id',
447+
'my-variant-id',
448+
new Pricing(99.9, 112.0, 80.5),
449+
$e->getForceToken()
450+
);
451+
} catch (MpApiException $e) {
452+
echo 'Unexpected error occurred during variant pricing update with force token: ' . $e->getMessage();
453+
}
432454
} catch (MpApiException $e) {
433455
echo 'Unexpected error occurred during variant pricing update: ' . $e->getMessage();
434456
}

src/Article/ArticleClient.php

Lines changed: 12 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -87,9 +87,13 @@ public function getProductPricing(string $productId): Pricing
8787
);
8888
}
8989

90-
public function updateProductPricing(string $productId, Pricing $pricing): void
90+
public function updateProductPricing(string $productId, Pricing $pricing, ?string $forceToken = null): void
9191
{
92-
$this->sendJson('PUT', sprintf(self::PRODUCT_PRICING, $productId), $pricing->getArrayForApi());
92+
$url = sprintf(self::PRODUCT_PRICING, $productId);
93+
if ($forceToken !== null) {
94+
$url = sprintf('%s?force_token=%s', $url, $forceToken);
95+
}
96+
$this->sendJson('PUT', $url, $pricing->getArrayForApi());
9397
}
9498

9599
public function listProductVariants(string $productId, ?Filter $filter): BasicVariantList
@@ -144,9 +148,13 @@ public function getVariantPricing(string $productId, string $variantId): Pricing
144148
);
145149
}
146150

147-
public function updateVariantPricing(string $productId, string $variantId, Pricing $pricing): void
151+
public function updateVariantPricing(string $productId, string $variantId, Pricing $pricing, ?string $forceToken = null): void
148152
{
149-
$this->sendJson('PUT', sprintf(self::VARIANT_PRICING, $productId, $variantId), $pricing->getArrayForApi());
153+
$url = sprintf(self::VARIANT_PRICING, $productId, $variantId);
154+
if ($forceToken !== null) {
155+
$url = sprintf('%s?force_token=%s', $url, $forceToken);
156+
}
157+
$this->sendJson('PUT', $url, $pricing->getArrayForApi());
150158
}
151159

152160
public function updateBatchAvailability(BatchAvailabilityIterator $availability): void

src/Common/Interfaces/ArticleClientInterface.php

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -59,7 +59,7 @@ public function getProductPricing(string $productId): Pricing;
5959
* @throws MpApiException
6060
* @deprecated Will be replaced with batch endpoint, similar to BatchAvailability
6161
*/
62-
public function updateProductPricing(string $productId, Pricing $pricing): void;
62+
public function updateProductPricing(string $productId, Pricing $pricing, ?string $forceToken = null): void;
6363

6464
/**
6565
* @throws MpApiException
@@ -102,7 +102,7 @@ public function getVariantPricing(string $productId, string $variantId): Pricing
102102
* @throws MpApiException
103103
* @deprecated Will be replaced with batch endpoint, similar to BatchAvailability
104104
*/
105-
public function updateVariantPricing(string $productId, string $variantId, Pricing $pricing): void;
105+
public function updateVariantPricing(string $productId, string $variantId, Pricing $pricing, ?string $forceToken = null): void;
106106

107107
/**
108108
* @throws MpApiException

src/Exception/BadResponseException.php

Lines changed: 39 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -16,32 +16,54 @@ class BadResponseException extends MpApiException
1616
private array $errorCodes;
1717

1818
/**
19-
* @param string $message
20-
* @param int $code
21-
* @param Throwable|null $previous
22-
* @param ErrorCode[] $errorCodes
19+
* @var array<string, mixed>
2320
*/
24-
final private function __construct(string $message = '', int $code = 0, Throwable $previous = null, array $errorCodes = [])
21+
private array $body;
22+
23+
/**
24+
* @param string $message
25+
* @param int $code
26+
* @param Throwable|null $previous
27+
* @param array<string, mixed> $body
28+
* @param ErrorCode[] $errorCodes
29+
*/
30+
final private function __construct(string $message = '', int $code = 0, Throwable $previous = null, array $body = [], array $errorCodes = [])
2531
{
2632
parent::__construct($message, $code, $previous);
33+
$this->body = $body;
2734
$this->errorCodes = $errorCodes;
2835
}
2936

3037
/**
31-
* @param string $message
32-
* @param int $code
33-
* @param GuzzleBadResponseException $previous
34-
* @param array<int, array<string, mixed>> $errorCodes
35-
* @return static
38+
* @param string $message
39+
* @param int $code
40+
* @param GuzzleBadResponseException $previous
41+
* @param array<string, mixed> $body
42+
* @return BadResponseException
43+
*
44+
* @internal
45+
*/
46+
public static function createFromGuzzle(string $message, int $code, GuzzleBadResponseException $previous, array $body = []): BadResponseException
47+
{
48+
$errorCodes = array_map(fn(array $item): ErrorCode => ErrorCode::createFromApi($item), $body['errorCodes'] ?? []);
49+
if ($errorCodes === []) {
50+
return new static($message, $code, $previous, $body);
51+
}
52+
53+
switch ($errorCodes[0]->getCode()) {
54+
case PriceProtectionException::ERROR_CODE:
55+
return new PriceProtectionException($message, $code, $previous, $body, $errorCodes);
56+
default:
57+
return new static($message, $code, $previous, $body, $errorCodes);
58+
}
59+
}
60+
61+
/**
62+
* @return array<string, mixed>
3663
*/
37-
public static function createFromGuzzle(string $message, int $code, GuzzleBadResponseException $previous, array $errorCodes = []): BadResponseException
64+
public function getBody(): array
3865
{
39-
return new static(
40-
$message,
41-
$code,
42-
$previous,
43-
array_map(fn(array $item): ErrorCode => ErrorCode::createFromApi($item), $errorCodes),
44-
);
66+
return $this->body;
4567
}
4668

4769
/**

src/Exception/ExceptionFactory.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -39,7 +39,7 @@ public static function fromGuzzleBadResponse(GuzzleBadResponseException $e): MpA
3939
return TooManyRequestsException::createFromGuzzle($message, $code, $e);
4040
default:
4141
/** @psalm-suppress PossiblyInvalidArgument - https://github.com/vimeo/psalm/issues/4295 */
42-
return BadResponseException::createFromGuzzle($message, $code, $e, $body['errorCodes'] ?? []);
42+
return BadResponseException::createFromGuzzle($message, $code, $e, $body);
4343
}
4444
}
4545

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
<?php declare(strict_types=1);
2+
3+
namespace MpApiClient\Exception;
4+
5+
use LogicException;
6+
7+
final class PriceProtectionException extends BadResponseException
8+
{
9+
10+
public const ERROR_CODE = 'PRICE_PROTECTION_ERROR';
11+
12+
/**
13+
* @throws LogicException
14+
*/
15+
public function getForceToken(): string
16+
{
17+
if (!isset($this->getBody()['data']['data']['forceToken'])) {
18+
throw new LogicException('forceToken not present in response');
19+
}
20+
21+
return (string) $this->getBody()['data']['data']['forceToken'];
22+
}
23+
24+
}

0 commit comments

Comments
 (0)