From f888c6821d9c135eeaec734c878e7508b0924e93 Mon Sep 17 00:00:00 2001 From: Alexey Kopytko Date: Thu, 20 Jun 2019 06:35:16 +0900 Subject: [PATCH 01/11] Add CalculationWithTariffListRequest Fixes #45 --- src/CdekClient.php | 1 + src/Requests/CalculationAuthorizedRequest.php | 3 +- src/Requests/CalculationRequest.php | 14 +- ...ulationWithTariffListAuthorizedRequest.php | 45 +++++ .../CalculationWithTariffListRequest.php | 39 +++++ .../Concerns/AnonymousJsonRequest.php | 44 +++++ .../CalculationWithTariffListResponse.php | 103 +++++++++++ src/Responses/Types/Result.php | 62 ++++++- src/Responses/Types/TariffResult.php | 130 ++++++++++++++ src/Serialization/Serializer.php | 7 +- .../CalculationWithTariffListResponseTest.php | 163 ++++++++++++++++++ .../CalculationRequestTariffListResponse.json | 1 + ...ationRequestTariffListResponseExample.json | 40 +++++ ...alculationWithTariffListResponseError.json | 1 + tests/Integration/CalculationRequestTest.php | 1 + .../CalculationWithTariffListRequestTest.php | 128 ++++++++++++++ .../Serialization/CalculationRequestTest.php | 40 +++++ 17 files changed, 808 insertions(+), 14 deletions(-) create mode 100644 src/Requests/CalculationWithTariffListAuthorizedRequest.php create mode 100644 src/Requests/CalculationWithTariffListRequest.php create mode 100644 src/Requests/Concerns/AnonymousJsonRequest.php create mode 100644 src/Responses/CalculationWithTariffListResponse.php create mode 100644 src/Responses/Types/TariffResult.php create mode 100644 tests/Deserialization/CalculationWithTariffListResponseTest.php create mode 100644 tests/Fixtures/data/CalculationRequestTariffListResponse.json create mode 100644 tests/Fixtures/data/CalculationRequestTariffListResponseExample.json create mode 100644 tests/Fixtures/data/CalculationWithTariffListResponseError.json create mode 100644 tests/Integration/CalculationWithTariffListRequestTest.php diff --git a/src/CdekClient.php b/src/CdekClient.php index 54c87ac..a31eefe 100644 --- a/src/CdekClient.php +++ b/src/CdekClient.php @@ -59,6 +59,7 @@ * @method Responses\PreAlertResponse sendPreAlertRequest(Requests\PreAlertRequest $request) * @method Responses\InfoReportResponse|Common\Order[] sendInfoReportRequest(Requests\InfoReportRequest $request) * @method Responses\CalculationResponse sendCalculationRequest(Requests\CalculationAuthorizedRequest $request) + * @method Responses\CalculationWithTariffListResponse sendCalculationWithTariffListRequest(Requests\CalculationWithTariffListAuthorizedRequest $request) * @method Responses\StatusReportResponse|Common\Order[] sendStatusReportRequest(Requests\StatusReportRequest $request) * @method Responses\FileResponse sendPrintReceiptsRequest(Requests\PrintReceiptsRequest $request) * @method Responses\FileResponse sendPrintLabelsRequest(Requests\PrintLabelsRequest $request) diff --git a/src/Requests/CalculationAuthorizedRequest.php b/src/Requests/CalculationAuthorizedRequest.php index 43affd7..d8c0143 100644 --- a/src/Requests/CalculationAuthorizedRequest.php +++ b/src/Requests/CalculationAuthorizedRequest.php @@ -197,7 +197,7 @@ public function setTariffId($id) * * @return self */ - public function addTariffToList($id, $priority, $modeId = null) + public function addTariffToList($id, $priority = null, $modeId = null) { $this->tariffId = null; @@ -293,6 +293,7 @@ public function jsonSerialize() 'services' => $this->services, 'receiverCityId' => $this->receiverCityId, 'receiverCityPostCode' => $this->receiverCityPostCode, + 'currency' => $this->currency, 'dateExecute' => $this->dateExecute instanceof \DateTimeInterface ? $this->dateExecute->format('Y-m-d') : null, ]); diff --git a/src/Requests/CalculationRequest.php b/src/Requests/CalculationRequest.php index 53fdfb4..cadbf48 100644 --- a/src/Requests/CalculationRequest.php +++ b/src/Requests/CalculationRequest.php @@ -28,6 +28,8 @@ namespace CdekSDK\Requests; +use CdekSDK\Requests\Concerns\AnonymousJsonRequest; + /** * Class CalculationRequest. * @@ -35,15 +37,5 @@ */ class CalculationRequest extends CalculationAuthorizedRequest { - /** - * @phan-suppress PhanDeprecatedProperty - * - * @return array - */ - public function jsonSerialize() - { - $this->account = ''; - - return parent::jsonSerialize(); - } + use AnonymousJsonRequest; } diff --git a/src/Requests/CalculationWithTariffListAuthorizedRequest.php b/src/Requests/CalculationWithTariffListAuthorizedRequest.php new file mode 100644 index 0000000..0c936ae --- /dev/null +++ b/src/Requests/CalculationWithTariffListAuthorizedRequest.php @@ -0,0 +1,45 @@ + and contributors + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +declare(strict_types=1); + +namespace CdekSDK\Requests; + +use CdekSDK\Responses\CalculationWithTariffListResponse; + +/** + * @final + */ +class CalculationWithTariffListAuthorizedRequest extends CalculationAuthorizedRequest +{ + const ADDRESS = 'https://api.cdek.ru/calculator/calculate_tarifflist.php'; + const RESPONSE = CalculationWithTariffListResponse::class; + + public function setTariffId($id) + { + return $this->addTariffToList($id); + } +} diff --git a/src/Requests/CalculationWithTariffListRequest.php b/src/Requests/CalculationWithTariffListRequest.php new file mode 100644 index 0000000..f3dd0da --- /dev/null +++ b/src/Requests/CalculationWithTariffListRequest.php @@ -0,0 +1,39 @@ + and contributors + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +declare(strict_types=1); + +namespace CdekSDK\Requests; + +use CdekSDK\Requests\Concerns\AnonymousJsonRequest; + +/** + * @final + */ +class CalculationWithTariffListRequest extends CalculationWithTariffListAuthorizedRequest +{ + use AnonymousJsonRequest; +} diff --git a/src/Requests/Concerns/AnonymousJsonRequest.php b/src/Requests/Concerns/AnonymousJsonRequest.php new file mode 100644 index 0000000..e42ebdf --- /dev/null +++ b/src/Requests/Concerns/AnonymousJsonRequest.php @@ -0,0 +1,44 @@ + and contributors + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +declare(strict_types=1); + +namespace CdekSDK\Requests\Concerns; + +trait AnonymousJsonRequest +{ + /** + * @phan-suppress PhanUndeclaredProperty + * + * @return array + */ + final public function jsonSerialize() + { + $this->account = ''; + + return parent::jsonSerialize(); + } +} diff --git a/src/Responses/CalculationWithTariffListResponse.php b/src/Responses/CalculationWithTariffListResponse.php new file mode 100644 index 0000000..9cec0df --- /dev/null +++ b/src/Responses/CalculationWithTariffListResponse.php @@ -0,0 +1,103 @@ + and contributors + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +declare(strict_types=1); + +namespace CdekSDK\Responses; + +use CdekSDK\Contracts\HasErrorCode; +use CdekSDK\Contracts\Response; +use CdekSDK\Responses\Types\Error; +use CdekSDK\Responses\Types\TariffResult; +use JMS\Serializer\Annotation as JMS; + +/** + * Class CalculationWithTariffListResponse. + */ +final class CalculationWithTariffListResponse implements Response, \IteratorAggregate +{ + /** + * @JMS\Type("array") + * + * @var TariffResult[] + */ + private $result = []; + + /** + * @JMS\SerializedName("error") + * @JMS\Type("array") + * + * @var Error[] + */ + private $errors = []; + + /** + * @return bool + */ + public function hasErrors(): bool + { + return !empty($this->errors); + } + + /** + * @return HasErrorCode[]|Error[] + */ + public function getErrors(): array + { + return $this->errors; + } + + /** + * {@inheritdoc} + */ + public function getMessages() + { + yield from $this->getErrors(); + } + + /** + * @return TariffResult[] + */ + public function getResults() + { + return $this->result; + } + + /** + * @phan-suppress PhanUnextractableAnnotationSuffix + * + * @return \Traversable|TariffResult[] + */ + public function getIterator() + { + return new \ArrayIterator($this->result); + } + + public function jsonSerialize() + { + return []; + } +} diff --git a/src/Responses/Types/Result.php b/src/Responses/Types/Result.php index c0c146a..2dc096a 100644 --- a/src/Responses/Types/Result.php +++ b/src/Responses/Types/Result.php @@ -28,9 +28,11 @@ namespace CdekSDK\Responses\Types; +use CdekSDK\Contracts\HasErrorCode; +use CdekSDK\Contracts\Response; use JMS\Serializer\Annotation as JMS; -final class Result +final class Result implements Response { /** * @JMS\Type("float") @@ -88,6 +90,13 @@ final class Result */ private $currency; + /** + * @JMS\Type("int") + * + * @var int + */ + private $percentVAT; + /** * @JMS\Type("array") * @@ -95,6 +104,14 @@ final class Result */ private $services = []; + /** + * @JMS\SerializedName("errors") + * @JMS\Type("CdekSDK\Responses\Types\Error") + * + * @var Error + */ + private $error; + /** * @return float|null */ @@ -143,6 +160,14 @@ public function getCurrency() return $this->currency; } + /** + * @return int|null + */ + public function getPercentVAT() + { + return $this->percentVAT; + } + /** * @return \DateTimeImmutable|null */ @@ -166,4 +191,39 @@ public function getAdditionalServices() { return $this->services; } + + /** + * @return bool + */ + public function hasErrors(): bool + { + return $this->error !== null; + } + + /** + * @return HasErrorCode[]|Error[] + */ + public function getErrors(): array + { + if (!$this->hasErrors()) { + return []; + } + + return [ + $this->error, + ]; + } + + /** + * {@inheritdoc} + */ + public function getMessages() + { + yield from $this->getErrors(); + } + + public function jsonSerialize() + { + return []; + } } diff --git a/src/Responses/Types/TariffResult.php b/src/Responses/Types/TariffResult.php new file mode 100644 index 0000000..a8bce32 --- /dev/null +++ b/src/Responses/Types/TariffResult.php @@ -0,0 +1,130 @@ + and contributors + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +declare(strict_types=1); + +namespace CdekSDK\Responses\Types; + +use CdekSDK\Contracts\HasErrorCode; +use CdekSDK\Contracts\Response; +use JMS\Serializer\Annotation as JMS; + +/** + * Class TariffResult. + * + * @method float|null getPrice() + * @method int|null getDeliveryPeriodMin() + * @method int|null getDeliveryPeriodMax() + * @method float|null getPriceByCurrency() + * @method string|null getCurrency() + * @method \DateTimeImmutable|null getDeliveryDateMin() + * @method int getPercentVAT() + * @method \DateTimeImmutable|null getDeliveryDateMax() + * @method AdditionalService[] getAdditionalServices() + */ +final class TariffResult implements Response +{ + /** + * @JMS\Type("int") + * + * @var int + */ + private $tariffId; + + /** + * @JMS\Type("bool") + * + * @var bool + */ + private $status; + + /** + * @JMS\Type("CdekSDK\Responses\Types\Result") + * + * @var Result + */ + private $result; + + /** + * @return bool + */ + public function hasErrors(): bool + { + return $this->result->hasErrors(); + } + + /** + * @return HasErrorCode[]|Error[] + */ + public function getErrors(): array + { + return $this->result->getErrors(); + } + + /** + * {@inheritdoc} + */ + public function getMessages() + { + yield from $this->getErrors(); + } + + /** + * @return int|null + */ + public function getTariffId() + { + return $this->tariffId; + } + + public function getStatus(): bool + { + return $this->status; + } + + public function getResult(): Result + { + return $this->result; + } + + public function __call(string $name, array $arguments) + { + if ($this->hasErrors()) { + throw new \RuntimeException('Calculation request was not successful. Please check for errors before calling any instance methods.'); + } + + if ($this->result && \method_exists($this->result, $name)) { + return $this->result->{$name}(...$arguments); + } + + throw new \BadMethodCallException(\sprintf('Method [%s] not found in [%s].', $name, __CLASS__)); + } + + public function jsonSerialize() + { + return []; + } +} diff --git a/src/Serialization/Serializer.php b/src/Serialization/Serializer.php index 8fd1261..d9ba78a 100644 --- a/src/Serialization/Serializer.php +++ b/src/Serialization/Serializer.php @@ -28,6 +28,7 @@ namespace CdekSDK\Serialization; +use CdekSDK\Contracts\Request; use CdekSDK\Serialization\Exception\DeserializationException; use CdekSDK\Serialization\Exception\LibXMLError; use CdekSDK\Serialization\Exception\XmlErrorException; @@ -187,7 +188,11 @@ public function deserialize($data, $type, $format, DeserializationContext $conte */ throw new XmlErrorException(LibXMLError::fromLibXMLError($e->getXmlError(), $data), $e->getCode(), $e); } catch (\JMS\Serializer\Exception\RuntimeException $e) { - throw DeserializationException::fromRuntimeException($e, $this->getLastSeenSimpleXMLElement()); + if (Request::SERIALIZATION_XML === $format) { + throw DeserializationException::fromRuntimeException($e, $this->getLastSeenSimpleXMLElement()); + } + + throw $e; } } diff --git a/tests/Deserialization/CalculationWithTariffListResponseTest.php b/tests/Deserialization/CalculationWithTariffListResponseTest.php new file mode 100644 index 0000000..19ce4a7 --- /dev/null +++ b/tests/Deserialization/CalculationWithTariffListResponseTest.php @@ -0,0 +1,163 @@ + and contributors + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +declare(strict_types=1); + +namespace Tests\CdekSDK\Deserialization; + +use CdekSDK\Responses\CalculationWithTariffListResponse; +use CdekSDK\Responses\Types\TariffResult; +use Tests\CdekSDK\Fixtures\FixtureLoader; + +/** + * @covers \CdekSDK\Responses\CalculationWithTariffListResponse + * @covers \CdekSDK\Responses\Types\Result + * @covers \CdekSDK\Responses\Types\Error + * @covers \CdekSDK\Responses\Types\TariffResult + */ +class CalculationWithTariffListResponseTest extends TestCase +{ + public function test_it_deserializes_errors() + { + $response = $this->getSerializer()->deserialize(FixtureLoader::load('CalculationWithTariffListResponseError.json'), CalculationWithTariffListResponse::class, 'json'); + + /** @var $response CalculationWithTariffListResponse */ + $this->assertInstanceOf(CalculationWithTariffListResponse::class, $response); + + $this->assertTrue($response->hasErrors()); + + $this->assertCount(4, $response->getErrors()); + + foreach ($response->getErrors() as $error) { + $this->assertSame('Не задан город-отправитель', $error->getText()); + $this->assertSame(7, $error->getCode()); + + $this->assertSame('Не задан город-отправитель', $error->getMessage()); + $this->assertSame('7', $error->getErrorCode()); + break; + } + + $this->assertCount(4, $response->getMessages()); + + foreach ($response->getMessages() as $error) { + $this->assertSame('Не задан город-отправитель', $error->getMessage()); + $this->assertSame('7', $error->getErrorCode()); + break; + } + } + + public function test_it_deserializes_correct_response() + { + $response = $this->getSerializer()->deserialize(FixtureLoader::load('CalculationRequestTariffListResponse.json'), CalculationWithTariffListResponse::class, 'json'); + + /** @var $response CalculationWithTariffListResponse */ + $this->assertInstanceOf(CalculationWithTariffListResponse::class, $response); + + $this->assertFalse($response->hasErrors()); + + $this->assertCount(0, $response->getErrors()); + + $this->assertCount(2, $response); + $this->assertCount(2, $response->getResults()); + + foreach ($response->getResults() as $result) { + $this->assertInstanceOf(TariffResult::class, $result); + } + + $result = $response->getResults()[0]; + + $this->assertTrue($result->getStatus()); + $this->assertSame(1, $result->getTariffId()); + $this->assertSame(1, $result->getResult()->getTariffId()); + $this->assertSame(1190.0, $result->getPrice()); + $this->assertSame(2, $result->getDeliveryPeriodMin()); + $this->assertSame(3, $result->getDeliveryPeriodMax()); + $this->assertSame(1190.0, $result->getPriceByCurrency()); + $this->assertSame('RUB', $result->getCurrency()); + + $this->assertCount(0, $result->getResult()->getMessages()); + $this->assertSame([], $result->getResult()->jsonSerialize()); + + $this->assertCount(1, $result->getAdditionalServices()); + $this->assertSame(2, $result->getAdditionalServices()[0]->getId()); + $this->assertSame('Страхование', $result->getAdditionalServices()[0]->getTitle()); + $this->assertSame(300.0, $result->getAdditionalServices()[0]->getPrice()); + $this->assertSame(0.8, $result->getAdditionalServices()[0]->getRate()); + + $result = $response->getResults()[1]; + + $this->assertFalse($result->getStatus()); + $this->assertSame(8, $result->getTariffId()); + $this->assertCount(1, $result->getErrors()); + $this->assertCount(1, $result->getMessages()); + $this->assertSame([], $result->jsonSerialize()); + + $error = $result->getErrors()[0]; + + $this->assertSame('Невозможно осуществить доставку по этому направлению при заданных условиях', $error->getText()); + $this->assertSame(3, $error->getCode()); + + $this->assertSame('Невозможно осуществить доставку по этому направлению при заданных условиях', $error->getMessage()); + $this->assertSame('3', $error->getErrorCode()); + + $this->expectException(\RuntimeException::class); + $result->getPrice(); + } + + public function test_it_deserializes_example_response() + { + $response = $this->getSerializer()->deserialize(FixtureLoader::load('CalculationRequestTariffListResponseExample.json'), CalculationWithTariffListResponse::class, 'json'); + + /** @var $response CalculationWithTariffListResponse */ + $this->assertInstanceOf(CalculationWithTariffListResponse::class, $response); + + $this->assertFalse($response->hasErrors()); + + $this->assertCount(0, $response->getErrors()); + + $this->assertCount(2, $response); + $this->assertCount(2, $response->getResults()); + + $result = $response->getResults()[0]; + + $this->assertTrue($result->getStatus()); + $this->assertSame(20, $result->getPercentVAT()); + } + + public function test_it_errors_on_unknown_method_within_a_result() + { + $response = $this->getSerializer()->deserialize(FixtureLoader::load('CalculationRequestTariffListResponse.json'), CalculationWithTariffListResponse::class, 'json'); + + $this->expectException(\BadMethodCallException::class); + \call_user_func([$response->getResults()[0], 'foo']); + } + + public function test_it_serializes_to_empty_json() + { + $response = new CalculationWithTariffListResponse(); + $this->assertSame([], $response->jsonSerialize()); + } +} diff --git a/tests/Fixtures/data/CalculationRequestTariffListResponse.json b/tests/Fixtures/data/CalculationRequestTariffListResponse.json new file mode 100644 index 0000000..9d83039 --- /dev/null +++ b/tests/Fixtures/data/CalculationRequestTariffListResponse.json @@ -0,0 +1 @@ +{"result":[{"tariffId":1,"status":true,"result":{"price":"1190","deliveryPeriodMin":2,"deliveryPeriodMax":3,"tariffId":1,"priceByCurrency":1190,"currency":"RUB","services":[{"id":2,"title":"\u0421\u0442\u0440\u0430\u0445\u043e\u0432\u0430\u043d\u0438\u0435","price":300,"rate":0.8}]}},{"tariffId":8,"status":false,"result":{"errors":{"code":3,"text":"\u041d\u0435\u0432\u043e\u0437\u043c\u043e\u0436\u043d\u043e \u043e\u0441\u0443\u0449\u0435\u0441\u0442\u0432\u0438\u0442\u044c \u0434\u043e\u0441\u0442\u0430\u0432\u043a\u0443 \u043f\u043e \u044d\u0442\u043e\u043c\u0443 \u043d\u0430\u043f\u0440\u0430\u0432\u043b\u0435\u043d\u0438\u044e \u043f\u0440\u0438 \u0437\u0430\u0434\u0430\u043d\u043d\u044b\u0445 \u0443\u0441\u043b\u043e\u0432\u0438\u044f\u0445"}}}]} \ No newline at end of file diff --git a/tests/Fixtures/data/CalculationRequestTariffListResponseExample.json b/tests/Fixtures/data/CalculationRequestTariffListResponseExample.json new file mode 100644 index 0000000..da5a56f --- /dev/null +++ b/tests/Fixtures/data/CalculationRequestTariffListResponseExample.json @@ -0,0 +1,40 @@ +{ + "result": + [ + { + "tariffId":1, + "status":true, + "result": + { + "price":"1077", + "deliveryPeriodMin":2, + "deliveryPeriodMax":3, + "tariffId":1, + "priceByCurrency":1077, + "currency":"RUB", + "percentVAT":20, + "services": + [ + { + "id":2, + "title":"Страхование", + "price":7.5, + "rate":0.75 + } + ] + } + }, + { + "tariffId":8, + "status":false, + "result": + { + "errors": + { + "code":3, + "text":"Невозможно осуществить доставку по этому направлению при заданных условиях" + } + } + } + ] +} diff --git a/tests/Fixtures/data/CalculationWithTariffListResponseError.json b/tests/Fixtures/data/CalculationWithTariffListResponseError.json new file mode 100644 index 0000000..a9d1484 --- /dev/null +++ b/tests/Fixtures/data/CalculationWithTariffListResponseError.json @@ -0,0 +1 @@ +{"error":[{"code":7,"text":"\u041d\u0435 \u0437\u0430\u0434\u0430\u043d \u0433\u043e\u0440\u043e\u0434-\u043e\u0442\u043f\u0440\u0430\u0432\u0438\u0442\u0435\u043b\u044c"},{"code":8,"text":"\u041d\u0435 \u0437\u0430\u0434\u0430\u043d \u0433\u043e\u0440\u043e\u0434-\u043f\u043e\u043b\u0443\u0447\u0430\u0442\u0435\u043b\u044c"},{"code":5,"text":"\u041d\u0435 \u0437\u0430\u0434\u0430\u043d\u043e \u043d\u0438 \u043e\u0434\u043d\u043e\u0433\u043e \u043c\u0435\u0441\u0442\u0430 \u0434\u043b\u044f \u043e\u0442\u043f\u0440\u0430\u0432\u043b\u0435\u043d\u0438\u044f"},{"code":6,"text":"\u041d\u0435 \u0437\u0430\u0434\u0430\u043d \u0442\u0430\u0440\u0438\u0444 \u0438\u043b\u0438 \u0441\u043f\u0438\u0441\u043e\u043a \u0442\u0430\u0440\u0438\u0444\u043e\u0432"}]} diff --git a/tests/Integration/CalculationRequestTest.php b/tests/Integration/CalculationRequestTest.php index 8f34375..fac5566 100644 --- a/tests/Integration/CalculationRequestTest.php +++ b/tests/Integration/CalculationRequestTest.php @@ -33,6 +33,7 @@ /** * @covers \CdekSDK\Requests\CalculationRequest + * @covers \CdekSDK\Requests\CalculationAuthorizedRequest * @covers \CdekSDK\Responses\CalculationResponse * * @group integration diff --git a/tests/Integration/CalculationWithTariffListRequestTest.php b/tests/Integration/CalculationWithTariffListRequestTest.php new file mode 100644 index 0000000..760813d --- /dev/null +++ b/tests/Integration/CalculationWithTariffListRequestTest.php @@ -0,0 +1,128 @@ + and contributors + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +declare(strict_types=1); + +namespace Tests\CdekSDK\Integration; + +use CdekSDK\Common\AdditionalService; +use CdekSDK\Requests\CalculationWithTariffListAuthorizedRequest; +use CdekSDK\Requests\CalculationWithTariffListRequest; + +/** + * @covers \CdekSDK\Requests\CalculationWithTariffListAuthorizedRequest + * @covers \CdekSDK\Requests\CalculationWithTariffListRequest + * @covers \CdekSDK\Responses\CalculationResponse + * + * @group integration + */ +class CalculationWithTariffListRequestTest extends TestCase +{ + const UNAUTHORIZED_ERROR = 2; + + public function test_success_anonymous() + { + $request = new CalculationWithTariffListRequest(); + $request->setSenderCityId(44) + ->setReceiverCityId(269) + ->setCurrency('RUB') + ->addTariffToList(1) + ->addTariffToList(8) + ->addPackage([ + 'weight' => 1, + 'length' => 1, + 'width' => 2, + 'height' => 7, + ]) + ->addAdditionalService(2, 1000); + + $response = $this->getAnonymousClient()->sendCalculationWithTariffListRequest($request); + + /** @var \CdekSDK\Responses\CalculationWithTariffListResponse $response */ + foreach ($response->getErrors() as $error) { + $this->assertEmpty($error->getMessage()); + $this->fail($error->getErrorCode()); + } + + $this->assertFalse($response->hasErrors()); + + $this->assertCount(2, $response); + } + + public function test_failing_anonymous() + { + $request = new CalculationWithTariffListRequest(); + + $response = $this->getAnonymousClient()->sendCalculationWithTariffListRequest($request); + + /** @var \CdekSDK\Responses\CalculationWithTariffListResponse $response */ + $this->assertTrue($response->hasErrors()); + + foreach ($response->getErrors() as $error) { + $this->assertGreaterThan(0, $error->getCode()); + $this->assertNotEmpty($error->getMessage()); + } + + $this->assertCount(4, $response->getErrors()); + $this->assertCount(0, $response->getResults()); + } + + public function test_authorized_success() + { + $request = new CalculationWithTariffListAuthorizedRequest(); + $request->setSenderCityPostCode('295000') + ->setReceiverCityPostCode('652632') + ->addAdditionalService(AdditionalService::SERVICE_INSURANCE, 2000) + ->setTariffId(137) + ->setTariffId(233) + ->addPackage([ + 'weight' => 0.2, + 'length' => 25, + 'width' => 15, + 'height' => 10, + ]); + + $response = $this->getClient()->sendCalculationRequest($request); + + foreach ($response->getErrors() as $error) { + if ((int) $error->getErrorCode() === self::UNAUTHORIZED_ERROR) { + $this->skipIfTestEndpointIsUsed("{$error->getErrorCode()}: {$error->getMessage()}"); + } + + $this->fail("{$error->getErrorCode()}: {$error->getMessage()}"); + } + + $this->assertFalse($response->hasErrors()); + + /** @var \CdekSDK\Responses\CalculationWithTariffListResponse $response */ + $this->assertCount(2, $response); + + foreach ($response as $result) { + /** @var \CdekSDK\Responses\Types\TariffResult $result */ + $this->assertGreaterThan(0, $result->getPriceByCurrency()); + } + } +} diff --git a/tests/Serialization/CalculationRequestTest.php b/tests/Serialization/CalculationRequestTest.php index 7e08f53..4be9c66 100644 --- a/tests/Serialization/CalculationRequestTest.php +++ b/tests/Serialization/CalculationRequestTest.php @@ -69,6 +69,44 @@ public function test_example() ], $request->getBody()); } + public function test_with_currency() + { + $request = new CalculationRequest(); + + $request->setSenderCityPostCode('295000') + ->setReceiverCityPostCode('652632') + ->addTariffToList(1) + ->addTariffToList(8) + ->addPackage([ + 'weight' => 0.2, + 'length' => 25, + 'width' => 15, + 'height' => 10, + ]); + + $this->assertSame([ + 'version' => '1.0', + 'goods' => [ + [ + 'weight' => 0.2, + 'length' => 25, + 'width' => 15, + 'height' => 10, + ], + ], + 'tariffList' => [ + [ + 'id' => 1, + ], + [ + 'id' => 8, + ], + ], + 'senderCityPostCode' => '295000', + 'receiverCityPostCode' => '652632', + ], $request->jsonSerialize()); + } + public function test_with_authorization() { $request = CalculationRequest::withAuthorization(); @@ -154,6 +192,7 @@ public function test_with_currency_and_date() $this->assertSame([ 'version' => '1.0', + 'currency' => 'EUR', 'dateExecute' => '2019-04-08', 'secure' => 'bar', 'authLogin' => 'foo', @@ -171,6 +210,7 @@ public function test_anonymous_request() $this->assertSame([ 'version' => '1.0', + 'currency' => 'EUR', 'dateExecute' => '2019-04-08', ], $request->jsonSerialize()); } From d79369a274bd887ad3d4939bb4d3a0af1b15c5b4 Mon Sep 17 00:00:00 2001 From: Alexey Kopytko Date: Thu, 20 Jun 2019 06:37:06 +0900 Subject: [PATCH 02/11] CalculationWithTariffListRequest with a single tariff ID --- tests/Integration/CalculationWithTariffListRequestTest.php | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/tests/Integration/CalculationWithTariffListRequestTest.php b/tests/Integration/CalculationWithTariffListRequestTest.php index 760813d..221bf70 100644 --- a/tests/Integration/CalculationWithTariffListRequestTest.php +++ b/tests/Integration/CalculationWithTariffListRequestTest.php @@ -97,7 +97,6 @@ public function test_authorized_success() ->setReceiverCityPostCode('652632') ->addAdditionalService(AdditionalService::SERVICE_INSURANCE, 2000) ->setTariffId(137) - ->setTariffId(233) ->addPackage([ 'weight' => 0.2, 'length' => 25, @@ -118,7 +117,7 @@ public function test_authorized_success() $this->assertFalse($response->hasErrors()); /** @var \CdekSDK\Responses\CalculationWithTariffListResponse $response */ - $this->assertCount(2, $response); + $this->assertCount(1, $response); foreach ($response as $result) { /** @var \CdekSDK\Responses\Types\TariffResult $result */ From dd23cb736ba8d084287c79e58d1ecc778e532df2 Mon Sep 17 00:00:00 2001 From: Alexey Kopytko Date: Thu, 20 Jun 2019 23:01:23 +0900 Subject: [PATCH 03/11] Improve test coverage --- tests/Deserialization/InvalidXMLTest.php | 10 ++ .../NullableDateTimeHandlerTest.php | 1 + tests/Deserialization/RegionsResponseTest.php | 7 ++ .../CalculationWithTariffListRequestTest.php | 105 ++++++++++++++++++ 4 files changed, 123 insertions(+) create mode 100644 tests/Serialization/CalculationWithTariffListRequestTest.php diff --git a/tests/Deserialization/InvalidXMLTest.php b/tests/Deserialization/InvalidXMLTest.php index 2d328c3..1f82f3a 100644 --- a/tests/Deserialization/InvalidXMLTest.php +++ b/tests/Deserialization/InvalidXMLTest.php @@ -29,8 +29,10 @@ namespace Tests\CdekSDK\Deserialization; use CdekSDK\Common\Item; +use CdekSDK\Responses\CalculationWithTariffListResponse; use CdekSDK\Serialization\Exception\LibXMLError; use CdekSDK\Serialization\Exception\XmlErrorException; +use JMS\Serializer\Exception\RuntimeException; /** * @covers \CdekSDK\Serialization\Serializer @@ -46,6 +48,14 @@ public function test_it_throws_expected_type_of_exception() $this->getSerializer()->deserialize('', Item::class, 'xml'); } + public function test_passes_through_original_exception_if_not_xml() + { + $this->expectException(RuntimeException::class); + $this->expectExceptionMessage('Invalid data'); + + $this->getSerializer()->deserialize(\json_encode(['error' => ['a' => 'b']]), CalculationWithTariffListResponse::class, 'json'); + } + public function test_error_contains_invalid_xml() { try { diff --git a/tests/Deserialization/NullableDateTimeHandlerTest.php b/tests/Deserialization/NullableDateTimeHandlerTest.php index 6652e7c..5604b7d 100644 --- a/tests/Deserialization/NullableDateTimeHandlerTest.php +++ b/tests/Deserialization/NullableDateTimeHandlerTest.php @@ -30,6 +30,7 @@ use CdekSDK\Common\Order; use CdekSDK\Responses\StatusReportResponse; +use CdekSDK\Responses\Types\Result; use CdekSDK\Serialization\Exception\DeserializationException; use CdekSDK\Serialization\NullableDateTimeHandler; use JMS\Serializer\Exception\RuntimeException; diff --git a/tests/Deserialization/RegionsResponseTest.php b/tests/Deserialization/RegionsResponseTest.php index 063e668..70ae12c 100644 --- a/tests/Deserialization/RegionsResponseTest.php +++ b/tests/Deserialization/RegionsResponseTest.php @@ -76,6 +76,13 @@ public function test_it_deserializes_old_style_response() $this->assertSame($region, $item); } + public function test_it_return_zero_for_unknown_country() + { + $region = $this->getSerializer()->deserialize('', Region::class, 'xml'); + + $this->assertSame(0, $region->getCountryCode()); + } + public function test_it_deserializes() { $response = $this->getSerializer()->deserialize(FixtureLoader::load('RegionsISO.xml'), RegionsResponse::class, 'xml'); diff --git a/tests/Serialization/CalculationWithTariffListRequestTest.php b/tests/Serialization/CalculationWithTariffListRequestTest.php new file mode 100644 index 0000000..6029e53 --- /dev/null +++ b/tests/Serialization/CalculationWithTariffListRequestTest.php @@ -0,0 +1,105 @@ + and contributors + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +declare(strict_types=1); + +namespace Tests\CdekSDK\Serialization; + +use CdekSDK\Requests\CalculationWithTariffListRequest; +use PHPUnit\Framework\TestCase; + +/** + * @covers \CdekSDK\Requests\CalculationWithTariffListAuthorizedRequest + * @covers \CdekSDK\Requests\CalculationWithTariffListRequest + */ +class CalculationWithTariffListRequestTest extends TestCase +{ + public function test_example() + { + $request = new CalculationWithTariffListRequest(); + $request->setDateExecute(new \DateTime('2019-04-01')); + $request->setSenderCityId(44) + ->setReceiverCityId(269) + ->setCurrency('RUB') + ->addTariffToList(1) + ->addTariffToList(8) + ->addPackage([ + 'weight' => 1, + 'length' => 1, + 'width' => 2, + 'height' => 7, + ]) + ->addAdditionalService(2, 1000); + + $this->assertEquals(\json_decode('{ + "version":"1.0", + "dateExecute":"2019-04-01", + "senderCityId":"44", + "receiverCityId":"269", + "currency":"RUB", + "tariffList": + [ + { + "id":1 + }, + { + "id":8 + } + ], + "goods": + [ + { + "weight":"1", + "length":"1", + "width":"2", + "height":"7" + } + ], + "services": + [ + { + "id":2, + "param":1000 + } + ] + }', true), $request->jsonSerialize()); + } + + public function test_set_tariff_adds_to_list() + { + $request = new CalculationWithTariffListRequest(); + + $request->setTariffId(1)->setTariffId(2); + + $this->assertSame([ + 'version' => '1.0', + 'tariffList' => [ + ['id' => 1], + ['id' => 2], + ], + ], $request->jsonSerialize()); + } +} From 5e8b86f3efa5bbc468279cae55c9fa832cf15b1b Mon Sep 17 00:00:00 2001 From: Alexey Kopytko Date: Thu, 20 Jun 2019 23:22:01 +0900 Subject: [PATCH 04/11] Resolve CI issues --- src/Requests/Concerns/AnonymousJsonRequest.php | 1 + src/Responses/CalculationWithTariffListResponse.php | 2 +- .../Integration/CalculationWithTariffListRequestTest.php | 8 ++++++++ 3 files changed, 10 insertions(+), 1 deletion(-) diff --git a/src/Requests/Concerns/AnonymousJsonRequest.php b/src/Requests/Concerns/AnonymousJsonRequest.php index e42ebdf..1578909 100644 --- a/src/Requests/Concerns/AnonymousJsonRequest.php +++ b/src/Requests/Concerns/AnonymousJsonRequest.php @@ -32,6 +32,7 @@ trait AnonymousJsonRequest { /** * @phan-suppress PhanUndeclaredProperty + * @phan-suppress PhanTraitParentReference * * @return array */ diff --git a/src/Responses/CalculationWithTariffListResponse.php b/src/Responses/CalculationWithTariffListResponse.php index 9cec0df..dedbccb 100644 --- a/src/Responses/CalculationWithTariffListResponse.php +++ b/src/Responses/CalculationWithTariffListResponse.php @@ -63,7 +63,7 @@ public function hasErrors(): bool } /** - * @return HasErrorCode[]|Error[] + * @return Error[]|HasErrorCode[] */ public function getErrors(): array { diff --git a/tests/Integration/CalculationWithTariffListRequestTest.php b/tests/Integration/CalculationWithTariffListRequestTest.php index 221bf70..dd8e1c7 100644 --- a/tests/Integration/CalculationWithTariffListRequestTest.php +++ b/tests/Integration/CalculationWithTariffListRequestTest.php @@ -31,6 +31,7 @@ use CdekSDK\Common\AdditionalService; use CdekSDK\Requests\CalculationWithTariffListAuthorizedRequest; use CdekSDK\Requests\CalculationWithTariffListRequest; +use CdekSDK\Responses\Types\Error; /** * @covers \CdekSDK\Requests\CalculationWithTariffListAuthorizedRequest @@ -81,7 +82,9 @@ public function test_failing_anonymous() /** @var \CdekSDK\Responses\CalculationWithTariffListResponse $response */ $this->assertTrue($response->hasErrors()); + /** @var Error $error */ foreach ($response->getErrors() as $error) { + $this->assertInstanceOf(Error::class, $error); $this->assertGreaterThan(0, $error->getCode()); $this->assertNotEmpty($error->getMessage()); } @@ -90,6 +93,11 @@ public function test_failing_anonymous() $this->assertCount(0, $response->getResults()); } + /** + * @psalm-suppress InvalidArgument + * @psalm-suppress MixedAssignment + * @psalm-suppress MixedMethodCall + */ public function test_authorized_success() { $request = new CalculationWithTariffListAuthorizedRequest(); From 991827239dc7f1ef8239d016e1480658cd8117d0 Mon Sep 17 00:00:00 2001 From: Alexey Kopytko Date: Fri, 21 Jun 2019 00:24:06 +0900 Subject: [PATCH 05/11] WrapsResult: Move off duplicate code into a trait --- src/Responses/CalculationResponse.php | 21 +------ src/Responses/Concerns/WrapsResult.php | 60 +++++++++++++++++++ src/Responses/Types/TariffResult.php | 23 +------ .../CalculationResponseTest.php | 1 + .../CalculationWithTariffListResponseTest.php | 1 + 5 files changed, 67 insertions(+), 39 deletions(-) create mode 100644 src/Responses/Concerns/WrapsResult.php diff --git a/src/Responses/CalculationResponse.php b/src/Responses/CalculationResponse.php index a4e4ec0..3b1ef96 100644 --- a/src/Responses/CalculationResponse.php +++ b/src/Responses/CalculationResponse.php @@ -30,6 +30,7 @@ use CdekSDK\Contracts\HasErrorCode; use CdekSDK\Contracts\Response; +use CdekSDK\Responses\Concerns\WrapsResult; use CdekSDK\Responses\Types\AdditionalService; use CdekSDK\Responses\Types\Error; use CdekSDK\Responses\Types\Result; @@ -50,12 +51,7 @@ */ final class CalculationResponse implements Response { - /** - * @JMS\Type("CdekSDK\Responses\Types\Result") - * - * @var Result - */ - private $result; + use WrapsResult; /** * @JMS\SerializedName("error") @@ -94,19 +90,6 @@ public function getResult(): Result return $this->result; } - public function __call(string $name, array $arguments) - { - if ($this->hasErrors()) { - throw new \RuntimeException('Calculation request was not successful. Please check for errors before calling any instance methods.'); - } - - if ($this->result && \method_exists($this->result, $name)) { - return $this->result->{$name}(...$arguments); - } - - throw new \BadMethodCallException(\sprintf('Method [%s] not found in [%s].', $name, __CLASS__)); - } - public function jsonSerialize() { return []; diff --git a/src/Responses/Concerns/WrapsResult.php b/src/Responses/Concerns/WrapsResult.php new file mode 100644 index 0000000..dc06310 --- /dev/null +++ b/src/Responses/Concerns/WrapsResult.php @@ -0,0 +1,60 @@ + and contributors + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +declare(strict_types=1); + +namespace CdekSDK\Responses\Concerns; + +use CdekSDK\Responses\CalculationResponse; +use CdekSDK\Responses\Types\Result; +use CdekSDK\Responses\Types\TariffResult; + +trait WrapsResult +{ + /** + * @JMS\Type("CdekSDK\Responses\Types\Result") + * + * @var Result + */ + private $result; + + /** + * @phan-suppress PhanInfiniteRecursion + */ + public function __call(string $name, array $arguments) + { + /** @var $this CalculationResponse|TariffResult */ + if ($this->hasErrors()) { + throw new \RuntimeException('Calculation request was not successful. Please check for errors before calling any instance methods.'); + } + + if ($this->result && \method_exists($this->result, $name)) { + return $this->result->{$name}(...$arguments); + } + + throw new \BadMethodCallException(\sprintf('Method [%s] not found in [%s].', $name, __CLASS__)); + } +} diff --git a/src/Responses/Types/TariffResult.php b/src/Responses/Types/TariffResult.php index a8bce32..616d714 100644 --- a/src/Responses/Types/TariffResult.php +++ b/src/Responses/Types/TariffResult.php @@ -30,6 +30,7 @@ use CdekSDK\Contracts\HasErrorCode; use CdekSDK\Contracts\Response; +use CdekSDK\Responses\Concerns\WrapsResult; use JMS\Serializer\Annotation as JMS; /** @@ -47,6 +48,8 @@ */ final class TariffResult implements Response { + use WrapsResult; + /** * @JMS\Type("int") * @@ -61,13 +64,6 @@ final class TariffResult implements Response */ private $status; - /** - * @JMS\Type("CdekSDK\Responses\Types\Result") - * - * @var Result - */ - private $result; - /** * @return bool */ @@ -110,19 +106,6 @@ public function getResult(): Result return $this->result; } - public function __call(string $name, array $arguments) - { - if ($this->hasErrors()) { - throw new \RuntimeException('Calculation request was not successful. Please check for errors before calling any instance methods.'); - } - - if ($this->result && \method_exists($this->result, $name)) { - return $this->result->{$name}(...$arguments); - } - - throw new \BadMethodCallException(\sprintf('Method [%s] not found in [%s].', $name, __CLASS__)); - } - public function jsonSerialize() { return []; diff --git a/tests/Deserialization/CalculationResponseTest.php b/tests/Deserialization/CalculationResponseTest.php index b0d4f2a..e3ada7c 100644 --- a/tests/Deserialization/CalculationResponseTest.php +++ b/tests/Deserialization/CalculationResponseTest.php @@ -37,6 +37,7 @@ * @covers \CdekSDK\Responses\Types\Result * @covers \CdekSDK\Responses\Types\Error * @covers \CdekSDK\Responses\Types\AdditionalService + * @covers \CdekSDK\Responses\Concerns\WrapsResult */ class CalculationResponseTest extends TestCase { diff --git a/tests/Deserialization/CalculationWithTariffListResponseTest.php b/tests/Deserialization/CalculationWithTariffListResponseTest.php index 19ce4a7..9a9e45d 100644 --- a/tests/Deserialization/CalculationWithTariffListResponseTest.php +++ b/tests/Deserialization/CalculationWithTariffListResponseTest.php @@ -37,6 +37,7 @@ * @covers \CdekSDK\Responses\Types\Result * @covers \CdekSDK\Responses\Types\Error * @covers \CdekSDK\Responses\Types\TariffResult + * @covers \CdekSDK\Responses\Concerns\WrapsResult */ class CalculationWithTariffListResponseTest extends TestCase { From 16f1faefc9abfcf00818fb23aecb43ea3af6a4a3 Mon Sep 17 00:00:00 2001 From: Alexey Kopytko Date: Fri, 21 Jun 2019 02:33:25 +0900 Subject: [PATCH 06/11] Add examples/045_CalculationWithTariffListRequest.php --- .../045_CalculationWithTariffListRequest.php | 77 +++++++++++++++++++ 1 file changed, 77 insertions(+) create mode 100644 examples/045_CalculationWithTariffListRequest.php diff --git a/examples/045_CalculationWithTariffListRequest.php b/examples/045_CalculationWithTariffListRequest.php new file mode 100644 index 0000000..c936426 --- /dev/null +++ b/examples/045_CalculationWithTariffListRequest.php @@ -0,0 +1,77 @@ + and contributors + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +declare(strict_types=1); +use CdekSDK\Requests; + +$client = new \CdekSDK\CdekClient('account', 'password'); + +// для выполнения запроса без авторизации используется +// $request = new Requests\CalculationWithTariffListRequest(); +// $request->set...() и так далее + +$request = new Requests\CalculationWithTariffListAuthorizedRequest(); +$request->setSenderCityPostCode('295000') + ->setReceiverCityPostCode('652632') + ->addTariffToList(1) + ->addTariffToList(8) + ->addPackage([ + 'weight' => 0.2, + 'length' => 25, + 'width' => 15, + 'height' => 10, + ]); + +$response = $client->sendCalculationWithTariffListRequest($request); + +/** @var \CdekSDK\Responses\CalculationWithTariffListResponse $response */ +if ($response->hasErrors()) { + // обработка ошибок +} + +foreach ($response->getResults() as $result) { + if ($result->hasErrors()) { + // обработка ошибок + + continue; + } + + if (!$result->getStatus()) { + continue; + } + + $result->getTariffId(); + // int(1) + + $result->getPrice(); + // double(1570) + + $result->getDeliveryPeriodMin(); + // int(4) + + $result->getDeliveryPeriodMax(); + // int(5) +} From a3ec53d90da92de5315d63c226f50f93e8ab4468 Mon Sep 17 00:00:00 2001 From: Alexey Kopytko Date: Fri, 21 Jun 2019 02:35:40 +0900 Subject: [PATCH 07/11] CalculationWithTariffListRequest can safely be made final --- src/Requests/CalculationWithTariffListAuthorizedRequest.php | 2 +- src/Requests/CalculationWithTariffListRequest.php | 5 +---- 2 files changed, 2 insertions(+), 5 deletions(-) diff --git a/src/Requests/CalculationWithTariffListAuthorizedRequest.php b/src/Requests/CalculationWithTariffListAuthorizedRequest.php index 0c936ae..e0505e8 100644 --- a/src/Requests/CalculationWithTariffListAuthorizedRequest.php +++ b/src/Requests/CalculationWithTariffListAuthorizedRequest.php @@ -38,7 +38,7 @@ class CalculationWithTariffListAuthorizedRequest extends CalculationAuthorizedRe const ADDRESS = 'https://api.cdek.ru/calculator/calculate_tarifflist.php'; const RESPONSE = CalculationWithTariffListResponse::class; - public function setTariffId($id) + final public function setTariffId($id) { return $this->addTariffToList($id); } diff --git a/src/Requests/CalculationWithTariffListRequest.php b/src/Requests/CalculationWithTariffListRequest.php index f3dd0da..84b58de 100644 --- a/src/Requests/CalculationWithTariffListRequest.php +++ b/src/Requests/CalculationWithTariffListRequest.php @@ -30,10 +30,7 @@ use CdekSDK\Requests\Concerns\AnonymousJsonRequest; -/** - * @final - */ -class CalculationWithTariffListRequest extends CalculationWithTariffListAuthorizedRequest +final class CalculationWithTariffListRequest extends CalculationWithTariffListAuthorizedRequest { use AnonymousJsonRequest; } From 69c7ec5e2112eab2d9485c07038902d3f08c7734 Mon Sep 17 00:00:00 2001 From: Alexey Kopytko Date: Fri, 21 Jun 2019 02:43:50 +0900 Subject: [PATCH 08/11] Document CalculationWithTariffListRequest --- README.md | 2 +- docs/index.md | 60 +++++++++++++++++++++++++++++++++++++++++++++++++-- 2 files changed, 59 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index 2a289e7..abcbe6c 100644 --- a/README.md +++ b/README.md @@ -16,7 +16,7 @@ - [x] расчёт тарифов и обращения к справочникам - [x] [расчёт стоимости доставки по тарифам с приоритетом](https://cdek-sdk.readthedocs.io/#CalculationRequest) :unlock: :closed_lock_with_key: - - [ ] расчёт стоимости по тарифам без приоритета :unlock: :closed_lock_with_key: + - [x] [расчёт стоимости по тарифам без приоритета](https://cdek-sdk.readthedocs.io/#CalculationWithTariffListRequest) :unlock: :closed_lock_with_key: - [x] [получение списка пунктов выдачи заказов (ПВЗ) с фильтрацией](https://cdek-sdk.readthedocs.io/#PvzListRequest) :unlock: - [x] [получение списка регионов-субъектов РФ](https://cdek-sdk.readthedocs.io/#RegionsRequest) :unlock: - [x] [получение списка городов](https://cdek-sdk.readthedocs.io/#CitiesRequest) :unlock: diff --git a/docs/index.md b/docs/index.md index 5969b49..ef80746 100644 --- a/docs/index.md +++ b/docs/index.md @@ -66,7 +66,8 @@ $client = new \CdekSDK\CdekClient('Account', 'Secure', new \GuzzleHttp\Client([ | [Вызов курьера](#CallCourierRequest) | `sendCallCourierRequest` | `CallCourierRequest` | | [Создание преалерта](#PreAlertRequest) | `sendPreAlertRequest` | `PreAlertRequest` | | [Отчет "Информация по заказам"](#InfoReportRequest) | `sendInfoReportRequest` | `InfoReportRequest` | -| [Расчёт стоимости доставки](#CalculationRequest) | `sendCalculationRequest` | `CalculationRequest` | +| [Расчёт стоимости доставки с приоритетом](#CalculationRequest) | `sendCalculationRequest` | `CalculationRequest` | +| [Расчёт стоимости доставки без приоритета](#CalculationWithTariffListRequest) | `sendCalculationWithTariffListRequest` | `CalculationWithTariffListRequest` | | [Отчет "Статусы заказов"](#StatusReportRequest) | `sendStatusReportRequest` | `StatusReportRequest` | | [Печать квитанции к заказу](#PrintReceiptsRequest) | `sendPrintReceiptsRequest` | `PrintReceiptsRequest` | | [Печать ШК-мест](#PrintLabelsRequest) | `sendPrintLabelsRequest` | `PrintLabelsRequest` | @@ -160,7 +161,7 @@ foreach ($response as $item) { } ``` -### Расчёт стоимости доставки {: #CalculationRequest } +### Расчёт стоимости доставки с приоритетом {: #CalculationRequest } ```php use CdekSDK\Requests; @@ -199,6 +200,61 @@ $response->getPrice(); При прочих равных лучше всегда использовать запрос с авторизацией. +### Расчет стоимости по тарифам без приоритета {: #CalculationWithTariffListRequest } + +Этот способ расчёта подразумевает получение нескольких расчётов стоимости доставки для каждого из запрошенных тарифов. + +``` +use CdekSDK\Requests; + +// для выполнения запроса без авторизации используется +// $request = new Requests\CalculationWithTariffListRequest(); +// $request->set...() и так далее + +$request = new Requests\CalculationWithTariffListAuthorizedRequest(); +$request->setSenderCityPostCode('295000') + ->setReceiverCityPostCode('652632') + ->addTariffToList(1) + ->addTariffToList(8) + ->addPackage([ + 'weight' => 0.2, + 'length' => 25, + 'width' => 15, + 'height' => 10, + ]); + +$response = $client->sendCalculationWithTariffListRequest($request); + +/** @var \CdekSDK\Responses\CalculationWithTariffListResponse $response */ +if ($response->hasErrors()) { + // обработка ошибок +} + +foreach ($response->getResults() as $result) { + if ($result->hasErrors()) { + // обработка ошибок + + continue; + } + + if (!$result->getStatus()) { + continue; + } + + $result->getTariffId(); + // int(1) + + $result->getPrice(); + // double(1570) + + $result->getDeliveryPeriodMin(); + // int(4) + + $result->getDeliveryPeriodMax(); + // int(5) +} +``` + ### Список регионов/субъектов РФ {: #RegionsRequest } ```php From 375b713cf3320a9a1c0aebf06941f0ebc07150fe Mon Sep 17 00:00:00 2001 From: Alexey Kopytko Date: Fri, 21 Jun 2019 02:55:54 +0900 Subject: [PATCH 09/11] Tag more functions as final --- src/Common/Fillable.php | 4 ++++ src/Requests/Concerns/MagicSetters.php | 3 +++ src/Requests/Concerns/ParamRequest.php | 3 +++ src/Responses/Concerns/HasErrors.php | 3 +++ src/Responses/Concerns/WrapsResult.php | 1 + 5 files changed, 14 insertions(+) diff --git a/src/Common/Fillable.php b/src/Common/Fillable.php index 809ceef..a56ba74 100644 --- a/src/Common/Fillable.php +++ b/src/Common/Fillable.php @@ -35,6 +35,8 @@ trait Fillable * @psalm-suppress MixedArgument * * @param array $data + * + * @final */ public function __construct(array $data = []) { @@ -55,6 +57,8 @@ public function __construct(array $data = []) * @phan-suppress PhanTypeInstantiateTrait * * @return static + * + * @final */ public static function create($data = []) { diff --git a/src/Requests/Concerns/MagicSetters.php b/src/Requests/Concerns/MagicSetters.php index e68f42d..50f7bc0 100644 --- a/src/Requests/Concerns/MagicSetters.php +++ b/src/Requests/Concerns/MagicSetters.php @@ -30,6 +30,9 @@ trait MagicSetters { + /** + * @final + */ public function __call(string $name, array $arguments) { if (0 === \strpos($name, 'set') && \property_exists($this, $property = \lcfirst(\substr($name, 3)))) { diff --git a/src/Requests/Concerns/ParamRequest.php b/src/Requests/Concerns/ParamRequest.php index c450cd3..ed6039f 100644 --- a/src/Requests/Concerns/ParamRequest.php +++ b/src/Requests/Concerns/ParamRequest.php @@ -30,6 +30,9 @@ trait ParamRequest { + /** + * @final + */ public function getParams(): array { return \array_filter(\get_object_vars($this), function ($value) { diff --git a/src/Responses/Concerns/HasErrors.php b/src/Responses/Concerns/HasErrors.php index ae03707..13a919a 100644 --- a/src/Responses/Concerns/HasErrors.php +++ b/src/Responses/Concerns/HasErrors.php @@ -32,6 +32,9 @@ trait HasErrors { + /** + * @final + */ public function hasErrors(): bool { \assert($this instanceof Response); diff --git a/src/Responses/Concerns/WrapsResult.php b/src/Responses/Concerns/WrapsResult.php index dc06310..a6ecdf8 100644 --- a/src/Responses/Concerns/WrapsResult.php +++ b/src/Responses/Concerns/WrapsResult.php @@ -43,6 +43,7 @@ trait WrapsResult /** * @phan-suppress PhanInfiniteRecursion + * @final */ public function __call(string $name, array $arguments) { From e6dcadd8ea3d72cc5b7f376905ee3a7db3f10812 Mon Sep 17 00:00:00 2001 From: Alexey Kopytko Date: Fri, 21 Jun 2019 03:07:30 +0900 Subject: [PATCH 10/11] Refactor CalculationAuthorizedRequest into Templates\CalculationAuthorizedRequest --- src/Requests/CalculationAuthorizedRequest.php | 259 +-------------- ...ulationWithTariffListAuthorizedRequest.php | 2 +- .../CalculationAuthorizedRequest.php | 296 ++++++++++++++++++ tests/Integration/CalculationRequestTest.php | 6 + .../Serialization/CalculationRequestTest.php | 1 + .../CalculationWithTariffListRequestTest.php | 1 + 6 files changed, 306 insertions(+), 259 deletions(-) create mode 100644 src/Requests/Templates/CalculationAuthorizedRequest.php diff --git a/src/Requests/CalculationAuthorizedRequest.php b/src/Requests/CalculationAuthorizedRequest.php index d8c0143..09a3f84 100644 --- a/src/Requests/CalculationAuthorizedRequest.php +++ b/src/Requests/CalculationAuthorizedRequest.php @@ -28,12 +28,6 @@ namespace CdekSDK\Requests; -use CdekSDK\Common\AdditionalService; -use CdekSDK\Contracts\DateAware; -use CdekSDK\Contracts\JsonRequest; -use CdekSDK\Contracts\ShouldAuthorize; -use CdekSDK\Requests\Concerns\Authorized; -use CdekSDK\Requests\Concerns\RequestCore; use CdekSDK\Responses\CalculationResponse; /** @@ -41,98 +35,11 @@ * * @final */ -class CalculationAuthorizedRequest implements JsonRequest, \JsonSerializable, DateAware, ShouldAuthorize +class CalculationAuthorizedRequest extends Templates\CalculationAuthorizedRequest { - use RequestCore; - use Authorized; - - const VERSION = '1.0'; - - const SERVICE_INSURANCE = AdditionalService::SERVICE_INSURANCE; // Страховка - const SERVICE_DANGEROUS_GOODS = AdditionalService::SERVICE_DANGEROUS_GOODS; // Опасный груз - const SERVICE_PICKUP = AdditionalService::SERVICE_PICKUP; // Забор в городе отправителе - const SERVICE_DELIVERY_TO_DOOR = AdditionalService::SERVICE_DELIVERY_TO_DOOR; // Доставка в городе получателе - const SERVICE_PACKAGE_1 = AdditionalService::SERVICE_PACKAGE_1; // Упаковка 1 - const SERVICE_PACKAGE_2 = AdditionalService::SERVICE_PACKAGE_2; // Упаковка 2 - const SERVICE_TRY_AT_HOME = AdditionalService::SERVICE_TRY_AT_HOME; // Примерка на дому - const SERVICE_PERSONAL_DELIVERY = AdditionalService::SERVICE_PERSONAL_DELIVERY; // Доставка лично в руки - const SERVICE_DOCUMENTS_COPY = AdditionalService::SERVICE_DOCUMENTS_COPY; // Скан документов - const SERVICE_PARTIAL_DELIVERY = AdditionalService::SERVICE_PARTIAL_DELIVERY; // Частичная доставка - const SERVICE_CARGO_CHECK = AdditionalService::SERVICE_CARGO_CHECK; // Осмотр вложения - - const MODE_DOOR_DOOR = 1; - const MODE_DOOR_WAREHOUSE = 2; - const MODE_WAREHOUSE_DOOR = 3; - const MODE_WAREHOUSE_WAREHOUSE = 4; - - const METHOD = 'POST'; const ADDRESS = 'https://api.cdek.ru/calculator/calculate_price_by_json.php'; const RESPONSE = CalculationResponse::class; - /** - * Код города отправителя из базы СДЭК. - */ - protected $senderCityId; - - /** - * Индекс города отправителя из базы СДЭКm. - */ - protected $senderCityPostCode; - - /** - * Код города получателя из базы СДЭК. - */ - protected $receiverCityId; - - /** - * Индекс города получателя из базы СДЭК. - */ - protected $receiverCityPostCode; - - /** - * Габаритные характеристики места. - * - * @var array[] - */ - protected $goods = []; - - protected $modeId; - - /** - * Список передаваемых дополнительных услуг. - * - * @var array[] - */ - protected $services; - - /** - * Код выбранного тарифа. - * - * @var int|null - */ - protected $tariffId; - - /** - * Список тарифов. - * - * @var array[] - */ - protected $tariffList = []; - - /** - * Валюта, в которой необходимо рассчитать стоимость доставки. По умолчанию - RUB. - * - * @var string - */ - protected $currency; - - /** - * Планируемая дата отправки заказа в формате. - * - * @var \DateTimeInterface|null - */ - protected $dateExecute; - /** * @deprecated * @phan-suppress PhanDeprecatedClass @@ -143,168 +50,4 @@ public static function withAuthorization(): CalculationAuthorizedRequest { return new CalculationAuthorizedRequest(); } - - /** @return self */ - public function setSenderCityId($id) - { - $this->senderCityId = $id; - - return $this; - } - - /** @return self */ - public function setReceiverCityId($id) - { - $this->receiverCityId = $id; - - return $this; - } - - /** @return self */ - public function setSenderCityPostCode($code) - { - $this->senderCityPostCode = $code; - - return $this; - } - - /** @return self */ - public function setReceiverCityPostCode($code) - { - $this->receiverCityPostCode = $code; - - return $this; - } - - /** - * @param mixed $id - * - * @return self - */ - public function setTariffId($id) - { - $this->tariffList = []; - - $this->tariffId = (int) $id; - - return $this; - } - - /** - * @param mixed $id - * @param mixed $priority - * @param mixed $modeId - * - * @return self - */ - public function addTariffToList($id, $priority = null, $modeId = null) - { - $this->tariffId = null; - - $this->tariffList[] = \array_filter([ - 'id' => $id, - 'priority' => $priority, - 'modeId' => $modeId, - ], function ($value) { - return null !== $value; - }); - - return $this; - } - - /** @return self */ - public function setModeId($id) - { - $this->modeId = $id; - - return $this; - } - - /** - * @param array $good - * - * @return self - */ - public function addPackage($good) - { - $this->goods[] = $good; - - return $this; - } - - /** - * @param int $serviceId - * @param int|float|string $param - * - * @return self - */ - public function addAdditionalService($serviceId, $param = null) - { - $this->services[] = [ - 'id' => (int) $serviceId, - 'param' => $param, - ]; - - return $this; - } - - /** @return self */ - public function setCurrency(string $currencyCode) - { - $this->currency = $currencyCode; - - return $this; - } - - /** @return static */ - public function setDateExecute(\DateTimeInterface $date) - { - $this->dateExecute = $date; - - return $this; - } - - public function getRequestDate(): \DateTimeInterface - { - return $this->dateExecute ?? new \DateTimeImmutable(); - } - - /** @deprecated */ - public function getBody(): array - { - return $this->jsonSerialize(); - } - - /** - * @phan-suppress PhanDeprecatedProperty - * - * @return array - */ - public function jsonSerialize() - { - $result = \array_filter([ - 'version' => self::VERSION, - 'goods' => $this->goods, - 'modeId' => $this->modeId, - 'tariffId' => $this->tariffId, - 'tariffList' => $this->tariffList, - 'senderCityId' => $this->senderCityId, - 'senderCityPostCode' => $this->senderCityPostCode, - 'services' => $this->services, - 'receiverCityId' => $this->receiverCityId, - 'receiverCityPostCode' => $this->receiverCityPostCode, - 'currency' => $this->currency, - 'dateExecute' => $this->dateExecute instanceof \DateTimeInterface ? $this->dateExecute->format('Y-m-d') : null, - ]); - - if ($this->account === '') { - return $result; - } - - return \array_merge($result, [ - 'secure' => $this->secure, - 'authLogin' => $this->account, - 'dateExecute' => $this->date->format('Y-m-d'), - ]); - } } diff --git a/src/Requests/CalculationWithTariffListAuthorizedRequest.php b/src/Requests/CalculationWithTariffListAuthorizedRequest.php index e0505e8..229994c 100644 --- a/src/Requests/CalculationWithTariffListAuthorizedRequest.php +++ b/src/Requests/CalculationWithTariffListAuthorizedRequest.php @@ -33,7 +33,7 @@ /** * @final */ -class CalculationWithTariffListAuthorizedRequest extends CalculationAuthorizedRequest +class CalculationWithTariffListAuthorizedRequest extends Templates\CalculationAuthorizedRequest { const ADDRESS = 'https://api.cdek.ru/calculator/calculate_tarifflist.php'; const RESPONSE = CalculationWithTariffListResponse::class; diff --git a/src/Requests/Templates/CalculationAuthorizedRequest.php b/src/Requests/Templates/CalculationAuthorizedRequest.php new file mode 100644 index 0000000..d8ec6d7 --- /dev/null +++ b/src/Requests/Templates/CalculationAuthorizedRequest.php @@ -0,0 +1,296 @@ + and contributors + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +declare(strict_types=1); + +namespace CdekSDK\Requests\Templates; + +use CdekSDK\Common\AdditionalService; +use CdekSDK\Contracts\DateAware; +use CdekSDK\Contracts\JsonRequest; +use CdekSDK\Contracts\ShouldAuthorize; +use CdekSDK\Requests\Concerns\Authorized; +use CdekSDK\Requests\Concerns\RequestCore; + +/** + * Class CalculationAuthorizedRequest. + */ +abstract class CalculationAuthorizedRequest implements JsonRequest, \JsonSerializable, DateAware, ShouldAuthorize +{ + use RequestCore; + use Authorized; + + const METHOD = 'POST'; + const ADDRESS = ''; + const RESPONSE = ''; + + const VERSION = '1.0'; + + const SERVICE_INSURANCE = AdditionalService::SERVICE_INSURANCE; // Страховка + const SERVICE_DANGEROUS_GOODS = AdditionalService::SERVICE_DANGEROUS_GOODS; // Опасный груз + const SERVICE_PICKUP = AdditionalService::SERVICE_PICKUP; // Забор в городе отправителе + const SERVICE_DELIVERY_TO_DOOR = AdditionalService::SERVICE_DELIVERY_TO_DOOR; // Доставка в городе получателе + const SERVICE_PACKAGE_1 = AdditionalService::SERVICE_PACKAGE_1; // Упаковка 1 + const SERVICE_PACKAGE_2 = AdditionalService::SERVICE_PACKAGE_2; // Упаковка 2 + const SERVICE_TRY_AT_HOME = AdditionalService::SERVICE_TRY_AT_HOME; // Примерка на дому + const SERVICE_PERSONAL_DELIVERY = AdditionalService::SERVICE_PERSONAL_DELIVERY; // Доставка лично в руки + const SERVICE_DOCUMENTS_COPY = AdditionalService::SERVICE_DOCUMENTS_COPY; // Скан документов + const SERVICE_PARTIAL_DELIVERY = AdditionalService::SERVICE_PARTIAL_DELIVERY; // Частичная доставка + const SERVICE_CARGO_CHECK = AdditionalService::SERVICE_CARGO_CHECK; // Осмотр вложения + + const MODE_DOOR_DOOR = 1; + const MODE_DOOR_WAREHOUSE = 2; + const MODE_WAREHOUSE_DOOR = 3; + const MODE_WAREHOUSE_WAREHOUSE = 4; + + /** + * Код города отправителя из базы СДЭК. + */ + protected $senderCityId; + + /** + * Индекс города отправителя из базы СДЭКm. + */ + protected $senderCityPostCode; + + /** + * Код города получателя из базы СДЭК. + */ + protected $receiverCityId; + + /** + * Индекс города получателя из базы СДЭК. + */ + protected $receiverCityPostCode; + + /** + * Габаритные характеристики места. + * + * @var array[] + */ + protected $goods = []; + + protected $modeId; + + /** + * Список передаваемых дополнительных услуг. + * + * @var array[] + */ + protected $services; + + /** + * Код выбранного тарифа. + * + * @var int|null + */ + protected $tariffId; + + /** + * Список тарифов. + * + * @var array[] + */ + protected $tariffList = []; + + /** + * Валюта, в которой необходимо рассчитать стоимость доставки. По умолчанию - RUB. + * + * @var string + */ + protected $currency; + + /** + * Планируемая дата отправки заказа в формате. + * + * @var \DateTimeInterface|null + */ + protected $dateExecute; + + /** @return self */ + public function setSenderCityId($id) + { + $this->senderCityId = $id; + + return $this; + } + + /** @return self */ + public function setReceiverCityId($id) + { + $this->receiverCityId = $id; + + return $this; + } + + /** @return self */ + public function setSenderCityPostCode($code) + { + $this->senderCityPostCode = $code; + + return $this; + } + + /** @return self */ + public function setReceiverCityPostCode($code) + { + $this->receiverCityPostCode = $code; + + return $this; + } + + /** + * @param mixed $id + * + * @return self + */ + public function setTariffId($id) + { + $this->tariffList = []; + + $this->tariffId = (int) $id; + + return $this; + } + + /** + * @param mixed $id + * @param mixed $priority + * @param mixed $modeId + * + * @return self + */ + public function addTariffToList($id, $priority = null, $modeId = null) + { + $this->tariffId = null; + + $this->tariffList[] = \array_filter([ + 'id' => $id, + 'priority' => $priority, + 'modeId' => $modeId, + ], function ($value) { + return null !== $value; + }); + + return $this; + } + + /** @return self */ + public function setModeId($id) + { + $this->modeId = $id; + + return $this; + } + + /** + * @param array $good + * + * @return self + */ + public function addPackage($good) + { + $this->goods[] = $good; + + return $this; + } + + /** + * @param int $serviceId + * @param int|float|string $param + * + * @return self + */ + public function addAdditionalService($serviceId, $param = null) + { + $this->services[] = [ + 'id' => (int) $serviceId, + 'param' => $param, + ]; + + return $this; + } + + /** @return self */ + public function setCurrency(string $currencyCode) + { + $this->currency = $currencyCode; + + return $this; + } + + /** @return static */ + public function setDateExecute(\DateTimeInterface $date) + { + $this->dateExecute = $date; + + return $this; + } + + public function getRequestDate(): \DateTimeInterface + { + return $this->dateExecute ?? new \DateTimeImmutable(); + } + + /** @deprecated */ + public function getBody(): array + { + return $this->jsonSerialize(); + } + + /** + * @phan-suppress PhanDeprecatedProperty + * + * @return array + */ + public function jsonSerialize() + { + $result = \array_filter([ + 'version' => self::VERSION, + 'goods' => $this->goods, + 'modeId' => $this->modeId, + 'tariffId' => $this->tariffId, + 'tariffList' => $this->tariffList, + 'senderCityId' => $this->senderCityId, + 'senderCityPostCode' => $this->senderCityPostCode, + 'services' => $this->services, + 'receiverCityId' => $this->receiverCityId, + 'receiverCityPostCode' => $this->receiverCityPostCode, + 'currency' => $this->currency, + 'dateExecute' => $this->dateExecute instanceof \DateTimeInterface ? $this->dateExecute->format('Y-m-d') : null, + ]); + + if ($this->account === '') { + return $result; + } + + return \array_merge($result, [ + 'secure' => $this->secure, + 'authLogin' => $this->account, + 'dateExecute' => $this->date->format('Y-m-d'), + ]); + } +} diff --git a/tests/Integration/CalculationRequestTest.php b/tests/Integration/CalculationRequestTest.php index fac5566..6e2cbfa 100644 --- a/tests/Integration/CalculationRequestTest.php +++ b/tests/Integration/CalculationRequestTest.php @@ -68,6 +68,9 @@ public function test_success_anonymous() $this->assertGreaterThan(0, $response->getPrice()); } + /** + * @psalm-suppress ArgumentTypeCoercion + */ public function test_authorized_success() { $request = CalculationRequest::withAuthorization() @@ -99,6 +102,9 @@ public function test_authorized_success() $this->assertGreaterThan(0, $response->getPrice()); } + /** + * @psalm-suppress ArgumentTypeCoercion + */ public function test_failure() { $request = (new CalculationRequest()) diff --git a/tests/Serialization/CalculationRequestTest.php b/tests/Serialization/CalculationRequestTest.php index 4be9c66..cb46a96 100644 --- a/tests/Serialization/CalculationRequestTest.php +++ b/tests/Serialization/CalculationRequestTest.php @@ -36,6 +36,7 @@ /** * @covers \CdekSDK\Requests\CalculationRequest * @covers \CdekSDK\Requests\CalculationAuthorizedRequest + * @covers \CdekSDK\Requests\Templates\CalculationAuthorizedRequest */ class CalculationRequestTest extends TestCase { diff --git a/tests/Serialization/CalculationWithTariffListRequestTest.php b/tests/Serialization/CalculationWithTariffListRequestTest.php index 6029e53..cd80119 100644 --- a/tests/Serialization/CalculationWithTariffListRequestTest.php +++ b/tests/Serialization/CalculationWithTariffListRequestTest.php @@ -34,6 +34,7 @@ /** * @covers \CdekSDK\Requests\CalculationWithTariffListAuthorizedRequest * @covers \CdekSDK\Requests\CalculationWithTariffListRequest + * @covers \CdekSDK\Requests\Templates\CalculationAuthorizedRequest */ class CalculationWithTariffListRequestTest extends TestCase { From 929599cd8906a50b1a4daacf7f8152d37ed37954 Mon Sep 17 00:00:00 2001 From: Alexey Kopytko Date: Fri, 21 Jun 2019 03:10:56 +0900 Subject: [PATCH 11/11] Fix RegionsRequestTest by looking for all variants of country's name --- tests/Integration/RegionsRequestTest.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/Integration/RegionsRequestTest.php b/tests/Integration/RegionsRequestTest.php index a94e87d..daf55a9 100644 --- a/tests/Integration/RegionsRequestTest.php +++ b/tests/Integration/RegionsRequestTest.php @@ -64,7 +64,7 @@ public function test_example() $this->assertSame(14, $region->getCode()); $this->assertSame(27, $region->getCodeExt()); $this->assertSame('7d468b39-1afa-41ec-8c4f-97a8603cb3d4', $region->getFiasGuid()); - $this->assertSame('Russia', $region->getCountryName()); + $this->assertContains($region->getCountryName(), ['Россия', 'Russia']); $this->assertSame(643, $region->getCountryCodeExt()); $this->assertSame('RU', $region->getCountryCodeISO()); }