diff --git a/.github/workflows/index.yml b/.github/workflows/index.yml index 1b1a182f..1dfd3326 100644 --- a/.github/workflows/index.yml +++ b/.github/workflows/index.yml @@ -7,26 +7,31 @@ jobs: runs-on: ubuntu-latest steps: - name: Checkout - uses: actions/checkout@v2 + uses: actions/checkout@v4 + + - name: Setup PHP + uses: shivammathur/setup-php@v2 + with: + php-version: '7.4' - name: Cache vendor folder - uses: actions/cache@v1 + uses: actions/cache@v4 with: path: vendor key: php-${{ hashFiles('composer.lock') }} - name: Cache composer folder - uses: actions/cache@v1 + uses: actions/cache@v4 with: path: ~/.composer/cache key: php-composer-cache - - run: composer install + - run: composer install --no-interaction --prefer-source - name: Run auto indexing run: php vendor/bin/autoindex - - uses: stefanzweifel/git-auto-commit-action@v4 + - uses: stefanzweifel/git-auto-commit-action@v5 with: commit_message: Adding auto indexes @@ -36,26 +41,30 @@ jobs: runs-on: ubuntu-latest steps: - name: Checkout - uses: actions/checkout@v2 + uses: actions/checkout@v4 + + - name: Setup PHP + uses: shivammathur/setup-php@v2 + with: + php-version: '7.4' - name: Cache vendor folder - uses: actions/cache@v1 + uses: actions/cache@v4 with: path: vendor key: php-${{ hashFiles('composer.lock') }} - name: Cache composer folder - uses: actions/cache@v1 + uses: actions/cache@v4 with: path: ~/.composer/cache key: php-composer-cache - - run: composer install + - run: composer install --no-interaction --prefer-source - name: Adding licenses run: vendor/bin/header-stamp --license=assets/afl.txt --exclude=vendor,node_modules - - uses: stefanzweifel/git-auto-commit-action@v4 + - uses: stefanzweifel/git-auto-commit-action@v5 with: commit_message: Automatic license addition applying - diff --git a/config/service.yml b/config/service.yml index 1271387d..815da557 100644 --- a/config/service.yml +++ b/config/service.yml @@ -213,11 +213,15 @@ services: - '@invertus.dpdbaltics_api.factory.apirequest.collection_request_factory' - '@dpdbaltics' + invertus.dpdbaltics.service.api.parser.courier_request_response_parser: + class: 'Invertus\dpdBaltics\Service\API\Parser\CourierRequestResponseParser' + invertus.dpdbaltics.service.api.courier_request_service: class: 'Invertus\dpdBaltics\Service\API\CourierRequestService' arguments: - '@invertus.dpdbaltics_api.factory.apirequest.courier_request_factory' - '@dpdbaltics' + - '@invertus.dpdbaltics.service.api.parser.courier_request_response_parser' invertus.dpdbaltics.service.parcel.parcel_update_service: class: 'Invertus\dpdBaltics\Service\Parcel\ParcelUpdateService' diff --git a/controllers/admin/AdminDPDBalticsCourierRequestController.php b/controllers/admin/AdminDPDBalticsCourierRequestController.php index 9d527ccf..0f4b2d9c 100644 --- a/controllers/admin/AdminDPDBalticsCourierRequestController.php +++ b/controllers/admin/AdminDPDBalticsCourierRequestController.php @@ -30,6 +30,7 @@ use Invertus\dpdBaltics\Repository\PhonePrefixRepository; use Invertus\dpdBaltics\Service\API\CourierRequestService; use Invertus\dpdBaltics\Service\Exception\ExceptionService; +use Invertus\dpdBaltics\Util\PickupTimeSlotUtility; use Invertus\dpdBaltics\Util\TimeZoneUtility; use Invertus\dpdBaltics\Validate\CourierRequest\CourierRequestValidator; use Invertus\dpdBalticsApi\Exception\DPDBalticsAPIException; @@ -156,16 +157,35 @@ private function initForm() 'required' => true, ], [ - 'label' => $this->l('Desired pick-up time'), - 'name' => 'pick_up_time', - 'type' => 'datetime', + 'label' => $this->l('Pick-up date'), + 'name' => 'pick_up_date', + 'type' => 'date', 'required' => true, ], [ - 'label' => $this->l('Last pick-up time'), - 'name' => 'sender_work_until', - 'type' => 'datetime', + 'label' => $this->l('Pick-up time from'), + 'name' => 'pick_up_time_from', + 'type' => 'select', + 'class' => 'fixed-width-xxl', 'required' => true, + 'desc' => $this->l('Only these time slots are accepted by DPD.'), + 'options' => [ + 'id' => 'id', + 'name' => 'name', + 'query' => $this->getPickupTimeSlotOptions(PickupTimeSlotUtility::getPickupTimeFromSlots()), + ], + ], + [ + 'label' => $this->l('Pick-up time until'), + 'name' => 'pick_up_time_to', + 'type' => 'select', + 'class' => 'fixed-width-xxl', + 'required' => true, + 'options' => [ + 'id' => 'id', + 'name' => 'name', + 'query' => $this->getPickupTimeSlotOptions(PickupTimeSlotUtility::getPickupTimeToSlots()), + ], ], [ 'label' => $this->l('Weight'), @@ -247,9 +267,11 @@ private function initForm() $phoneData['sender_phone_code_list'] ); - if (!Tools::getValue('pick_up_time') && !Tools::getValue('sender_work_until')) { - $this->fields_value['pick_up_time'] = TimeZoneUtility::getCourierDefaultPickUpTime(); - $this->fields_value['sender_work_until'] = TimeZoneUtility::getCourierDefaultWorkUntil(); + if (!Tools::getValue('pick_up_date')) { + $defaultPickUpSlot = TimeZoneUtility::getCourierDefaultPickUpSlot(); + $this->fields_value['pick_up_date'] = $defaultPickUpSlot['date']; + $this->fields_value['pick_up_time_from'] = $defaultPickUpSlot['from']; + $this->fields_value['pick_up_time_to'] = $defaultPickUpSlot['to']; } if (!Tools::getValue('order_nr')) { $this->fields_value['order_nr'] = (new DateTime())->getTimestamp(); @@ -311,6 +333,16 @@ public function setMedia($isNewTheme = false) $this->addCSS($this->module->getPathUri() . 'views/css/admin/courier_request.css'); } + private function getPickupTimeSlotOptions(array $slots) + { + $options = []; + foreach ($slots as $slot) { + $options[] = ['id' => $slot, 'name' => $slot]; + } + + return $options; + } + private function renderPrefillSelect($prefix) { /** @var AddressRepository $addressRepository */ @@ -333,11 +365,24 @@ public function postProcess() /** @var CourierRequestValidator $courierRequestValidator */ $formDataConverter = $this->module->getModuleContainer('invertus.dpdbaltics.converter.form_data_converter'); $courierRequestValidator = $this->module->getModuleContainer('invertus.dpdbaltics.validate.courier_request.courier_request_validator'); + + $_POST['pick_up_time'] = Tools::getValue('pick_up_date') . ' ' . Tools::getValue('pick_up_time_from') . ':00'; + $_POST['sender_work_until'] = Tools::getValue('pick_up_date') . ' ' . Tools::getValue('pick_up_time_to') . ':00'; + $data = Tools::getAllValues(); /** @var CourierRequestData $courierRequestObj */ $courierRequestObj = $formDataConverter->convertCourierRequestFormDataToCourierRequestObj($data); + if (!$courierRequestValidator->validatePickupTimeSlots($courierRequestObj)) { + $this->errors[] = sprintf( + $this->l('Pick-up time must use the time slots DPD accepts. "From" slots: %s. "Until" slots: %s.'), + implode(', ', PickupTimeSlotUtility::getPickupTimeFromSlots()), + implode(', ', PickupTimeSlotUtility::getPickupTimeToSlots()) + ); + return parent::postProcess(); + } + $countryIso = Configuration::get(Config::WEB_SERVICE_COUNTRY); if (!$courierRequestValidator->validate($courierRequestObj, $countryIso)) { $this->errors[] = sprintf( diff --git a/src/Config/Config.php b/src/Config/Config.php index c50f5c1d..4d229d6e 100644 --- a/src/Config/Config.php +++ b/src/Config/Config.php @@ -243,6 +243,13 @@ class Config const COURIER_SAME_DAY_TIME_LIMITATION = '15:00'; const COURIER_SAME_DAY_TIME_ADDITIONAL_MINUTES = '30'; + const COURIER_PICKUP_TIME_FROM_SLOTS = [ + '08:00', '09:00', '10:00', '11:00', '12:00', '12:30', '13:00', '13:30', '14:00', '14:30', '15:00', + ]; + const COURIER_PICKUP_TIME_TO_SLOTS = ['15:00', '16:00', '17:00', '18:00']; + const COURIER_DEFAULT_PICKUP_TIME_FROM_SLOT = '08:00'; + const COURIER_DEFAULT_PICKUP_TIME_TO_SLOT = '17:00'; + const SAME_DAY_DELIVERY_CITY = 'Rīga'; const DOCUMENT_RETURN_CODE = '-DOCRET'; diff --git a/src/DTO/CourierRequestData.php b/src/DTO/CourierRequestData.php index 887bcaa4..faeb612b 100644 --- a/src/DTO/CourierRequestData.php +++ b/src/DTO/CourierRequestData.php @@ -94,6 +94,21 @@ class CourierRequestData */ private $pickupTime; + /** + * @var string + */ + private $pickupDate; + + /** + * @var string + */ + private $pickupTimeFrom; + + /** + * @var string + */ + private $pickupTimeTo; + /** * @var string */ @@ -338,6 +353,54 @@ public function setPickupTime($pickupTime) $this->pickupTime = $pickupTime; } + /** + * @return string + */ + public function getPickupDate() + { + return $this->pickupDate; + } + + /** + * @param string $pickupDate + */ + public function setPickupDate($pickupDate) + { + $this->pickupDate = $pickupDate; + } + + /** + * @return string + */ + public function getPickupTimeFrom() + { + return $this->pickupTimeFrom; + } + + /** + * @param string $pickupTimeFrom + */ + public function setPickupTimeFrom($pickupTimeFrom) + { + $this->pickupTimeFrom = $pickupTimeFrom; + } + + /** + * @return string + */ + public function getPickupTimeTo() + { + return $this->pickupTimeTo; + } + + /** + * @param string $pickupTimeTo + */ + public function setPickupTimeTo($pickupTimeTo) + { + $this->pickupTimeTo = $pickupTimeTo; + } + /** * @return string */ diff --git a/src/Infrastructure/Adapter/ModuleFactory.php b/src/Infrastructure/Adapter/ModuleFactory.php index e6882c2b..8a6a782a 100644 --- a/src/Infrastructure/Adapter/ModuleFactory.php +++ b/src/Infrastructure/Adapter/ModuleFactory.php @@ -1,4 +1,23 @@ + * @copyright Since 2007 PrestaShop SA and Contributors + * @license https://opensource.org/licenses/AFL-3.0 Academic Free License version 3.0 + */ + namespace Invertus\dpdBaltics\Infrastructure\Adapter; diff --git a/src/Infrastructure/Bootstrap/Install/Installer.php b/src/Infrastructure/Bootstrap/Install/Installer.php index db21ce65..01ff0d58 100644 --- a/src/Infrastructure/Bootstrap/Install/Installer.php +++ b/src/Infrastructure/Bootstrap/Install/Installer.php @@ -1,4 +1,23 @@ + * @copyright Since 2007 PrestaShop SA and Contributors + * @license https://opensource.org/licenses/AFL-3.0 Academic Free License version 3.0 + */ + namespace Invertus\dpdBaltics\Infrastructure\Bootstrap\Install; diff --git a/src/Infrastructure/Bootstrap/ModuleTabs.php b/src/Infrastructure/Bootstrap/ModuleTabs.php index 56cc16cd..b9e8559f 100644 --- a/src/Infrastructure/Bootstrap/ModuleTabs.php +++ b/src/Infrastructure/Bootstrap/ModuleTabs.php @@ -1,4 +1,23 @@ + * @copyright Since 2007 PrestaShop SA and Contributors + * @license https://opensource.org/licenses/AFL-3.0 Academic Free License version 3.0 + */ + namespace Invertus\dpdBaltics\Infrastructure\Bootstrap; diff --git a/src/Service/API/CourierRequestService.php b/src/Service/API/CourierRequestService.php index 1958fe1c..c1f9ae81 100644 --- a/src/Service/API/CourierRequestService.php +++ b/src/Service/API/CourierRequestService.php @@ -23,8 +23,8 @@ use Country; use DPDBaltics; -use Invertus\dpdBaltics\Config\Config; use Invertus\dpdBaltics\DTO\courierRequestData; +use Invertus\dpdBaltics\Service\API\Parser\CourierRequestResponseParser; use Invertus\dpdBalticsApi\Api\DTO\Request\CourierRequestRequest; use Invertus\dpdBalticsApi\Api\DTO\Response\courierRequestResponse; use Invertus\dpdBalticsApi\Factory\APIRequest\courierRequestFactory; @@ -40,11 +40,19 @@ class CourierRequestService * @var DPDBaltics */ private $module; + /** + * @var CourierRequestResponseParser + */ + private $responseParser; - public function __construct(CourierRequestFactory $courierRequestFactory, DPDBaltics $module) - { + public function __construct( + CourierRequestFactory $courierRequestFactory, + DPDBaltics $module, + CourierRequestResponseParser $responseParser + ) { $this->courierRequestFactory = $courierRequestFactory; $this->module = $module; + $this->responseParser = $responseParser; } public function createCourierRequest(CourierRequestData $courierRequestData) @@ -70,16 +78,22 @@ public function createCourierRequest(CourierRequestData $courierRequestData) $courierRequestData->getWeight(), $courierRequestData->getParcelsCount() ); - + + if ($courierRequestData->getPickupTimeFrom() && $courierRequestData->getPickupTimeTo()) { + $request->setPickupDate($courierRequestData->getPickupDate()); + $request->setPickupTimeFrom($courierRequestData->getPickupTimeFrom()); + $request->setPickupTimeTo($courierRequestData->getPickupTimeTo()); + } + $courierRequest = $this->courierRequestFactory->makecourierRequest(); /** @var courierRequestResponse $response */ $response = $courierRequest->courierRequest($request); - if (!$this->checkIfCourierRequestIsSuccess($response)) { + if (!$this->responseParser->isSuccess($response)) { return [ 'status' => false, - 'message' => $this->getCourierRequestError($response) + 'message' => $this->responseParser->getError($response) ]; } @@ -88,23 +102,4 @@ public function createCourierRequest(CourierRequestData $courierRequestData) 'message' => $this->module->l('courier request was successfully created!') ]; } - - private function checkIfCourierRequestIsSuccess($courierRequestResponse) - { - if ($courierRequestResponse === Config::API_COURIER_REQUEST_SUCCESS_STATUS) { - return true; - } - - return false; - } - - private function getCourierRequestError($courierRequestResponse) - { - $errorPosition = strpos( - $courierRequestResponse, - Config::API_COURIER_REQUEST_ERROR_STATUS - ); - - return substr($courierRequestResponse, $errorPosition); - } } diff --git a/src/Service/API/Parser/CourierRequestResponseParser.php b/src/Service/API/Parser/CourierRequestResponseParser.php new file mode 100644 index 00000000..cbf2caa3 --- /dev/null +++ b/src/Service/API/Parser/CourierRequestResponseParser.php @@ -0,0 +1,71 @@ + + * @copyright Since 2007 PrestaShop SA and Contributors + * @license https://opensource.org/licenses/AFL-3.0 Academic Free License version 3.0 + */ + + +namespace Invertus\dpdBaltics\Service\API\Parser; + +use Invertus\dpdBaltics\Config\Config; + +class CourierRequestResponseParser +{ + /** + * @param mixed $response + * + * @return bool + */ + public function isSuccess($response) + { + if (is_string($response)) { + return strpos($response, Config::API_COURIER_REQUEST_SUCCESS_STATUS) !== false; + } + + return false; + } + + /** + * @param mixed $response + * + * @return string + */ + public function getError($response) + { + if (is_string($response)) { + $errorPosition = strpos($response, Config::API_COURIER_REQUEST_ERROR_STATUS); + + if ($errorPosition === false) { + return $response; + } + + return substr($response, $errorPosition); + } + + if (is_object($response)) { + if (isset($response->body->message)) { + return (string) $response->body->message; + } + + if (isset($response->errlog)) { + return (string) $response->errlog; + } + } + + return json_encode($response); + } +} diff --git a/src/Service/API/Parser/index.php b/src/Service/API/Parser/index.php new file mode 100644 index 00000000..15aba820 --- /dev/null +++ b/src/Service/API/Parser/index.php @@ -0,0 +1,11 @@ + + * @copyright Since 2007 PrestaShop SA and Contributors + * @license https://opensource.org/licenses/AFL-3.0 Academic Free License version 3.0 + */ + + +namespace Invertus\dpdBaltics\Util; + +use Invertus\dpdBaltics\Config\Config; + +class PickupTimeSlotUtility +{ + /** + * @return string[] + */ + public static function getPickupTimeFromSlots() + { + return Config::COURIER_PICKUP_TIME_FROM_SLOTS; + } + + /** + * @return string[] + */ + public static function getPickupTimeToSlots() + { + return Config::COURIER_PICKUP_TIME_TO_SLOTS; + } + + /** + * @param string $time + * + * @return bool + */ + public static function isValidPickupTimeFromSlot($time) + { + return in_array($time, Config::COURIER_PICKUP_TIME_FROM_SLOTS, true); + } + + /** + * @param string $time + * + * @return bool + */ + public static function isValidPickupTimeToSlot($time) + { + return in_array($time, Config::COURIER_PICKUP_TIME_TO_SLOTS, true); + } + + /** + * @param string $time + * + * @return string|null + */ + public static function findNextPickupTimeFromSlot($time) + { + foreach (Config::COURIER_PICKUP_TIME_FROM_SLOTS as $slot) { + if ($slot >= $time) { + return $slot; + } + } + + return null; + } +} diff --git a/src/Util/TimeZoneUtility.php b/src/Util/TimeZoneUtility.php index 91f9cac4..9019a79a 100644 --- a/src/Util/TimeZoneUtility.php +++ b/src/Util/TimeZoneUtility.php @@ -73,6 +73,35 @@ public static function getCourierDefaultWorkUntil() } } + /** + * @return array ['date' => 'Y-m-d', 'from' => 'H:i', 'to' => 'H:i'] + */ + public static function getCourierDefaultPickUpSlot() + { + $now = self::getBalticTimeZoneAsDateTime(); + $earliest = clone $now; + $earliest->modify('+' . Config::COURIER_SAME_DAY_TIME_ADDITIONAL_MINUTES . ' minutes'); + + $fromSlot = PickupTimeSlotUtility::findNextPickupTimeFromSlot($earliest->format('H:i')); + + if ($fromSlot !== null && $earliest->format('Y-m-d') === $now->format('Y-m-d')) { + return [ + 'date' => $now->format('Y-m-d'), + 'from' => $fromSlot, + 'to' => Config::COURIER_DEFAULT_PICKUP_TIME_TO_SLOT, + ]; + } + + $tomorrow = clone $now; + $tomorrow->modify('+1 day'); + + return [ + 'date' => $tomorrow->format('Y-m-d'), + 'from' => Config::COURIER_DEFAULT_PICKUP_TIME_FROM_SLOT, + 'to' => Config::COURIER_DEFAULT_PICKUP_TIME_TO_SLOT, + ]; + } + public static function getBalticTimeZoneAsDateTime() { $tz = 'Europe/Vilnius'; diff --git a/src/Validate/CourierRequest/CourierRequestValidator.php b/src/Validate/CourierRequest/CourierRequestValidator.php index 87057765..6538b8cc 100644 --- a/src/Validate/CourierRequest/CourierRequestValidator.php +++ b/src/Validate/CourierRequest/CourierRequestValidator.php @@ -24,9 +24,29 @@ use DateTime; use Invertus\dpdBaltics\Config\Config; use Invertus\dpdBaltics\DTO\CourierRequestData; +use Invertus\dpdBaltics\Util\PickupTimeSlotUtility; class CourierRequestValidator { + /** + * @return bool + */ + public function validatePickupTimeSlots(CourierRequestData $courierRequestData) + { + $from = $courierRequestData->getPickupTimeFrom(); + $to = $courierRequestData->getPickupTimeTo(); + + if (!PickupTimeSlotUtility::isValidPickupTimeFromSlot($from)) { + return false; + } + + if (!PickupTimeSlotUtility::isValidPickupTimeToSlot($to)) { + return false; + } + + return $from < $to; + } + public function validate(CourierRequestData $courierRequestData, $countryIso) { $dateFrom = new DateTime($courierRequestData->getPickupTime()); diff --git a/tests/Unit/Service/API/Parser/CourierRequestResponseParserTest.php b/tests/Unit/Service/API/Parser/CourierRequestResponseParserTest.php new file mode 100644 index 00000000..ab681b96 --- /dev/null +++ b/tests/Unit/Service/API/Parser/CourierRequestResponseParserTest.php @@ -0,0 +1,104 @@ + + * @copyright Since 2007 PrestaShop SA and Contributors + * @license https://opensource.org/licenses/AFL-3.0 Academic Free License version 3.0 + */ + +use Invertus\dpdBaltics\Service\API\Parser\CourierRequestResponseParser; +use PHPUnit\Framework\TestCase; + +class CourierRequestResponseParserTest extends TestCase +{ + /** + * @var CourierRequestResponseParser + */ + private $parser; + + protected function setUp() + { + $this->parser = new CourierRequestResponseParser(); + } + + public function testLegacyDoneStringIsSuccess() + { + $this->assertTrue($this->parser->isSuccess('

DONE')); + } + + public function testLegacyDoneHtmlDocumentIsSuccess() + { + $html = "\n</head>\n<body>\n<p>DONE</p>\n</body>\n</html>"; + + $this->assertTrue($this->parser->isSuccess($html)); + } + + public function testLegacyErrorStringIsNotSuccessAndErrorIsExtracted() + { + $response = 'HTTP 402 Error: Pickup order to time wrong for Product 1'; + + $this->assertFalse($this->parser->isSuccess($response)); + $this->assertSame('402 Error: Pickup order to time wrong for Product 1', $this->parser->getError($response)); + } + + public function testLegacyStringWithoutErrorMarkerFallsBackToWholeString() + { + $response = 'Some unexpected plain-text failure'; + + $this->assertFalse($this->parser->isSuccess($response)); + $this->assertSame($response, $this->parser->getError($response)); + } + + public function testJsonErrorObjectIsNotSuccessAndMessageIsExtracted() + { + $message = 'Available "pickupTimeFrom" values: [08:00, 09:00, 10:00, 11:00, 12:00, 12:30, 13:00, ' + . '13:30, 14:00, 14:30, 15:00]. Available "pickupTimeTo" values: [15:00, 16:00, 17:00, 18:00].'; + $response = json_decode(json_encode([ + 'level' => 'error', + 'body' => ['message' => $message], + ])); + + $this->assertFalse($this->parser->isSuccess($response)); + $this->assertSame($message, $this->parser->getError($response)); + } + + public function testJsonErrlogObjectIsNotSuccessAndErrlogIsExtracted() + { + $response = json_decode(json_encode([ + 'status' => 'err', + 'errlog' => 'Failed to Authenticate User. Check your user name and password!', + ])); + + $this->assertFalse($this->parser->isSuccess($response)); + $this->assertSame( + 'Failed to Authenticate User. Check your user name and password!', + $this->parser->getError($response) + ); + } + + public function testUnknownObjectShapeIsNotSuccessAndIsSurfacedAsJson() + { + $response = json_decode(json_encode(['foo' => 'bar'])); + + $this->assertFalse($this->parser->isSuccess($response)); + $this->assertSame('{"foo":"bar"}', $this->parser->getError($response)); + } + + public function testEmptyArrayResponseIsNotSuccessAndDoesNotCrash() + { + $this->assertFalse($this->parser->isSuccess([])); + $this->assertSame('[]', $this->parser->getError([])); + } +} diff --git a/tests/Unit/Service/API/Parser/index.php b/tests/Unit/Service/API/Parser/index.php new file mode 100644 index 00000000..15aba820 --- /dev/null +++ b/tests/Unit/Service/API/Parser/index.php @@ -0,0 +1,11 @@ +<?php + +header("Expires: Mon, 26 Jul 1997 05:00:00 GMT"); +header("Last-Modified: ".gmdate("D, d M Y H:i:s")." GMT"); + +header("Cache-Control: no-store, no-cache, must-revalidate"); +header("Cache-Control: post-check=0, pre-check=0", false); +header("Pragma: no-cache"); + +header("Location: ../"); +exit; diff --git a/tests/Unit/Service/API/index.php b/tests/Unit/Service/API/index.php new file mode 100644 index 00000000..15aba820 --- /dev/null +++ b/tests/Unit/Service/API/index.php @@ -0,0 +1,11 @@ +<?php + +header("Expires: Mon, 26 Jul 1997 05:00:00 GMT"); +header("Last-Modified: ".gmdate("D, d M Y H:i:s")." GMT"); + +header("Cache-Control: no-store, no-cache, must-revalidate"); +header("Cache-Control: post-check=0, pre-check=0", false); +header("Pragma: no-cache"); + +header("Location: ../"); +exit; diff --git a/tests/Unit/Util/PickupTimeSlotUtilityTest.php b/tests/Unit/Util/PickupTimeSlotUtilityTest.php new file mode 100644 index 00000000..fec63353 --- /dev/null +++ b/tests/Unit/Util/PickupTimeSlotUtilityTest.php @@ -0,0 +1,63 @@ +<?php +/** + * Copyright since 2007 PrestaShop SA and Contributors + * PrestaShop is an International Registered Trademark & Property of PrestaShop SA + * + * NOTICE OF LICENSE + * + * This source file is subject to the Academic Free License version 3.0 + * that is bundled with this package in the file LICENSE.md. + * It is also available through the world-wide-web at this URL: + * https://opensource.org/licenses/AFL-3.0 + * If you did not receive a copy of the license and are unable to + * obtain it through the world-wide-web, please send an email + * to license@prestashop.com so we can send you a copy immediately. + * + * @author PrestaShop SA and Contributors <contact@prestashop.com> + * @copyright Since 2007 PrestaShop SA and Contributors + * @license https://opensource.org/licenses/AFL-3.0 Academic Free License version 3.0 + */ + +use Invertus\dpdBaltics\Util\PickupTimeSlotUtility; +use PHPUnit\Framework\TestCase; + +class PickupTimeSlotUtilityTest extends TestCase +{ + public function testValidPickupTimeFromSlots() + { + $this->assertTrue(PickupTimeSlotUtility::isValidPickupTimeFromSlot('08:00')); + $this->assertTrue(PickupTimeSlotUtility::isValidPickupTimeFromSlot('12:30')); + $this->assertTrue(PickupTimeSlotUtility::isValidPickupTimeFromSlot('15:00')); + + $this->assertFalse(PickupTimeSlotUtility::isValidPickupTimeFromSlot('08:15')); + $this->assertFalse(PickupTimeSlotUtility::isValidPickupTimeFromSlot('16:00')); + $this->assertFalse(PickupTimeSlotUtility::isValidPickupTimeFromSlot('11:35:26')); + $this->assertFalse(PickupTimeSlotUtility::isValidPickupTimeFromSlot('')); + } + + public function testValidPickupTimeToSlots() + { + $this->assertTrue(PickupTimeSlotUtility::isValidPickupTimeToSlot('15:00')); + $this->assertTrue(PickupTimeSlotUtility::isValidPickupTimeToSlot('17:00')); + $this->assertTrue(PickupTimeSlotUtility::isValidPickupTimeToSlot('18:00')); + + $this->assertFalse(PickupTimeSlotUtility::isValidPickupTimeToSlot('08:00')); + $this->assertFalse(PickupTimeSlotUtility::isValidPickupTimeToSlot('17:30')); + $this->assertFalse(PickupTimeSlotUtility::isValidPickupTimeToSlot('')); + } + + public function testFindNextPickupTimeFromSlotSnapsForward() + { + $this->assertSame('08:00', PickupTimeSlotUtility::findNextPickupTimeFromSlot('06:45')); + $this->assertSame('08:00', PickupTimeSlotUtility::findNextPickupTimeFromSlot('08:00')); + $this->assertSame('12:00', PickupTimeSlotUtility::findNextPickupTimeFromSlot('11:35')); + $this->assertSame('12:30', PickupTimeSlotUtility::findNextPickupTimeFromSlot('12:05')); + $this->assertSame('15:00', PickupTimeSlotUtility::findNextPickupTimeFromSlot('14:31')); + } + + public function testFindNextPickupTimeFromSlotReturnsNullAfterLastSlot() + { + $this->assertNull(PickupTimeSlotUtility::findNextPickupTimeFromSlot('15:01')); + $this->assertNull(PickupTimeSlotUtility::findNextPickupTimeFromSlot('23:59')); + } +} diff --git a/tests/Unit/Util/index.php b/tests/Unit/Util/index.php new file mode 100644 index 00000000..15aba820 --- /dev/null +++ b/tests/Unit/Util/index.php @@ -0,0 +1,11 @@ +<?php + +header("Expires: Mon, 26 Jul 1997 05:00:00 GMT"); +header("Last-Modified: ".gmdate("D, d M Y H:i:s")." GMT"); + +header("Cache-Control: no-store, no-cache, must-revalidate"); +header("Cache-Control: post-check=0, pre-check=0", false); +header("Pragma: no-cache"); + +header("Location: ../"); +exit; diff --git a/tests/Unit/Validate/CourierRequest/CourierRequestValidatorTest.php b/tests/Unit/Validate/CourierRequest/CourierRequestValidatorTest.php new file mode 100644 index 00000000..dc3305c9 --- /dev/null +++ b/tests/Unit/Validate/CourierRequest/CourierRequestValidatorTest.php @@ -0,0 +1,92 @@ +<?php +/** + * Copyright since 2007 PrestaShop SA and Contributors + * PrestaShop is an International Registered Trademark & Property of PrestaShop SA + * + * NOTICE OF LICENSE + * + * This source file is subject to the Academic Free License version 3.0 + * that is bundled with this package in the file LICENSE.md. + * It is also available through the world-wide-web at this URL: + * https://opensource.org/licenses/AFL-3.0 + * If you did not receive a copy of the license and are unable to + * obtain it through the world-wide-web, please send an email + * to license@prestashop.com so we can send you a copy immediately. + * + * @author PrestaShop SA and Contributors <contact@prestashop.com> + * @copyright Since 2007 PrestaShop SA and Contributors + * @license https://opensource.org/licenses/AFL-3.0 Academic Free License version 3.0 + */ + +use Invertus\dpdBaltics\DTO\CourierRequestData; +use Invertus\dpdBaltics\Validate\CourierRequest\CourierRequestValidator; +use PHPUnit\Framework\TestCase; + +class CourierRequestValidatorTest extends TestCase +{ + /** + * @var CourierRequestValidator + */ + private $validator; + + protected function setUp() + { + $this->validator = new CourierRequestValidator(); + } + + public function testValidSlotPairPassesSlotValidation() + { + $data = $this->createCourierRequestData('08:00', '17:00'); + + $this->assertTrue($this->validator->validatePickupTimeSlots($data)); + } + + public function testNonWhitelistedFromSlotFailsSlotValidation() + { + $data = $this->createCourierRequestData('11:35', '17:00'); + + $this->assertFalse($this->validator->validatePickupTimeSlots($data)); + } + + public function testNonWhitelistedToSlotFailsSlotValidation() + { + $data = $this->createCourierRequestData('08:00', '12:00'); + + $this->assertFalse($this->validator->validatePickupTimeSlots($data)); + } + + public function testFromSlotEqualOrLaterThanToSlotFailsSlotValidation() + { + $data = $this->createCourierRequestData('15:00', '15:00'); + + $this->assertFalse($this->validator->validatePickupTimeSlots($data)); + } + + public function testMinimalIntervalValidationStillPassesForComposedDatetimes() + { + $data = $this->createCourierRequestData('08:00', '17:00'); + $data->setPickupTime('2030-02-20 08:00:00'); + $data->setSenderWorkUntil('2030-02-20 17:00:00'); + + $this->assertTrue($this->validator->validate($data, 'LT')); + } + + public function testMinimalIntervalValidationStillFailsWhenIntervalTooShort() + { + $data = $this->createCourierRequestData('15:00', '16:00'); + $data->setPickupTime('2030-02-20 15:00:00'); + $data->setSenderWorkUntil('2030-02-20 16:00:00'); + + $this->assertFalse($this->validator->validate($data, 'LT')); + } + + private function createCourierRequestData($from, $to) + { + $data = new CourierRequestData(); + $data->setPickupDate('2030-02-20'); + $data->setPickupTimeFrom($from); + $data->setPickupTimeTo($to); + + return $data; + } +} diff --git a/tests/Unit/Validate/CourierRequest/index.php b/tests/Unit/Validate/CourierRequest/index.php new file mode 100644 index 00000000..15aba820 --- /dev/null +++ b/tests/Unit/Validate/CourierRequest/index.php @@ -0,0 +1,11 @@ +<?php + +header("Expires: Mon, 26 Jul 1997 05:00:00 GMT"); +header("Last-Modified: ".gmdate("D, d M Y H:i:s")." GMT"); + +header("Cache-Control: no-store, no-cache, must-revalidate"); +header("Cache-Control: post-check=0, pre-check=0", false); +header("Pragma: no-cache"); + +header("Location: ../"); +exit; diff --git a/wiremock/index.php b/wiremock/index.php new file mode 100644 index 00000000..15aba820 --- /dev/null +++ b/wiremock/index.php @@ -0,0 +1,11 @@ +<?php + +header("Expires: Mon, 26 Jul 1997 05:00:00 GMT"); +header("Last-Modified: ".gmdate("D, d M Y H:i:s")." GMT"); + +header("Cache-Control: no-store, no-cache, must-revalidate"); +header("Cache-Control: post-check=0, pre-check=0", false); +header("Pragma: no-cache"); + +header("Location: ../"); +exit; diff --git a/wiremock/mappings/index.php b/wiremock/mappings/index.php new file mode 100644 index 00000000..15aba820 --- /dev/null +++ b/wiremock/mappings/index.php @@ -0,0 +1,11 @@ +<?php + +header("Expires: Mon, 26 Jul 1997 05:00:00 GMT"); +header("Last-Modified: ".gmdate("D, d M Y H:i:s")." GMT"); + +header("Cache-Control: no-store, no-cache, must-revalidate"); +header("Cache-Control: post-check=0, pre-check=0", false); +header("Pragma: no-cache"); + +header("Location: ../"); +exit; diff --git a/wiremock/mappings/pickup-order-save-live-rejection.json b/wiremock/mappings/pickup-order-save-live-rejection.json new file mode 100644 index 00000000..0b602cf6 --- /dev/null +++ b/wiremock/mappings/pickup-order-save-live-rejection.json @@ -0,0 +1,18 @@ +{ + "request": { + "method": "POST", + "urlPath": "/ws-mapper-rest/pickupOrderSave_" + }, + "response": { + "status": 200, + "headers": { + "Content-Type": "application/json" + }, + "jsonBody": { + "level": "error", + "body": { + "message": "Available \"pickupTimeFrom\" values: [08:00, 09:00, 10:00, 11:00, 12:00, 12:30, 13:00, 13:30, 14:00, 14:30, 15:00]. Available \"pickupTimeTo\" values: [15:00, 16:00, 17:00, 18:00]." + } + } + } +}