From e815be8061bc26877cc66ec961158893a7a5da2a Mon Sep 17 00:00:00 2001 From: Stas Demin Date: Fri, 31 May 2024 11:00:18 +0300 Subject: [PATCH 01/50] feat: reindex shop orders with new uuid --- src/Actions/Schedule/ReindexOrders.php | 155 +++++++++++++++++++++++++ src/CdekApi.php | 11 ++ src/CdekCoreApi.php | 107 +++++++++++++++++ src/CdekShippingMethod.php | 23 +++- src/Config.php | 2 + src/Helpers/DBCoreTokenStorage.php | 86 ++++++++++++++ src/Loader.php | 5 + src/UI/MetaBoxes.php | 35 ++++++ 8 files changed, 423 insertions(+), 1 deletion(-) create mode 100644 src/Actions/Schedule/ReindexOrders.php create mode 100644 src/CdekCoreApi.php create mode 100644 src/Helpers/DBCoreTokenStorage.php diff --git a/src/Actions/Schedule/ReindexOrders.php b/src/Actions/Schedule/ReindexOrders.php new file mode 100644 index 0000000..ce258cc --- /dev/null +++ b/src/Actions/Schedule/ReindexOrders.php @@ -0,0 +1,155 @@ +api = new CdekCoreApi(); + } + + public static function initOrdersSend() + { + $reindex = new self(); + + $reindex->run(); + + status_header(200); + + exit("Server received '{$_REQUEST['data']}' from your browser."); + } + + public static function getReindexOrders() + { + $reindex = new self(); + + $reindex->checkReindexOrders(); + $reindex->writeReindexOrders(); + + } + + public function run() + { + (new CdekShippingMethod())->update_option('cdek_start_reindex', 'Y'); + + $this->getOrders(); + $this->exchangeOrders(); + + if(isset($this->error)){ + + status_header(500); + + exit($this->error->message); + + } + + if (false === as_has_scheduled_action('get_reindex_orders') ) { + wp_schedule_single_event( + strtotime('tomorrow'), + 'get_reindex_orders' + ); + } + } + + protected function checkReindexOrders() + { + $response = $this->api->checkUpdateOrders(); + $exchangeObj = json_decode($response, true); + + if(property_exists($exchangeObj, 'errors') || empty($exchangeObj['body']['orders'])){ + $this->error = + new Validate( + false, + __('An error occurred while creating request. Try again later', 'cdekdelivery'), + ); + + return; + } + + $this->responseOrders = $exchangeObj['body']['orders']; + + if(empty($response['body']['completed'])){ + wp_schedule_single_event( + time() + 60 * 5, + 'get_reindex_orders' + ); + } + } + + protected function writeReindexOrders() + { + if(empty($this->responseOrders)){ + return; + } + + $this->getOrders(); + + foreach ($this->orders as $orderId){ + $orderIndex = array_search($orderId, array_column($this->responseOrders, 'order_id')); + + if(empty($orderIndex)){ + continue; + } + + $responseOrder = $this->responseOrders[$orderIndex]; + + OrderMetaData::updateMetaByOrderId( + $orderId, + [ + 'order_number' => $responseOrder['order_number'], + 'order_uuid' => $responseOrder['order_uuid'] + ] + ); + } + + } + + protected function getOrders() + { + $query = new \WC_Order_Query( + [ + 'orderby' => 'id', + 'order' => 'ASC', + 'return' => 'ids', + ], + ); + + foreach ($query->get_orders() as $orderId) { + $this->orders[] = $orderId; + } + } + + protected function exchangeOrders() + { + $response = $this->api->reindexOrders($this->orders); + $exchangeObj = json_decode($response, true); + + if (property_exists($exchangeObj, 'errors') || $exchangeObj['response']['code'] !== 202) { + $this->error = + new Validate( + false, + __('An error occurred while creating request. Try again later', 'cdekdelivery'), + ); + } + + } + + } +} diff --git a/src/CdekApi.php b/src/CdekApi.php index f9a3b2c..d9c1c3f 100644 --- a/src/CdekApi.php +++ b/src/CdekApi.php @@ -103,6 +103,17 @@ final public function getOrder(string $uuid) return HttpClient::sendCdekRequest($url, 'GET', $this->tokenStorage->getToken()); } + /** + * @throws \JsonException + * @throws \Cdek\Exceptions\CdekApiException + */ + final public function getOrderByNumber(string $orderNumber) + { + $url = $this->apiUrl . self::ORDERS_PATH . '?cdek_number=' . $orderNumber; + + return HttpClient::sendCdekRequest($url, 'GET', $this->tokenStorage->getToken()); + } + /** * @throws \Cdek\Exceptions\RestApiInvalidRequestException * @throws \Cdek\Exceptions\CdekApiException diff --git a/src/CdekCoreApi.php b/src/CdekCoreApi.php new file mode 100644 index 0000000..2b2d1e8 --- /dev/null +++ b/src/CdekCoreApi.php @@ -0,0 +1,107 @@ +deliveryMethod = Helper::getActualShippingMethod($shippingInstanceId); + $this->apiUrl = $this->getApiUrl(); + $this->generalTokenStorage = $tokenStorage ?? new DBTokenStorage(); + $this->tokenCoreStorage = $tokenCoreStorage ?? new DBCoreTokenStorage(); + } + + public function fetchShopToken() + { + $body = json_decode( + HttpCoreClient::sendCdekRequest( + $this->getAuthUrl(), + 'POST', + $this->generalTokenStorage->getToken() + ), + true + )['body']; + + if ($body === null || isset($body['error_description']) || isset($body['error'])) { + throw new CdekApiException('[CDEKDelivery] Failed to get shop token', + 'cdek_error.shop_token.auth', + $body, + true); + } + + return $body['token']; + } + + private function getStoreUuid() + { + $response = HttpCoreClient::sendCdekRequest( + $this->apiUrl . self::SHOP, + 'POST', + $this->generalTokenStorage->getToken() + ); + + if(empty($response) || $response['error']){ + throw new CdekApiException('[CDEKDelivery] Failed to get shop uuid', + 'cdek_error.uuid.auth', + $response, + true); + } + + $body = json_decode($response, true)['body']; + + if(empty($body) || $body['error']){ + throw new CdekApiException('[CDEKDelivery] Failed to get shop uuid', + 'cdek_error.uuid.auth', + $response, + true); + } + + return $body['uuid']; + } + + public function reindexOrders($orders) + { + return HttpCoreClient::sendCdekRequest($this->apiUrl . self::REINDEX_ORDERS, 'PUT', $this->tokenCoreStorage->getToken(), $orders); + } + + public function checkUpdateOrders() + { + return HttpCoreClient::sendCdekRequest( + $this->apiUrl . self::REINDEX_ORDERS, + 'GET', + $this->tokenCoreStorage->getToken() + ); + } + + private function getAuthUrl(): string + { + return sprintf($this->apiUrl . self::TOKEN_PATH, $this->getStoreUuid()); + } + + private function getApiUrl(): string + { + if ($this->deliveryMethod->get_option('test_mode') === 'yes') { + return $_ENV['CDEK_REST_CORE_API'] ?? Config::TEST_API_CORE_URL; + } + + return Config::API_CORE_URL; + } +} diff --git a/src/CdekShippingMethod.php b/src/CdekShippingMethod.php index 4c8169a..2a345fe 100644 --- a/src/CdekShippingMethod.php +++ b/src/CdekShippingMethod.php @@ -49,7 +49,28 @@ final public function init_form_fields(): void ], ]; - $this->form_fields = [ + $reindexCreated = $this->get_option('cdek_start_reindex'); + + if($reindexCreated == 'Y'){ + $arReindex = []; + }else{ + $settings_page_url = admin_url('admin-post.php?action=reindex_orders&data=all'); + $arReindex = [ + 'reindex_orders' => [ + 'title' => '' . + __('Reindex order', 'cdekdelivery') . '', + 'type' => 'text', + 'hidden' => true, + 'class' => 'cdek_setting_block_button', + 'custom_attributes' => [ + 'hidden' => 'hidden', + 'onClick' => 'javascript::void(0)', + ], + ], + ]; + } + + $this->form_fields = $arReindex + [ 'auth_block_name' => [ 'title' => '

'.esc_html__('Authorization', 'cdekdelivery').'

', 'type' => 'title', diff --git a/src/Config.php b/src/Config.php index d3b4b8c..b62cb56 100644 --- a/src/Config.php +++ b/src/Config.php @@ -15,6 +15,8 @@ class Config public const ORDER_AUTOMATION_HOOK_NAME = 'cdekdelivery_automation'; public const API_URL = 'https://api.cdek.ru/v2/'; public const TEST_API_URL = 'https://api.edu.cdek.ru/v2/'; + public const API_CORE_URL = 'https://api.cdek.ru/v2/'; //todo change to current url + public const TEST_API_CORE_URL = 'localhost:9939'; //todo change to current url public const TEST_CLIENT_ID = 'EMscd6r9JnFiQ3bLoyjJY6eM78JrJceI'; public const TEST_CLIENT_SECRET = 'PjLZkKBHEiLK3YsjtNrt3TGNG0ahs3kG'; public const GRAPHICS_TIMEOUT_SEC = 60; diff --git a/src/Helpers/DBCoreTokenStorage.php b/src/Helpers/DBCoreTokenStorage.php new file mode 100644 index 0000000..278cb53 --- /dev/null +++ b/src/Helpers/DBCoreTokenStorage.php @@ -0,0 +1,86 @@ +update_option('token', null); + } + + final public function getToken(): string + { + $token = $this->getTokenFromCache(); + + if (empty($token)) { + $token = $this->getTokenFromSettings(); + } + + if (empty($token)) { + $token = $this->updateToken(); + } + + return 'Bearer ' . $token; + } + + private function getTokenFromCache(): ?string + { + return !empty(self::$tokenStatic) && self::$tokenExpStatic > time() ? self::$tokenStatic : null; + } + + private function getTokenFromSettings(): ?string + { + $tokenSetting = Helper::getActualShippingMethod()->get_option('core_token'); + if (empty($tokenSetting)) { + return null; + } + $decryptToken = $this->decryptToken($tokenSetting, Helper::getActualShippingMethod()->get_option('client_id')); + if (empty($decryptToken)) { + return null; + } + $tokenExpSetting = $this->getTokenExp($decryptToken); + if ($tokenExpSetting < time()) { + return null; + } + self::$tokenStatic = $decryptToken; + self::$tokenExpStatic = $tokenExpSetting; + return $decryptToken; + } + + /** + * @throws \JsonException + */ + private function getTokenExp(string $token): int + { + return json_decode(base64_decode(strtr(explode('.', $token)[1], '-_', '+/')), false, 512, JSON_THROW_ON_ERROR)->exp; + } + + final public function updateToken(): string + { + $tokenApi = $this->fetchTokenFromApi(); + $clientId = Helper::getActualShippingMethod()->get_option('client_id'); + $tokenEncrypt = $this->encryptToken($tokenApi, $clientId); + Helper::getActualShippingMethod()->update_option('core_token', $tokenEncrypt); + self::$tokenStatic = $tokenApi; + self::$tokenExpStatic = $this->getTokenExp($tokenApi); + return $tokenApi; + } + + /** + * @throws CdekApiException + */ + final public function fetchTokenFromApi(): string + { + return (new CdekCoreApi)->fetchShopToken(); + } + +} diff --git a/src/Loader.php b/src/Loader.php index 130bab2..69f053e 100644 --- a/src/Loader.php +++ b/src/Loader.php @@ -15,6 +15,7 @@ use Cdek\Actions\ProcessWoocommerceCreateShippingAction; use Cdek\Actions\RecalculateShippingAction; use Cdek\Actions\SaveCustomCheckoutFieldsAction; + use Cdek\Actions\Schedule\ReindexOrders; use Cdek\Blocks\CheckoutMapBlock; use Cdek\Controllers\CourierController; use Cdek\Controllers\LocationController; @@ -176,6 +177,10 @@ public function __invoke(string $pluginMainFile): void add_action(Config::ORDER_AUTOMATION_HOOK_NAME, new CreateOrderAction, 10, 2); + add_action('admin_post_reindex_orders', [ReindexOrders::class, 'initOrdersSend']); + + add_action('get_reindex_orders', [ReindexOrders::class, 'getReindexOrders']); + (new CdekWidget)(); (new Admin)(); (new Frontend)(); diff --git a/src/UI/MetaBoxes.php b/src/UI/MetaBoxes.php index 250b595..9c8b227 100644 --- a/src/UI/MetaBoxes.php +++ b/src/UI/MetaBoxes.php @@ -149,6 +149,16 @@ public static function createOrderMetaBox($post): void $orderNumber = $orderData['order_number'] ?? null; $orderUuid = $orderData['order_uuid'] ?? null; +// if(empty($orderData['uuid_confirmed']) && self::confirmOrderUuid($orderNumber, $orderUuid)){ +// OrderMetaData::updateMetaByOrderId( +// $orderIdWP, +// [ +// 'order_uuid' => $orderUuid, +// 'uuid_confirmed' => true +// ] +// ); +// } + try { $cdekStatuses = Helper::getCdekOrderStatuses($orderUuid); $actionOrderAvailable = Helper::getCdekActionOrderAvailable($cdekStatuses); @@ -185,6 +195,31 @@ public static function notAvailableEditOrderData(): void

'; } +// public static function confirmOrderUuid($orderNumber, &$orderUuid) +// { +// if(strpos($orderNumber, '-') !== false){ +// $orderUuid = self::reCreateOrderUuid($orderNumber); +// +// return !empty($orderUuid); +// } +// +// return false; +// } +// +// private static function reCreateOrderUuid(string $orderNumber, int $iteration = 1) +// { +// sleep(1); +// +// if ($iteration === 5) { +// return null; +// } +// +// $orderInfoJson = (new CdekApi())->getOrderByNumber($orderNumber); +// $orderInfo = json_decode($orderInfoJson, true); +// +// return $orderInfo['entity']['uuid'] ?? self::reCreateOrderUuid($orderNumber, $iteration + 1); +// } + public function __invoke(): void { add_action('add_meta_boxes', [__CLASS__, 'registerMetaBoxes'], 100, 2); From 0197bf1f5e736b53547c8d6ec4b23b034867d23c Mon Sep 17 00:00:00 2001 From: Stas Demin Date: Fri, 31 May 2024 12:09:41 +0300 Subject: [PATCH 02/50] fix: changes in request to core api --- src/CdekCoreApi.php | 9 ++- src/Transport/HttpCoreClient.php | 126 +++++++++++++++++++++++++++++++ 2 files changed, 134 insertions(+), 1 deletion(-) create mode 100644 src/Transport/HttpCoreClient.php diff --git a/src/CdekCoreApi.php b/src/CdekCoreApi.php index 2b2d1e8..869a1a0 100644 --- a/src/CdekCoreApi.php +++ b/src/CdekCoreApi.php @@ -55,7 +55,14 @@ private function getStoreUuid() $response = HttpCoreClient::sendCdekRequest( $this->apiUrl . self::SHOP, 'POST', - $this->generalTokenStorage->getToken() + $this->generalTokenStorage->getToken(), + [ + "url" => [ + "rest" => rest_url(), + "home" => home_url(), + "admin" => admin_url(), + ], + ] ); if(empty($response) || $response['error']){ diff --git a/src/Transport/HttpCoreClient.php b/src/Transport/HttpCoreClient.php new file mode 100644 index 0000000..e8eb593 --- /dev/null +++ b/src/Transport/HttpCoreClient.php @@ -0,0 +1,126 @@ + [ + 'Content-Type' => 'application/json', + 'Authorization' => $token, + 'X-App-Name' => 'wordpress', + 'X-App-Version' => $pluginVersion, + 'X-User-Locale' => get_user_locale(), + 'X-Correlation-Id' => self::generateUuid(), + 'user-agent' => Loader::getPluginName() . ':' . get_bloginfo('version'), + ], + 'timeout' => 60, + ]; + + if (!empty($data)) { + $config['body'] = ($method === WP_REST_Server::READABLE) ? $data : wp_json_encode($data); + } + + return self::sendRequest($url, $method, $config); + } + + public static function sendCdekRequest( + string $url, + string $method, + string $token, + array $data = null + ) + { + $config = [ + 'headers' => [ + 'Content-Type' => 'application/json', + 'Authorization' => $token + ], + 'timeout' => 60, + ]; + + if (!empty($data)) { + $config['body'] = ($method === WP_REST_Server::READABLE) ? $data : wp_json_encode($data); + } + + return self::sendRequest($url, $method, $config); + } + + public static function sendRequest(string $url, string $method, array $config = []) + { + $resp = wp_remote_request( + $url, + array_merge( + $config, + [ + 'method' => $method, + 'Content-Type' => 'application/json', + 'headers' => [ + 'Content-Type' => 'application/json', + 'X-App-Name' => 'wordpress', + 'X-App-Version' => Loader::getPluginVersion(), + 'X-User-Locale' => get_user_locale(), + 'X-Correlation-Id' => self::generateUuid(), + 'user-agent' => Loader::getPluginName() . ':' . get_bloginfo('version'), + ], + 'timeout' => 60, + ], + ), + ); + + if (is_array($resp)) { + return $resp; + } + + $ip = @file_get_contents('https://ipecho.net/plain'); + + if (!headers_sent()) { + header("X-Requester-IP: $ip"); + } + + return wp_json_encode(['error' => true, 'ip' => $ip]); + } + + private static function generateUuid(): string + { + return sprintf( + '%04x%04x-%04x-%04x-%04x-%04x%04x%04x', + mt_rand(0, 0xffff), + mt_rand(0, 0xffff), + mt_rand(0, 0xffff), + mt_rand(0, 0x0fff) | 0x4000, + mt_rand(0, 0x3fff) | 0x8000, + mt_rand(0, 0xffff), + mt_rand(0, 0xffff), + mt_rand(0, 0xffff), + ); + } + } + +} From 1832c8ec4e55947b7a0047ac858d1b192977291b Mon Sep 17 00:00:00 2001 From: Stas Demin Date: Fri, 31 May 2024 12:20:29 +0300 Subject: [PATCH 03/50] fix: response check success answer --- src/CdekCoreApi.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/CdekCoreApi.php b/src/CdekCoreApi.php index 869a1a0..95ea75d 100644 --- a/src/CdekCoreApi.php +++ b/src/CdekCoreApi.php @@ -65,7 +65,7 @@ private function getStoreUuid() ] ); - if(empty($response) || $response['error']){ + if(empty($response['success'])){ throw new CdekApiException('[CDEKDelivery] Failed to get shop uuid', 'cdek_error.uuid.auth', $response, From 5e5102bfeb830c6974c58aff2c38bd9c99f6fe7e Mon Sep 17 00:00:00 2001 From: Stas Demin Date: Fri, 31 May 2024 12:35:48 +0300 Subject: [PATCH 04/50] fix: remove not used method --- src/CdekCoreApi.php | 9 ++++---- src/Transport/HttpCoreClient.php | 39 +------------------------------- 2 files changed, 6 insertions(+), 42 deletions(-) diff --git a/src/CdekCoreApi.php b/src/CdekCoreApi.php index 95ea75d..1c306e3 100644 --- a/src/CdekCoreApi.php +++ b/src/CdekCoreApi.php @@ -57,10 +57,11 @@ private function getStoreUuid() 'POST', $this->generalTokenStorage->getToken(), [ - "url" => [ - "rest" => rest_url(), - "home" => home_url(), - "admin" => admin_url(), + 'site_name' => get_bloginfo('name'), + 'url' => [ + 'rest' => rest_url(), + 'home' => home_url(), + 'admin' => admin_url(), ], ] ); diff --git a/src/Transport/HttpCoreClient.php b/src/Transport/HttpCoreClient.php index e8eb593..a4d7ce6 100644 --- a/src/Transport/HttpCoreClient.php +++ b/src/Transport/HttpCoreClient.php @@ -13,43 +13,6 @@ class HttpCoreClient { - /** - * @param string $url - * @param string $method - * @param string $token - shop token - * @param array|null $data - * - * @return array|false|string|\WP_Error - */ - public static function sendCdekShopRequest( - string $url, - string $method, - string $token, - array $data = null - ) - { - $pluginVersion = Loader::getPluginVersion(); - - $config = [ - 'headers' => [ - 'Content-Type' => 'application/json', - 'Authorization' => $token, - 'X-App-Name' => 'wordpress', - 'X-App-Version' => $pluginVersion, - 'X-User-Locale' => get_user_locale(), - 'X-Correlation-Id' => self::generateUuid(), - 'user-agent' => Loader::getPluginName() . ':' . get_bloginfo('version'), - ], - 'timeout' => 60, - ]; - - if (!empty($data)) { - $config['body'] = ($method === WP_REST_Server::READABLE) ? $data : wp_json_encode($data); - } - - return self::sendRequest($url, $method, $config); - } - public static function sendCdekRequest( string $url, string $method, @@ -69,7 +32,7 @@ public static function sendCdekRequest( $config['body'] = ($method === WP_REST_Server::READABLE) ? $data : wp_json_encode($data); } - return self::sendRequest($url, $method, $config); + return static::sendRequest($url, $method, $config); } public static function sendRequest(string $url, string $method, array $config = []) From 9f3c0785794f8b9dc3686a29b3aa423820a67cee Mon Sep 17 00:00:00 2001 From: Stas Demin Date: Fri, 31 May 2024 12:38:24 +0300 Subject: [PATCH 05/50] fix: site name key change --- src/CdekCoreApi.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/CdekCoreApi.php b/src/CdekCoreApi.php index 1c306e3..d224bd5 100644 --- a/src/CdekCoreApi.php +++ b/src/CdekCoreApi.php @@ -57,7 +57,7 @@ private function getStoreUuid() 'POST', $this->generalTokenStorage->getToken(), [ - 'site_name' => get_bloginfo('name'), + 'name' => get_bloginfo('name'), 'url' => [ 'rest' => rest_url(), 'home' => home_url(), From 02c3ff5f776865ff36bd9124d9ed6561166867e2 Mon Sep 17 00:00:00 2001 From: Stas Demin Date: Fri, 31 May 2024 13:12:00 +0300 Subject: [PATCH 06/50] fix: exchange token to shop token was changed, get shop uuid inside fetch method --- src/CdekCoreApi.php | 48 ++++++++++++++++++-------------------------- src/UI/MetaBoxes.php | 35 -------------------------------- 2 files changed, 20 insertions(+), 63 deletions(-) diff --git a/src/CdekCoreApi.php b/src/CdekCoreApi.php index d224bd5..9dc0078 100644 --- a/src/CdekCoreApi.php +++ b/src/CdekCoreApi.php @@ -30,27 +30,6 @@ public function __construct( } public function fetchShopToken() - { - $body = json_decode( - HttpCoreClient::sendCdekRequest( - $this->getAuthUrl(), - 'POST', - $this->generalTokenStorage->getToken() - ), - true - )['body']; - - if ($body === null || isset($body['error_description']) || isset($body['error'])) { - throw new CdekApiException('[CDEKDelivery] Failed to get shop token', - 'cdek_error.shop_token.auth', - $body, - true); - } - - return $body['token']; - } - - private function getStoreUuid() { $response = HttpCoreClient::sendCdekRequest( $this->apiUrl . self::SHOP, @@ -75,14 +54,32 @@ private function getStoreUuid() $body = json_decode($response, true)['body']; - if(empty($body) || $body['error']){ + if(empty($body) || empty($body['id']) || $body['error']){ throw new CdekApiException('[CDEKDelivery] Failed to get shop uuid', 'cdek_error.uuid.auth', $response, true); } - return $body['uuid']; + sleep(5); + + $body = json_decode( + HttpCoreClient::sendCdekRequest( + sprintf($this->apiUrl . self::TOKEN_PATH, $body['id']), + 'POST', + $this->generalTokenStorage->getToken() + ), + true + )['body']; + + if ($body === null || isset($body['error_description']) || isset($body['error'])) { + throw new CdekApiException('[CDEKDelivery] Failed to get shop token', + 'cdek_error.shop_token.auth', + $body, + true); + } + + return $body['token']; } public function reindexOrders($orders) @@ -99,11 +96,6 @@ public function checkUpdateOrders() ); } - private function getAuthUrl(): string - { - return sprintf($this->apiUrl . self::TOKEN_PATH, $this->getStoreUuid()); - } - private function getApiUrl(): string { if ($this->deliveryMethod->get_option('test_mode') === 'yes') { diff --git a/src/UI/MetaBoxes.php b/src/UI/MetaBoxes.php index 9c8b227..250b595 100644 --- a/src/UI/MetaBoxes.php +++ b/src/UI/MetaBoxes.php @@ -149,16 +149,6 @@ public static function createOrderMetaBox($post): void $orderNumber = $orderData['order_number'] ?? null; $orderUuid = $orderData['order_uuid'] ?? null; -// if(empty($orderData['uuid_confirmed']) && self::confirmOrderUuid($orderNumber, $orderUuid)){ -// OrderMetaData::updateMetaByOrderId( -// $orderIdWP, -// [ -// 'order_uuid' => $orderUuid, -// 'uuid_confirmed' => true -// ] -// ); -// } - try { $cdekStatuses = Helper::getCdekOrderStatuses($orderUuid); $actionOrderAvailable = Helper::getCdekActionOrderAvailable($cdekStatuses); @@ -195,31 +185,6 @@ public static function notAvailableEditOrderData(): void

'; } -// public static function confirmOrderUuid($orderNumber, &$orderUuid) -// { -// if(strpos($orderNumber, '-') !== false){ -// $orderUuid = self::reCreateOrderUuid($orderNumber); -// -// return !empty($orderUuid); -// } -// -// return false; -// } -// -// private static function reCreateOrderUuid(string $orderNumber, int $iteration = 1) -// { -// sleep(1); -// -// if ($iteration === 5) { -// return null; -// } -// -// $orderInfoJson = (new CdekApi())->getOrderByNumber($orderNumber); -// $orderInfo = json_decode($orderInfoJson, true); -// -// return $orderInfo['entity']['uuid'] ?? self::reCreateOrderUuid($orderNumber, $iteration + 1); -// } - public function __invoke(): void { add_action('add_meta_boxes', [__CLASS__, 'registerMetaBoxes'], 100, 2); From aeae10d81e95acd6f917290ceb6fe2c370e9437f Mon Sep 17 00:00:00 2001 From: Stas Demin Date: Fri, 31 May 2024 18:30:41 +0300 Subject: [PATCH 07/50] fix: cache token in file and get from cache --- src/Cache/FileCache.php | 109 +++++++++++++++++++++++++++++ src/CdekCoreApi.php | 8 +-- src/Config.php | 9 +-- src/Helpers/DBCoreTokenStorage.php | 31 ++++---- src/Transport/HttpCoreClient.php | 2 - 5 files changed, 134 insertions(+), 25 deletions(-) create mode 100644 src/Cache/FileCache.php diff --git a/src/Cache/FileCache.php b/src/Cache/FileCache.php new file mode 100644 index 0000000..911a4e6 --- /dev/null +++ b/src/Cache/FileCache.php @@ -0,0 +1,109 @@ +file = $fileName; + } + public static function get($name) + { + if (self::$enable) { + $file = Loader::getPluginPath() . self::$path . '/' . $name . self::FILE_EXT; + if (file_exists($file)) { + return file_get_contents($file); + } else { + self::$keys[] = $name; + return false; + } + } else { + return ''; + } + } + + public function getVars() + { + return require_once(Loader::getPluginPath() . '/' . $this->file . self::FILE_EXT); + } + + public function putVars($vars) + { + if(empty($vars)){ + return; + } + + $logFile = fopen( Loader::getPluginPath() . '/' . $this->file . self::FILE_EXT, 'w+'); + $content = 'recurseContent($content, $vars); + $content .= '];'; + + fwrite($logFile, $content); + fclose($logFile); + } + + private function recurseContent(&$content, $vars) + { + foreach ($vars as $key => $var){ + if(is_array($var)){ + $content .= '"' . $key . '" => ['; + $this->recurseContent($content, $var); + $content .= '],'; + }else{ + $content .= '"' . $key . '" => "' . $var . '",'; + } + + } + } + + public static function set($content) + { + if (self::$enable) { + $name = array_pop(self::$keys); + $dir = Loader::getPluginPath() . self::$path . '/'; + if (!is_dir($dir)) { + @mkdir($dir, 0777, true); + } + file_put_contents($dir . '/' . $name . self::FILE_EXT, $content); + } + + return $content; + } + + public static function begin($name) + { + if ($content = self::get($name)) { + echo $content; + return false; + } else { + ob_start(); + return true; + } + } + + public static function end() + { + echo self::set(ob_get_clean()); + } + + public static function clear() + { + $dir = Loader::getPluginPath() . self::$path; + foreach (glob($dir . '/*') as $file) { + if (is_file($file)) { + unlink($file); + } + } + } +} diff --git a/src/CdekCoreApi.php b/src/CdekCoreApi.php index 9dc0078..11c4eb9 100644 --- a/src/CdekCoreApi.php +++ b/src/CdekCoreApi.php @@ -9,9 +9,9 @@ class CdekCoreApi { - private const TOKEN_PATH = 'cms/wordpress/shop/%s/token'; - private const REINDEX_ORDERS = 'cms/wordpress/full-sync'; - private const SHOP = 'cms/wordpress/shop'; + private const TOKEN_PATH = 'shop/%s/token'; + private const REINDEX_ORDERS = 'full-sync'; + private const SHOP = 'shop'; private string $apiUrl; private CdekShippingMethod $deliveryMethod; private TokenStorageContract $generalTokenStorage; @@ -99,7 +99,7 @@ public function checkUpdateOrders() private function getApiUrl(): string { if ($this->deliveryMethod->get_option('test_mode') === 'yes') { - return $_ENV['CDEK_REST_CORE_API'] ?? Config::TEST_API_CORE_URL; + return $_ENV['CDEK_REST_CORE_API'] ?? Config::API_CORE_URL; } return Config::API_CORE_URL; diff --git a/src/Config.php b/src/Config.php index b62cb56..a980d52 100644 --- a/src/Config.php +++ b/src/Config.php @@ -13,10 +13,11 @@ class Config public const META_KEY = 'order_data'; public const ORDER_META_BOX_KEY = 'official_cdek_order'; public const ORDER_AUTOMATION_HOOK_NAME = 'cdekdelivery_automation'; - public const API_URL = 'https://api.cdek.ru/v2/'; - public const TEST_API_URL = 'https://api.edu.cdek.ru/v2/'; - public const API_CORE_URL = 'https://api.cdek.ru/v2/'; //todo change to current url - public const TEST_API_CORE_URL = 'localhost:9939'; //todo change to current url + public const API_CORE_URL = 'https://api.cdek.ru/'; + public const API_VERSION = 'v2/'; + public const CMS_VERSION = 'wordpress/'; + public const API_URL = 'https://api.cdek.ru/' . self::API_VERSION; + public const TEST_API_URL = 'https://api.edu.cdek.ru/' . self::API_VERSION; public const TEST_CLIENT_ID = 'EMscd6r9JnFiQ3bLoyjJY6eM78JrJceI'; public const TEST_CLIENT_SECRET = 'PjLZkKBHEiLK3YsjtNrt3TGNG0ahs3kG'; public const GRAPHICS_TIMEOUT_SEC = 60; diff --git a/src/Helpers/DBCoreTokenStorage.php b/src/Helpers/DBCoreTokenStorage.php index 278cb53..b45d940 100644 --- a/src/Helpers/DBCoreTokenStorage.php +++ b/src/Helpers/DBCoreTokenStorage.php @@ -2,6 +2,7 @@ namespace Cdek\Helpers; +use Cdek\Cache\FileCache; use Cdek\CdekCoreApi; use Cdek\Contracts\TokenStorageContract; use Cdek\Exceptions\CdekApiException; @@ -9,6 +10,7 @@ class DBCoreTokenStorage extends TokenStorageContract { + const CACHE_FILE_NAME = '.cache'; private static string $tokenStatic = ''; private static int $tokenExpStatic = 0; @@ -39,20 +41,14 @@ private function getTokenFromCache(): ?string private function getTokenFromSettings(): ?string { - $tokenSetting = Helper::getActualShippingMethod()->get_option('core_token'); - if (empty($tokenSetting)) { - return null; - } - $decryptToken = $this->decryptToken($tokenSetting, Helper::getActualShippingMethod()->get_option('client_id')); - if (empty($decryptToken)) { - return null; - } - $tokenExpSetting = $this->getTokenExp($decryptToken); - if ($tokenExpSetting < time()) { + $cache = (new FileCache(self::CACHE_FILE_NAME))->getVars(); + + if (empty($cache['token'])) { return null; } - self::$tokenStatic = $decryptToken; - self::$tokenExpStatic = $tokenExpSetting; + + $decryptToken = $cache['token']; + self::$tokenStatic = $decryptToken; return $decryptToken; } @@ -67,9 +63,14 @@ private function getTokenExp(string $token): int final public function updateToken(): string { $tokenApi = $this->fetchTokenFromApi(); - $clientId = Helper::getActualShippingMethod()->get_option('client_id'); - $tokenEncrypt = $this->encryptToken($tokenApi, $clientId); - Helper::getActualShippingMethod()->update_option('core_token', $tokenEncrypt); + + $cache = new FileCache(self::CACHE_FILE_NAME); + $cache->putVars( + [ + 'token' => $tokenApi + ] + ); + self::$tokenStatic = $tokenApi; self::$tokenExpStatic = $this->getTokenExp($tokenApi); return $tokenApi; diff --git a/src/Transport/HttpCoreClient.php b/src/Transport/HttpCoreClient.php index a4d7ce6..fa2dae2 100644 --- a/src/Transport/HttpCoreClient.php +++ b/src/Transport/HttpCoreClient.php @@ -22,7 +22,6 @@ public static function sendCdekRequest( { $config = [ 'headers' => [ - 'Content-Type' => 'application/json', 'Authorization' => $token ], 'timeout' => 60, @@ -45,7 +44,6 @@ public static function sendRequest(string $url, string $method, array $config = 'method' => $method, 'Content-Type' => 'application/json', 'headers' => [ - 'Content-Type' => 'application/json', 'X-App-Name' => 'wordpress', 'X-App-Version' => Loader::getPluginVersion(), 'X-User-Locale' => get_user_locale(), From e42e71920bf1d942a34be5e293ac35f21274103f Mon Sep 17 00:00:00 2001 From: Stas Demin Date: Mon, 3 Jun 2024 12:10:43 +0300 Subject: [PATCH 08/50] fix: get and create api tasks --- src/Actions/Schedule/TaskManager.php | 80 ++++++++++++++++++++++++++++ src/CdekCoreApi.php | 25 ++++++--- src/Helpers/DBCoreTokenStorage.php | 18 ++++++- src/Loader.php | 20 ++++++- src/Model/TaskData.php | 71 ++++++++++++++++++++++++ 5 files changed, 204 insertions(+), 10 deletions(-) create mode 100644 src/Actions/Schedule/TaskManager.php create mode 100644 src/Model/TaskData.php diff --git a/src/Actions/Schedule/TaskManager.php b/src/Actions/Schedule/TaskManager.php new file mode 100644 index 0000000..f1c0443 --- /dev/null +++ b/src/Actions/Schedule/TaskManager.php @@ -0,0 +1,80 @@ +getResponse(); + $this->initTasks(); + } + + public function init() + { + $taskManager = new self(); + $taskManager->startTasksWork(); + } + + public function startTasksWork() + { + foreach ($this->taskCollection as $task){ + $this->startTask($task); + } + } + + public function getErrors() + { + return $this->errorCollection; + } + + private function startTask(TaskData $task) + { + if(!$task->isAvailableTask()){ + return; + } + + $task->createTaskWork(); + } + + private function getResponse() + { + $response = (new CdekCoreApi())->taskManager(); + $decodeResponse = json_decode($response, true); + + if( + $decodeResponse['error'] + ){ + $this->errorCollection[] = $decodeResponse['error']; + } + + if(empty($response['cursor'])){ + $this->errorCollection[] = 'Cursor data not found'; + } + + if(empty($this->errorCollection)){ + $this->responseData = $response['data']; + $this->responseCursor = $response['cursor']; + } + } + + private function initTasks() + { + if(!empty($this->errorCollection)){ + return; + } + + foreach ($this->responseData as $data){ + $this->taskCollection[] = new TaskData($data); + } + } +} diff --git a/src/CdekCoreApi.php b/src/CdekCoreApi.php index 11c4eb9..fbbae05 100644 --- a/src/CdekCoreApi.php +++ b/src/CdekCoreApi.php @@ -11,6 +11,7 @@ class CdekCoreApi { private const TOKEN_PATH = 'shop/%s/token'; private const REINDEX_ORDERS = 'full-sync'; + private const TASKS = 'tasks'; private const SHOP = 'shop'; private string $apiUrl; private CdekShippingMethod $deliveryMethod; @@ -42,7 +43,7 @@ public function fetchShopToken() 'home' => home_url(), 'admin' => admin_url(), ], - ] + ], ); if(empty($response['success'])){ @@ -67,9 +68,9 @@ public function fetchShopToken() HttpCoreClient::sendCdekRequest( sprintf($this->apiUrl . self::TOKEN_PATH, $body['id']), 'POST', - $this->generalTokenStorage->getToken() + $this->generalTokenStorage->getToken(), ), - true + true, )['body']; if ($body === null || isset($body['error_description']) || isset($body['error'])) { @@ -82,20 +83,32 @@ public function fetchShopToken() return $body['token']; } + public function taskManager() + { + return HttpCoreClient::sendCdekRequest($this->getShopApiUrl() . '/' . self::TASKS, 'GET', + $this->tokenCoreStorage->getToken()); + } + public function reindexOrders($orders) { - return HttpCoreClient::sendCdekRequest($this->apiUrl . self::REINDEX_ORDERS, 'PUT', $this->tokenCoreStorage->getToken(), $orders); + return HttpCoreClient::sendCdekRequest($this->getShopApiUrl() . '/' . self::REINDEX_ORDERS, 'PUT', + $this->tokenCoreStorage->getToken(), $orders); } public function checkUpdateOrders() { return HttpCoreClient::sendCdekRequest( - $this->apiUrl . self::REINDEX_ORDERS, + $this->getShopApiUrl() . '/' . self::REINDEX_ORDERS, 'GET', - $this->tokenCoreStorage->getToken() + $this->tokenCoreStorage->getToken(), ); } + private function getShopApiUrl() + { + return $this->apiUrl . $this->tokenCoreStorage->getPath(); + } + private function getApiUrl(): string { if ($this->deliveryMethod->get_option('test_mode') === 'yes') { diff --git a/src/Helpers/DBCoreTokenStorage.php b/src/Helpers/DBCoreTokenStorage.php index b45d940..f7f429d 100644 --- a/src/Helpers/DBCoreTokenStorage.php +++ b/src/Helpers/DBCoreTokenStorage.php @@ -13,6 +13,7 @@ class DBCoreTokenStorage extends TokenStorageContract const CACHE_FILE_NAME = '.cache'; private static string $tokenStatic = ''; private static int $tokenExpStatic = 0; + private static string $apiUrlString = ''; final public static function flushCache(): void { @@ -34,6 +35,19 @@ final public function getToken(): string return 'Bearer ' . $token; } + public function getPath() + { + if(isset(static::$apiUrlString)){ + return static::$apiUrlString; + } + + $token = $this->getToken(); + + $arToken = explode('.', $token); + + return json_decode(base64_decode($arToken[count($arToken) - 1]))['token']; + } + private function getTokenFromCache(): ?string { return !empty(self::$tokenStatic) && self::$tokenExpStatic > time() ? self::$tokenStatic : null; @@ -67,8 +81,8 @@ final public function updateToken(): string $cache = new FileCache(self::CACHE_FILE_NAME); $cache->putVars( [ - 'token' => $tokenApi - ] + 'token' => $tokenApi, + ], ); self::$tokenStatic = $tokenApi; diff --git a/src/Loader.php b/src/Loader.php index 69f053e..88f856f 100644 --- a/src/Loader.php +++ b/src/Loader.php @@ -16,6 +16,7 @@ use Cdek\Actions\RecalculateShippingAction; use Cdek\Actions\SaveCustomCheckoutFieldsAction; use Cdek\Actions\Schedule\ReindexOrders; + use Cdek\Actions\Schedule\TaskManager; use Cdek\Blocks\CheckoutMapBlock; use Cdek\Controllers\CourierController; use Cdek\Controllers\LocationController; @@ -177,9 +178,24 @@ public function __invoke(string $pluginMainFile): void add_action(Config::ORDER_AUTOMATION_HOOK_NAME, new CreateOrderAction, 10, 2); - add_action('admin_post_reindex_orders', [ReindexOrders::class, 'initOrdersSend']); +// add_action('admin_post_reindex_orders', [ReindexOrders::class, 'initOrdersSend']); +// +// add_action('get_reindex_orders', [ReindexOrders::class, 'getReindexOrders']); + + if ( false === as_has_scheduled_action('cdek_task_manager') ) { + as_schedule_recurring_action( + strtotime('tomorrow'), + DAY_IN_SECONDS, + 'cdek_task_manager', + [], + '', + true + ); + } + + add_action( 'init', 'cdek_task_manager' ); - add_action('get_reindex_orders', [ReindexOrders::class, 'getReindexOrders']); + add_action('cdek_task_manager', [TaskManager::class, 'init']); (new CdekWidget)(); (new Admin)(); diff --git a/src/Model/TaskData.php b/src/Model/TaskData.php new file mode 100644 index 0000000..d3e597e --- /dev/null +++ b/src/Model/TaskData.php @@ -0,0 +1,71 @@ +id = $requestData['id']; + $this->name = $requestData['name']; + $this->schedule = $requestData['schedule']; + $this->metaData = []; + + if(!empty($requestData['meta'])){ + $this->metaData = $requestData['meta']; + } + } + + public function createTaskWork() + { + //todo logic of work task + } + + /** + * @return mixed + */ + public function getId() + { + return $this->id; + } + + /** + * @return mixed + */ + public function getName() + { + return $this->name; + } + + /** + * @return mixed + */ + public function getSchedule() + { + return $this->schedule; + } + + /** + * @return mixed + */ + public function getMetaData() + { + return $this->metaData; + } + + public function isAvailableTask() + { + return in_array($this->name, self::AVAILABLE_TASKS); + } + +} From c40b6aa4e7cfb078e9cf91da3a2ff1191f0d7e7c Mon Sep 17 00:00:00 2001 From: Stas Demin Date: Mon, 3 Jun 2024 14:15:23 +0300 Subject: [PATCH 09/50] fix: start task as schedule work --- src/Actions/Schedule/TaskCreator.php | 43 ++++++++++++++++++++++++++++ src/CdekCoreApi.php | 4 +-- src/Loader.php | 2 +- src/Model/TaskData.php | 32 ++++++++++++++++++--- 4 files changed, 74 insertions(+), 7 deletions(-) create mode 100644 src/Actions/Schedule/TaskCreator.php diff --git a/src/Actions/Schedule/TaskCreator.php b/src/Actions/Schedule/TaskCreator.php new file mode 100644 index 0000000..5dff532 --- /dev/null +++ b/src/Actions/Schedule/TaskCreator.php @@ -0,0 +1,43 @@ +initTask($taskId); + } + + public function getTask(): TaskData + { + return $this->taskData; + } + + private function initTask($taskId) + { + $response = (new CdekCoreApi())->taskManager($taskId); + $decodeResponse = json_decode($response, true); + + if( + $decodeResponse['error'] + ){ + $this->errorCollection[] = $decodeResponse['error']; + } + + if(empty($response['cursor'])){ + $this->errorCollection[] = 'Cursor data not found'; + } + + if(empty($this->errorCollection)){ + $this->taskData = new TaskData(reset($response['data'])); + $this->responseCursor = $response['cursor']; + } + } +} diff --git a/src/CdekCoreApi.php b/src/CdekCoreApi.php index fbbae05..715ccad 100644 --- a/src/CdekCoreApi.php +++ b/src/CdekCoreApi.php @@ -83,10 +83,10 @@ public function fetchShopToken() return $body['token']; } - public function taskManager() + public function taskManager($data = null) { return HttpCoreClient::sendCdekRequest($this->getShopApiUrl() . '/' . self::TASKS, 'GET', - $this->tokenCoreStorage->getToken()); + $this->tokenCoreStorage->getToken(), $data); } public function reindexOrders($orders) diff --git a/src/Loader.php b/src/Loader.php index 88f856f..a4c7155 100644 --- a/src/Loader.php +++ b/src/Loader.php @@ -193,7 +193,7 @@ public function __invoke(string $pluginMainFile): void ); } - add_action( 'init', 'cdek_task_manager' ); + add_action('init', 'cdek_task_manager'); add_action('cdek_task_manager', [TaskManager::class, 'init']); diff --git a/src/Model/TaskData.php b/src/Model/TaskData.php index d3e597e..592a6d9 100644 --- a/src/Model/TaskData.php +++ b/src/Model/TaskData.php @@ -4,15 +4,19 @@ class TaskData { + const TASK_COLLECT_ORPHANED_ORDERS = 'collect_orphaned-orders'; + const TASK_RESTORE_ORDER_UUIDS = 'restore-order-uuids'; + const AVAILABLE_TASKS = [ - 'collect_orphaned-orders', - 'restore-order-uuids', + self::TASK_COLLECT_ORPHANED_ORDERS, + self::TASK_RESTORE_ORDER_UUIDS, ]; private $id; private $name; private $schedule; private $metaData; + private $time; public function __construct($requestData) { @@ -21,14 +25,34 @@ public function __construct($requestData) $this->schedule = $requestData['schedule']; $this->metaData = []; - if(!empty($requestData['meta'])){ + if (!empty($requestData['meta'])) { $this->metaData = $requestData['meta']; } + + $this->time = time(); } public function createTaskWork() { - //todo logic of work task + $this->time += 5 * 60; + if ($this->schedule) { + if (false === as_has_scheduled_action($this->name)) { + as_schedule_recurring_action( + $this->time, + $this->schedule, + $this->name, + $this->metaData, + '', + true + ); + } + } else { + as_schedule_single_action( + $this->time, + $this->name, + $this->metaData, + ); + } } /** From 335aa4fac3f3369428a9e20e84c09dc220c2bb3c Mon Sep 17 00:00:00 2001 From: Stas Demin Date: Mon, 3 Jun 2024 16:50:06 +0300 Subject: [PATCH 10/50] fix: rewrite cache, start events, tasks --- src/Actions/Schedule/CollectOrders.php | 66 ++++++++++++++++ src/Actions/Schedule/ReindexOrders.php | 103 ++++--------------------- src/Actions/Schedule/TaskManager.php | 3 +- src/Cache/FileCache.php | 72 +++-------------- src/CdekShippingMethod.php | 88 +++++++++------------ src/Contracts/TaskContract.php | 9 +++ src/Helpers/DBCoreTokenStorage.php | 2 +- src/Loader.php | 47 +++++++---- src/Model/TaskData.php | 6 +- 9 files changed, 176 insertions(+), 220 deletions(-) create mode 100644 src/Actions/Schedule/CollectOrders.php create mode 100644 src/Contracts/TaskContract.php diff --git a/src/Actions/Schedule/CollectOrders.php b/src/Actions/Schedule/CollectOrders.php new file mode 100644 index 0000000..3f9b3fa --- /dev/null +++ b/src/Actions/Schedule/CollectOrders.php @@ -0,0 +1,66 @@ +api = new CdekCoreApi(); + } + + public static function getName(): string + { + return 'collect_orphaned-orders'; + } + + public static function init($metaData = []) + { + $reindexOrders = new self(); + $reindexOrders->start(); + } + + public function start() + { + $this->initOrders(); + $this->exchangeOrders(); + } + + protected function initOrders() + { + $query = new \WC_Order_Query( + [ + 'orderby' => 'id', + 'order' => 'ASC', + 'return' => 'ids', + ], + ); + + foreach ($query->get_orders() as $orderId) { + $this->orders[] = $orderId; + } + } + + private function exchangeOrders() + { + $response = $this->api->reindexOrders($this->orders); + $exchangeObj = json_decode($response, true); + + if (property_exists($exchangeObj, 'errors') || $exchangeObj['response']['code'] !== 202) { + $this->error = + new Validate( + false, + __('An error occurred while creating request. Try again later', 'cdekdelivery'), + ); + } + + } +} diff --git a/src/Actions/Schedule/ReindexOrders.php b/src/Actions/Schedule/ReindexOrders.php index ce258cc..a512619 100644 --- a/src/Actions/Schedule/ReindexOrders.php +++ b/src/Actions/Schedule/ReindexOrders.php @@ -10,96 +10,39 @@ use Cdek\CdekCoreApi; use Cdek\CdekShippingMethod; + use Cdek\Contracts\TaskContract; use Cdek\Model\OrderMetaData; use Cdek\Model\Validate; - class ReindexOrders + class ReindexOrders extends TaskContract { - private CdekCoreApi $api; private array $orders; - private Validate $error; private array $responseOrders = []; + private Validate $error; - public function __construct() - { - $this->api = new CdekCoreApi(); - } - - public static function initOrdersSend() - { - $reindex = new self(); - - $reindex->run(); - - status_header(200); - - exit("Server received '{$_REQUEST['data']}' from your browser."); - } - - public static function getReindexOrders() - { - $reindex = new self(); - - $reindex->checkReindexOrders(); - $reindex->writeReindexOrders(); - - } - - public function run() + public static function getName(): string { - (new CdekShippingMethod())->update_option('cdek_start_reindex', 'Y'); - - $this->getOrders(); - $this->exchangeOrders(); - - if(isset($this->error)){ - - status_header(500); - - exit($this->error->message); - - } - - if (false === as_has_scheduled_action('get_reindex_orders') ) { - wp_schedule_single_event( - strtotime('tomorrow'), - 'get_reindex_orders' - ); - } + return 'restore-order-uuids'; } - protected function checkReindexOrders() + public static function init($metaData = []) { - $response = $this->api->checkUpdateOrders(); - $exchangeObj = json_decode($response, true); - - if(property_exists($exchangeObj, 'errors') || empty($exchangeObj['body']['orders'])){ - $this->error = - new Validate( - false, - __('An error occurred while creating request. Try again later', 'cdekdelivery'), - ); - + if(empty($metaData)){ return; } - $this->responseOrders = $exchangeObj['body']['orders']; - - if(empty($response['body']['completed'])){ - wp_schedule_single_event( - time() + 60 * 5, - 'get_reindex_orders' - ); - } + $reindexOrders = new self(); + $reindexOrders->setResponseOrders($metaData['orders']); + $reindexOrders->start(); } - protected function writeReindexOrders() + public function start() { if(empty($this->responseOrders)){ return; } - $this->getOrders(); + $this->initOrders(); foreach ($this->orders as $orderId){ $orderIndex = array_search($orderId, array_column($this->responseOrders, 'order_id')); @@ -114,14 +57,13 @@ protected function writeReindexOrders() $orderId, [ 'order_number' => $responseOrder['order_number'], - 'order_uuid' => $responseOrder['order_uuid'] - ] + 'order_uuid' => $responseOrder['order_uuid'], + ], ); } - } - protected function getOrders() + protected function initOrders() { $query = new \WC_Order_Query( [ @@ -136,20 +78,9 @@ protected function getOrders() } } - protected function exchangeOrders() + public function setResponseOrders($orders) { - $response = $this->api->reindexOrders($this->orders); - $exchangeObj = json_decode($response, true); - - if (property_exists($exchangeObj, 'errors') || $exchangeObj['response']['code'] !== 202) { - $this->error = - new Validate( - false, - __('An error occurred while creating request. Try again later', 'cdekdelivery'), - ); - } - + $this->responseOrders = $orders; } - } } diff --git a/src/Actions/Schedule/TaskManager.php b/src/Actions/Schedule/TaskManager.php index f1c0443..e237e54 100644 --- a/src/Actions/Schedule/TaskManager.php +++ b/src/Actions/Schedule/TaskManager.php @@ -3,6 +3,7 @@ namespace Cdek\Actions\Schedule; use Cdek\CdekCoreApi; +use Cdek\Contracts\TaskContract; use Cdek\Model\TaskData; class TaskManager @@ -19,7 +20,7 @@ public function __construct() $this->initTasks(); } - public function init() + public static function init() { $taskManager = new self(); $taskManager->startTasksWork(); diff --git a/src/Cache/FileCache.php b/src/Cache/FileCache.php index 911a4e6..e54cac2 100644 --- a/src/Cache/FileCache.php +++ b/src/Cache/FileCache.php @@ -6,35 +6,17 @@ class FileCache { - const FILE_EXT = '.php'; - - public static $enable = true; - public static $path = '/cache'; - private static $keys = []; + private static array $store; private string $file; public function __construct($fileName) { $this->file = $fileName; } - public static function get($name) - { - if (self::$enable) { - $file = Loader::getPluginPath() . self::$path . '/' . $name . self::FILE_EXT; - if (file_exists($file)) { - return file_get_contents($file); - } else { - self::$keys[] = $name; - return false; - } - } else { - return ''; - } - } public function getVars() { - return require_once(Loader::getPluginPath() . '/' . $this->file . self::FILE_EXT); + return self::$store[$this->file] ?? self::$store[$this->file] = require_once(Loader::getPluginPath() . DIRECTORY_SEPARATOR . $this->file); } public function putVars($vars) @@ -43,7 +25,7 @@ public function putVars($vars) return; } - $logFile = fopen( Loader::getPluginPath() . '/' . $this->file . self::FILE_EXT, 'w+'); + $logFile = fopen( Loader::getPluginPath() . DIRECTORY_SEPARATOR . $this->file, 'w+'); $content = 'recurseContent($content, $vars); @@ -55,55 +37,23 @@ public function putVars($vars) private function recurseContent(&$content, $vars) { + $countVars = count($vars); + $i = 0; + foreach ($vars as $key => $var){ + $i++; if(is_array($var)){ $content .= '"' . $key . '" => ['; $this->recurseContent($content, $var); - $content .= '],'; + $content .= ']'; }else{ - $content .= '"' . $key . '" => "' . $var . '",'; + $content .= '"' . $key . '" => "' . $var . '"'; } - } - } - - public static function set($content) - { - if (self::$enable) { - $name = array_pop(self::$keys); - $dir = Loader::getPluginPath() . self::$path . '/'; - if (!is_dir($dir)) { - @mkdir($dir, 0777, true); + if($i < $countVars){ + $content .= ','; } - file_put_contents($dir . '/' . $name . self::FILE_EXT, $content); - } - return $content; - } - - public static function begin($name) - { - if ($content = self::get($name)) { - echo $content; - return false; - } else { - ob_start(); - return true; - } - } - - public static function end() - { - echo self::set(ob_get_clean()); - } - - public static function clear() - { - $dir = Loader::getPluginPath() . self::$path; - foreach (glob($dir . '/*') as $file) { - if (is_file($file)) { - unlink($file); - } } } } diff --git a/src/CdekShippingMethod.php b/src/CdekShippingMethod.php index 2a345fe..33f2313 100644 --- a/src/CdekShippingMethod.php +++ b/src/CdekShippingMethod.php @@ -14,16 +14,16 @@ class CdekShippingMethod extends WC_Shipping_Method public function __construct($instance_id = 0) { parent::__construct($instance_id); - $this->id = Config::DELIVERY_NAME; - $this->instance_id = absint($instance_id); - $this->method_title = esc_html__('CDEK Shipping', 'cdekdelivery'); + $this->id = Config::DELIVERY_NAME; + $this->instance_id = absint($instance_id); + $this->method_title = esc_html__('CDEK Shipping', 'cdekdelivery'); $this->method_description = esc_html__('Official Shipping Method for Cdek', 'cdekdelivery'); - $this->supports = [ + $this->supports = [ 'settings', 'shipping-zones', 'instance-settings', ]; - $this->enabled = 'yes'; + $this->enabled = 'yes'; $this->init(); } @@ -31,7 +31,7 @@ final public function init(): void { $this->title = esc_html__('CDEK Shipping', 'cdekdelivery'); $this->init_settings(); - add_action('woocommerce_update_options_shipping_'.$this->id, [$this, 'process_admin_options']); + add_action('woocommerce_update_options_shipping_' . $this->id, [$this, 'process_admin_options']); $this->init_form_fields(); } @@ -49,30 +49,9 @@ final public function init_form_fields(): void ], ]; - $reindexCreated = $this->get_option('cdek_start_reindex'); - - if($reindexCreated == 'Y'){ - $arReindex = []; - }else{ - $settings_page_url = admin_url('admin-post.php?action=reindex_orders&data=all'); - $arReindex = [ - 'reindex_orders' => [ - 'title' => '' . - __('Reindex order', 'cdekdelivery') . '', - 'type' => 'text', - 'hidden' => true, - 'class' => 'cdek_setting_block_button', - 'custom_attributes' => [ - 'hidden' => 'hidden', - 'onClick' => 'javascript::void(0)', - ], - ], - ]; - } - - $this->form_fields = $arReindex + [ + $this->form_fields = [ 'auth_block_name' => [ - 'title' => '

'.esc_html__('Authorization', 'cdekdelivery').'

', + 'title' => '

' . esc_html__('Authorization', 'cdekdelivery') . '

', 'type' => 'title', 'class' => 'cdek_setting_block_name', ], @@ -109,7 +88,7 @@ final public function init_form_fields(): void ], ], 'seller_block_name' => [ - 'title' => '

'.esc_html__('Client', 'cdekdelivery').'

', + 'title' => '

' . esc_html__('Client', 'cdekdelivery') . '

', 'type' => 'title', 'class' => 'cdek_setting_block_name', ], @@ -210,7 +189,7 @@ final public function init_form_fields(): void 'date_format' => 'd.m.Y', ], 'delivery_block_name' => [ - 'title' => '

'.esc_html__('Delivery', 'cdekdelivery').'

', + 'title' => '

' . esc_html__('Delivery', 'cdekdelivery') . '

', 'type' => 'title', 'class' => 'cdek_delivery_block_name', ], @@ -218,7 +197,7 @@ final public function init_form_fields(): void 'title' => esc_html__('Automatically create orders in CDEK', 'cdekdelivery'), 'type' => 'checkbox', 'description' => esc_html__('If you have information about the dimensions and correctly filled in shipping addresses, the CDEK invoice will be created automatically', - 'cdekdelivery'), + 'cdekdelivery'), ], 'tariff_list' => [ 'title' => esc_html__('Tariff', 'cdekdelivery'), @@ -226,21 +205,22 @@ final public function init_form_fields(): void 'desc_tip' => true, 'options' => Tariff::getTariffList(), 'description' => esc_html__('To select multiple tariffs, hold down the "CTRL" key and select tariffs with the left mouse button.', - 'cdekdelivery'), + 'cdekdelivery'), 'css' => 'height: 400px;', ], 'tariff_name' => [ 'title' => esc_html__('Change tariff name', 'cdekdelivery'), 'type' => 'text', 'description' => sprintf(esc_html__('In the list of tariffs in the field "Tariffs" the tariff code is indicated in brackets.\n\r To change the name of the tariff, an entry in the code-name format is added to the field; for multiple changes,\n\r tariffs are separated by a semicolon, for example, an entry that will change the name of tariff 136 and 137 looks like this:%s If the value is not specified, the tariff names will be standard.', - 'cdekdelivery'), '136-Доставка до пвз;137-Доставка курьером
'), + 'cdekdelivery'), + '136-Доставка до пвз;137-Доставка курьером
'), ], 'has_packages_mode' => [ 'title' => esc_html__('Multi-seater', 'cdekdelivery'), 'type' => 'checkbox', 'desc_tip' => true, 'description' => esc_html__('When the "Multi-seat" mode is enabled, the detailed order page will display the ability to create several packages for one order and distribute goods among the created packages', - 'cdekdelivery'), + 'cdekdelivery'), 'default' => 'no', ], 'extra_day' => [ @@ -248,7 +228,7 @@ final public function init_form_fields(): void 'type' => 'number', 'desc_tip' => true, 'description' => esc_html__('Number of days will be added to the estimated delivery time', - 'cdekdelivery'), + 'cdekdelivery'), 'default' => 0, 'custom_attributes' => [ 'min' => 0, @@ -260,7 +240,7 @@ final public function init_form_fields(): void 'type' => 'checkbox', 'desc_tip' => true, 'description' => esc_html__('If this setting is enabled, then after selecting a pick-up point on the checkout page, the card will automatically close.', - 'cdekdelivery'), + 'cdekdelivery'), 'default' => 'no', ], 'map' => [ @@ -277,18 +257,20 @@ final public function init_form_fields(): void 'type' => 'hidden', ], 'package_setting_block_name' => [ - 'title' => '

'.esc_html__('Dimensions', 'cdekdelivery').'

', + 'title' => '

' . esc_html__('Dimensions', 'cdekdelivery') . '

', 'type' => 'title', 'class' => 'cdek_package_setting_block_name', ], 'product_weight_default' => [ - 'title' => esc_html__('Default weight of one item in', 'cdekdelivery'). - ' ('. - get_option('woocommerce_weight_unit'). + 'title' => esc_html__('Default weight of one item in', 'cdekdelivery') . + ' (' . + get_option('woocommerce_weight_unit') . ')', 'desc_tip' => true, 'description' => sprintf(esc_html__('All goods must have their weight indicated, if there are goods without %s a specified weight, then for such goods the value from this field will be substituted. %s This will affect the accuracy of the delivery calculation. The default value is 1 weight unit specified in the settings.', - 'cdekdelivery'), "
", "
"), + 'cdekdelivery'), + "
", + "
"), 'type' => 'number', 'default' => 1, 'custom_attributes' => [ @@ -332,20 +314,20 @@ final public function init_form_fields(): void 'product_package_default_toggle' => [ 'title' => esc_html__('Product dimensions on/off', 'cdekdelivery'), 'description' => esc_html__('Force the use of product dimensions (length, width and height) by default for all products', - 'cdekdelivery'), + 'cdekdelivery'), 'type' => 'checkbox', 'desc_tip' => true, 'default' => 'no', ], 'services_block_name' => [ - 'title' => '

'.esc_html__('Services', 'cdekdelivery').'

', + 'title' => '

' . esc_html__('Services', 'cdekdelivery') . '

', 'type' => 'title', 'class' => 'cdek_delivery_block_name', ], 'services_ban_attachment_inspection' => [ 'title' => esc_html__('Prohibition of inspection of attachment', 'cdekdelivery'), 'description' => esc_html__('This service is not available for tariffs to the parcel locker and is only available to clients with an IM type agreement.\n\r Also, the prohibition on inspecting the attachment does not work when the services of fitting at home and partial delivery are included.', - 'cdekdelivery'), + 'cdekdelivery'), 'type' => 'checkbox', 'default' => 'no', ], @@ -362,7 +344,7 @@ final public function init_form_fields(): void 'default' => 'no', ], 'delivery_price_block_name' => [ - 'title' => '

'.esc_html__('Delivery cost', 'cdekdelivery').'

', + 'title' => '

' . esc_html__('Delivery cost', 'cdekdelivery') . '

', 'type' => 'title', 'class' => 'cdek_delivery_price_block_name', ], @@ -382,13 +364,15 @@ final public function init_form_fields(): void 'title' => esc_html__('Cash on delivery settings', 'cdekdelivery'), 'type' => 'title', 'description' => esc_html__('Cash on delivery settings are applied only when sending an order from the admin panels and for the user on the checkout page are not displayed', - 'cdekdelivery'), + 'cdekdelivery'), ], 'percentcod' => [ 'title' => esc_html__('Extra charge on order as a percentage', 'cdekdelivery'), 'type' => 'number', 'description' => sprintf(esc_html__('Calculated from the cost of the order. Changes the total amount on the receipt.%s The surcharge will only appear on the receipt.%s Therefore, it is recommended to inform the user on the checkout page about extra charges when sending by cash on delivery.', - 'cdekdelivery'), "
", " "), + 'cdekdelivery'), + "
", + " "), 'custom_attributes' => [ 'min' => 100, 'step' => 1, @@ -421,14 +405,16 @@ public function get_option($key, $empty_value = null) if ($this->get_instance_option("use_$key", false) === 'yes') { return $instanceValue; } - } elseif (!empty($instanceValue) || strpos($key, 'use_') === 0) { + } else if (!empty($instanceValue) || strpos($key, 'use_') === 0) { return $instanceValue; } } // Return global option. - $option = apply_filters('woocommerce_shipping_'.$this->id.'_option', - WC_Settings_API::get_option($key, $empty_value), $key, $this); + $option = apply_filters('woocommerce_shipping_' . $this->id . '_option', + WC_Settings_API::get_option($key, $empty_value), + $key, + $this); return $option; } diff --git a/src/Contracts/TaskContract.php b/src/Contracts/TaskContract.php new file mode 100644 index 0000000..2da53c8 --- /dev/null +++ b/src/Contracts/TaskContract.php @@ -0,0 +1,9 @@ +time += 5 * 60; if ($this->schedule) { if (false === as_has_scheduled_action($this->name)) { - as_schedule_recurring_action( + as_schedule_cron_action( $this->time, $this->schedule, $this->name, @@ -47,10 +47,10 @@ public function createTaskWork() ); } } else { - as_schedule_single_action( + as_enqueue_async_action( $this->time, $this->name, - $this->metaData, + $this->metaData ); } } From 353bb23da49dcc4284e34a305e39384cfce65dd8 Mon Sep 17 00:00:00 2001 From: Stas Demin Date: Mon, 3 Jun 2024 17:07:39 +0300 Subject: [PATCH 11/50] fix: task hook add prefix --- src/Config.php | 1 + src/Loader.php | 5 ++++- src/Model/TaskData.php | 6 ++++-- 3 files changed, 9 insertions(+), 3 deletions(-) diff --git a/src/Config.php b/src/Config.php index a980d52..1149440 100644 --- a/src/Config.php +++ b/src/Config.php @@ -10,6 +10,7 @@ class Config { public const DELIVERY_NAME = 'official_cdek'; + public const TASK_PREFIX = 'cdek'; public const META_KEY = 'order_data'; public const ORDER_META_BOX_KEY = 'official_cdek_order'; public const ORDER_AUTOMATION_HOOK_NAME = 'cdekdelivery_automation'; diff --git a/src/Loader.php b/src/Loader.php index b58d3c3..cfbe6dc 100644 --- a/src/Loader.php +++ b/src/Loader.php @@ -212,7 +212,10 @@ private static function registerTasks() foreach ($arTaskClasses as $arTaskClass){ if($arTaskClass instanceof TaskContract){ - add_action($arTaskClass::getName(), [$arTaskClass, 'init']); + add_action( + Config::DELIVERY_NAME . '_' . Config::TASK_PREFIX . '_' . $arTaskClass::getName(), + [$arTaskClass, 'init'] + ); } } } diff --git a/src/Model/TaskData.php b/src/Model/TaskData.php index de8364f..86c7ce4 100644 --- a/src/Model/TaskData.php +++ b/src/Model/TaskData.php @@ -2,6 +2,8 @@ namespace Cdek\Model; +use Cdek\Config; + class TaskData { const TASK_COLLECT_ORPHANED_ORDERS = 'collect_orphaned-orders'; @@ -40,7 +42,7 @@ public function createTaskWork() as_schedule_cron_action( $this->time, $this->schedule, - $this->name, + Config::DELIVERY_NAME . '_' . Config::TASK_PREFIX . '_' . $this->name, $this->metaData, '', true @@ -49,7 +51,7 @@ public function createTaskWork() } else { as_enqueue_async_action( $this->time, - $this->name, + Config::DELIVERY_NAME . '_' . Config::TASK_PREFIX . '_' . $this->name, $this->metaData ); } From de2422dfea34ee144359756cd9c3764420ebb9dd Mon Sep 17 00:00:00 2001 From: Stas Demin Date: Mon, 3 Jun 2024 17:50:20 +0300 Subject: [PATCH 12/50] fix: small fix --- src/Actions/Schedule/TaskManager.php | 1 - src/Model/TaskData.php | 26 ++++++++++++++++---------- 2 files changed, 16 insertions(+), 11 deletions(-) diff --git a/src/Actions/Schedule/TaskManager.php b/src/Actions/Schedule/TaskManager.php index e237e54..72ff4ff 100644 --- a/src/Actions/Schedule/TaskManager.php +++ b/src/Actions/Schedule/TaskManager.php @@ -10,7 +10,6 @@ class TaskManager { private array $responseData = []; private array $responseCursor; - private TaskData $task; private array $taskCollection; private ?array $errorCollection; diff --git a/src/Model/TaskData.php b/src/Model/TaskData.php index 86c7ce4..022095d 100644 --- a/src/Model/TaskData.php +++ b/src/Model/TaskData.php @@ -17,8 +17,8 @@ class TaskData private $id; private $name; private $schedule; - private $metaData; - private $time; + private ?array $metaData; + private int $time; public function __construct($requestData) { @@ -37,22 +37,23 @@ public function __construct($requestData) public function createTaskWork() { $this->time += 5 * 60; - if ($this->schedule) { - if (false === as_has_scheduled_action($this->name)) { + + if ($this->isScheduleTask()) { + if (false === as_has_scheduled_action($this->getName())) { as_schedule_cron_action( $this->time, - $this->schedule, - Config::DELIVERY_NAME . '_' . Config::TASK_PREFIX . '_' . $this->name, - $this->metaData, + $this->getSchedule(), + Config::DELIVERY_NAME . '_' . Config::TASK_PREFIX . '_' . $this->getName(), + $this->getMetaData(), '', - true + true, ); } } else { as_enqueue_async_action( $this->time, - Config::DELIVERY_NAME . '_' . Config::TASK_PREFIX . '_' . $this->name, - $this->metaData + Config::DELIVERY_NAME . '_' . Config::TASK_PREFIX . '_' . $this->getName(), + $this->getMetaData(), ); } } @@ -94,4 +95,9 @@ public function isAvailableTask() return in_array($this->name, self::AVAILABLE_TASKS); } + public function isScheduleTask() + { + return !empty($this->schedule); + } + } From b9d0a7c460fcdb150f85deadb1a54354d4982b43 Mon Sep 17 00:00:00 2001 From: Stas Demin Date: Tue, 4 Jun 2024 13:20:25 +0300 Subject: [PATCH 13/50] feat: unregister events, rewrite api send, additional headers, rewrite manager and task logic --- src/Actions/Schedule/CollectOrders.php | 30 +++++- src/Actions/Schedule/ReindexOrders.php | 34 ++++--- src/Actions/Schedule/TaskCreator.php | 43 --------- src/Actions/Schedule/TaskManager.php | 80 ---------------- src/CdekCoreApi.php | 5 + src/Config.php | 1 + src/Contracts/TaskContract.php | 78 ++++++++++++++- src/Loader.php | 35 ++----- src/Managers/TaskManager.php | 126 +++++++++++++++++++++++++ src/Model/TaskData.php | 31 +----- src/Transport/HttpCoreClient.php | 15 ++- src/Uninstaller.php | 20 ++++ src/uninstall.php | 15 +++ 13 files changed, 312 insertions(+), 201 deletions(-) delete mode 100644 src/Actions/Schedule/TaskCreator.php delete mode 100644 src/Actions/Schedule/TaskManager.php create mode 100644 src/Managers/TaskManager.php create mode 100644 src/Uninstaller.php create mode 100644 src/uninstall.php diff --git a/src/Actions/Schedule/CollectOrders.php b/src/Actions/Schedule/CollectOrders.php index 3f9b3fa..951edfa 100644 --- a/src/Actions/Schedule/CollectOrders.php +++ b/src/Actions/Schedule/CollectOrders.php @@ -9,11 +9,13 @@ class CollectOrders extends TaskContract { private CdekCoreApi $api; + private string $taskId; private array $orders; private Validate $error; - public function __construct() + public function __construct($taskId) { + $this->taskId = $taskId; $this->api = new CdekCoreApi(); } @@ -24,7 +26,10 @@ public static function getName(): string public static function init($metaData = []) { - $reindexOrders = new self(); + if(empty($metaData['task_id'])){ + return; + } + $reindexOrders = new self($metaData['task_id']); $reindexOrders->start(); } @@ -44,9 +49,28 @@ protected function initOrders() ], ); - foreach ($query->get_orders() as $orderId) { + $pagination = $this->getTaskMeta($this->taskId)['pagination']; + + if(!empty($pagination)){ + $query->set('page', $pagination['page']); + }else{ + $pagination['page'] = 1; + } + + $count = count($query->get_orders()); + + $query->set('limit', self::ORDERS_LIMIT); + + $arOrders = $query->get_orders(); + + foreach ($arOrders as $orderId) { $this->orders[] = $orderId; } + + $this->reportResult( + ceil($count/self::ORDERS_LIMIT), + $pagination['page'] + ); } private function exchangeOrders() diff --git a/src/Actions/Schedule/ReindexOrders.php b/src/Actions/Schedule/ReindexOrders.php index a512619..70248c2 100644 --- a/src/Actions/Schedule/ReindexOrders.php +++ b/src/Actions/Schedule/ReindexOrders.php @@ -16,10 +16,16 @@ class ReindexOrders extends TaskContract { + private string $taskId; private array $orders; - private array $responseOrders = []; private Validate $error; + public function __construct(string $taskId) + { + $this->taskId = $taskId; + $this->initTaskData($taskId); + } + public static function getName(): string { return 'restore-order-uuids'; @@ -27,31 +33,30 @@ public static function getName(): string public static function init($metaData = []) { - if(empty($metaData)){ + if(empty($metaData['task_id'])){ return; } - $reindexOrders = new self(); - $reindexOrders->setResponseOrders($metaData['orders']); + $reindexOrders = new static($metaData['task_id']); $reindexOrders->start(); } public function start() { - if(empty($this->responseOrders)){ + if(empty($this->getTaskMeta($this->taskId)['orders'])){ return; } $this->initOrders(); foreach ($this->orders as $orderId){ - $orderIndex = array_search($orderId, array_column($this->responseOrders, 'order_id')); + $orderIndex = array_search($orderId, array_column($this->getTaskMeta($this->taskId)['orders'], 'order_id')); if(empty($orderIndex)){ continue; } - $responseOrder = $this->responseOrders[$orderIndex]; + $responseOrder = $this->getTaskMeta($this->taskId)['orders'][$orderIndex]; OrderMetaData::updateMetaByOrderId( $orderId, @@ -70,17 +75,20 @@ protected function initOrders() 'orderby' => 'id', 'order' => 'ASC', 'return' => 'ids', - ], + ] ); + $pagination = $this->getTaskMeta($this->taskId)['pagination']; + + if(!empty($pagination)){ + $query->set('page', $pagination['page']); + } + + $query->set('limit', self::ORDERS_LIMIT); + foreach ($query->get_orders() as $orderId) { $this->orders[] = $orderId; } } - - public function setResponseOrders($orders) - { - $this->responseOrders = $orders; - } } } diff --git a/src/Actions/Schedule/TaskCreator.php b/src/Actions/Schedule/TaskCreator.php deleted file mode 100644 index 5dff532..0000000 --- a/src/Actions/Schedule/TaskCreator.php +++ /dev/null @@ -1,43 +0,0 @@ -initTask($taskId); - } - - public function getTask(): TaskData - { - return $this->taskData; - } - - private function initTask($taskId) - { - $response = (new CdekCoreApi())->taskManager($taskId); - $decodeResponse = json_decode($response, true); - - if( - $decodeResponse['error'] - ){ - $this->errorCollection[] = $decodeResponse['error']; - } - - if(empty($response['cursor'])){ - $this->errorCollection[] = 'Cursor data not found'; - } - - if(empty($this->errorCollection)){ - $this->taskData = new TaskData(reset($response['data'])); - $this->responseCursor = $response['cursor']; - } - } -} diff --git a/src/Actions/Schedule/TaskManager.php b/src/Actions/Schedule/TaskManager.php deleted file mode 100644 index 72ff4ff..0000000 --- a/src/Actions/Schedule/TaskManager.php +++ /dev/null @@ -1,80 +0,0 @@ -getResponse(); - $this->initTasks(); - } - - public static function init() - { - $taskManager = new self(); - $taskManager->startTasksWork(); - } - - public function startTasksWork() - { - foreach ($this->taskCollection as $task){ - $this->startTask($task); - } - } - - public function getErrors() - { - return $this->errorCollection; - } - - private function startTask(TaskData $task) - { - if(!$task->isAvailableTask()){ - return; - } - - $task->createTaskWork(); - } - - private function getResponse() - { - $response = (new CdekCoreApi())->taskManager(); - $decodeResponse = json_decode($response, true); - - if( - $decodeResponse['error'] - ){ - $this->errorCollection[] = $decodeResponse['error']; - } - - if(empty($response['cursor'])){ - $this->errorCollection[] = 'Cursor data not found'; - } - - if(empty($this->errorCollection)){ - $this->responseData = $response['data']; - $this->responseCursor = $response['cursor']; - } - } - - private function initTasks() - { - if(!empty($this->errorCollection)){ - return; - } - - foreach ($this->responseData as $data){ - $this->taskCollection[] = new TaskData($data); - } - } -} diff --git a/src/CdekCoreApi.php b/src/CdekCoreApi.php index 715ccad..1ff0807 100644 --- a/src/CdekCoreApi.php +++ b/src/CdekCoreApi.php @@ -104,6 +104,11 @@ public function checkUpdateOrders() ); } + public function addHeaders(array $addHeaders): void + { + HttpCoreClient::addHeaders($addHeaders); + } + private function getShopApiUrl() { return $this->apiUrl . $this->tokenCoreStorage->getPath(); diff --git a/src/Config.php b/src/Config.php index 1149440..5ba6c1a 100644 --- a/src/Config.php +++ b/src/Config.php @@ -14,6 +14,7 @@ class Config public const META_KEY = 'order_data'; public const ORDER_META_BOX_KEY = 'official_cdek_order'; public const ORDER_AUTOMATION_HOOK_NAME = 'cdekdelivery_automation'; + public const TASK_MANAGER_HOOK_NAME = 'cdekdelivery_task_manager'; public const API_CORE_URL = 'https://api.cdek.ru/'; public const API_VERSION = 'v2/'; public const CMS_VERSION = 'wordpress/'; diff --git a/src/Contracts/TaskContract.php b/src/Contracts/TaskContract.php index 2da53c8..2852858 100644 --- a/src/Contracts/TaskContract.php +++ b/src/Contracts/TaskContract.php @@ -2,8 +2,82 @@ namespace Cdek\Contracts; +use Cdek\CdekCoreApi; +use Cdek\Config; +use Cdek\Model\TaskData; + abstract class TaskContract { - abstract public static function getName(): string; - abstract public static function init($metaData = []); + const ORDERS_LIMIT = 10000; + protected static array $errorCollection = []; + protected static array $taskData = []; + protected static array $responseCursor = []; + protected array $headers = []; + + abstract protected static function getName(): string; + abstract public static function init(); + public function getHeaders() + { + return $this->headers; + } + public static function registerAction(): void + { + add_action( + sprintf('%s-%s', Config::TASK_MANAGER_HOOK_NAME, static::getName()), + [static::class, 'init'], + 20, + 1, + ); + } + protected function getTaskMeta(string $taskId): array + { + if(empty(self::$taskData[$taskId])){ + $this->initTaskData($taskId); + } + + return self::$taskData[$taskId]['meta']; + } + protected function getTaskCursor(string $taskId): array + { + if(empty(self::$responseCursor[$taskId])){ + $this->initTaskData($taskId); + } + + return self::$responseCursor[$taskId]['meta']; + } + protected function reportResult(int $totalPages, int $currentPage) + { + $this->headers = [ + 'X-Total-Pages' => $totalPages, + 'X-Current-Page' => $currentPage, + ]; + } + + protected function initTaskData(string $taskId): void + { + $cdekCoreApi = new CdekCoreApi(); + + if(!empty($this->getHeaders())){ + $cdekCoreApi->addHeaders($this->getHeaders()); + } + + $response = $cdekCoreApi->taskManager($taskId); + + $decodeResponse = json_decode($response, true); + + if( + $decodeResponse['error'] + ){ + self::$errorCollection[$taskId][] = $decodeResponse['error']; + } + + if(empty($response['cursor'])){ + self::$errorCollection[$taskId][] = 'Cursor data not found'; + } + + if(empty(self::$errorCollection)){ + self::$taskData[$taskId] = new TaskData(reset($response['data'])); + self::$responseCursor[$taskId] = $response['cursor']; + } + } } diff --git a/src/Loader.php b/src/Loader.php index cfbe6dc..c7534c1 100644 --- a/src/Loader.php +++ b/src/Loader.php @@ -15,18 +15,14 @@ use Cdek\Actions\ProcessWoocommerceCreateShippingAction; use Cdek\Actions\RecalculateShippingAction; use Cdek\Actions\SaveCustomCheckoutFieldsAction; - use Cdek\Actions\Schedule\CollectOrders; - use Cdek\Actions\Schedule\ReindexOrders; - use Cdek\Actions\Schedule\TaskManager; + use Cdek\Managers\TaskManager; use Cdek\Blocks\CheckoutMapBlock; - use Cdek\Contracts\TaskContract; use Cdek\Controllers\CourierController; use Cdek\Controllers\LocationController; use Cdek\Controllers\OrderController; use Cdek\Controllers\RestController; use Cdek\Helpers\CheckoutHelper; use Cdek\Helpers\DataWPScraber; - use Cdek\Model\TaskData; use Cdek\UI\Admin; use Cdek\UI\AdminNotices; use Cdek\UI\AdminShippingFields; @@ -87,11 +83,11 @@ public static function activate(): void self::checkRequirements(); - if (as_has_scheduled_action('cdek_task_manager') === false) { - as_schedule_recurring_action( - strtotime('tomorrow'), + if (as_has_scheduled_action(Config::TASK_MANAGER_HOOK_NAME) === false) { + as_schedule_cron_action( + time(), DAY_IN_SECONDS, - 'cdek_task_manager', + Config::TASK_MANAGER_HOOK_NAME, [], '', true, @@ -192,9 +188,7 @@ public function __invoke(string $pluginMainFile): void add_action(Config::ORDER_AUTOMATION_HOOK_NAME, new CreateOrderAction, 10, 2); - add_action('cdek_task_manager', [TaskManager::class, 'init']); - - self::registerTasks(); + TaskManager::registerTasks(); (new CdekWidget)(); (new Admin)(); @@ -203,23 +197,6 @@ public function __invoke(string $pluginMainFile): void (new AdminNotices)(); } - private static function registerTasks() - { - $arTaskClasses = [ - ReindexOrders::class, - CollectOrders::class - ]; - - foreach ($arTaskClasses as $arTaskClass){ - if($arTaskClass instanceof TaskContract){ - add_action( - Config::DELIVERY_NAME . '_' . Config::TASK_PREFIX . '_' . $arTaskClass::getName(), - [$arTaskClass, 'init'] - ); - } - } - } - private static function declareCompatibility(): void { add_action('before_woocommerce_init', static function () { diff --git a/src/Managers/TaskManager.php b/src/Managers/TaskManager.php new file mode 100644 index 0000000..6a29a58 --- /dev/null +++ b/src/Managers/TaskManager.php @@ -0,0 +1,126 @@ +getResponse(); + $this->initTasks(); + } + + public static function init(): void + { + $taskManager = new self(); + $taskManager->startTasksWork(); + } + + public function startTasksWork(): void + { + foreach ($this->taskCollection as $task) { + $this->startTask($task); + } + } + + public static function getName(): string + { + return Config::TASK_MANAGER_HOOK_NAME; + } + + public static function registerAction(): void + { + add_action(static::getName(), [static::class, 'init']); + } + + public function getErrors(): array + { + return self::$errorCollection['task_manager']; + } + + + public static function registerTasks(): void + { + foreach (self::TASK_CLASSES as $arTaskClass) { + if ($arTaskClass instanceof TaskContract) { + $arTaskClass::registerAction(); + } + } + } + + public static function getTasksHooks() + { + return array_map( + static fn(TaskContract $class) => $class::getName() === static::getName() ? + static::getName() : + sprintf('%s-%s', + Config::TASK_MANAGER_HOOK_NAME, + $class::getName(), + ), + self::TASK_CLASSES, + ); + } + + private function startTask(TaskData $task): void + { + if (!in_array( + $task->getName(), + array_map( + static fn(TaskContract $class) => $class::getName(), + self::TASK_CLASSES, + ), + ) + ) { + return; + } + + $task->createTaskWork(); + } + + private function getResponse(): void + { + $response = (new CdekCoreApi())->taskManager(); + $decodeResponse = json_decode($response, true); + + if ( + $decodeResponse['error'] + ) { + self::$errorCollection['task_manager'][] = $decodeResponse['error']; + } + + if (empty($response['cursor'])) { + self::$errorCollection['task_manager'][] = 'Cursor data not found'; + } + + if (empty($this->errorCollection)) { + self::$taskData['task_manager'] = $response['data']; + self::$responseCursor['task_manager'] = $response['cursor']; + } + } + + private function initTasks(): void + { + if (!empty(self::$errorCollection)) { + return; + } + + foreach (self::$taskData['task_manager'] as $data) { + $this->taskCollection[] = new TaskData($data); + } + } +} diff --git a/src/Model/TaskData.php b/src/Model/TaskData.php index 022095d..000133b 100644 --- a/src/Model/TaskData.php +++ b/src/Model/TaskData.php @@ -6,18 +6,9 @@ class TaskData { - const TASK_COLLECT_ORPHANED_ORDERS = 'collect_orphaned-orders'; - const TASK_RESTORE_ORDER_UUIDS = 'restore-order-uuids'; - - const AVAILABLE_TASKS = [ - self::TASK_COLLECT_ORPHANED_ORDERS, - self::TASK_RESTORE_ORDER_UUIDS, - ]; - private $id; private $name; private $schedule; - private ?array $metaData; private int $time; public function __construct($requestData) @@ -25,11 +16,6 @@ public function __construct($requestData) $this->id = $requestData['id']; $this->name = $requestData['name']; $this->schedule = $requestData['schedule']; - $this->metaData = []; - - if (!empty($requestData['meta'])) { - $this->metaData = $requestData['meta']; - } $this->time = time(); } @@ -44,7 +30,7 @@ public function createTaskWork() $this->time, $this->getSchedule(), Config::DELIVERY_NAME . '_' . Config::TASK_PREFIX . '_' . $this->getName(), - $this->getMetaData(), + ['task_id' => $this->getId()], '', true, ); @@ -53,7 +39,7 @@ public function createTaskWork() as_enqueue_async_action( $this->time, Config::DELIVERY_NAME . '_' . Config::TASK_PREFIX . '_' . $this->getName(), - $this->getMetaData(), + ['task_id' => $this->getId()], ); } } @@ -82,19 +68,6 @@ public function getSchedule() return $this->schedule; } - /** - * @return mixed - */ - public function getMetaData() - { - return $this->metaData; - } - - public function isAvailableTask() - { - return in_array($this->name, self::AVAILABLE_TASKS); - } - public function isScheduleTask() { return !empty($this->schedule); diff --git a/src/Transport/HttpCoreClient.php b/src/Transport/HttpCoreClient.php index fa2dae2..6b7b7c7 100644 --- a/src/Transport/HttpCoreClient.php +++ b/src/Transport/HttpCoreClient.php @@ -13,6 +13,13 @@ class HttpCoreClient { + private static array $addHeaders = []; + + public static function addHeaders(array $addHeaders) + { + self::$addHeaders = $addHeaders; + } + public static function sendCdekRequest( string $url, string $method, @@ -22,7 +29,7 @@ public static function sendCdekRequest( { $config = [ 'headers' => [ - 'Authorization' => $token + 'Authorization' => $token, ], 'timeout' => 60, ]; @@ -49,12 +56,16 @@ public static function sendRequest(string $url, string $method, array $config = 'X-User-Locale' => get_user_locale(), 'X-Correlation-Id' => self::generateUuid(), 'user-agent' => Loader::getPluginName() . ':' . get_bloginfo('version'), - ], + ] + self::$addHeaders, 'timeout' => 60, ], ), ); + if(!empty(self::$addHeaders)){ + self::$addHeaders = []; + } + if (is_array($resp)) { return $resp; } diff --git a/src/Uninstaller.php b/src/Uninstaller.php new file mode 100644 index 0000000..77d276d --- /dev/null +++ b/src/Uninstaller.php @@ -0,0 +1,20 @@ + Date: Tue, 4 Jun 2024 15:14:06 +0300 Subject: [PATCH 14/50] fix: unregister events --- src/Uninstaller.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Uninstaller.php b/src/Uninstaller.php index 77d276d..377e877 100644 --- a/src/Uninstaller.php +++ b/src/Uninstaller.php @@ -9,7 +9,7 @@ class Uninstaller public function __invoke() { foreach (TaskManager::getTasksHooks() as $hook){ - if (as_has_scheduled_action(Config::TASK_MANAGER_HOOK_NAME) === false) { + if (as_has_scheduled_action(Config::TASK_MANAGER_HOOK_NAME) !== false) { wp_unschedule_event( time(), $hook From 293425028019b0788143221b1263fac408e82688 Mon Sep 17 00:00:00 2001 From: Stas Demin Date: Wed, 5 Jun 2024 08:15:29 +0300 Subject: [PATCH 15/50] fix: after review fixes --- src/Actions/Schedule/CollectOrders.php | 3 ++- src/Actions/Schedule/ReindexOrders.php | 1 + src/Cache/FileCache.php | 28 ++------------------------ src/CdekApi.php | 11 ---------- src/CdekCoreApi.php | 21 ++++--------------- src/Contracts/TaskContract.php | 1 - src/Helpers/DBCoreTokenStorage.php | 14 +++---------- src/Transport/HttpCoreClient.php | 2 +- src/Uninstaller.php | 2 +- src/uninstall.php | 8 +++----- 10 files changed, 17 insertions(+), 74 deletions(-) diff --git a/src/Actions/Schedule/CollectOrders.php b/src/Actions/Schedule/CollectOrders.php index 951edfa..d336b2a 100644 --- a/src/Actions/Schedule/CollectOrders.php +++ b/src/Actions/Schedule/CollectOrders.php @@ -8,6 +8,7 @@ class CollectOrders extends TaskContract { + const ORDERS_LIMIT = 10000; private CdekCoreApi $api; private string $taskId; private array $orders; @@ -21,7 +22,7 @@ public function __construct($taskId) public static function getName(): string { - return 'collect_orphaned-orders'; + return 'collect-orphaned-orders'; } public static function init($metaData = []) diff --git a/src/Actions/Schedule/ReindexOrders.php b/src/Actions/Schedule/ReindexOrders.php index 70248c2..81ae626 100644 --- a/src/Actions/Schedule/ReindexOrders.php +++ b/src/Actions/Schedule/ReindexOrders.php @@ -16,6 +16,7 @@ class ReindexOrders extends TaskContract { + const ORDERS_LIMIT = 10000; private string $taskId; private array $orders; private Validate $error; diff --git a/src/Cache/FileCache.php b/src/Cache/FileCache.php index e54cac2..57fb353 100644 --- a/src/Cache/FileCache.php +++ b/src/Cache/FileCache.php @@ -6,6 +6,7 @@ class FileCache { + const CACHE_FILE_NAME = '.cache.php'; private static array $store; private string $file; @@ -26,34 +27,9 @@ public function putVars($vars) } $logFile = fopen( Loader::getPluginPath() . DIRECTORY_SEPARATOR . $this->file, 'w+'); - $content = 'recurseContent($content, $vars); - $content .= '];'; + $content = ' $var){ - $i++; - if(is_array($var)){ - $content .= '"' . $key . '" => ['; - $this->recurseContent($content, $var); - $content .= ']'; - }else{ - $content .= '"' . $key . '" => "' . $var . '"'; - } - - if($i < $countVars){ - $content .= ','; - } - - } - } } diff --git a/src/CdekApi.php b/src/CdekApi.php index d9c1c3f..f9a3b2c 100644 --- a/src/CdekApi.php +++ b/src/CdekApi.php @@ -103,17 +103,6 @@ final public function getOrder(string $uuid) return HttpClient::sendCdekRequest($url, 'GET', $this->tokenStorage->getToken()); } - /** - * @throws \JsonException - * @throws \Cdek\Exceptions\CdekApiException - */ - final public function getOrderByNumber(string $orderNumber) - { - $url = $this->apiUrl . self::ORDERS_PATH . '?cdek_number=' . $orderNumber; - - return HttpClient::sendCdekRequest($url, 'GET', $this->tokenStorage->getToken()); - } - /** * @throws \Cdek\Exceptions\RestApiInvalidRequestException * @throws \Cdek\Exceptions\CdekApiException diff --git a/src/CdekCoreApi.php b/src/CdekCoreApi.php index 1ff0807..26cbd02 100644 --- a/src/CdekCoreApi.php +++ b/src/CdekCoreApi.php @@ -46,14 +46,16 @@ public function fetchShopToken() ], ); - if(empty($response['success'])){ + $arResponse = json_decode($response, true); + + if(empty($arResponse['success'])){ throw new CdekApiException('[CDEKDelivery] Failed to get shop uuid', 'cdek_error.uuid.auth', $response, true); } - $body = json_decode($response, true)['body']; + $body = $arResponse['body']; if(empty($body) || empty($body['id']) || $body['error']){ throw new CdekApiException('[CDEKDelivery] Failed to get shop uuid', @@ -62,8 +64,6 @@ public function fetchShopToken() true); } - sleep(5); - $body = json_decode( HttpCoreClient::sendCdekRequest( sprintf($this->apiUrl . self::TOKEN_PATH, $body['id']), @@ -95,15 +95,6 @@ public function reindexOrders($orders) $this->tokenCoreStorage->getToken(), $orders); } - public function checkUpdateOrders() - { - return HttpCoreClient::sendCdekRequest( - $this->getShopApiUrl() . '/' . self::REINDEX_ORDERS, - 'GET', - $this->tokenCoreStorage->getToken(), - ); - } - public function addHeaders(array $addHeaders): void { HttpCoreClient::addHeaders($addHeaders); @@ -116,10 +107,6 @@ private function getShopApiUrl() private function getApiUrl(): string { - if ($this->deliveryMethod->get_option('test_mode') === 'yes') { - return $_ENV['CDEK_REST_CORE_API'] ?? Config::API_CORE_URL; - } - return Config::API_CORE_URL; } } diff --git a/src/Contracts/TaskContract.php b/src/Contracts/TaskContract.php index 2852858..e287010 100644 --- a/src/Contracts/TaskContract.php +++ b/src/Contracts/TaskContract.php @@ -8,7 +8,6 @@ abstract class TaskContract { - const ORDERS_LIMIT = 10000; protected static array $errorCollection = []; protected static array $taskData = []; protected static array $responseCursor = []; diff --git a/src/Helpers/DBCoreTokenStorage.php b/src/Helpers/DBCoreTokenStorage.php index ed3577d..eedd443 100644 --- a/src/Helpers/DBCoreTokenStorage.php +++ b/src/Helpers/DBCoreTokenStorage.php @@ -10,16 +10,9 @@ class DBCoreTokenStorage extends TokenStorageContract { - const CACHE_FILE_NAME = '.cache.php'; private static string $tokenStatic = ''; - private static int $tokenExpStatic = 0; private static string $apiUrlString = ''; - final public static function flushCache(): void - { - Helper::getActualShippingMethod()->update_option('token', null); - } - final public function getToken(): string { $token = $this->getTokenFromCache(); @@ -50,12 +43,12 @@ public function getPath() private function getTokenFromCache(): ?string { - return !empty(self::$tokenStatic) && self::$tokenExpStatic > time() ? self::$tokenStatic : null; + return !empty(self::$tokenStatic) ? self::$tokenStatic : null; } private function getTokenFromSettings(): ?string { - $cache = (new FileCache(self::CACHE_FILE_NAME))->getVars(); + $cache = (new FileCache(FileCache::CACHE_FILE_NAME))->getVars(); if (empty($cache['token'])) { return null; @@ -78,7 +71,7 @@ final public function updateToken(): string { $tokenApi = $this->fetchTokenFromApi(); - $cache = new FileCache(self::CACHE_FILE_NAME); + $cache = new FileCache(FileCache::CACHE_FILE_NAME); $cache->putVars( [ 'token' => $tokenApi, @@ -86,7 +79,6 @@ final public function updateToken(): string ); self::$tokenStatic = $tokenApi; - self::$tokenExpStatic = $this->getTokenExp($tokenApi); return $tokenApi; } diff --git a/src/Transport/HttpCoreClient.php b/src/Transport/HttpCoreClient.php index 6b7b7c7..dffb3d0 100644 --- a/src/Transport/HttpCoreClient.php +++ b/src/Transport/HttpCoreClient.php @@ -55,7 +55,7 @@ public static function sendRequest(string $url, string $method, array $config = 'X-App-Version' => Loader::getPluginVersion(), 'X-User-Locale' => get_user_locale(), 'X-Correlation-Id' => self::generateUuid(), - 'user-agent' => Loader::getPluginName() . ':' . get_bloginfo('version'), + 'user-agent' => Loader::getPluginName() . '_' . get_bloginfo('version'), ] + self::$addHeaders, 'timeout' => 60, ], diff --git a/src/Uninstaller.php b/src/Uninstaller.php index 377e877..059bbf9 100644 --- a/src/Uninstaller.php +++ b/src/Uninstaller.php @@ -9,7 +9,7 @@ class Uninstaller public function __invoke() { foreach (TaskManager::getTasksHooks() as $hook){ - if (as_has_scheduled_action(Config::TASK_MANAGER_HOOK_NAME) !== false) { + if (as_has_scheduled_action($hook) !== false) { wp_unschedule_event( time(), $hook diff --git a/src/uninstall.php b/src/uninstall.php index 8b79f6e..f92d91f 100644 --- a/src/uninstall.php +++ b/src/uninstall.php @@ -5,11 +5,9 @@ require __DIR__ . '/../vendor/autoload.php'; } -use Cdek\Uninstaller; - -if (!class_exists(Uninstaller::class)) { - trigger_error('BC Sync not fully installed! Please install with Composer or download full release archive.', +if (!class_exists(\Cdek\Uninstaller::class)) { + trigger_error('CDEKDelivery not fully installed! Please install with Composer or download full release archive.', E_USER_ERROR); } -(new Uninstaller)(); +(new \Cdek\Uninstaller)(); From e25970158a234e963e389ed61a77fe2dbd97f942 Mon Sep 17 00:00:00 2001 From: Stas Demin Date: Wed, 5 Jun 2024 17:51:33 +0300 Subject: [PATCH 16/50] fix: test and fix work of core api --- src/Actions/Schedule/CollectOrders.php | 47 +++++---------------- src/Actions/Schedule/ReindexOrders.php | 20 +++------ src/Cache/FileCache.php | 4 ++ src/CdekCoreApi.php | 39 ++++++++++-------- src/Contracts/TaskContract.php | 57 +++++++++++++++----------- src/Helpers/DBCoreTokenStorage.php | 10 +---- src/Managers/TaskManager.php | 13 +++--- src/Transport/HttpCoreClient.php | 31 +++++++------- src/Uninstaller.php | 5 +-- 9 files changed, 98 insertions(+), 128 deletions(-) diff --git a/src/Actions/Schedule/CollectOrders.php b/src/Actions/Schedule/CollectOrders.php index d336b2a..eecea27 100644 --- a/src/Actions/Schedule/CollectOrders.php +++ b/src/Actions/Schedule/CollectOrders.php @@ -10,13 +10,12 @@ class CollectOrders extends TaskContract { const ORDERS_LIMIT = 10000; private CdekCoreApi $api; - private string $taskId; private array $orders; private Validate $error; public function __construct($taskId) { - $this->taskId = $taskId; + parent::__construct($taskId); $this->api = new CdekCoreApi(); } @@ -37,7 +36,6 @@ public static function init($metaData = []) public function start() { $this->initOrders(); - $this->exchangeOrders(); } protected function initOrders() @@ -46,46 +44,21 @@ protected function initOrders() [ 'orderby' => 'id', 'order' => 'ASC', - 'return' => 'ids', + 'paginate' => true, + 'limit' => self::ORDERS_LIMIT, + 'return' => 'ids' ], ); - $pagination = $this->getTaskMeta($this->taskId)['pagination']; + for ($page = 1, $maxPages = 1; $page <= $maxPages; $page++){ + $query->set('page', $page); + $result = $query->get_orders(); - if(!empty($pagination)){ - $query->set('page', $pagination['page']); - }else{ - $pagination['page'] = 1; - } - - $count = count($query->get_orders()); - - $query->set('limit', self::ORDERS_LIMIT); + $maxPages = $result->max_num_pages; - $arOrders = $query->get_orders(); + $this->addPageHeaders($maxPages, $page); - foreach ($arOrders as $orderId) { - $this->orders[] = $orderId; + $this->sendTaskData($result['orders']); } - - $this->reportResult( - ceil($count/self::ORDERS_LIMIT), - $pagination['page'] - ); - } - - private function exchangeOrders() - { - $response = $this->api->reindexOrders($this->orders); - $exchangeObj = json_decode($response, true); - - if (property_exists($exchangeObj, 'errors') || $exchangeObj['response']['code'] !== 202) { - $this->error = - new Validate( - false, - __('An error occurred while creating request. Try again later', 'cdekdelivery'), - ); - } - } } diff --git a/src/Actions/Schedule/ReindexOrders.php b/src/Actions/Schedule/ReindexOrders.php index 81ae626..0744df9 100644 --- a/src/Actions/Schedule/ReindexOrders.php +++ b/src/Actions/Schedule/ReindexOrders.php @@ -17,14 +17,13 @@ class ReindexOrders extends TaskContract { const ORDERS_LIMIT = 10000; - private string $taskId; private array $orders; private Validate $error; public function __construct(string $taskId) { - $this->taskId = $taskId; - $this->initTaskData($taskId); + parent::__construct($taskId); + $this->initTaskData(); } public static function getName(): string @@ -44,20 +43,20 @@ public static function init($metaData = []) public function start() { - if(empty($this->getTaskMeta($this->taskId)['orders'])){ + if(empty($this->getTaskMeta())){ return; } $this->initOrders(); foreach ($this->orders as $orderId){ - $orderIndex = array_search($orderId, array_column($this->getTaskMeta($this->taskId)['orders'], 'order_id')); + $orderIndex = array_search($orderId, array_column($this->getTaskMeta()['orders'], 'order_id')); if(empty($orderIndex)){ continue; } - $responseOrder = $this->getTaskMeta($this->taskId)['orders'][$orderIndex]; + $responseOrder = $this->getTaskMeta()['orders'][$orderIndex]; OrderMetaData::updateMetaByOrderId( $orderId, @@ -76,17 +75,10 @@ protected function initOrders() 'orderby' => 'id', 'order' => 'ASC', 'return' => 'ids', + 'post__in' => array_keys($this->getTaskMeta()), ] ); - $pagination = $this->getTaskMeta($this->taskId)['pagination']; - - if(!empty($pagination)){ - $query->set('page', $pagination['page']); - } - - $query->set('limit', self::ORDERS_LIMIT); - foreach ($query->get_orders() as $orderId) { $this->orders[] = $orderId; } diff --git a/src/Cache/FileCache.php b/src/Cache/FileCache.php index 57fb353..0813ef3 100644 --- a/src/Cache/FileCache.php +++ b/src/Cache/FileCache.php @@ -17,6 +17,10 @@ public function __construct($fileName) public function getVars() { + if(!file_exists(Loader::getPluginPath() . DIRECTORY_SEPARATOR . $this->file)){ + return null; + } + return self::$store[$this->file] ?? self::$store[$this->file] = require_once(Loader::getPluginPath() . DIRECTORY_SEPARATOR . $this->file); } diff --git a/src/CdekCoreApi.php b/src/CdekCoreApi.php index 26cbd02..d92fb6a 100644 --- a/src/CdekCoreApi.php +++ b/src/CdekCoreApi.php @@ -6,33 +6,32 @@ use Cdek\Helpers\DBCoreTokenStorage; use Cdek\Helpers\DBTokenStorage; use Cdek\Transport\HttpCoreClient; +use WpOrg\Requests\Exception; class CdekCoreApi { - private const TOKEN_PATH = 'shop/%s/token'; - private const REINDEX_ORDERS = 'full-sync'; - private const TASKS = 'tasks'; - private const SHOP = 'shop'; + private const TOKEN_PATH = 'api/cms/wordpress/shop/%s/token'; + private const SHOP = 'cms/wordpress/shops'; + private const TASKS = 'cms/wordpress/tasks'; private string $apiUrl; - private CdekShippingMethod $deliveryMethod; private TokenStorageContract $generalTokenStorage; private TokenStorageContract $tokenCoreStorage; + private HttpCoreClient $coreClient; public function __construct( - ?int $shippingInstanceId = null, ?TokenStorageContract $tokenStorage = null, ?TokenStorageContract $tokenCoreStorage = null ) { - $this->deliveryMethod = Helper::getActualShippingMethod($shippingInstanceId); $this->apiUrl = $this->getApiUrl(); + $this->coreClient = new HttpCoreClient(); $this->generalTokenStorage = $tokenStorage ?? new DBTokenStorage(); $this->tokenCoreStorage = $tokenCoreStorage ?? new DBCoreTokenStorage(); } public function fetchShopToken() { - $response = HttpCoreClient::sendCdekRequest( + $response = $this->coreClient->sendCdekRequest( $this->apiUrl . self::SHOP, 'POST', $this->generalTokenStorage->getToken(), @@ -46,16 +45,14 @@ public function fetchShopToken() ], ); - $arResponse = json_decode($response, true); - - if(empty($arResponse['success'])){ + if(empty($response['success'])){ throw new CdekApiException('[CDEKDelivery] Failed to get shop uuid', 'cdek_error.uuid.auth', $response, true); } - $body = $arResponse['body']; + $body = json_decode($response['body'], true); if(empty($body) || empty($body['id']) || $body['error']){ throw new CdekApiException('[CDEKDelivery] Failed to get shop uuid', @@ -65,7 +62,7 @@ public function fetchShopToken() } $body = json_decode( - HttpCoreClient::sendCdekRequest( + $this->coreClient->sendCdekRequest( sprintf($this->apiUrl . self::TOKEN_PATH, $body['id']), 'POST', $this->generalTokenStorage->getToken(), @@ -85,19 +82,25 @@ public function fetchShopToken() public function taskManager($data = null) { - return HttpCoreClient::sendCdekRequest($this->getShopApiUrl() . '/' . self::TASKS, 'GET', + return $this->coreClient->sendCdekRequest($this->getShopApiUrl() . '/' . self::TASKS, 'GET', $this->tokenCoreStorage->getToken(), $data); } - public function reindexOrders($orders) + public function taskInfo($taskId, $data = null) { - return HttpCoreClient::sendCdekRequest($this->getShopApiUrl() . '/' . self::REINDEX_ORDERS, 'PUT', - $this->tokenCoreStorage->getToken(), $orders); + return $this->coreClient->sendCdekRequest($this->getShopApiUrl() . '/' . self::TASKS . '/' . $taskId, 'GET', + $this->tokenCoreStorage->getToken(), $data); + } + + public function sendTaskData($taskId, $data) + { + return $this->coreClient->sendCdekRequest($this->getShopApiUrl() . '/' . self::TASKS . '/' . $taskId, 'PUT', + $this->tokenCoreStorage->getToken(), $data); } public function addHeaders(array $addHeaders): void { - HttpCoreClient::addHeaders($addHeaders); + $this->coreClient->addHeaders($addHeaders); } private function getShopApiUrl() diff --git a/src/Contracts/TaskContract.php b/src/Contracts/TaskContract.php index e287010..5d372e2 100644 --- a/src/Contracts/TaskContract.php +++ b/src/Contracts/TaskContract.php @@ -8,17 +8,19 @@ abstract class TaskContract { + public function __construct(string $taskId) + { + $this->taskId = $taskId; + } protected static array $errorCollection = []; protected static array $taskData = []; protected static array $responseCursor = []; protected array $headers = []; + protected string $taskId; abstract protected static function getName(): string; abstract public static function init(); - public function getHeaders() - { - return $this->headers; - } + public static function registerAction(): void { add_action( @@ -28,55 +30,64 @@ public static function registerAction(): void 1, ); } - protected function getTaskMeta(string $taskId): array + protected function getTaskMeta(): array { - if(empty(self::$taskData[$taskId])){ - $this->initTaskData($taskId); + if(empty(self::$taskData[$this->taskId])){ + $this->initTaskData($this->taskId); } - return self::$taskData[$taskId]['meta']; + return self::$taskData[$this->taskId]['meta']; } - protected function getTaskCursor(string $taskId): array + protected function getTaskCursor(): array { - if(empty(self::$responseCursor[$taskId])){ - $this->initTaskData($taskId); + if(empty(self::$responseCursor[$this->taskId])){ + $this->initTaskData($this->taskId); } - return self::$responseCursor[$taskId]['meta']; + return self::$responseCursor[$this->taskId]['meta']; } - protected function reportResult(int $totalPages, int $currentPage) + protected function addPageHeaders(int $totalPages, int $currentPage) { $this->headers = [ 'X-Total-Pages' => $totalPages, - 'X-Current-Page' => $currentPage, + 'X-Current-Page' => $currentPage ]; } - protected function initTaskData(string $taskId): void + protected function initTaskData($data = null): void { $cdekCoreApi = new CdekCoreApi(); - if(!empty($this->getHeaders())){ - $cdekCoreApi->addHeaders($this->getHeaders()); - } + $this->initData($cdekCoreApi->taskInfo($this->taskId, $data)); + } - $response = $cdekCoreApi->taskManager($taskId); + protected function sendTaskData($data) + { + $cdekCoreApi = new CdekCoreApi(); + $cdekCoreApi->addHeaders($data); + + $this->initData($cdekCoreApi->sendTaskData($this->taskId, $data)); + } + + private function initData($response) + { $decodeResponse = json_decode($response, true); if( $decodeResponse['error'] ){ - self::$errorCollection[$taskId][] = $decodeResponse['error']; + self::$errorCollection[$this->taskId][] = $decodeResponse['error']; } if(empty($response['cursor'])){ - self::$errorCollection[$taskId][] = 'Cursor data not found'; + self::$errorCollection[$this->taskId][] = 'Cursor data not found'; } if(empty(self::$errorCollection)){ - self::$taskData[$taskId] = new TaskData(reset($response['data'])); - self::$responseCursor[$taskId] = $response['cursor']; + self::$taskData[$this->taskId] = new TaskData(reset($response['data'])); + self::$responseCursor[$this->taskId] = $response['cursor']; } + } } diff --git a/src/Helpers/DBCoreTokenStorage.php b/src/Helpers/DBCoreTokenStorage.php index eedd443..53208cc 100644 --- a/src/Helpers/DBCoreTokenStorage.php +++ b/src/Helpers/DBCoreTokenStorage.php @@ -59,17 +59,9 @@ private function getTokenFromSettings(): ?string return $decryptToken; } - /** - * @throws \JsonException - */ - private function getTokenExp(string $token): int - { - return json_decode(base64_decode(strtr(explode('.', $token)[1], '-_', '+/')), false, 512, JSON_THROW_ON_ERROR)->exp; - } - final public function updateToken(): string { - $tokenApi = $this->fetchTokenFromApi(); + $tokenApi = $this->fetchTokenFromApi(); $cache = new FileCache(FileCache::CACHE_FILE_NAME); $cache->putVars( diff --git a/src/Managers/TaskManager.php b/src/Managers/TaskManager.php index 6a29a58..49fc0dd 100644 --- a/src/Managers/TaskManager.php +++ b/src/Managers/TaskManager.php @@ -21,6 +21,7 @@ class TaskManager extends TaskContract public function __construct() { + parent::__construct('task_manager'); $this->getResponse(); $this->initTasks(); } @@ -50,7 +51,7 @@ public static function registerAction(): void public function getErrors(): array { - return self::$errorCollection['task_manager']; + return self::$errorCollection[$this->taskId]; } @@ -100,16 +101,16 @@ private function getResponse(): void if ( $decodeResponse['error'] ) { - self::$errorCollection['task_manager'][] = $decodeResponse['error']; + self::$errorCollection[$this->taskId][] = $decodeResponse['error']; } if (empty($response['cursor'])) { - self::$errorCollection['task_manager'][] = 'Cursor data not found'; + self::$errorCollection[$this->taskId][] = 'Cursor data not found'; } if (empty($this->errorCollection)) { - self::$taskData['task_manager'] = $response['data']; - self::$responseCursor['task_manager'] = $response['cursor']; + self::$taskData[$this->taskId] = $response['data']; + self::$responseCursor[$this->taskId] = $response['cursor']; } } @@ -119,7 +120,7 @@ private function initTasks(): void return; } - foreach (self::$taskData['task_manager'] as $data) { + foreach (self::$taskData[$this->taskId] as $data) { $this->taskCollection[] = new TaskData($data); } } diff --git a/src/Transport/HttpCoreClient.php b/src/Transport/HttpCoreClient.php index dffb3d0..0b5c328 100644 --- a/src/Transport/HttpCoreClient.php +++ b/src/Transport/HttpCoreClient.php @@ -13,14 +13,14 @@ class HttpCoreClient { - private static array $addHeaders = []; + private array $addHeaders = []; - public static function addHeaders(array $addHeaders) + public function addHeaders(array $addHeaders) { - self::$addHeaders = $addHeaders; + $this->addHeaders = $addHeaders; } - public static function sendCdekRequest( + public function sendCdekRequest( string $url, string $method, string $token, @@ -34,14 +34,15 @@ public static function sendCdekRequest( 'timeout' => 60, ]; + if (!empty($data)) { - $config['body'] = ($method === WP_REST_Server::READABLE) ? $data : wp_json_encode($data); + $config['body'] = ($method === WP_REST_Server::READABLE) ? $data : json_encode($data); } return static::sendRequest($url, $method, $config); } - public static function sendRequest(string $url, string $method, array $config = []) + public function sendRequest(string $url, string $method, array $config = []) { $resp = wp_remote_request( $url, @@ -51,21 +52,17 @@ public static function sendRequest(string $url, string $method, array $config = 'method' => $method, 'Content-Type' => 'application/json', 'headers' => [ - 'X-App-Name' => 'wordpress', - 'X-App-Version' => Loader::getPluginVersion(), - 'X-User-Locale' => get_user_locale(), - 'X-Correlation-Id' => self::generateUuid(), - 'user-agent' => Loader::getPluginName() . '_' . get_bloginfo('version'), - ] + self::$addHeaders, + 'X-App-Name' => 'wordpress', + 'X-App-Version' => Loader::getPluginVersion(), + 'X-User-Locale' => get_user_locale(), + 'X-Correlation-Id' => self::generateUuid(), + 'user-agent' => Loader::getPluginName() . '_' . get_bloginfo('version'), + ] + $this->addHeaders, 'timeout' => 60, ], - ), + ) ); - if(!empty(self::$addHeaders)){ - self::$addHeaders = []; - } - if (is_array($resp)) { return $resp; } diff --git a/src/Uninstaller.php b/src/Uninstaller.php index 059bbf9..48637b1 100644 --- a/src/Uninstaller.php +++ b/src/Uninstaller.php @@ -10,10 +10,7 @@ public function __invoke() { foreach (TaskManager::getTasksHooks() as $hook){ if (as_has_scheduled_action($hook) !== false) { - wp_unschedule_event( - time(), - $hook - ); + as_unschedule_action($hook); } } } From c75dba755e7d2015b7dba0ea342e4b8436d73dfc Mon Sep 17 00:00:00 2001 From: Stas Demin Date: Thu, 6 Jun 2024 14:55:44 +0300 Subject: [PATCH 17/50] fix: rewrite classes for optimal work with core api --- src/Actions/Schedule/CollectOrders.php | 42 ++++++++++++++------------ src/Actions/Schedule/ReindexOrders.php | 16 ++++------ src/CdekCoreApi.php | 38 ++++++++++++----------- src/Config.php | 2 -- src/Contracts/TaskContract.php | 30 ++++++------------ src/Helpers/DBCoreTokenStorage.php | 42 +++++++++++++++++--------- src/Loader.php | 4 +-- src/Managers/TaskManager.php | 24 +++++++-------- src/Model/TaskData.php | 9 +++--- src/Transport/HttpCoreClient.php | 15 +++++---- 10 files changed, 112 insertions(+), 110 deletions(-) diff --git a/src/Actions/Schedule/CollectOrders.php b/src/Actions/Schedule/CollectOrders.php index eecea27..79cbbf2 100644 --- a/src/Actions/Schedule/CollectOrders.php +++ b/src/Actions/Schedule/CollectOrders.php @@ -8,15 +8,12 @@ class CollectOrders extends TaskContract { - const ORDERS_LIMIT = 10000; - private CdekCoreApi $api; - private array $orders; + const ORDERS_LIMIT = 2; private Validate $error; public function __construct($taskId) { parent::__construct($taskId); - $this->api = new CdekCoreApi(); } public static function getName(): string @@ -24,41 +21,48 @@ public static function getName(): string return 'collect-orphaned-orders'; } - public static function init($metaData = []) + public static function init($taskId) { - if(empty($metaData['task_id'])){ - return; - } - $reindexOrders = new self($metaData['task_id']); + $reindexOrders = new self($taskId); $reindexOrders->start(); } public function start() { - $this->initOrders(); + $this->reportOrders(); } - protected function initOrders() + protected function reportOrders() { $query = new \WC_Order_Query( [ - 'orderby' => 'id', - 'order' => 'ASC', - 'paginate' => true, - 'limit' => self::ORDERS_LIMIT, - 'return' => 'ids' + 'orderby' => 'id', + 'order' => 'ASC', + 'paginate' => true, + 'limit' => self::ORDERS_LIMIT, + 'return' => 'ids', ], ); - for ($page = 1, $maxPages = 1; $page <= $maxPages; $page++){ + for ($page = 1, $maxPages = 1; $page <= $maxPages; $page++) { $query->set('page', $page); $result = $query->get_orders(); $maxPages = $result->max_num_pages; - $this->addPageHeaders($maxPages, $page); + $this->cdekCoreApi->addPageHeaders($maxPages, $page); - $this->sendTaskData($result['orders']); + $this->sendTaskData( + [ + 'status' => 'success', + 'result' => [ + 'orders' => array_map( + static fn($order) => (string)$order, + $result->orders + ) + ] + ] + ); } } } diff --git a/src/Actions/Schedule/ReindexOrders.php b/src/Actions/Schedule/ReindexOrders.php index 0744df9..be4054c 100644 --- a/src/Actions/Schedule/ReindexOrders.php +++ b/src/Actions/Schedule/ReindexOrders.php @@ -31,13 +31,9 @@ public static function getName(): string return 'restore-order-uuids'; } - public static function init($metaData = []) + public static function init($taskId) { - if(empty($metaData['task_id'])){ - return; - } - - $reindexOrders = new static($metaData['task_id']); + $reindexOrders = new static($taskId); $reindexOrders->start(); } @@ -50,13 +46,13 @@ public function start() $this->initOrders(); foreach ($this->orders as $orderId){ - $orderIndex = array_search($orderId, array_column($this->getTaskMeta()['orders'], 'order_id')); + $orderIndex = array_search($orderId, array_column($this->getTaskMeta(), 'external_id')); if(empty($orderIndex)){ continue; } - $responseOrder = $this->getTaskMeta()['orders'][$orderIndex]; + $responseOrder = $this->getTaskMeta()[$orderIndex]; OrderMetaData::updateMetaByOrderId( $orderId, @@ -75,11 +71,11 @@ protected function initOrders() 'orderby' => 'id', 'order' => 'ASC', 'return' => 'ids', - 'post__in' => array_keys($this->getTaskMeta()), + 'post__in' => array_column($this->getTaskMeta(), 'external_id'), ] ); - foreach ($query->get_orders() as $orderId) { + foreach ($query->get_orders()->orders as $orderId) { $this->orders[] = $orderId; } } diff --git a/src/CdekCoreApi.php b/src/CdekCoreApi.php index d92fb6a..44a28d1 100644 --- a/src/CdekCoreApi.php +++ b/src/CdekCoreApi.php @@ -10,9 +10,9 @@ class CdekCoreApi { - private const TOKEN_PATH = 'api/cms/wordpress/shop/%s/token'; + private const TOKEN_PATH = 'cms/wordpress/shops/%s/token'; private const SHOP = 'cms/wordpress/shops'; - private const TASKS = 'cms/wordpress/tasks'; + private const TASKS = 'wordpress/tasks'; private string $apiUrl; private TokenStorageContract $generalTokenStorage; private TokenStorageContract $tokenCoreStorage; @@ -45,7 +45,7 @@ public function fetchShopToken() ], ); - if(empty($response['success'])){ + if(empty($response['body'])){ throw new CdekApiException('[CDEKDelivery] Failed to get shop uuid', 'cdek_error.uuid.auth', $response, @@ -54,30 +54,29 @@ public function fetchShopToken() $body = json_decode($response['body'], true); - if(empty($body) || empty($body['id']) || $body['error']){ + if(empty($body) || empty($body['data']['id'])){ throw new CdekApiException('[CDEKDelivery] Failed to get shop uuid', 'cdek_error.uuid.auth', $response, true); } - $body = json_decode( - $this->coreClient->sendCdekRequest( - sprintf($this->apiUrl . self::TOKEN_PATH, $body['id']), - 'POST', - $this->generalTokenStorage->getToken(), - ), - true, - )['body']; + $response = $this->coreClient->sendCdekRequest( + sprintf($this->apiUrl . self::TOKEN_PATH, $body['data']['id']), + 'POST', + $this->generalTokenStorage->getToken(), + ); - if ($body === null || isset($body['error_description']) || isset($body['error'])) { + $body = json_decode($response['body'],true); + + if ($body === null || !$body['success'] || empty($body['data'])) { throw new CdekApiException('[CDEKDelivery] Failed to get shop token', 'cdek_error.shop_token.auth', $body, true); } - return $body['token']; + return ['tokens' => $body['data']]; } public function taskManager($data = null) @@ -98,14 +97,19 @@ public function sendTaskData($taskId, $data) $this->tokenCoreStorage->getToken(), $data); } - public function addHeaders(array $addHeaders): void + public function addPageHeaders(int $totalPages, int $currentPage) { - $this->coreClient->addHeaders($addHeaders); + $this->coreClient->addHeaders( + [ + 'X-Total-Pages' => $totalPages, + 'X-Current-Page' => $currentPage + ] + ); } private function getShopApiUrl() { - return $this->apiUrl . $this->tokenCoreStorage->getPath(); + return $this->tokenCoreStorage->getPath(); } private function getApiUrl(): string diff --git a/src/Config.php b/src/Config.php index 5ba6c1a..f70a58f 100644 --- a/src/Config.php +++ b/src/Config.php @@ -10,14 +10,12 @@ class Config { public const DELIVERY_NAME = 'official_cdek'; - public const TASK_PREFIX = 'cdek'; public const META_KEY = 'order_data'; public const ORDER_META_BOX_KEY = 'official_cdek_order'; public const ORDER_AUTOMATION_HOOK_NAME = 'cdekdelivery_automation'; public const TASK_MANAGER_HOOK_NAME = 'cdekdelivery_task_manager'; public const API_CORE_URL = 'https://api.cdek.ru/'; public const API_VERSION = 'v2/'; - public const CMS_VERSION = 'wordpress/'; public const API_URL = 'https://api.cdek.ru/' . self::API_VERSION; public const TEST_API_URL = 'https://api.edu.cdek.ru/' . self::API_VERSION; public const TEST_CLIENT_ID = 'EMscd6r9JnFiQ3bLoyjJY6eM78JrJceI'; diff --git a/src/Contracts/TaskContract.php b/src/Contracts/TaskContract.php index 5d372e2..8584ad6 100644 --- a/src/Contracts/TaskContract.php +++ b/src/Contracts/TaskContract.php @@ -8,8 +8,11 @@ abstract class TaskContract { + protected cdekCoreApi $cdekCoreApi; + public function __construct(string $taskId) { + $this->cdekCoreApi = new CdekCoreApi(); $this->taskId = $taskId; } protected static array $errorCollection = []; @@ -19,7 +22,7 @@ public function __construct(string $taskId) protected string $taskId; abstract protected static function getName(): string; - abstract public static function init(); + abstract public static function init($taskId); public static function registerAction(): void { @@ -46,42 +49,29 @@ protected function getTaskCursor(): array return self::$responseCursor[$this->taskId]['meta']; } - protected function addPageHeaders(int $totalPages, int $currentPage) - { - $this->headers = [ - 'X-Total-Pages' => $totalPages, - 'X-Current-Page' => $currentPage - ]; - } protected function initTaskData($data = null): void { - $cdekCoreApi = new CdekCoreApi(); - - $this->initData($cdekCoreApi->taskInfo($this->taskId, $data)); + $this->initData($this->cdekCoreApi->taskInfo($this->taskId, $data)); } protected function sendTaskData($data) { - $cdekCoreApi = new CdekCoreApi(); - - $cdekCoreApi->addHeaders($data); - - $this->initData($cdekCoreApi->sendTaskData($this->taskId, $data)); + $this->initData($this->cdekCoreApi->sendTaskData($this->taskId, $data)); } private function initData($response) { - $decodeResponse = json_decode($response, true); + $decodeResponse = json_decode($response['body'], true); if( - $decodeResponse['error'] + empty($decodeResponse['success']) ){ - self::$errorCollection[$this->taskId][] = $decodeResponse['error']; + self::$errorCollection[$this->taskId][] = __('Request to api was failed', 'cdekdelivery'); } if(empty($response['cursor'])){ - self::$errorCollection[$this->taskId][] = 'Cursor data not found'; + self::$errorCollection[$this->taskId][] = __('Cursor data not found', 'cdekdelivery'); } if(empty(self::$errorCollection)){ diff --git a/src/Helpers/DBCoreTokenStorage.php b/src/Helpers/DBCoreTokenStorage.php index 53208cc..05e7b1d 100644 --- a/src/Helpers/DBCoreTokenStorage.php +++ b/src/Helpers/DBCoreTokenStorage.php @@ -10,8 +10,10 @@ class DBCoreTokenStorage extends TokenStorageContract { + private static string $tokenAdmin = ''; private static string $tokenStatic = ''; - private static string $apiUrlString = ''; + private static string $tokenFrontend = ''; + private static string $apiUrlString; final public function getToken(): string { @@ -34,11 +36,19 @@ public function getPath() return static::$apiUrlString; } + $cache = (new FileCache(FileCache::CACHE_FILE_NAME))->getVars(); + + if (!empty($cache['end_point'])) { + return static::$apiUrlString = $cache['end_point']; + } + $token = $this->getToken(); $arToken = explode('.', $token); - return json_decode(base64_decode($arToken[count($arToken) - 1]))['token']; + $token = json_decode(base64_decode($arToken[count($arToken) - 1]), true); + + return static::$apiUrlString = $token['endpoint']; } private function getTokenFromCache(): ?string @@ -50,34 +60,36 @@ private function getTokenFromSettings(): ?string { $cache = (new FileCache(FileCache::CACHE_FILE_NAME))->getVars(); - if (empty($cache['token'])) { + if (empty($cache['tokens'])) { return null; } - $decryptToken = $cache['token']; - self::$tokenStatic = $decryptToken; - return $decryptToken; + self::$tokenAdmin = $cache['tokens']['admin']; + self::$tokenStatic = $cache['tokens']['common']; + self::$tokenFrontend = $cache['tokens']['frontend']; + return self::$tokenStatic; } final public function updateToken(): string { $tokenApi = $this->fetchTokenFromApi(); + self::$tokenAdmin = $tokenApi['tokens']['admin']; + self::$tokenStatic = $tokenApi['tokens']['common']; + self::$tokenFrontend = $tokenApi['tokens']['frontend']; + + $tokenApi['end_point'] = $this->getPath(); + $cache = new FileCache(FileCache::CACHE_FILE_NAME); - $cache->putVars( - [ - 'token' => $tokenApi, - ], - ); - - self::$tokenStatic = $tokenApi; - return $tokenApi; + $cache->putVars($tokenApi); + + return self::$tokenStatic; } /** * @throws CdekApiException */ - final public function fetchTokenFromApi(): string + final public function fetchTokenFromApi(): array { return (new CdekCoreApi)->fetchShopToken(); } diff --git a/src/Loader.php b/src/Loader.php index c7534c1..1bd136e 100644 --- a/src/Loader.php +++ b/src/Loader.php @@ -77,7 +77,7 @@ public static function getPluginFile(): string */ public static function activate(): void { - if (!current_user_can('activate_plugins')) { + if (!current_user_can('activate_plugins') || as_has_scheduled_action(Config::TASK_MANAGER_HOOK_NAME) === false) { return; } @@ -89,7 +89,7 @@ public static function activate(): void DAY_IN_SECONDS, Config::TASK_MANAGER_HOOK_NAME, [], - '', + 'cdek', true, ); } diff --git a/src/Managers/TaskManager.php b/src/Managers/TaskManager.php index 49fc0dd..ef1e134 100644 --- a/src/Managers/TaskManager.php +++ b/src/Managers/TaskManager.php @@ -19,16 +19,16 @@ class TaskManager extends TaskContract private array $taskCollection; - public function __construct() + public function __construct($taskId) { - parent::__construct('task_manager'); + parent::__construct($taskId); $this->getResponse(); $this->initTasks(); } - public static function init(): void + public static function init($taskId = 'task_manager'): void { - $taskManager = new self(); + $taskManager = new self($taskId); $taskManager->startTasksWork(); } @@ -58,8 +58,8 @@ public function getErrors(): array public static function registerTasks(): void { foreach (self::TASK_CLASSES as $arTaskClass) { - if ($arTaskClass instanceof TaskContract) { - $arTaskClass::registerAction(); + if ('\\' . $arTaskClass instanceof TaskContract) { + '\\' . $arTaskClass::registerAction(); } } } @@ -67,7 +67,7 @@ public static function registerTasks(): void public static function getTasksHooks() { return array_map( - static fn(TaskContract $class) => $class::getName() === static::getName() ? + static fn($class) => $class::getName() === static::getName() ? static::getName() : sprintf('%s-%s', Config::TASK_MANAGER_HOOK_NAME, @@ -82,7 +82,7 @@ private function startTask(TaskData $task): void if (!in_array( $task->getName(), array_map( - static fn(TaskContract $class) => $class::getName(), + static fn($class) => $class::getName(), self::TASK_CLASSES, ), ) @@ -96,7 +96,7 @@ private function startTask(TaskData $task): void private function getResponse(): void { $response = (new CdekCoreApi())->taskManager(); - $decodeResponse = json_decode($response, true); + $decodeResponse = json_decode($response['body'], true); if ( $decodeResponse['error'] @@ -104,13 +104,13 @@ private function getResponse(): void self::$errorCollection[$this->taskId][] = $decodeResponse['error']; } - if (empty($response['cursor'])) { + if (empty($decodeResponse['cursor'])) { self::$errorCollection[$this->taskId][] = 'Cursor data not found'; } if (empty($this->errorCollection)) { - self::$taskData[$this->taskId] = $response['data']; - self::$responseCursor[$this->taskId] = $response['cursor']; + self::$taskData[$this->taskId] = $decodeResponse['data']; + self::$responseCursor[$this->taskId] = $decodeResponse['cursor']; } } diff --git a/src/Model/TaskData.php b/src/Model/TaskData.php index 000133b..f554b06 100644 --- a/src/Model/TaskData.php +++ b/src/Model/TaskData.php @@ -29,17 +29,16 @@ public function createTaskWork() as_schedule_cron_action( $this->time, $this->getSchedule(), - Config::DELIVERY_NAME . '_' . Config::TASK_PREFIX . '_' . $this->getName(), - ['task_id' => $this->getId()], + sprintf('%s-%s', Config::TASK_MANAGER_HOOK_NAME, static::getName()), + [$this->getId()], '', true, ); } } else { as_enqueue_async_action( - $this->time, - Config::DELIVERY_NAME . '_' . Config::TASK_PREFIX . '_' . $this->getName(), - ['task_id' => $this->getId()], + sprintf('%s-%s', Config::TASK_MANAGER_HOOK_NAME, static::getName()), + [$this->getId()] ); } } diff --git a/src/Transport/HttpCoreClient.php b/src/Transport/HttpCoreClient.php index 0b5c328..368f6e4 100644 --- a/src/Transport/HttpCoreClient.php +++ b/src/Transport/HttpCoreClient.php @@ -17,7 +17,7 @@ class HttpCoreClient public function addHeaders(array $addHeaders) { - $this->addHeaders = $addHeaders; + $this->addHeaders = $this->addHeaders + $addHeaders; } public function sendCdekRequest( @@ -29,9 +29,8 @@ public function sendCdekRequest( { $config = [ 'headers' => [ - 'Authorization' => $token, + 'Authorization' => $token, ], - 'timeout' => 60, ]; @@ -49,18 +48,18 @@ public function sendRequest(string $url, string $method, array $config = []) array_merge( $config, [ - 'method' => $method, - 'Content-Type' => 'application/json', + 'method' => $method, 'headers' => [ + 'Content-Type' => 'application/json', 'X-App-Name' => 'wordpress', 'X-App-Version' => Loader::getPluginVersion(), 'X-User-Locale' => get_user_locale(), 'X-Correlation-Id' => self::generateUuid(), - 'user-agent' => Loader::getPluginName() . '_' . get_bloginfo('version'), - ] + $this->addHeaders, + 'user-agent' => 'wp/' . get_bloginfo('version'), + ] + $this->addHeaders + $config['headers'] ?? [], 'timeout' => 60, ], - ) + ), ); if (is_array($resp)) { From baecdb7463c09808bb8c11d3635e2daf77e22410 Mon Sep 17 00:00:00 2001 From: Stas Demin Date: Thu, 6 Jun 2024 15:14:03 +0300 Subject: [PATCH 18/50] fix: remove check event on activate hook --- src/Loader.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Loader.php b/src/Loader.php index 1bd136e..13ab3a0 100644 --- a/src/Loader.php +++ b/src/Loader.php @@ -77,7 +77,7 @@ public static function getPluginFile(): string */ public static function activate(): void { - if (!current_user_can('activate_plugins') || as_has_scheduled_action(Config::TASK_MANAGER_HOOK_NAME) === false) { + if (!current_user_can('activate_plugins')) { return; } From 2c876384ad974f8639c3f417059f83043d625db6 Mon Sep 17 00:00:00 2001 From: Stas Demin Date: Thu, 6 Jun 2024 16:13:30 +0300 Subject: [PATCH 19/50] fix: change headers fixed --- src/Actions/Schedule/CollectOrders.php | 2 +- src/Loader.php | 28 ++++++++++++++++---------- src/Transport/HttpCoreClient.php | 2 +- 3 files changed, 19 insertions(+), 13 deletions(-) diff --git a/src/Actions/Schedule/CollectOrders.php b/src/Actions/Schedule/CollectOrders.php index 79cbbf2..83ece20 100644 --- a/src/Actions/Schedule/CollectOrders.php +++ b/src/Actions/Schedule/CollectOrders.php @@ -8,7 +8,7 @@ class CollectOrders extends TaskContract { - const ORDERS_LIMIT = 2; + const ORDERS_LIMIT = 10000; private Validate $error; public function __construct($taskId) diff --git a/src/Loader.php b/src/Loader.php index 13ab3a0..61fcd3d 100644 --- a/src/Loader.php +++ b/src/Loader.php @@ -82,17 +82,7 @@ public static function activate(): void } self::checkRequirements(); - - if (as_has_scheduled_action(Config::TASK_MANAGER_HOOK_NAME) === false) { - as_schedule_cron_action( - time(), - DAY_IN_SECONDS, - Config::TASK_MANAGER_HOOK_NAME, - [], - 'cdek', - true, - ); - } + self::addPluginScheduleEvents(); } /** @@ -186,6 +176,8 @@ public function __invoke(string $pluginMainFile): void add_action('woocommerce_before_order_itemmeta', new AdminShippingFields, 10, 2); + add_action('upgrader_process_complete', self::addPluginScheduleEvents()); + add_action(Config::ORDER_AUTOMATION_HOOK_NAME, new CreateOrderAction, 10, 2); TaskManager::registerTasks(); @@ -197,6 +189,20 @@ public function __invoke(string $pluginMainFile): void (new AdminNotices)(); } + private static function addPluginScheduleEvents() + { + if (as_has_scheduled_action(Config::TASK_MANAGER_HOOK_NAME) === false) { + as_schedule_cron_action( + time(), + DAY_IN_SECONDS, + Config::TASK_MANAGER_HOOK_NAME, + [], + '', + true, + ); + } + } + private static function declareCompatibility(): void { add_action('before_woocommerce_init', static function () { diff --git a/src/Transport/HttpCoreClient.php b/src/Transport/HttpCoreClient.php index 368f6e4..d91f4d9 100644 --- a/src/Transport/HttpCoreClient.php +++ b/src/Transport/HttpCoreClient.php @@ -17,7 +17,7 @@ class HttpCoreClient public function addHeaders(array $addHeaders) { - $this->addHeaders = $this->addHeaders + $addHeaders; + $this->addHeaders = $addHeaders + $this->addHeaders; } public function sendCdekRequest( From f497c68b40b0437bf533204646e3c8091de58615 Mon Sep 17 00:00:00 2001 From: Stas Demin Date: Thu, 6 Jun 2024 16:54:40 +0300 Subject: [PATCH 20/50] feat: work with statuses --- src/Actions/Schedule/ReindexOrders.php | 3 +-- src/Contracts/TaskContract.php | 32 +++++++++++++++++++++++++- 2 files changed, 32 insertions(+), 3 deletions(-) diff --git a/src/Actions/Schedule/ReindexOrders.php b/src/Actions/Schedule/ReindexOrders.php index be4054c..23779f7 100644 --- a/src/Actions/Schedule/ReindexOrders.php +++ b/src/Actions/Schedule/ReindexOrders.php @@ -16,7 +16,6 @@ class ReindexOrders extends TaskContract { - const ORDERS_LIMIT = 10000; private array $orders; private Validate $error; @@ -72,7 +71,7 @@ protected function initOrders() 'order' => 'ASC', 'return' => 'ids', 'post__in' => array_column($this->getTaskMeta(), 'external_id'), - ] + ], ); foreach ($query->get_orders()->orders as $orderId) { diff --git a/src/Contracts/TaskContract.php b/src/Contracts/TaskContract.php index 8584ad6..90d58bb 100644 --- a/src/Contracts/TaskContract.php +++ b/src/Contracts/TaskContract.php @@ -4,10 +4,15 @@ use Cdek\CdekCoreApi; use Cdek\Config; +use Cdek\Exceptions\CdekApiException; use Cdek\Model\TaskData; abstract class TaskContract { + const FINISH_STATUS = 201; + const RESTART_STATUS = 202; + const UNKNOWN_METHOD = 404; + const FATAL_ERRORS = [500, 502, 503]; protected cdekCoreApi $cdekCoreApi; public function __construct(string $taskId) @@ -18,8 +23,8 @@ public function __construct(string $taskId) protected static array $errorCollection = []; protected static array $taskData = []; protected static array $responseCursor = []; - protected array $headers = []; protected string $taskId; + protected int $status; abstract protected static function getName(): string; abstract public static function init($taskId); @@ -62,6 +67,27 @@ protected function sendTaskData($data) private function initData($response) { + $this->status = $response['status']; + + if( + !in_array( + $this->status, + [self::FINISH_STATUS, self::RESTART_STATUS], + ) + ){ + if(in_array($this->status, self::FATAL_ERRORS)){ + $this->postponeTask(); + return; + }else{ + throw new CdekApiException('[CDEKDelivery] Failed to get core api response', + 'cdek_error.core.response', + $response, + true); + + } + + } + $decodeResponse = json_decode($response['body'], true); if( @@ -78,6 +104,10 @@ private function initData($response) self::$taskData[$this->taskId] = new TaskData(reset($response['data'])); self::$responseCursor[$this->taskId] = $response['cursor']; } + } + protected function postponeTask() + { + //todo finish that and start next one later } } From 2383a4c9cd02e20064d96a8ef7fe505be34673fd Mon Sep 17 00:00:00 2001 From: Stas Demin Date: Fri, 7 Jun 2024 12:24:13 +0300 Subject: [PATCH 21/50] fix: remove cache, unschedule events with deactivation plugin, fix activation, file check in cache --- src/Actions/Schedule/CollectOrders.php | 6 ---- src/Actions/Schedule/ReindexOrders.php | 6 ---- src/Cache/FileCache.php | 26 ++++++++++++++++- src/CdekCoreApi.php | 10 ++----- src/Contracts/TaskContract.php | 9 +++++- src/Helpers/DBCoreTokenStorage.php | 31 +++++++++++--------- src/Loader.php | 39 ++++++++++++++++++-------- src/Managers/TaskManager.php | 8 +----- src/Uninstaller.php | 7 ++--- 9 files changed, 83 insertions(+), 59 deletions(-) diff --git a/src/Actions/Schedule/CollectOrders.php b/src/Actions/Schedule/CollectOrders.php index 83ece20..74db3d2 100644 --- a/src/Actions/Schedule/CollectOrders.php +++ b/src/Actions/Schedule/CollectOrders.php @@ -21,12 +21,6 @@ public static function getName(): string return 'collect-orphaned-orders'; } - public static function init($taskId) - { - $reindexOrders = new self($taskId); - $reindexOrders->start(); - } - public function start() { $this->reportOrders(); diff --git a/src/Actions/Schedule/ReindexOrders.php b/src/Actions/Schedule/ReindexOrders.php index 23779f7..b6b7fab 100644 --- a/src/Actions/Schedule/ReindexOrders.php +++ b/src/Actions/Schedule/ReindexOrders.php @@ -30,12 +30,6 @@ public static function getName(): string return 'restore-order-uuids'; } - public static function init($taskId) - { - $reindexOrders = new static($taskId); - $reindexOrders->start(); - } - public function start() { if(empty($this->getTaskMeta())){ diff --git a/src/Cache/FileCache.php b/src/Cache/FileCache.php index 0813ef3..b78025a 100644 --- a/src/Cache/FileCache.php +++ b/src/Cache/FileCache.php @@ -2,6 +2,7 @@ namespace Cdek\Cache; +use Cdek\Exceptions\CdekApiException; use Cdek\Loader; class FileCache @@ -10,7 +11,7 @@ class FileCache private static array $store; private string $file; - public function __construct($fileName) + public function __construct($fileName = self::CACHE_FILE_NAME) { $this->file = $fileName; } @@ -30,10 +31,33 @@ public function putVars($vars) return; } + if(!is_writable(Loader::getPluginPath())){ + throw new CdekApiException('[CDEKDelivery] Failed check directory rights', + 'cdek_error.cache.rights', + ['path' => Loader::getPluginPath()], + true); + } + + $arPath = explode(DIRECTORY_SEPARATOR, $this->file); + unset($arPath[count($arPath) - 1]); + + if(!is_writable(Loader::getPluginPath() . implode(DIRECTORY_SEPARATOR, $arPath))){ + throw new CdekApiException('[CDEKDelivery] Failed check directory rights', + 'cdek_error.cache.rights', + ['path' => Loader::getPluginPath() . implode(DIRECTORY_SEPARATOR, $arPath)], + true); + } + $logFile = fopen( Loader::getPluginPath() . DIRECTORY_SEPARATOR . $this->file, 'w+'); + $content = 'file); + } } diff --git a/src/CdekCoreApi.php b/src/CdekCoreApi.php index 44a28d1..4693d75 100644 --- a/src/CdekCoreApi.php +++ b/src/CdekCoreApi.php @@ -23,7 +23,6 @@ public function __construct( ?TokenStorageContract $tokenCoreStorage = null ) { - $this->apiUrl = $this->getApiUrl(); $this->coreClient = new HttpCoreClient(); $this->generalTokenStorage = $tokenStorage ?? new DBTokenStorage(); $this->tokenCoreStorage = $tokenCoreStorage ?? new DBCoreTokenStorage(); @@ -32,7 +31,7 @@ public function __construct( public function fetchShopToken() { $response = $this->coreClient->sendCdekRequest( - $this->apiUrl . self::SHOP, + Config::API_CORE_URL . self::SHOP, 'POST', $this->generalTokenStorage->getToken(), [ @@ -62,7 +61,7 @@ public function fetchShopToken() } $response = $this->coreClient->sendCdekRequest( - sprintf($this->apiUrl . self::TOKEN_PATH, $body['data']['id']), + sprintf(Config::API_CORE_URL . self::TOKEN_PATH, $body['data']['id']), 'POST', $this->generalTokenStorage->getToken(), ); @@ -111,9 +110,4 @@ private function getShopApiUrl() { return $this->tokenCoreStorage->getPath(); } - - private function getApiUrl(): string - { - return Config::API_CORE_URL; - } } diff --git a/src/Contracts/TaskContract.php b/src/Contracts/TaskContract.php index 90d58bb..46ef8fd 100644 --- a/src/Contracts/TaskContract.php +++ b/src/Contracts/TaskContract.php @@ -27,7 +27,14 @@ public function __construct(string $taskId) protected int $status; abstract protected static function getName(): string; - abstract public static function init($taskId); + + abstract function start(); + + public static function init($taskId = 'task_manager'): void + { + $taskManager = new static($taskId); + $taskManager->start(); + } public static function registerAction(): void { diff --git a/src/Helpers/DBCoreTokenStorage.php b/src/Helpers/DBCoreTokenStorage.php index 05e7b1d..8424b18 100644 --- a/src/Helpers/DBCoreTokenStorage.php +++ b/src/Helpers/DBCoreTokenStorage.php @@ -14,6 +14,8 @@ class DBCoreTokenStorage extends TokenStorageContract private static string $tokenStatic = ''; private static string $tokenFrontend = ''; private static string $apiUrlString; + private static string $frontendUrlString; + private static string $adminUrlString; final public function getToken(): string { @@ -36,19 +38,13 @@ public function getPath() return static::$apiUrlString; } - $cache = (new FileCache(FileCache::CACHE_FILE_NAME))->getVars(); + $cache = (new FileCache())->getVars(); - if (!empty($cache['end_point'])) { - return static::$apiUrlString = $cache['end_point']; + if (!empty($cache['end_point']['common'])) { + return static::$apiUrlString = $cache['end_point']['common']; } - $token = $this->getToken(); - - $arToken = explode('.', $token); - - $token = json_decode(base64_decode($arToken[count($arToken) - 1]), true); - - return static::$apiUrlString = $token['endpoint']; + return static::$apiUrlString = $this->getEndPointFromToken($this->getToken()); } private function getTokenFromCache(): ?string @@ -58,7 +54,7 @@ private function getTokenFromCache(): ?string private function getTokenFromSettings(): ?string { - $cache = (new FileCache(FileCache::CACHE_FILE_NAME))->getVars(); + $cache = (new FileCache())->getVars(); if (empty($cache['tokens'])) { return null; @@ -78,9 +74,11 @@ final public function updateToken(): string self::$tokenStatic = $tokenApi['tokens']['common']; self::$tokenFrontend = $tokenApi['tokens']['frontend']; - $tokenApi['end_point'] = $this->getPath(); + $tokenApi['end_point']['admin'] = static::$adminUrlString = $this->getEndPointFromToken(self::$tokenAdmin); + $tokenApi['end_point']['common'] = static::$apiUrlString = $this->getEndPointFromToken(self::$tokenStatic); + $tokenApi['end_point']['frontend'] = static::$frontendUrlString = $this->getEndPointFromToken(self::$tokenFrontend); - $cache = new FileCache(FileCache::CACHE_FILE_NAME); + $cache = new FileCache(); $cache->putVars($tokenApi); return self::$tokenStatic; @@ -94,4 +92,11 @@ final public function fetchTokenFromApi(): array return (new CdekCoreApi)->fetchShopToken(); } + private function getEndPointFromToken($token) + { + $arToken = explode('.', $token); + + return json_decode(base64_decode($arToken[count($arToken) - 1]), true)['endpoint']; + } + } diff --git a/src/Loader.php b/src/Loader.php index 61fcd3d..cccb872 100644 --- a/src/Loader.php +++ b/src/Loader.php @@ -15,6 +15,7 @@ use Cdek\Actions\ProcessWoocommerceCreateShippingAction; use Cdek\Actions\RecalculateShippingAction; use Cdek\Actions\SaveCustomCheckoutFieldsAction; + use Cdek\Cache\FileCache; use Cdek\Managers\TaskManager; use Cdek\Blocks\CheckoutMapBlock; use Cdek\Controllers\CourierController; @@ -85,6 +86,15 @@ public static function activate(): void self::addPluginScheduleEvents(); } + public static function deactivate() + { + foreach (TaskManager::getTasksHooks() as $hook){ + if (as_has_scheduled_action($hook) !== false) { + as_unschedule_action($hook); + } + } + } + /** * @throws RuntimeException */ @@ -119,8 +129,6 @@ public function __invoke(string $pluginMainFile): void { self::$pluginMainFilePath = $pluginMainFile; - add_action("activate_$pluginMainFile", [__CLASS__, 'activate']); - try { self::checkRequirements(); } catch (RuntimeException $e) { @@ -134,6 +142,9 @@ public function __invoke(string $pluginMainFile): void self::$pluginName = get_file_data(self::$pluginMainFilePath, ['Plugin Name'])[0]; self::$pluginMainFile = plugin_basename(self::$pluginMainFilePath); + add_action("activate_" . plugin_basename($pluginMainFile), [__CLASS__, 'activate']); + add_action("deactivate_" . plugin_basename($pluginMainFile), [__CLASS__, 'deactivate']); + self::declareCompatibility(); add_action('plugins_loaded', @@ -176,7 +187,7 @@ public function __invoke(string $pluginMainFile): void add_action('woocommerce_before_order_itemmeta', new AdminShippingFields, 10, 2); - add_action('upgrader_process_complete', self::addPluginScheduleEvents()); + add_action('upgrader_process_complete', [__CLASS__, 'addPluginScheduleEvents']); add_action(Config::ORDER_AUTOMATION_HOOK_NAME, new CreateOrderAction, 10, 2); @@ -191,16 +202,20 @@ public function __invoke(string $pluginMainFile): void private static function addPluginScheduleEvents() { - if (as_has_scheduled_action(Config::TASK_MANAGER_HOOK_NAME) === false) { - as_schedule_cron_action( - time(), - DAY_IN_SECONDS, - Config::TASK_MANAGER_HOOK_NAME, - [], - '', - true, - ); + if (as_has_scheduled_action(Config::TASK_MANAGER_HOOK_NAME) !== false) { + as_unschedule_action(Config::TASK_MANAGER_HOOK_NAME); } + + $dateTime = new \DateTime('now + 1 hour'); + + as_schedule_cron_action( + time(), + $dateTime->format('i') . ' ' . $dateTime->format('H') . ' * * *', + Config::TASK_MANAGER_HOOK_NAME, + [], + '', + true, + ); } private static function declareCompatibility(): void diff --git a/src/Managers/TaskManager.php b/src/Managers/TaskManager.php index ef1e134..428bf0e 100644 --- a/src/Managers/TaskManager.php +++ b/src/Managers/TaskManager.php @@ -26,13 +26,7 @@ public function __construct($taskId) $this->initTasks(); } - public static function init($taskId = 'task_manager'): void - { - $taskManager = new self($taskId); - $taskManager->startTasksWork(); - } - - public function startTasksWork(): void + public function start(): void { foreach ($this->taskCollection as $task) { $this->startTask($task); diff --git a/src/Uninstaller.php b/src/Uninstaller.php index 48637b1..c96c6c2 100644 --- a/src/Uninstaller.php +++ b/src/Uninstaller.php @@ -2,16 +2,13 @@ namespace Cdek; +use Cdek\Cache\FileCache; use Cdek\Managers\TaskManager; class Uninstaller { public function __invoke() { - foreach (TaskManager::getTasksHooks() as $hook){ - if (as_has_scheduled_action($hook) !== false) { - as_unschedule_action($hook); - } - } + (new FileCache())->clear(); } } From ff4d14905c7631ab9e3fe2e84f8c5203b080dcd7 Mon Sep 17 00:00:00 2001 From: Stas Demin Date: Fri, 7 Jun 2024 12:59:02 +0300 Subject: [PATCH 22/50] fix: change send headers logic --- src/Actions/Schedule/CollectOrders.php | 6 ++-- src/CdekCoreApi.php | 22 +++++------- src/Contracts/TaskContract.php | 4 +-- src/Transport/HttpCoreClient.php | 48 ++++++++++---------------- 4 files changed, 32 insertions(+), 48 deletions(-) diff --git a/src/Actions/Schedule/CollectOrders.php b/src/Actions/Schedule/CollectOrders.php index 74db3d2..c2a856c 100644 --- a/src/Actions/Schedule/CollectOrders.php +++ b/src/Actions/Schedule/CollectOrders.php @@ -44,8 +44,6 @@ protected function reportOrders() $maxPages = $result->max_num_pages; - $this->cdekCoreApi->addPageHeaders($maxPages, $page); - $this->sendTaskData( [ 'status' => 'success', @@ -55,6 +53,10 @@ protected function reportOrders() $result->orders ) ] + ], + [ + 'X-Total-Pages' => $maxPages, + 'X-Current-Page' => $page ] ); } diff --git a/src/CdekCoreApi.php b/src/CdekCoreApi.php index 4693d75..387eced 100644 --- a/src/CdekCoreApi.php +++ b/src/CdekCoreApi.php @@ -13,7 +13,6 @@ class CdekCoreApi private const TOKEN_PATH = 'cms/wordpress/shops/%s/token'; private const SHOP = 'cms/wordpress/shops'; private const TASKS = 'wordpress/tasks'; - private string $apiUrl; private TokenStorageContract $generalTokenStorage; private TokenStorageContract $tokenCoreStorage; private HttpCoreClient $coreClient; @@ -84,25 +83,20 @@ public function taskManager($data = null) $this->tokenCoreStorage->getToken(), $data); } - public function taskInfo($taskId, $data = null) + public function taskInfo($taskId, $data = null, $headers = []) { return $this->coreClient->sendCdekRequest($this->getShopApiUrl() . '/' . self::TASKS . '/' . $taskId, 'GET', $this->tokenCoreStorage->getToken(), $data); } - public function sendTaskData($taskId, $data) + public function sendTaskData($taskId, $data, $headers = []) { - return $this->coreClient->sendCdekRequest($this->getShopApiUrl() . '/' . self::TASKS . '/' . $taskId, 'PUT', - $this->tokenCoreStorage->getToken(), $data); - } - - public function addPageHeaders(int $totalPages, int $currentPage) - { - $this->coreClient->addHeaders( - [ - 'X-Total-Pages' => $totalPages, - 'X-Current-Page' => $currentPage - ] + return $this->coreClient->sendCdekRequest( + $this->getShopApiUrl() . '/' . self::TASKS . '/' . $taskId, + 'PUT', + $this->tokenCoreStorage->getToken(), + $data, + $headers ); } diff --git a/src/Contracts/TaskContract.php b/src/Contracts/TaskContract.php index 46ef8fd..36a952e 100644 --- a/src/Contracts/TaskContract.php +++ b/src/Contracts/TaskContract.php @@ -67,9 +67,9 @@ protected function initTaskData($data = null): void $this->initData($this->cdekCoreApi->taskInfo($this->taskId, $data)); } - protected function sendTaskData($data) + protected function sendTaskData($data, $headers = []) { - $this->initData($this->cdekCoreApi->sendTaskData($this->taskId, $data)); + $this->initData($this->cdekCoreApi->sendTaskData($this->taskId, $data, $headers)); } private function initData($response) diff --git a/src/Transport/HttpCoreClient.php b/src/Transport/HttpCoreClient.php index d91f4d9..ecc8f10 100644 --- a/src/Transport/HttpCoreClient.php +++ b/src/Transport/HttpCoreClient.php @@ -13,53 +13,41 @@ class HttpCoreClient { - private array $addHeaders = []; - - public function addHeaders(array $addHeaders) - { - $this->addHeaders = $addHeaders + $this->addHeaders; - } - public function sendCdekRequest( string $url, string $method, string $token, - array $data = null + array $data = null, + array $headers = [] ) { - $config = [ - 'headers' => [ - 'Authorization' => $token, - ], - ]; + $config = []; + $headers['Authorization'] = $token; if (!empty($data)) { $config['body'] = ($method === WP_REST_Server::READABLE) ? $data : json_encode($data); } - return static::sendRequest($url, $method, $config); + return self::sendRequest($url, $method, $config, $headers); } - public function sendRequest(string $url, string $method, array $config = []) + public function sendRequest(string $url, string $method, array $config = [], array $headers = []) { $resp = wp_remote_request( $url, - array_merge( - $config, - [ - 'method' => $method, - 'headers' => [ - 'Content-Type' => 'application/json', - 'X-App-Name' => 'wordpress', - 'X-App-Version' => Loader::getPluginVersion(), - 'X-User-Locale' => get_user_locale(), - 'X-Correlation-Id' => self::generateUuid(), - 'user-agent' => 'wp/' . get_bloginfo('version'), - ] + $this->addHeaders + $config['headers'] ?? [], - 'timeout' => 60, - ], - ), + [ + 'method' => $method, + 'headers' => [ + 'Content-Type' => 'application/json', + 'X-App-Name' => 'wordpress', + 'X-App-Version' => Loader::getPluginVersion(), + 'X-User-Locale' => get_user_locale(), + 'X-Correlation-Id' => self::generateUuid(), + 'user-agent' => 'wp/' . get_bloginfo('version'), + ] + $headers, + 'timeout' => 60, + ] + $config, ); if (is_array($resp)) { From 9ff066bfa535871ad750f07eb671f9bc379fe4cd Mon Sep 17 00:00:00 2001 From: Stas Demin Date: Fri, 7 Jun 2024 13:48:17 +0300 Subject: [PATCH 23/50] fix: postpone task for server fatal errors answer --- src/Contracts/TaskContract.php | 23 +++++++++++++++++++++-- 1 file changed, 21 insertions(+), 2 deletions(-) diff --git a/src/Contracts/TaskContract.php b/src/Contracts/TaskContract.php index 36a952e..02b607b 100644 --- a/src/Contracts/TaskContract.php +++ b/src/Contracts/TaskContract.php @@ -92,7 +92,6 @@ private function initData($response) true); } - } $decodeResponse = json_decode($response['body'], true); @@ -115,6 +114,26 @@ private function initData($response) protected function postponeTask() { - //todo finish that and start next one later + $hooks = as_get_scheduled_actions( + [ + 'hook' => sprintf('%s-%s', Config::TASK_MANAGER_HOOK_NAME, static::getName()), + 'status' => \ActionScheduler_Store::STATUS_PENDING + ] + ); + + if(empty($hooks)){ + return; + } + + $hook = reset($hooks); + + if(!$hook->get_schedule() instanceof \ActionScheduler_CronSchedule){ + (new TaskData( + [ + 'id' => $this->taskId, + 'name' => sprintf('%s-%s', Config::TASK_MANAGER_HOOK_NAME, static::getName()) + ] + ))->createTaskWork(); + } } } From 5f6b0b75519e7fa9f8f3b2cf5845166aefa67fdf Mon Sep 17 00:00:00 2001 From: Stas Demin Date: Mon, 10 Jun 2024 09:31:31 +0300 Subject: [PATCH 24/50] feat: change exception to rest for schedule events --- src/CdekCoreApi.php | 8 ++++---- src/Contracts/TaskContract.php | 4 ++-- src/Exceptions/CdekCoreApiException.php | 7 +++++++ src/Exceptions/CdekException.php | 3 ++- src/Loader.php | 1 - 5 files changed, 15 insertions(+), 8 deletions(-) create mode 100644 src/Exceptions/CdekCoreApiException.php diff --git a/src/CdekCoreApi.php b/src/CdekCoreApi.php index 387eced..419f26c 100644 --- a/src/CdekCoreApi.php +++ b/src/CdekCoreApi.php @@ -2,7 +2,7 @@ namespace Cdek; use Cdek\Contracts\TokenStorageContract; -use Cdek\Exceptions\CdekApiException; +use Cdek\Exceptions\CdekCoreApiException; use Cdek\Helpers\DBCoreTokenStorage; use Cdek\Helpers\DBTokenStorage; use Cdek\Transport\HttpCoreClient; @@ -44,7 +44,7 @@ public function fetchShopToken() ); if(empty($response['body'])){ - throw new CdekApiException('[CDEKDelivery] Failed to get shop uuid', + throw new CdekCoreApiException('[CDEKDelivery] Failed to get shop uuid', 'cdek_error.uuid.auth', $response, true); @@ -53,7 +53,7 @@ public function fetchShopToken() $body = json_decode($response['body'], true); if(empty($body) || empty($body['data']['id'])){ - throw new CdekApiException('[CDEKDelivery] Failed to get shop uuid', + throw new CdekCoreApiException('[CDEKDelivery] Failed to get shop uuid', 'cdek_error.uuid.auth', $response, true); @@ -68,7 +68,7 @@ public function fetchShopToken() $body = json_decode($response['body'],true); if ($body === null || !$body['success'] || empty($body['data'])) { - throw new CdekApiException('[CDEKDelivery] Failed to get shop token', + throw new CdekCoreApiException('[CDEKDelivery] Failed to get shop token', 'cdek_error.shop_token.auth', $body, true); diff --git a/src/Contracts/TaskContract.php b/src/Contracts/TaskContract.php index 02b607b..da2af88 100644 --- a/src/Contracts/TaskContract.php +++ b/src/Contracts/TaskContract.php @@ -4,7 +4,7 @@ use Cdek\CdekCoreApi; use Cdek\Config; -use Cdek\Exceptions\CdekApiException; +use Cdek\Exceptions\CdekCoreApiException; use Cdek\Model\TaskData; abstract class TaskContract @@ -86,7 +86,7 @@ private function initData($response) $this->postponeTask(); return; }else{ - throw new CdekApiException('[CDEKDelivery] Failed to get core api response', + throw new CdekCoreApiException('[CDEKDelivery] Failed to get core api response', 'cdek_error.core.response', $response, true); diff --git a/src/Exceptions/CdekCoreApiException.php b/src/Exceptions/CdekCoreApiException.php new file mode 100644 index 0000000..810ea50 --- /dev/null +++ b/src/Exceptions/CdekCoreApiException.php @@ -0,0 +1,7 @@ +data = $data ?? []; $this->message = $message; - if ($stopPropagation && defined('REST_REQUEST')) { + if ($stopPropagation && (defined('REST_REQUEST') || $this->isSchedule)) { wp_die($this->getWpError()); } diff --git a/src/Loader.php b/src/Loader.php index cccb872..1cc94ff 100644 --- a/src/Loader.php +++ b/src/Loader.php @@ -15,7 +15,6 @@ use Cdek\Actions\ProcessWoocommerceCreateShippingAction; use Cdek\Actions\RecalculateShippingAction; use Cdek\Actions\SaveCustomCheckoutFieldsAction; - use Cdek\Cache\FileCache; use Cdek\Managers\TaskManager; use Cdek\Blocks\CheckoutMapBlock; use Cdek\Controllers\CourierController; From 18df8e4af9c6932a46cdb3935afacba5c4182d49 Mon Sep 17 00:00:00 2001 From: Stas Demin Date: Mon, 10 Jun 2024 15:03:01 +0300 Subject: [PATCH 25/50] fix: methods witch work with update uuids from core api --- src/Actions/Schedule/CollectOrders.php | 1 + src/Actions/Schedule/ReindexOrders.php | 20 +++++------ src/CdekCoreApi.php | 24 ++++++------- src/Contracts/TaskContract.php | 47 ++++++++++++-------------- src/Managers/TaskManager.php | 4 +++ 5 files changed, 49 insertions(+), 47 deletions(-) diff --git a/src/Actions/Schedule/CollectOrders.php b/src/Actions/Schedule/CollectOrders.php index c2a856c..84076f4 100644 --- a/src/Actions/Schedule/CollectOrders.php +++ b/src/Actions/Schedule/CollectOrders.php @@ -2,6 +2,7 @@ namespace Cdek\Actions\Schedule; +use Cdek\Cache\FileCache; use Cdek\CdekCoreApi; use Cdek\Contracts\TaskContract; use Cdek\Model\Validate; diff --git a/src/Actions/Schedule/ReindexOrders.php b/src/Actions/Schedule/ReindexOrders.php index b6b7fab..9f281a0 100644 --- a/src/Actions/Schedule/ReindexOrders.php +++ b/src/Actions/Schedule/ReindexOrders.php @@ -8,15 +8,13 @@ namespace Cdek\Actions\Schedule { - use Cdek\CdekCoreApi; - use Cdek\CdekShippingMethod; use Cdek\Contracts\TaskContract; use Cdek\Model\OrderMetaData; use Cdek\Model\Validate; class ReindexOrders extends TaskContract { - private array $orders; + private array $orders = []; private Validate $error; public function __construct(string $taskId) @@ -41,20 +39,22 @@ public function start() foreach ($this->orders as $orderId){ $orderIndex = array_search($orderId, array_column($this->getTaskMeta(), 'external_id')); - if(empty($orderIndex)){ - continue; - } - $responseOrder = $this->getTaskMeta()[$orderIndex]; OrderMetaData::updateMetaByOrderId( $orderId, [ - 'order_number' => $responseOrder['order_number'], - 'order_uuid' => $responseOrder['order_uuid'], + 'order_number' => $responseOrder['external_id'], + 'order_uuid' => $responseOrder['id'], ], ); } + + $this->sendTaskData( + [ + 'status' => 'success', + ] + ); } protected function initOrders() @@ -68,7 +68,7 @@ protected function initOrders() ], ); - foreach ($query->get_orders()->orders as $orderId) { + foreach ($query->get_orders() as $orderId) { $this->orders[] = $orderId; } } diff --git a/src/CdekCoreApi.php b/src/CdekCoreApi.php index 419f26c..666dd2d 100644 --- a/src/CdekCoreApi.php +++ b/src/CdekCoreApi.php @@ -1,12 +1,12 @@ coreClient->sendCdekRequest( @@ -69,9 +69,9 @@ public function fetchShopToken() if ($body === null || !$body['success'] || empty($body['data'])) { throw new CdekCoreApiException('[CDEKDelivery] Failed to get shop token', - 'cdek_error.shop_token.auth', - $body, - true); + 'cdek_error.shop_token.auth', + $body, + true); } return ['tokens' => $body['data']]; @@ -80,13 +80,13 @@ public function fetchShopToken() public function taskManager($data = null) { return $this->coreClient->sendCdekRequest($this->getShopApiUrl() . '/' . self::TASKS, 'GET', - $this->tokenCoreStorage->getToken(), $data); + $this->tokenCoreStorage->getToken(), $data); } public function taskInfo($taskId, $data = null, $headers = []) { return $this->coreClient->sendCdekRequest($this->getShopApiUrl() . '/' . self::TASKS . '/' . $taskId, 'GET', - $this->tokenCoreStorage->getToken(), $data); + $this->tokenCoreStorage->getToken(), $data, $headers); } public function sendTaskData($taskId, $data, $headers = []) diff --git a/src/Contracts/TaskContract.php b/src/Contracts/TaskContract.php index da2af88..42a8db5 100644 --- a/src/Contracts/TaskContract.php +++ b/src/Contracts/TaskContract.php @@ -9,22 +9,23 @@ abstract class TaskContract { + const SUCCESS_STATUS = 200; const FINISH_STATUS = 201; const RESTART_STATUS = 202; const UNKNOWN_METHOD = 404; const FATAL_ERRORS = [500, 502, 503]; protected cdekCoreApi $cdekCoreApi; + protected static array $errorCollection = []; + protected static array $taskData = []; + protected static array $responseCursor = []; + protected string $taskId; + protected ?int $status; public function __construct(string $taskId) { $this->cdekCoreApi = new CdekCoreApi(); $this->taskId = $taskId; } - protected static array $errorCollection = []; - protected static array $taskData = []; - protected static array $responseCursor = []; - protected string $taskId; - protected int $status; abstract protected static function getName(): string; @@ -48,67 +49,63 @@ public static function registerAction(): void protected function getTaskMeta(): array { if(empty(self::$taskData[$this->taskId])){ - $this->initTaskData($this->taskId); + $this->initTaskData(); } - return self::$taskData[$this->taskId]['meta']; + return self::$taskData[$this->taskId]['meta'] ?? []; } protected function getTaskCursor(): array { if(empty(self::$responseCursor[$this->taskId])){ - $this->initTaskData($this->taskId); + $this->initTaskData(); } return self::$responseCursor[$this->taskId]['meta']; } - protected function initTaskData($data = null): void + protected function initTaskData(array $data = null): void { $this->initData($this->cdekCoreApi->taskInfo($this->taskId, $data)); } - protected function sendTaskData($data, $headers = []) + protected function sendTaskData(array $data, $headers = []) { $this->initData($this->cdekCoreApi->sendTaskData($this->taskId, $data, $headers)); } private function initData($response) { - $this->status = $response['status']; + $decodeResponse = json_decode($response['body'], true); + + $this->status = $decodeResponse['status']; if( !in_array( $this->status, - [self::FINISH_STATUS, self::RESTART_STATUS], + [self::FINISH_STATUS, self::RESTART_STATUS, self::SUCCESS_STATUS], ) ){ if(in_array($this->status, self::FATAL_ERRORS)){ $this->postponeTask(); return; }else{ - throw new CdekCoreApiException('[CDEKDelivery] Failed to get core api response', - 'cdek_error.core.response', - $response, - true); + throw new CdekCoreApiException('[CDEKDelivery] Failed to get core api response' . var_export($response, true), + 'cdek_error.core.response', + $response, + true); } } - $decodeResponse = json_decode($response['body'], true); - if( empty($decodeResponse['success']) ){ self::$errorCollection[$this->taskId][] = __('Request to api was failed', 'cdekdelivery'); } - if(empty($response['cursor'])){ - self::$errorCollection[$this->taskId][] = __('Cursor data not found', 'cdekdelivery'); - } - - if(empty(self::$errorCollection)){ - self::$taskData[$this->taskId] = new TaskData(reset($response['data'])); - self::$responseCursor[$this->taskId] = $response['cursor']; + if(empty(self::$errorCollection[$this->taskId])){ + self::$taskData[$this->taskId] = $decodeResponse['data']; + self::$responseCursor[$this->taskId] = $decodeResponse['cursor']; } } diff --git a/src/Managers/TaskManager.php b/src/Managers/TaskManager.php index 428bf0e..38f95b0 100644 --- a/src/Managers/TaskManager.php +++ b/src/Managers/TaskManager.php @@ -28,6 +28,10 @@ public function __construct($taskId) public function start(): void { + if(!isset($this->taskCollection)){ + return; + } + foreach ($this->taskCollection as $task) { $this->startTask($task); } From ebb2f818eea25e4f1b1a14658ff1a0b335873307 Mon Sep 17 00:00:00 2001 From: Stas Demin Date: Mon, 10 Jun 2024 15:44:51 +0300 Subject: [PATCH 26/50] fix: reschedule task manager event if case api core error --- src/CdekCoreApi.php | 41 +++++++++++++++++++++++++++--- src/Helpers/DBCoreTokenStorage.php | 17 ++++++++++++- src/Loader.php | 22 ++-------------- src/Managers/TaskManager.php | 30 +++++++++++++++++++++- 4 files changed, 85 insertions(+), 25 deletions(-) diff --git a/src/CdekCoreApi.php b/src/CdekCoreApi.php index 666dd2d..67b63ed 100644 --- a/src/CdekCoreApi.php +++ b/src/CdekCoreApi.php @@ -3,6 +3,7 @@ namespace Cdek; use Cdek\Contracts\TokenStorageContract; +use Cdek\Exceptions\CdekApiException; use Cdek\Exceptions\CdekCoreApiException; use Cdek\Helpers\DBCoreTokenStorage; use Cdek\Helpers\DBTokenStorage; @@ -27,7 +28,13 @@ public function __construct( $this->tokenCoreStorage = $tokenCoreStorage ?? new DBCoreTokenStorage(); } - public function fetchShopToken() + /** + * @return array + * @throws CdekApiException + * @throws CdekCoreApiException + * @throws \JsonException + */ + public function fetchShopToken(): array { $response = $this->coreClient->sendCdekRequest( Config::API_CORE_URL . self::SHOP, @@ -77,19 +84,47 @@ public function fetchShopToken() return ['tokens' => $body['data']]; } + /** + * @param $data + * + * @return array|false|string|\WP_Error + * @throws CdekApiException + * @throws CdekCoreApiException + * @throws \JsonException + */ public function taskManager($data = null) { return $this->coreClient->sendCdekRequest($this->getShopApiUrl() . '/' . self::TASKS, 'GET', $this->tokenCoreStorage->getToken(), $data); } - public function taskInfo($taskId, $data = null, $headers = []) + /** + * @param $taskId + * @param null $data + * @param array $headers + * + * @return array|false|string|\WP_Error + * @throws CdekApiException + * @throws CdekCoreApiException + * @throws \JsonException + */ + public function taskInfo($taskId, $data = null, array $headers = []) { return $this->coreClient->sendCdekRequest($this->getShopApiUrl() . '/' . self::TASKS . '/' . $taskId, 'GET', $this->tokenCoreStorage->getToken(), $data, $headers); } - public function sendTaskData($taskId, $data, $headers = []) + /** + * @param $taskId + * @param $data + * @param array $headers + * + * @return array|false|string|\WP_Error + * @throws CdekApiException + * @throws CdekCoreApiException + * @throws \JsonException + */ + public function sendTaskData($taskId, $data, array $headers = []) { return $this->coreClient->sendCdekRequest( $this->getShopApiUrl() . '/' . self::TASKS . '/' . $taskId, diff --git a/src/Helpers/DBCoreTokenStorage.php b/src/Helpers/DBCoreTokenStorage.php index 8424b18..f2ef943 100644 --- a/src/Helpers/DBCoreTokenStorage.php +++ b/src/Helpers/DBCoreTokenStorage.php @@ -6,7 +6,7 @@ use Cdek\CdekCoreApi; use Cdek\Contracts\TokenStorageContract; use Cdek\Exceptions\CdekApiException; -use Cdek\Helper; +use Cdek\Exceptions\CdekCoreApiException; class DBCoreTokenStorage extends TokenStorageContract { @@ -17,6 +17,12 @@ class DBCoreTokenStorage extends TokenStorageContract private static string $frontendUrlString; private static string $adminUrlString; + /** + * @return string + * @throws CdekApiException + * @throws CdekCoreApiException + * @throws \JsonException + */ final public function getToken(): string { $token = $this->getTokenFromCache(); @@ -66,6 +72,12 @@ private function getTokenFromSettings(): ?string return self::$tokenStatic; } + /** + * @return string + * @throws CdekApiException + * @throws CdekCoreApiException + * @throws \JsonException + */ final public function updateToken(): string { $tokenApi = $this->fetchTokenFromApi(); @@ -85,7 +97,10 @@ final public function updateToken(): string } /** + * @return array * @throws CdekApiException + * @throws CdekCoreApiException + * @throws \JsonException */ final public function fetchTokenFromApi(): array { diff --git a/src/Loader.php b/src/Loader.php index 1cc94ff..6b41052 100644 --- a/src/Loader.php +++ b/src/Loader.php @@ -82,7 +82,7 @@ public static function activate(): void } self::checkRequirements(); - self::addPluginScheduleEvents(); + TaskManager::addPluginScheduleEvents(); } public static function deactivate() @@ -186,7 +186,7 @@ public function __invoke(string $pluginMainFile): void add_action('woocommerce_before_order_itemmeta', new AdminShippingFields, 10, 2); - add_action('upgrader_process_complete', [__CLASS__, 'addPluginScheduleEvents']); + add_action('upgrader_process_complete', [TaskManager::class, 'addPluginScheduleEvents']); add_action(Config::ORDER_AUTOMATION_HOOK_NAME, new CreateOrderAction, 10, 2); @@ -199,24 +199,6 @@ public function __invoke(string $pluginMainFile): void (new AdminNotices)(); } - private static function addPluginScheduleEvents() - { - if (as_has_scheduled_action(Config::TASK_MANAGER_HOOK_NAME) !== false) { - as_unschedule_action(Config::TASK_MANAGER_HOOK_NAME); - } - - $dateTime = new \DateTime('now + 1 hour'); - - as_schedule_cron_action( - time(), - $dateTime->format('i') . ' ' . $dateTime->format('H') . ' * * *', - Config::TASK_MANAGER_HOOK_NAME, - [], - '', - true, - ); - } - private static function declareCompatibility(): void { add_action('before_woocommerce_init', static function () { diff --git a/src/Managers/TaskManager.php b/src/Managers/TaskManager.php index 38f95b0..fdda1c9 100644 --- a/src/Managers/TaskManager.php +++ b/src/Managers/TaskManager.php @@ -7,6 +7,8 @@ use Cdek\CdekCoreApi; use Cdek\Config; use Cdek\Contracts\TaskContract; +use Cdek\Exceptions\CdekApiException; +use Cdek\Exceptions\CdekCoreApiException; use Cdek\Model\TaskData; class TaskManager extends TaskContract @@ -75,6 +77,25 @@ public static function getTasksHooks() ); } + public static function addPluginScheduleEvents() + { + if (as_has_scheduled_action(Config::TASK_MANAGER_HOOK_NAME) !== false) { + as_unschedule_action(Config::TASK_MANAGER_HOOK_NAME); + } + + $dateTime = new \DateTime('now + 1 hour'); + + as_schedule_cron_action( + time(), + $dateTime->format('i') . ' ' . $dateTime->format('H') . ' * * *', + Config::TASK_MANAGER_HOOK_NAME, + [], + '', + true, + ); + + } + private function startTask(TaskData $task): void { if (!in_array( @@ -93,7 +114,14 @@ private function startTask(TaskData $task): void private function getResponse(): void { - $response = (new CdekCoreApi())->taskManager(); + try { + $response = (new CdekCoreApi())->taskManager(); + } catch (CdekCoreApiException $e) { + self::$errorCollection[$this->taskId][] = $e->getMessage(); + static::addPluginScheduleEvents(); + return; + } + $decodeResponse = json_decode($response['body'], true); if ( From 4a64f54852428d4b31d51e01c17f25e7d701e070 Mon Sep 17 00:00:00 2001 From: Stas Demin Date: Mon, 10 Jun 2024 15:53:16 +0300 Subject: [PATCH 27/50] fix: code style --- src/Actions/Schedule/CollectOrders.php | 12 ++++++------ src/Actions/Schedule/ReindexOrders.php | 16 ++++++++-------- 2 files changed, 14 insertions(+), 14 deletions(-) diff --git a/src/Actions/Schedule/CollectOrders.php b/src/Actions/Schedule/CollectOrders.php index 84076f4..355a7d4 100644 --- a/src/Actions/Schedule/CollectOrders.php +++ b/src/Actions/Schedule/CollectOrders.php @@ -51,14 +51,14 @@ protected function reportOrders() 'result' => [ 'orders' => array_map( static fn($order) => (string)$order, - $result->orders - ) - ] + $result->orders, + ), + ], ], [ - 'X-Total-Pages' => $maxPages, - 'X-Current-Page' => $page - ] + 'X-Total-Pages' => $maxPages, + 'X-Current-Page' => $page, + ], ); } } diff --git a/src/Actions/Schedule/ReindexOrders.php b/src/Actions/Schedule/ReindexOrders.php index 9f281a0..8fed077 100644 --- a/src/Actions/Schedule/ReindexOrders.php +++ b/src/Actions/Schedule/ReindexOrders.php @@ -30,13 +30,13 @@ public static function getName(): string public function start() { - if(empty($this->getTaskMeta())){ + if (empty($this->getTaskMeta())) { return; } $this->initOrders(); - foreach ($this->orders as $orderId){ + foreach ($this->orders as $orderId) { $orderIndex = array_search($orderId, array_column($this->getTaskMeta(), 'external_id')); $responseOrder = $this->getTaskMeta()[$orderIndex]; @@ -45,7 +45,7 @@ public function start() $orderId, [ 'order_number' => $responseOrder['external_id'], - 'order_uuid' => $responseOrder['id'], + 'order_uuid' => $responseOrder['id'], ], ); } @@ -53,7 +53,7 @@ public function start() $this->sendTaskData( [ 'status' => 'success', - ] + ], ); } @@ -61,10 +61,10 @@ protected function initOrders() { $query = new \WC_Order_Query( [ - 'orderby' => 'id', - 'order' => 'ASC', - 'return' => 'ids', - 'post__in' => array_column($this->getTaskMeta(), 'external_id'), + 'orderby' => 'id', + 'order' => 'ASC', + 'return' => 'ids', + 'post__in' => array_column($this->getTaskMeta(), 'external_id'), ], ); From 7f2fa930c86e465e8f3b450376c3ea1e81ecca1a Mon Sep 17 00:00:00 2001 From: Stas Demin Date: Tue, 11 Jun 2024 07:59:23 +0300 Subject: [PATCH 28/50] fix: fix after review --- src/Actions/Schedule/CollectOrders.php | 10 ------- src/Actions/Schedule/ReindexOrders.php | 36 ++++++-------------------- src/Contracts/TaskContract.php | 22 +++++++++++----- src/Helpers/DBCoreTokenStorage.php | 10 +++---- 4 files changed, 29 insertions(+), 49 deletions(-) diff --git a/src/Actions/Schedule/CollectOrders.php b/src/Actions/Schedule/CollectOrders.php index 355a7d4..97e6cc8 100644 --- a/src/Actions/Schedule/CollectOrders.php +++ b/src/Actions/Schedule/CollectOrders.php @@ -12,22 +12,12 @@ class CollectOrders extends TaskContract const ORDERS_LIMIT = 10000; private Validate $error; - public function __construct($taskId) - { - parent::__construct($taskId); - } - public static function getName(): string { return 'collect-orphaned-orders'; } public function start() - { - $this->reportOrders(); - } - - protected function reportOrders() { $query = new \WC_Order_Query( [ diff --git a/src/Actions/Schedule/ReindexOrders.php b/src/Actions/Schedule/ReindexOrders.php index 8fed077..606be01 100644 --- a/src/Actions/Schedule/ReindexOrders.php +++ b/src/Actions/Schedule/ReindexOrders.php @@ -9,12 +9,12 @@ namespace Cdek\Actions\Schedule { use Cdek\Contracts\TaskContract; + use Cdek\Exceptions\CdekCoreApiException; use Cdek\Model\OrderMetaData; use Cdek\Model\Validate; class ReindexOrders extends TaskContract { - private array $orders = []; private Validate $error; public function __construct(string $taskId) @@ -31,21 +31,17 @@ public static function getName(): string public function start() { if (empty($this->getTaskMeta())) { - return; + throw new CdekCoreApiException('[CDEKDelivery] Failed to get orders meta info', + 'cdek_error.core.data', + $this->getTaskData(), + true); } - $this->initOrders(); - - foreach ($this->orders as $orderId) { - $orderIndex = array_search($orderId, array_column($this->getTaskMeta(), 'external_id')); - - $responseOrder = $this->getTaskMeta()[$orderIndex]; - + foreach ($this->getTaskMeta() as $arOrder) { OrderMetaData::updateMetaByOrderId( - $orderId, + $arOrder['external_id'], [ - 'order_number' => $responseOrder['external_id'], - 'order_uuid' => $responseOrder['id'], + 'order_uuid' => $arOrder['id'], ], ); } @@ -56,21 +52,5 @@ public function start() ], ); } - - protected function initOrders() - { - $query = new \WC_Order_Query( - [ - 'orderby' => 'id', - 'order' => 'ASC', - 'return' => 'ids', - 'post__in' => array_column($this->getTaskMeta(), 'external_id'), - ], - ); - - foreach ($query->get_orders() as $orderId) { - $this->orders[] = $orderId; - } - } } } diff --git a/src/Contracts/TaskContract.php b/src/Contracts/TaskContract.php index 42a8db5..82834f7 100644 --- a/src/Contracts/TaskContract.php +++ b/src/Contracts/TaskContract.php @@ -13,7 +13,7 @@ abstract class TaskContract const FINISH_STATUS = 201; const RESTART_STATUS = 202; const UNKNOWN_METHOD = 404; - const FATAL_ERRORS = [500, 502, 503]; + const FATAL_ERRORS = [500, 502, 503, 504]; protected cdekCoreApi $cdekCoreApi; protected static array $errorCollection = []; protected static array $taskData = []; @@ -54,6 +54,16 @@ protected function getTaskMeta(): array return self::$taskData[$this->taskId]['meta'] ?? []; } + + protected function getTaskData(): array + { + if(empty(self::$taskData[$this->taskId])){ + $this->initTaskData(); + } + + return self::$taskData[$this->taskId] ?? []; + } + protected function getTaskCursor(): array { if(empty(self::$responseCursor[$this->taskId])){ @@ -89,7 +99,7 @@ private function initData($response) $this->postponeTask(); return; }else{ - throw new CdekCoreApiException('[CDEKDelivery] Failed to get core api response' . var_export($response, true), + throw new CdekCoreApiException('[CDEKDelivery] Failed to get core api response', 'cdek_error.core.response', $response, true); @@ -114,8 +124,8 @@ protected function postponeTask() $hooks = as_get_scheduled_actions( [ 'hook' => sprintf('%s-%s', Config::TASK_MANAGER_HOOK_NAME, static::getName()), - 'status' => \ActionScheduler_Store::STATUS_PENDING - ] + 'status' => \ActionScheduler_Store::STATUS_PENDING, + ], ); if(empty($hooks)){ @@ -128,8 +138,8 @@ protected function postponeTask() (new TaskData( [ 'id' => $this->taskId, - 'name' => sprintf('%s-%s', Config::TASK_MANAGER_HOOK_NAME, static::getName()) - ] + 'name' => sprintf('%s-%s', Config::TASK_MANAGER_HOOK_NAME, static::getName()), + ], ))->createTaskWork(); } } diff --git a/src/Helpers/DBCoreTokenStorage.php b/src/Helpers/DBCoreTokenStorage.php index f2ef943..4e8065f 100644 --- a/src/Helpers/DBCoreTokenStorage.php +++ b/src/Helpers/DBCoreTokenStorage.php @@ -46,8 +46,8 @@ public function getPath() $cache = (new FileCache())->getVars(); - if (!empty($cache['end_point']['common'])) { - return static::$apiUrlString = $cache['end_point']['common']; + if (!empty($cache['endpoint']['common'])) { + return static::$apiUrlString = $cache['endpoint']['common']; } return static::$apiUrlString = $this->getEndPointFromToken($this->getToken()); @@ -86,9 +86,9 @@ final public function updateToken(): string self::$tokenStatic = $tokenApi['tokens']['common']; self::$tokenFrontend = $tokenApi['tokens']['frontend']; - $tokenApi['end_point']['admin'] = static::$adminUrlString = $this->getEndPointFromToken(self::$tokenAdmin); - $tokenApi['end_point']['common'] = static::$apiUrlString = $this->getEndPointFromToken(self::$tokenStatic); - $tokenApi['end_point']['frontend'] = static::$frontendUrlString = $this->getEndPointFromToken(self::$tokenFrontend); + $tokenApi['endpoint']['admin'] = static::$adminUrlString = $this->getEndPointFromToken(self::$tokenAdmin); + $tokenApi['endpoint']['common'] = static::$apiUrlString = $this->getEndPointFromToken(self::$tokenStatic); + $tokenApi['endpoint']['frontend'] = static::$frontendUrlString = $this->getEndPointFromToken(self::$tokenFrontend); $cache = new FileCache(); $cache->putVars($tokenApi); From 9c82b7a93e52273e2bbb38618033e3af379d0957 Mon Sep 17 00:00:00 2001 From: Stas Demin Date: Tue, 11 Jun 2024 08:01:34 +0300 Subject: [PATCH 29/50] fix: getPath method doc --- src/Helpers/DBCoreTokenStorage.php | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/src/Helpers/DBCoreTokenStorage.php b/src/Helpers/DBCoreTokenStorage.php index 4e8065f..0dc90cd 100644 --- a/src/Helpers/DBCoreTokenStorage.php +++ b/src/Helpers/DBCoreTokenStorage.php @@ -38,6 +38,12 @@ final public function getToken(): string return 'Bearer ' . $token; } + /** + * @return mixed|string + * @throws CdekApiException + * @throws CdekCoreApiException + * @throws \JsonException + */ public function getPath() { if(isset(static::$apiUrlString)){ From 5b6f6559e08d23d0b6211a16d3daf79692d703f3 Mon Sep 17 00:00:00 2001 From: Stas Demin Date: Tue, 11 Jun 2024 09:28:50 +0300 Subject: [PATCH 30/50] fix: replace work with response logic to transport class --- src/Actions/Schedule/CollectOrders.php | 13 ++++--- src/Actions/Schedule/ReindexOrders.php | 13 +++---- src/CdekCoreApi.php | 50 ++++++++++++++++++++++---- src/Contracts/TaskContract.php | 42 ++++------------------ src/Managers/TaskManager.php | 14 ++------ src/Model/CoreApiHeadersData.php | 27 ++++++++++++++ 6 files changed, 95 insertions(+), 64 deletions(-) create mode 100644 src/Model/CoreApiHeadersData.php diff --git a/src/Actions/Schedule/CollectOrders.php b/src/Actions/Schedule/CollectOrders.php index 97e6cc8..6ac2951 100644 --- a/src/Actions/Schedule/CollectOrders.php +++ b/src/Actions/Schedule/CollectOrders.php @@ -5,6 +5,7 @@ use Cdek\Cache\FileCache; use Cdek\CdekCoreApi; use Cdek\Contracts\TaskContract; +use Cdek\Model\CoreApiHeadersData; use Cdek\Model\Validate; class CollectOrders extends TaskContract @@ -35,7 +36,8 @@ public function start() $maxPages = $result->max_num_pages; - $this->sendTaskData( + $response = $this->cdekCoreApi->sendTaskData( + $this->taskId, [ 'status' => 'success', 'result' => [ @@ -45,11 +47,12 @@ public function start() ), ], ], - [ - 'X-Total-Pages' => $maxPages, - 'X-Current-Page' => $page, - ], + (new CoreApiHeadersData()) + ->setCurrentPage($page) + ->setTotalPages($maxPages) ); + + $this->initData($response); } } } diff --git a/src/Actions/Schedule/ReindexOrders.php b/src/Actions/Schedule/ReindexOrders.php index 606be01..e1db70d 100644 --- a/src/Actions/Schedule/ReindexOrders.php +++ b/src/Actions/Schedule/ReindexOrders.php @@ -41,16 +41,17 @@ public function start() OrderMetaData::updateMetaByOrderId( $arOrder['external_id'], [ - 'order_uuid' => $arOrder['id'], - ], + 'order_uuid' => $arOrder['id'] + ] ); } - $this->sendTaskData( + $this->initData($this->cdekCoreApi->sendTaskData( + $this->taskId, [ - 'status' => 'success', - ], - ); + 'status' => 'success' + ] + )); } } } diff --git a/src/CdekCoreApi.php b/src/CdekCoreApi.php index 67b63ed..cb47eb3 100644 --- a/src/CdekCoreApi.php +++ b/src/CdekCoreApi.php @@ -7,13 +7,20 @@ use Cdek\Exceptions\CdekCoreApiException; use Cdek\Helpers\DBCoreTokenStorage; use Cdek\Helpers\DBTokenStorage; +use Cdek\Model\CoreApiHeadersData; use Cdek\Transport\HttpCoreClient; class CdekCoreApi { + const SUCCESS_STATUS = 200; + const FINISH_STATUS = 201; + const HAS_NEXT_INFO_STATUS = 202; + const UNKNOWN_METHOD = 404; + const FATAL_ERRORS = [500, 502, 503, 504]; private const TOKEN_PATH = 'cms/wordpress/shops/%s/token'; private const SHOP = 'cms/wordpress/shops'; private const TASKS = 'wordpress/tasks'; + public ?int $status; private TokenStorageContract $generalTokenStorage; private TokenStorageContract $tokenCoreStorage; private HttpCoreClient $coreClient; @@ -94,8 +101,10 @@ public function fetchShopToken(): array */ public function taskManager($data = null) { - return $this->coreClient->sendCdekRequest($this->getShopApiUrl() . '/' . self::TASKS, 'GET', + $response = $this->coreClient->sendCdekRequest($this->getShopApiUrl() . '/' . self::TASKS, 'GET', $this->tokenCoreStorage->getToken(), $data); + + return $this->initData($response); } /** @@ -108,35 +117,62 @@ public function taskManager($data = null) * @throws CdekCoreApiException * @throws \JsonException */ - public function taskInfo($taskId, $data = null, array $headers = []) + public function taskInfo($taskId, $data = null, ?CoreApiHeadersData $headers = null) { - return $this->coreClient->sendCdekRequest($this->getShopApiUrl() . '/' . self::TASKS . '/' . $taskId, 'GET', + $response = $this->coreClient->sendCdekRequest($this->getShopApiUrl() . '/' . self::TASKS . '/' . $taskId, 'GET', $this->tokenCoreStorage->getToken(), $data, $headers); + + return $this->initData($response); } /** * @param $taskId * @param $data - * @param array $headers + * @param ?CoreApiHeadersData $headers * * @return array|false|string|\WP_Error * @throws CdekApiException * @throws CdekCoreApiException * @throws \JsonException */ - public function sendTaskData($taskId, $data, array $headers = []) + public function sendTaskData($taskId, $data, ?CoreApiHeadersData $headers = null) { - return $this->coreClient->sendCdekRequest( + $response = $this->coreClient->sendCdekRequest( $this->getShopApiUrl() . '/' . self::TASKS . '/' . $taskId, 'PUT', $this->tokenCoreStorage->getToken(), $data, - $headers + $headers ? $headers->getHeaders() : [] ); + + return $this->initData($response); } private function getShopApiUrl() { return $this->tokenCoreStorage->getPath(); } + + private function initData($response) + { + $decodeResponse = json_decode($response['body'], true); + + $this->status = $decodeResponse['status']; + + if( + !in_array( + $this->status, + [self::FINISH_STATUS, self::HAS_NEXT_INFO_STATUS, self::SUCCESS_STATUS], + ) + && + !in_array($this->status, self::FATAL_ERRORS) + ){ + throw new CdekCoreApiException('[CDEKDelivery] Failed to get core api response', + 'cdek_error.core.response', + $response, + true); + } + + return $decodeResponse; + } } diff --git a/src/Contracts/TaskContract.php b/src/Contracts/TaskContract.php index 82834f7..d432bb3 100644 --- a/src/Contracts/TaskContract.php +++ b/src/Contracts/TaskContract.php @@ -9,17 +9,11 @@ abstract class TaskContract { - const SUCCESS_STATUS = 200; - const FINISH_STATUS = 201; - const RESTART_STATUS = 202; - const UNKNOWN_METHOD = 404; - const FATAL_ERRORS = [500, 502, 503, 504]; protected cdekCoreApi $cdekCoreApi; protected static array $errorCollection = []; protected static array $taskData = []; protected static array $responseCursor = []; protected string $taskId; - protected ?int $status; public function __construct(string $taskId) { @@ -78,44 +72,22 @@ protected function initTaskData(array $data = null): void $this->initData($this->cdekCoreApi->taskInfo($this->taskId, $data)); } - protected function sendTaskData(array $data, $headers = []) + protected function initData($response) { - $this->initData($this->cdekCoreApi->sendTaskData($this->taskId, $data, $headers)); - } - - private function initData($response) - { - $decodeResponse = json_decode($response['body'], true); - - $this->status = $decodeResponse['status']; - - if( - !in_array( - $this->status, - [self::FINISH_STATUS, self::RESTART_STATUS, self::SUCCESS_STATUS], - ) - ){ - if(in_array($this->status, self::FATAL_ERRORS)){ - $this->postponeTask(); - return; - }else{ - throw new CdekCoreApiException('[CDEKDelivery] Failed to get core api response', - 'cdek_error.core.response', - $response, - true); - - } + if(in_array($this->cdekCoreApi->status, $this->cdekCoreApi::FATAL_ERRORS)){ + $this->postponeTask(); + return; } if( - empty($decodeResponse['success']) + empty($response['success']) ){ self::$errorCollection[$this->taskId][] = __('Request to api was failed', 'cdekdelivery'); } if(empty(self::$errorCollection[$this->taskId])){ - self::$taskData[$this->taskId] = $decodeResponse['data']; - self::$responseCursor[$this->taskId] = $decodeResponse['cursor']; + self::$taskData[$this->taskId] = $response['data']; + self::$responseCursor[$this->taskId] = $response['cursor']; } } diff --git a/src/Managers/TaskManager.php b/src/Managers/TaskManager.php index fdda1c9..93f8cd5 100644 --- a/src/Managers/TaskManager.php +++ b/src/Managers/TaskManager.php @@ -122,21 +122,13 @@ private function getResponse(): void return; } - $decodeResponse = json_decode($response['body'], true); - - if ( - $decodeResponse['error'] - ) { - self::$errorCollection[$this->taskId][] = $decodeResponse['error']; - } - - if (empty($decodeResponse['cursor'])) { + if (empty($response['cursor'])) { self::$errorCollection[$this->taskId][] = 'Cursor data not found'; } if (empty($this->errorCollection)) { - self::$taskData[$this->taskId] = $decodeResponse['data']; - self::$responseCursor[$this->taskId] = $decodeResponse['cursor']; + self::$taskData[$this->taskId] = $response['data']; + self::$responseCursor[$this->taskId] = $response['cursor']; } } diff --git a/src/Model/CoreApiHeadersData.php b/src/Model/CoreApiHeadersData.php new file mode 100644 index 0000000..d58b8f9 --- /dev/null +++ b/src/Model/CoreApiHeadersData.php @@ -0,0 +1,27 @@ +headers; + } + + public function setCurrentPage(int $currentPage): self + { + $this->headers['X-Current-Page'] = $currentPage; + return $this; + } + + public function setTotalPages(int $totalPages): self + { + $this->headers['X-Total-Pages'] = $totalPages; + return $this; + } + + +} From f5f8fe1285b713e45ff0e22cb1c6efd1d83215c2 Mon Sep 17 00:00:00 2001 From: Stas Demin Date: Tue, 11 Jun 2024 10:08:44 +0300 Subject: [PATCH 31/50] fix: server errors check --- src/CdekCoreApi.php | 11 ++++++++--- src/Contracts/TaskContract.php | 2 +- 2 files changed, 9 insertions(+), 4 deletions(-) diff --git a/src/CdekCoreApi.php b/src/CdekCoreApi.php index cb47eb3..7343fd4 100644 --- a/src/CdekCoreApi.php +++ b/src/CdekCoreApi.php @@ -16,7 +16,7 @@ class CdekCoreApi const FINISH_STATUS = 201; const HAS_NEXT_INFO_STATUS = 202; const UNKNOWN_METHOD = 404; - const FATAL_ERRORS = [500, 502, 503, 504]; + const FATAL_ERRORS = 5; private const TOKEN_PATH = 'cms/wordpress/shops/%s/token'; private const SHOP = 'cms/wordpress/shops'; private const TASKS = 'wordpress/tasks'; @@ -142,12 +142,17 @@ public function sendTaskData($taskId, $data, ?CoreApiHeadersData $headers = null 'PUT', $this->tokenCoreStorage->getToken(), $data, - $headers ? $headers->getHeaders() : [] + $headers ? $headers->getHeaders() : [], ); return $this->initData($response); } + public function isServerError(): bool + { + return substr($this->status, 0, 1) == self::FATAL_ERRORS; + } + private function getShopApiUrl() { return $this->tokenCoreStorage->getPath(); @@ -165,7 +170,7 @@ private function initData($response) [self::FINISH_STATUS, self::HAS_NEXT_INFO_STATUS, self::SUCCESS_STATUS], ) && - !in_array($this->status, self::FATAL_ERRORS) + !$this->isServerError() ){ throw new CdekCoreApiException('[CDEKDelivery] Failed to get core api response', 'cdek_error.core.response', diff --git a/src/Contracts/TaskContract.php b/src/Contracts/TaskContract.php index d432bb3..83509a0 100644 --- a/src/Contracts/TaskContract.php +++ b/src/Contracts/TaskContract.php @@ -74,7 +74,7 @@ protected function initTaskData(array $data = null): void protected function initData($response) { - if(in_array($this->cdekCoreApi->status, $this->cdekCoreApi::FATAL_ERRORS)){ + if($this->cdekCoreApi->isServerError()){ $this->postponeTask(); return; } From 9fbd564062742900fc899c7063096f3e79979577 Mon Sep 17 00:00:00 2001 From: Stas Demin Date: Tue, 11 Jun 2024 10:19:22 +0300 Subject: [PATCH 32/50] fix: server errors check + rename schedule exceptions --- src/Actions/Schedule/ReindexOrders.php | 8 ++--- src/CdekCoreApi.php | 34 +++++++++---------- src/Contracts/TaskContract.php | 2 +- src/Exceptions/CdekCoreApiException.php | 7 ---- src/Exceptions/CdekScheduledTaskException.php | 16 +++++++++ src/Helpers/DBCoreTokenStorage.php | 10 +++--- src/Managers/TaskManager.php | 4 +-- 7 files changed, 45 insertions(+), 36 deletions(-) delete mode 100644 src/Exceptions/CdekCoreApiException.php create mode 100644 src/Exceptions/CdekScheduledTaskException.php diff --git a/src/Actions/Schedule/ReindexOrders.php b/src/Actions/Schedule/ReindexOrders.php index e1db70d..a2b0934 100644 --- a/src/Actions/Schedule/ReindexOrders.php +++ b/src/Actions/Schedule/ReindexOrders.php @@ -9,7 +9,7 @@ namespace Cdek\Actions\Schedule { use Cdek\Contracts\TaskContract; - use Cdek\Exceptions\CdekCoreApiException; + use Cdek\Exceptions\CdekScheduledTaskException; use Cdek\Model\OrderMetaData; use Cdek\Model\Validate; @@ -31,10 +31,10 @@ public static function getName(): string public function start() { if (empty($this->getTaskMeta())) { - throw new CdekCoreApiException('[CDEKDelivery] Failed to get orders meta info', + throw new CdekScheduledTaskException('[CDEKDelivery] Failed to get orders meta info', 'cdek_error.core.data', - $this->getTaskData(), - true); + $this->getTaskData() + ); } foreach ($this->getTaskMeta() as $arOrder) { diff --git a/src/CdekCoreApi.php b/src/CdekCoreApi.php index 7343fd4..e107c91 100644 --- a/src/CdekCoreApi.php +++ b/src/CdekCoreApi.php @@ -4,7 +4,7 @@ use Cdek\Contracts\TokenStorageContract; use Cdek\Exceptions\CdekApiException; -use Cdek\Exceptions\CdekCoreApiException; +use Cdek\Exceptions\CdekScheduledTaskException; use Cdek\Helpers\DBCoreTokenStorage; use Cdek\Helpers\DBTokenStorage; use Cdek\Model\CoreApiHeadersData; @@ -16,7 +16,7 @@ class CdekCoreApi const FINISH_STATUS = 201; const HAS_NEXT_INFO_STATUS = 202; const UNKNOWN_METHOD = 404; - const FATAL_ERRORS = 5; + const FATAL_ERRORS_FIRST_NUMBER = 5; private const TOKEN_PATH = 'cms/wordpress/shops/%s/token'; private const SHOP = 'cms/wordpress/shops'; private const TASKS = 'wordpress/tasks'; @@ -38,7 +38,7 @@ public function __construct( /** * @return array * @throws CdekApiException - * @throws CdekCoreApiException + * @throws CdekScheduledTaskException * @throws \JsonException */ public function fetchShopToken(): array @@ -58,19 +58,19 @@ public function fetchShopToken(): array ); if(empty($response['body'])){ - throw new CdekCoreApiException('[CDEKDelivery] Failed to get shop uuid', + throw new CdekScheduledTaskException('[CDEKDelivery] Failed to get shop uuid', 'cdek_error.uuid.auth', - $response, - true); + $response + ); } $body = json_decode($response['body'], true); if(empty($body) || empty($body['data']['id'])){ - throw new CdekCoreApiException('[CDEKDelivery] Failed to get shop uuid', + throw new CdekScheduledTaskException('[CDEKDelivery] Failed to get shop uuid', 'cdek_error.uuid.auth', - $response, - true); + $response + ); } $response = $this->coreClient->sendCdekRequest( @@ -82,10 +82,10 @@ public function fetchShopToken(): array $body = json_decode($response['body'],true); if ($body === null || !$body['success'] || empty($body['data'])) { - throw new CdekCoreApiException('[CDEKDelivery] Failed to get shop token', + throw new CdekScheduledTaskException('[CDEKDelivery] Failed to get shop token', 'cdek_error.shop_token.auth', - $body, - true); + $body + ); } return ['tokens' => $body['data']]; @@ -96,7 +96,7 @@ public function fetchShopToken(): array * * @return array|false|string|\WP_Error * @throws CdekApiException - * @throws CdekCoreApiException + * @throws CdekScheduledTaskException * @throws \JsonException */ public function taskManager($data = null) @@ -114,7 +114,7 @@ public function taskManager($data = null) * * @return array|false|string|\WP_Error * @throws CdekApiException - * @throws CdekCoreApiException + * @throws CdekScheduledTaskException * @throws \JsonException */ public function taskInfo($taskId, $data = null, ?CoreApiHeadersData $headers = null) @@ -132,7 +132,7 @@ public function taskInfo($taskId, $data = null, ?CoreApiHeadersData $headers = n * * @return array|false|string|\WP_Error * @throws CdekApiException - * @throws CdekCoreApiException + * @throws CdekScheduledTaskException * @throws \JsonException */ public function sendTaskData($taskId, $data, ?CoreApiHeadersData $headers = null) @@ -150,7 +150,7 @@ public function sendTaskData($taskId, $data, ?CoreApiHeadersData $headers = null public function isServerError(): bool { - return substr($this->status, 0, 1) == self::FATAL_ERRORS; + return substr($this->status, 0, 1) == self::FATAL_ERRORS_FIRST_NUMBER; } private function getShopApiUrl() @@ -172,7 +172,7 @@ private function initData($response) && !$this->isServerError() ){ - throw new CdekCoreApiException('[CDEKDelivery] Failed to get core api response', + throw new CdekScheduledTaskException('[CDEKDelivery] Failed to get core api response', 'cdek_error.core.response', $response, true); diff --git a/src/Contracts/TaskContract.php b/src/Contracts/TaskContract.php index 83509a0..826da28 100644 --- a/src/Contracts/TaskContract.php +++ b/src/Contracts/TaskContract.php @@ -4,7 +4,7 @@ use Cdek\CdekCoreApi; use Cdek\Config; -use Cdek\Exceptions\CdekCoreApiException; +use Cdek\Exceptions\CdekScheduledTaskException; use Cdek\Model\TaskData; abstract class TaskContract diff --git a/src/Exceptions/CdekCoreApiException.php b/src/Exceptions/CdekCoreApiException.php deleted file mode 100644 index 810ea50..0000000 --- a/src/Exceptions/CdekCoreApiException.php +++ /dev/null @@ -1,7 +0,0 @@ -taskManager(); - } catch (CdekCoreApiException $e) { + } catch (CdekScheduledTaskException $e) { self::$errorCollection[$this->taskId][] = $e->getMessage(); static::addPluginScheduleEvents(); return; From f781f45983b054410b35b28ed00ad310d6eba106 Mon Sep 17 00:00:00 2001 From: Stas Demin Date: Tue, 11 Jun 2024 10:31:39 +0300 Subject: [PATCH 33/50] fix: check DOING_CRON const in API exception --- src/Exceptions/CdekException.php | 3 +-- src/Exceptions/CdekScheduledTaskException.php | 2 -- 2 files changed, 1 insertion(+), 4 deletions(-) diff --git a/src/Exceptions/CdekException.php b/src/Exceptions/CdekException.php index 781a362..66a7014 100644 --- a/src/Exceptions/CdekException.php +++ b/src/Exceptions/CdekException.php @@ -13,7 +13,6 @@ abstract class CdekException extends Exception { protected $code = 'cdek_error'; - protected bool $isSchedule = false; private ?array $data; public function __construct( @@ -26,7 +25,7 @@ public function __construct( $this->data = $data ?? []; $this->message = $message; - if ($stopPropagation && (defined('REST_REQUEST') || $this->isSchedule)) { + if ($stopPropagation && (defined('REST_REQUEST') || defined('DOING_CRON'))) { wp_die($this->getWpError()); } diff --git a/src/Exceptions/CdekScheduledTaskException.php b/src/Exceptions/CdekScheduledTaskException.php index 5d691ac..cee01cb 100644 --- a/src/Exceptions/CdekScheduledTaskException.php +++ b/src/Exceptions/CdekScheduledTaskException.php @@ -3,8 +3,6 @@ namespace Cdek\Exceptions; class CdekScheduledTaskException extends \Cdek\Exceptions\CdekException { - protected bool $isSchedule = true; - public function __construct( string $message = '', string $code = 'cdek_error', From 7dbcab4dc46cd63a2652df9737c7e463b4e62228 Mon Sep 17 00:00:00 2001 From: Stas Demin Date: Tue, 11 Jun 2024 11:33:14 +0300 Subject: [PATCH 34/50] fix: cache class work with only one file --- src/Cache/FileCache.php | 39 ++++++++++++------------------ src/Helpers/DBCoreTokenStorage.php | 7 +++--- src/Uninstaller.php | 3 +-- 3 files changed, 19 insertions(+), 30 deletions(-) diff --git a/src/Cache/FileCache.php b/src/Cache/FileCache.php index b78025a..a207c4c 100644 --- a/src/Cache/FileCache.php +++ b/src/Cache/FileCache.php @@ -9,23 +9,16 @@ class FileCache { const CACHE_FILE_NAME = '.cache.php'; private static array $store; - private string $file; - - public function __construct($fileName = self::CACHE_FILE_NAME) - { - $this->file = $fileName; - } - - public function getVars() + public static function getVars() { - if(!file_exists(Loader::getPluginPath() . DIRECTORY_SEPARATOR . $this->file)){ + if(!file_exists(Loader::getPluginPath() . DIRECTORY_SEPARATOR . self::CACHE_FILE_NAME)){ return null; } - return self::$store[$this->file] ?? self::$store[$this->file] = require_once(Loader::getPluginPath() . DIRECTORY_SEPARATOR . $this->file); + return self::$store[self::CACHE_FILE_NAME] ?? self::$store[self::CACHE_FILE_NAME] = require_once(Loader::getPluginPath() . DIRECTORY_SEPARATOR . self::CACHE_FILE_NAME); } - public function putVars($vars) + public static function putVars($vars) { if(empty($vars)){ return; @@ -38,26 +31,24 @@ public function putVars($vars) true); } - $arPath = explode(DIRECTORY_SEPARATOR, $this->file); - unset($arPath[count($arPath) - 1]); - - if(!is_writable(Loader::getPluginPath() . implode(DIRECTORY_SEPARATOR, $arPath))){ - throw new CdekApiException('[CDEKDelivery] Failed check directory rights', - 'cdek_error.cache.rights', - ['path' => Loader::getPluginPath() . implode(DIRECTORY_SEPARATOR, $arPath)], - true); + if(file_exists(Loader::getPluginPath() . DIRECTORY_SEPARATOR . self::CACHE_FILE_NAME)){ + if(!is_writable(Loader::getPluginPath() . DIRECTORY_SEPARATOR . self::CACHE_FILE_NAME)){ + throw new CdekApiException('[CDEKDelivery] Failed check directory rights', + 'cdek_error.cache.rights', + ['path' => Loader::getPluginPath() . DIRECTORY_SEPARATOR . self::CACHE_FILE_NAME], + true); + } } - $logFile = fopen( Loader::getPluginPath() . DIRECTORY_SEPARATOR . $this->file, 'w+'); - $content = 'file); + unlink(Loader::getPluginPath() . DIRECTORY_SEPARATOR . self::CACHE_FILE_NAME); } } diff --git a/src/Helpers/DBCoreTokenStorage.php b/src/Helpers/DBCoreTokenStorage.php index 3e159bc..90855fc 100644 --- a/src/Helpers/DBCoreTokenStorage.php +++ b/src/Helpers/DBCoreTokenStorage.php @@ -50,7 +50,7 @@ public function getPath() return static::$apiUrlString; } - $cache = (new FileCache())->getVars(); + $cache = FileCache::getVars(); if (!empty($cache['endpoint']['common'])) { return static::$apiUrlString = $cache['endpoint']['common']; @@ -66,7 +66,7 @@ private function getTokenFromCache(): ?string private function getTokenFromSettings(): ?string { - $cache = (new FileCache())->getVars(); + $cache = FileCache::getVars(); if (empty($cache['tokens'])) { return null; @@ -96,8 +96,7 @@ final public function updateToken(): string $tokenApi['endpoint']['common'] = static::$apiUrlString = $this->getEndPointFromToken(self::$tokenStatic); $tokenApi['endpoint']['frontend'] = static::$frontendUrlString = $this->getEndPointFromToken(self::$tokenFrontend); - $cache = new FileCache(); - $cache->putVars($tokenApi); + FileCache::putVars($tokenApi); return self::$tokenStatic; } diff --git a/src/Uninstaller.php b/src/Uninstaller.php index c96c6c2..87ebf1c 100644 --- a/src/Uninstaller.php +++ b/src/Uninstaller.php @@ -3,12 +3,11 @@ namespace Cdek; use Cdek\Cache\FileCache; -use Cdek\Managers\TaskManager; class Uninstaller { public function __invoke() { - (new FileCache())->clear(); + FileCache::clear(); } } From 4e3377450e259949dafe13c97c5e5aa6a130c8a7 Mon Sep 17 00:00:00 2001 From: Stas Demin Date: Tue, 11 Jun 2024 12:38:00 +0300 Subject: [PATCH 35/50] fix: add core request data as dto model --- src/Actions/Schedule/CollectOrders.php | 19 +++++------- src/Actions/Schedule/ReindexOrders.php | 5 ++- src/CdekCoreApi.php | 38 ++++++++++++++--------- src/Contracts/TaskContract.php | 4 +-- src/Model/CoreRequestData.php | 43 ++++++++++++++++++++++++++ 5 files changed, 79 insertions(+), 30 deletions(-) create mode 100644 src/Model/CoreRequestData.php diff --git a/src/Actions/Schedule/CollectOrders.php b/src/Actions/Schedule/CollectOrders.php index 6ac2951..66a231a 100644 --- a/src/Actions/Schedule/CollectOrders.php +++ b/src/Actions/Schedule/CollectOrders.php @@ -2,10 +2,8 @@ namespace Cdek\Actions\Schedule; -use Cdek\Cache\FileCache; -use Cdek\CdekCoreApi; use Cdek\Contracts\TaskContract; -use Cdek\Model\CoreApiHeadersData; +use Cdek\Model\CoreRequestData; use Cdek\Model\Validate; class CollectOrders extends TaskContract @@ -38,18 +36,17 @@ public function start() $response = $this->cdekCoreApi->sendTaskData( $this->taskId, - [ - 'status' => 'success', - 'result' => [ + new CoreRequestData( + 'success', + [ 'orders' => array_map( static fn($order) => (string)$order, $result->orders, - ), + ) ], - ], - (new CoreApiHeadersData()) - ->setCurrentPage($page) - ->setTotalPages($maxPages) + $page, + $maxPages + ) ); $this->initData($response); diff --git a/src/Actions/Schedule/ReindexOrders.php b/src/Actions/Schedule/ReindexOrders.php index a2b0934..78641e4 100644 --- a/src/Actions/Schedule/ReindexOrders.php +++ b/src/Actions/Schedule/ReindexOrders.php @@ -10,6 +10,7 @@ use Cdek\Contracts\TaskContract; use Cdek\Exceptions\CdekScheduledTaskException; + use Cdek\Model\CoreRequestData; use Cdek\Model\OrderMetaData; use Cdek\Model\Validate; @@ -48,9 +49,7 @@ public function start() $this->initData($this->cdekCoreApi->sendTaskData( $this->taskId, - [ - 'status' => 'success' - ] + new CoreRequestData('success') )); } } diff --git a/src/CdekCoreApi.php b/src/CdekCoreApi.php index e107c91..f897587 100644 --- a/src/CdekCoreApi.php +++ b/src/CdekCoreApi.php @@ -7,7 +7,7 @@ use Cdek\Exceptions\CdekScheduledTaskException; use Cdek\Helpers\DBCoreTokenStorage; use Cdek\Helpers\DBTokenStorage; -use Cdek\Model\CoreApiHeadersData; +use Cdek\Model\CoreRequestData; use Cdek\Transport\HttpCoreClient; class CdekCoreApi @@ -108,41 +108,51 @@ public function taskManager($data = null) } /** - * @param $taskId - * @param null $data - * @param array $headers + * @param $taskId + * @param CoreRequestData $data * * @return array|false|string|\WP_Error - * @throws CdekApiException - * @throws CdekScheduledTaskException + * @throws \Cdek\Exceptions\CdekApiException + * @throws \Cdek\Exceptions\CdekScheduledTaskException * @throws \JsonException */ - public function taskInfo($taskId, $data = null, ?CoreApiHeadersData $headers = null) + public function taskInfo($taskId, CoreRequestData $data) { - $response = $this->coreClient->sendCdekRequest($this->getShopApiUrl() . '/' . self::TASKS . '/' . $taskId, 'GET', - $this->tokenCoreStorage->getToken(), $data, $headers); + $response = $this->coreClient->sendCdekRequest( + $this->getShopApiUrl() . '/' . self::TASKS . '/' . $taskId, 'GET', + $this->tokenCoreStorage->getToken(), + [ + 'status' => $data->getStatus(), + 'result' => $data->getData() + ] + ); return $this->initData($response); } /** * @param $taskId - * @param $data - * @param ?CoreApiHeadersData $headers + * @param CoreRequestData $data * * @return array|false|string|\WP_Error * @throws CdekApiException * @throws CdekScheduledTaskException * @throws \JsonException */ - public function sendTaskData($taskId, $data, ?CoreApiHeadersData $headers = null) + public function sendTaskData($taskId, CoreRequestData $data) { $response = $this->coreClient->sendCdekRequest( $this->getShopApiUrl() . '/' . self::TASKS . '/' . $taskId, 'PUT', $this->tokenCoreStorage->getToken(), - $data, - $headers ? $headers->getHeaders() : [], + [ + 'status' => $data->getStatus(), + 'result' => $data->getData() + ], + [ + 'X-Current-Page' => $data->getCurrentPage(), + 'X-Total-Pages' => $data->getTotalPages() + ] ); return $this->initData($response); diff --git a/src/Contracts/TaskContract.php b/src/Contracts/TaskContract.php index 826da28..c01ad09 100644 --- a/src/Contracts/TaskContract.php +++ b/src/Contracts/TaskContract.php @@ -4,7 +4,7 @@ use Cdek\CdekCoreApi; use Cdek\Config; -use Cdek\Exceptions\CdekScheduledTaskException; +use Cdek\Model\CoreRequestData; use Cdek\Model\TaskData; abstract class TaskContract @@ -69,7 +69,7 @@ protected function getTaskCursor(): array protected function initTaskData(array $data = null): void { - $this->initData($this->cdekCoreApi->taskInfo($this->taskId, $data)); + $this->initData($this->cdekCoreApi->taskInfo($this->taskId, new CoreRequestData('success', $data))); } protected function initData($response) diff --git a/src/Model/CoreRequestData.php b/src/Model/CoreRequestData.php new file mode 100644 index 0000000..b8c039e --- /dev/null +++ b/src/Model/CoreRequestData.php @@ -0,0 +1,43 @@ +status = $status; + $this->data = $data; + $this->currentPage = $currentPage; + $this->totalPages = $totalPages; + } + + public function getStatus(): string + { + return $this->status; + } + + public function getData(): ?array + { + return $this->data; + } + + public function getCurrentPage(): ?int + { + return $this->currentPage; + } + + public function getTotalPages(): ?int + { + return $this->totalPages; + } +} From 7dc1fa413b89e3c5ae3494dcbb00e4d404de96a4 Mon Sep 17 00:00:00 2001 From: Stas Demin Date: Tue, 11 Jun 2024 15:07:13 +0300 Subject: [PATCH 36/50] fix: remove headers data and fix status detect --- src/CdekCoreApi.php | 60 +++++++++++++++++--------------- src/Model/CoreApiHeadersData.php | 27 -------------- 2 files changed, 32 insertions(+), 55 deletions(-) delete mode 100644 src/Model/CoreApiHeadersData.php diff --git a/src/CdekCoreApi.php b/src/CdekCoreApi.php index f897587..87e27bf 100644 --- a/src/CdekCoreApi.php +++ b/src/CdekCoreApi.php @@ -49,7 +49,7 @@ public function fetchShopToken(): array $this->generalTokenStorage->getToken(), [ 'name' => get_bloginfo('name'), - 'url' => [ + 'url' => [ 'rest' => rest_url(), 'home' => home_url(), 'admin' => admin_url(), @@ -57,19 +57,19 @@ public function fetchShopToken(): array ], ); - if(empty($response['body'])){ + if (empty($response['body'])) { throw new CdekScheduledTaskException('[CDEKDelivery] Failed to get shop uuid', - 'cdek_error.uuid.auth', - $response + 'cdek_error.uuid.auth', + $response, ); } $body = json_decode($response['body'], true); - if(empty($body) || empty($body['data']['id'])){ + if (empty($body) || empty($body['data']['id'])) { throw new CdekScheduledTaskException('[CDEKDelivery] Failed to get shop uuid', - 'cdek_error.uuid.auth', - $response + 'cdek_error.uuid.auth', + $response, ); } @@ -79,12 +79,12 @@ public function fetchShopToken(): array $this->generalTokenStorage->getToken(), ); - $body = json_decode($response['body'],true); + $body = json_decode($response['body'], true); if ($body === null || !$body['success'] || empty($body['data'])) { throw new CdekScheduledTaskException('[CDEKDelivery] Failed to get shop token', - 'cdek_error.shop_token.auth', - $body + 'cdek_error.shop_token.auth', + $body, ); } @@ -101,8 +101,10 @@ public function fetchShopToken(): array */ public function taskManager($data = null) { - $response = $this->coreClient->sendCdekRequest($this->getShopApiUrl() . '/' . self::TASKS, 'GET', - $this->tokenCoreStorage->getToken(), $data); + $response = $this->coreClient->sendCdekRequest($this->getShopApiUrl() . '/' . self::TASKS, + 'GET', + $this->tokenCoreStorage->getToken(), + $data); return $this->initData($response); } @@ -119,19 +121,20 @@ public function taskManager($data = null) public function taskInfo($taskId, CoreRequestData $data) { $response = $this->coreClient->sendCdekRequest( - $this->getShopApiUrl() . '/' . self::TASKS . '/' . $taskId, 'GET', + $this->getShopApiUrl() . '/' . self::TASKS . '/' . $taskId, + 'GET', $this->tokenCoreStorage->getToken(), [ 'status' => $data->getStatus(), - 'result' => $data->getData() - ] + 'result' => $data->getData(), + ], ); return $this->initData($response); } /** - * @param $taskId + * @param $taskId * @param CoreRequestData $data * * @return array|false|string|\WP_Error @@ -142,17 +145,17 @@ public function taskInfo($taskId, CoreRequestData $data) public function sendTaskData($taskId, CoreRequestData $data) { $response = $this->coreClient->sendCdekRequest( - $this->getShopApiUrl() . '/' . self::TASKS . '/' . $taskId, + $this->getShopApiUrl() . '/' . self::TASKS . '/' . $taskId, 'PUT', $this->tokenCoreStorage->getToken(), [ 'status' => $data->getStatus(), - 'result' => $data->getData() + 'result' => $data->getData(), ], [ 'X-Current-Page' => $data->getCurrentPage(), - 'X-Total-Pages' => $data->getTotalPages() - ] + 'X-Total-Pages' => $data->getTotalPages(), + ], ); return $this->initData($response); @@ -160,7 +163,7 @@ public function sendTaskData($taskId, CoreRequestData $data) public function isServerError(): bool { - return substr($this->status, 0, 1) == self::FATAL_ERRORS_FIRST_NUMBER; + return empty($this->status) || substr($this->status, 0, 1) == self::FATAL_ERRORS_FIRST_NUMBER; } private function getShopApiUrl() @@ -172,20 +175,21 @@ private function initData($response) { $decodeResponse = json_decode($response['body'], true); - $this->status = $decodeResponse['status']; + $this->status = $decodeResponse['status'] ?? null; - if( + if ( !in_array( $this->status, [self::FINISH_STATUS, self::HAS_NEXT_INFO_STATUS, self::SUCCESS_STATUS], ) && !$this->isServerError() - ){ - throw new CdekScheduledTaskException('[CDEKDelivery] Failed to get core api response', - 'cdek_error.core.response', - $response, - true); + ) { + throw new CdekScheduledTaskException( + '[CDEKDelivery] Failed to get core api response', + 'cdek_error.core.response', + $response, + ); } return $decodeResponse; diff --git a/src/Model/CoreApiHeadersData.php b/src/Model/CoreApiHeadersData.php deleted file mode 100644 index d58b8f9..0000000 --- a/src/Model/CoreApiHeadersData.php +++ /dev/null @@ -1,27 +0,0 @@ -headers; - } - - public function setCurrentPage(int $currentPage): self - { - $this->headers['X-Current-Page'] = $currentPage; - return $this; - } - - public function setTotalPages(int $totalPages): self - { - $this->headers['X-Total-Pages'] = $totalPages; - return $this; - } - - -} From e24d810f573091a669f99b1c33919c02e792529b Mon Sep 17 00:00:00 2001 From: Stas Demin Date: Thu, 13 Jun 2024 16:59:51 +0300 Subject: [PATCH 37/50] fix: remove rename task output data, remove Task Contract unnecessary vars, work with exceptions, fix tasks, remove token in uninstaller --- src/Actions/Schedule/CollectOrders.php | 7 +- src/Actions/Schedule/ReindexOrders.php | 21 ++++-- src/Cache/FileCache.php | 30 +++++--- src/CdekCoreApi.php | 75 ++++++++++++++----- src/Contracts/TaskContract.php | 61 +++++++-------- src/Exceptions/CdekScheduledTaskException.php | 2 +- src/Helpers/DBCoreTokenStorage.php | 28 ++++--- src/Managers/TaskManager.php | 44 ++++++----- ...CoreRequestData.php => TaskOutputData.php} | 2 +- src/Uninstaller.php | 4 +- 10 files changed, 165 insertions(+), 109 deletions(-) rename src/Model/{CoreRequestData.php => TaskOutputData.php} (97%) diff --git a/src/Actions/Schedule/CollectOrders.php b/src/Actions/Schedule/CollectOrders.php index 66a231a..46bef55 100644 --- a/src/Actions/Schedule/CollectOrders.php +++ b/src/Actions/Schedule/CollectOrders.php @@ -3,13 +3,12 @@ namespace Cdek\Actions\Schedule; use Cdek\Contracts\TaskContract; -use Cdek\Model\CoreRequestData; +use Cdek\Model\TaskOutputData; use Cdek\Model\Validate; class CollectOrders extends TaskContract { const ORDERS_LIMIT = 10000; - private Validate $error; public static function getName(): string { @@ -36,12 +35,12 @@ public function start() $response = $this->cdekCoreApi->sendTaskData( $this->taskId, - new CoreRequestData( + new TaskOutputData( 'success', [ 'orders' => array_map( static fn($order) => (string)$order, - $result->orders, + $result->orders ) ], $page, diff --git a/src/Actions/Schedule/ReindexOrders.php b/src/Actions/Schedule/ReindexOrders.php index 78641e4..40482e4 100644 --- a/src/Actions/Schedule/ReindexOrders.php +++ b/src/Actions/Schedule/ReindexOrders.php @@ -9,8 +9,9 @@ namespace Cdek\Actions\Schedule { use Cdek\Contracts\TaskContract; + use Cdek\Exceptions\CdekApiException; use Cdek\Exceptions\CdekScheduledTaskException; - use Cdek\Model\CoreRequestData; + use Cdek\Model\TaskOutputData; use Cdek\Model\OrderMetaData; use Cdek\Model\Validate; @@ -29,12 +30,18 @@ public static function getName(): string return 'restore-order-uuids'; } + /** + * @return void + * @throws CdekApiException + * @throws CdekScheduledTaskException + * @throws \JsonException + */ public function start() { if (empty($this->getTaskMeta())) { - throw new CdekScheduledTaskException('[CDEKDelivery] Failed to get orders meta info', - 'cdek_error.core.data', - $this->getTaskData() + throw new CdekScheduledTaskException( + '[CDEKDelivery] Failed to get orders meta info', + 'cdek_error.core.data', ); } @@ -42,14 +49,14 @@ public function start() OrderMetaData::updateMetaByOrderId( $arOrder['external_id'], [ - 'order_uuid' => $arOrder['id'] - ] + 'order_uuid' => $arOrder['id'], + ], ); } $this->initData($this->cdekCoreApi->sendTaskData( $this->taskId, - new CoreRequestData('success') + new TaskOutputData('success'), )); } } diff --git a/src/Cache/FileCache.php b/src/Cache/FileCache.php index a207c4c..660d305 100644 --- a/src/Cache/FileCache.php +++ b/src/Cache/FileCache.php @@ -9,7 +9,8 @@ class FileCache { const CACHE_FILE_NAME = '.cache.php'; private static array $store; - public static function getVars() + + public static function getVars(): ?array { if(!file_exists(Loader::getPluginPath() . DIRECTORY_SEPARATOR . self::CACHE_FILE_NAME)){ return null; @@ -18,19 +19,18 @@ public static function getVars() return self::$store[self::CACHE_FILE_NAME] ?? self::$store[self::CACHE_FILE_NAME] = require_once(Loader::getPluginPath() . DIRECTORY_SEPARATOR . self::CACHE_FILE_NAME); } - public static function putVars($vars) + /** + * @param $vars + * + * @return void + * @throws CdekApiException + */ + public static function putVars($vars): void { if(empty($vars)){ return; } - if(!is_writable(Loader::getPluginPath())){ - throw new CdekApiException('[CDEKDelivery] Failed check directory rights', - 'cdek_error.cache.rights', - ['path' => Loader::getPluginPath()], - true); - } - if(file_exists(Loader::getPluginPath() . DIRECTORY_SEPARATOR . self::CACHE_FILE_NAME)){ if(!is_writable(Loader::getPluginPath() . DIRECTORY_SEPARATOR . self::CACHE_FILE_NAME)){ throw new CdekApiException('[CDEKDelivery] Failed check directory rights', @@ -38,6 +38,13 @@ public static function putVars($vars) ['path' => Loader::getPluginPath() . DIRECTORY_SEPARATOR . self::CACHE_FILE_NAME], true); } + }else{ + if(!is_writable(Loader::getPluginPath())){ + throw new CdekApiException('[CDEKDelivery] Failed check directory rights', + 'cdek_error.cache.rights', + ['path' => Loader::getPluginPath()], + true); + } } @@ -47,7 +54,10 @@ public static function putVars($vars) fclose($logFile); } - public static function clear() + /** + * @return void + */ + public static function clear(): void { unlink(Loader::getPluginPath() . DIRECTORY_SEPARATOR . self::CACHE_FILE_NAME); } diff --git a/src/CdekCoreApi.php b/src/CdekCoreApi.php index 87e27bf..5fd0274 100644 --- a/src/CdekCoreApi.php +++ b/src/CdekCoreApi.php @@ -7,7 +7,7 @@ use Cdek\Exceptions\CdekScheduledTaskException; use Cdek\Helpers\DBCoreTokenStorage; use Cdek\Helpers\DBTokenStorage; -use Cdek\Model\CoreRequestData; +use Cdek\Model\TaskOutputData; use Cdek\Transport\HttpCoreClient; class CdekCoreApi @@ -15,6 +15,7 @@ class CdekCoreApi const SUCCESS_STATUS = 200; const FINISH_STATUS = 201; const HAS_NEXT_INFO_STATUS = 202; + const EMPTY_ANSWER = 204; const UNKNOWN_METHOD = 404; const FATAL_ERRORS_FIRST_NUMBER = 5; private const TOKEN_PATH = 'cms/wordpress/shops/%s/token'; @@ -58,15 +59,15 @@ public function fetchShopToken(): array ); if (empty($response['body'])) { - throw new CdekScheduledTaskException('[CDEKDelivery] Failed to get shop uuid', - 'cdek_error.uuid.auth', + throw new CdekScheduledTaskException('[CDEKDelivery] Register shop failed', + 'cdek_error.register.shop', $response, ); } $body = json_decode($response['body'], true); - if (empty($body) || empty($body['data']['id'])) { + if (empty($body['data']['id'])) { throw new CdekScheduledTaskException('[CDEKDelivery] Failed to get shop uuid', 'cdek_error.uuid.auth', $response, @@ -111,14 +112,14 @@ public function taskManager($data = null) /** * @param $taskId - * @param CoreRequestData $data + * @param TaskOutputData $data * * @return array|false|string|\WP_Error - * @throws \Cdek\Exceptions\CdekApiException - * @throws \Cdek\Exceptions\CdekScheduledTaskException + * @throws CdekApiException + * @throws CdekScheduledTaskException * @throws \JsonException */ - public function taskInfo($taskId, CoreRequestData $data) + public function taskInfo($taskId, TaskOutputData $data) { $response = $this->coreClient->sendCdekRequest( $this->getShopApiUrl() . '/' . self::TASKS . '/' . $taskId, @@ -135,14 +136,14 @@ public function taskInfo($taskId, CoreRequestData $data) /** * @param $taskId - * @param CoreRequestData $data + * @param TaskOutputData $data * * @return array|false|string|\WP_Error * @throws CdekApiException * @throws CdekScheduledTaskException * @throws \JsonException */ - public function sendTaskData($taskId, CoreRequestData $data) + public function sendTaskData($taskId, TaskOutputData $data) { $response = $this->coreClient->sendCdekRequest( $this->getShopApiUrl() . '/' . self::TASKS . '/' . $taskId, @@ -163,35 +164,71 @@ public function sendTaskData($taskId, CoreRequestData $data) public function isServerError(): bool { - return empty($this->status) || substr($this->status, 0, 1) == self::FATAL_ERRORS_FIRST_NUMBER; + return empty($this->status) || str_starts_with($this->status, self::FATAL_ERRORS_FIRST_NUMBER); } - private function getShopApiUrl() + /** + * @return mixed|string + * @throws CdekApiException + * @throws CdekScheduledTaskException + * @throws \JsonException + */ + private function getShopApiUrl(): string { return $this->tokenCoreStorage->getPath(); } - private function initData($response) + /** + * @param $response + * + * @return array + * @throws CdekScheduledTaskException + */ + private function initData($response): array { $decodeResponse = json_decode($response['body'], true); - $this->status = $decodeResponse['status'] ?? null; + $this->status = $response['response']['status']; if ( - !in_array( - $this->status, - [self::FINISH_STATUS, self::HAS_NEXT_INFO_STATUS, self::SUCCESS_STATUS], - ) + !$this->isSuccessStatus() && !$this->isServerError() + || + ( + empty($decodeResponse['success']) + && + $this->status !== self::EMPTY_ANSWER + ) ) { throw new CdekScheduledTaskException( '[CDEKDelivery] Failed to get core api response', 'cdek_error.core.response', - $response, + $response ); } return $decodeResponse; } + + private function isSuccessStatus(): bool + { + if($this->status === self::SUCCESS_STATUS){ + return true; + } + + if($this->status === self::FINISH_STATUS){ + return true; + } + + if($this->status === self::HAS_NEXT_INFO_STATUS){ + return true; + } + + if($this->status === self::EMPTY_ANSWER){ + return true; + } + + return false; + } } diff --git a/src/Contracts/TaskContract.php b/src/Contracts/TaskContract.php index c01ad09..55eab6b 100644 --- a/src/Contracts/TaskContract.php +++ b/src/Contracts/TaskContract.php @@ -4,15 +4,16 @@ use Cdek\CdekCoreApi; use Cdek\Config; -use Cdek\Model\CoreRequestData; +use Cdek\Exceptions\CdekApiException; +use Cdek\Exceptions\CdekScheduledTaskException; +use Cdek\Model\TaskOutputData; use Cdek\Model\TaskData; abstract class TaskContract { protected cdekCoreApi $cdekCoreApi; protected static array $errorCollection = []; - protected static array $taskData = []; - protected static array $responseCursor = []; + protected array $taskMeta = []; protected string $taskId; public function __construct(string $taskId) @@ -40,58 +41,50 @@ public static function registerAction(): void 1, ); } - protected function getTaskMeta(): array - { - if(empty(self::$taskData[$this->taskId])){ - $this->initTaskData(); - } - return self::$taskData[$this->taskId]['meta'] ?? []; - } - - protected function getTaskData(): array - { - if(empty(self::$taskData[$this->taskId])){ - $this->initTaskData(); - } - - return self::$taskData[$this->taskId] ?? []; - } - - protected function getTaskCursor(): array + /** + * @return array + * @throws CdekApiException + * @throws CdekScheduledTaskException + * @throws \JsonException + */ + protected function getTaskMeta(): array { - if(empty(self::$responseCursor[$this->taskId])){ + if(empty($this->taskMeta)){ $this->initTaskData(); } - return self::$responseCursor[$this->taskId]['meta']; + return $this->taskMeta ?? []; } + /** + * @throws CdekScheduledTaskException + * @throws CdekApiException + * @throws \JsonException + */ protected function initTaskData(array $data = null): void { - $this->initData($this->cdekCoreApi->taskInfo($this->taskId, new CoreRequestData('success', $data))); + $this->initData($this->cdekCoreApi->taskInfo($this->taskId, new TaskOutputData('success', $data))); } - protected function initData($response) + /** + * @param $response + * + * @return void + */ + protected function initData($response): void { if($this->cdekCoreApi->isServerError()){ $this->postponeTask(); return; } - if( - empty($response['success']) - ){ - self::$errorCollection[$this->taskId][] = __('Request to api was failed', 'cdekdelivery'); - } - if(empty(self::$errorCollection[$this->taskId])){ - self::$taskData[$this->taskId] = $response['data']; - self::$responseCursor[$this->taskId] = $response['cursor']; + $this->taskMeta = $response['data']['meta']; } } - protected function postponeTask() + protected function postponeTask(): void { $hooks = as_get_scheduled_actions( [ diff --git a/src/Exceptions/CdekScheduledTaskException.php b/src/Exceptions/CdekScheduledTaskException.php index cee01cb..8ff64a0 100644 --- a/src/Exceptions/CdekScheduledTaskException.php +++ b/src/Exceptions/CdekScheduledTaskException.php @@ -4,7 +4,7 @@ class CdekScheduledTaskException extends \Cdek\Exceptions\CdekException { public function __construct( - string $message = '', + string $message, string $code = 'cdek_error', ?array $data = null ) diff --git a/src/Helpers/DBCoreTokenStorage.php b/src/Helpers/DBCoreTokenStorage.php index 90855fc..f6c10a0 100644 --- a/src/Helpers/DBCoreTokenStorage.php +++ b/src/Helpers/DBCoreTokenStorage.php @@ -10,9 +10,9 @@ class DBCoreTokenStorage extends TokenStorageContract { - private static string $tokenAdmin = ''; - private static string $tokenStatic = ''; - private static string $tokenFrontend = ''; + private static ?string $tokenAdmin = null; + private static ?string $tokenStatic = null; + private static ?string $tokenFrontend = null; private static string $apiUrlString; private static string $frontendUrlString; private static string $adminUrlString; @@ -25,10 +25,10 @@ class DBCoreTokenStorage extends TokenStorageContract */ final public function getToken(): string { - $token = $this->getTokenFromCache(); + $token = self::$tokenStatic; if (empty($token)) { - $token = $this->getTokenFromSettings(); + $token = $this->getTokenFromCache(); } if (empty($token)) { @@ -44,7 +44,7 @@ final public function getToken(): string * @throws CdekScheduledTaskException * @throws \JsonException */ - public function getPath() + public function getPath(): string { if(isset(static::$apiUrlString)){ return static::$apiUrlString; @@ -56,15 +56,19 @@ public function getPath() return static::$apiUrlString = $cache['endpoint']['common']; } - return static::$apiUrlString = $this->getEndPointFromToken($this->getToken()); - } + $this->updateToken(); - private function getTokenFromCache(): ?string - { - return !empty(self::$tokenStatic) ? self::$tokenStatic : null; + if(!isset(static::$apiUrlString)){ + throw new CdekScheduledTaskException( + '[CDEKDelivery] Failed to get token path', + 'cdek_error.token.path' + ); + } + + return static::$apiUrlString; } - private function getTokenFromSettings(): ?string + private function getTokenFromCache(): ?string { $cache = FileCache::getVars(); diff --git a/src/Managers/TaskManager.php b/src/Managers/TaskManager.php index 08ddc24..ca57c37 100644 --- a/src/Managers/TaskManager.php +++ b/src/Managers/TaskManager.php @@ -20,7 +20,15 @@ class TaskManager extends TaskContract ]; private array $taskCollection; - + private array $taskData = []; + + /** + * @param $taskId + * + * @throws CdekApiException + * @throws CdekScheduledTaskException + * @throws \JsonException + */ public function __construct($taskId) { parent::__construct($taskId); @@ -49,12 +57,6 @@ public static function registerAction(): void add_action(static::getName(), [static::class, 'init']); } - public function getErrors(): array - { - return self::$errorCollection[$this->taskId]; - } - - public static function registerTasks(): void { foreach (self::TASK_CLASSES as $arTaskClass) { @@ -64,7 +66,7 @@ public static function registerTasks(): void } } - public static function getTasksHooks() + public static function getTasksHooks(): array { return array_map( static fn($class) => $class::getName() === static::getName() ? @@ -77,7 +79,7 @@ public static function getTasksHooks() ); } - public static function addPluginScheduleEvents() + public static function addPluginScheduleEvents(): void { if (as_has_scheduled_action(Config::TASK_MANAGER_HOOK_NAME) !== false) { as_unschedule_action(Config::TASK_MANAGER_HOOK_NAME); @@ -102,8 +104,8 @@ private function startTask(TaskData $task): void $task->getName(), array_map( static fn($class) => $class::getName(), - self::TASK_CLASSES, - ), + self::TASK_CLASSES + ) ) ) { return; @@ -112,23 +114,27 @@ private function startTask(TaskData $task): void $task->createTaskWork(); } + /** + * @return void + * @throws CdekApiException + * @throws CdekScheduledTaskException + * @throws \JsonException + */ private function getResponse(): void { try { $response = (new CdekCoreApi())->taskManager(); } catch (CdekScheduledTaskException $e) { - self::$errorCollection[$this->taskId][] = $e->getMessage(); static::addPluginScheduleEvents(); - return; - } - if (empty($response['cursor'])) { - self::$errorCollection[$this->taskId][] = 'Cursor data not found'; + throw new CdekScheduledTaskException( + $e->getMessage(), + 'cdek_error.task.manager' + ); } if (empty($this->errorCollection)) { - self::$taskData[$this->taskId] = $response['data']; - self::$responseCursor[$this->taskId] = $response['cursor']; + $this->taskData = $response['data']; } } @@ -138,7 +144,7 @@ private function initTasks(): void return; } - foreach (self::$taskData[$this->taskId] as $data) { + foreach ($this->taskData as $data) { $this->taskCollection[] = new TaskData($data); } } diff --git a/src/Model/CoreRequestData.php b/src/Model/TaskOutputData.php similarity index 97% rename from src/Model/CoreRequestData.php rename to src/Model/TaskOutputData.php index b8c039e..19e8ed7 100644 --- a/src/Model/CoreRequestData.php +++ b/src/Model/TaskOutputData.php @@ -2,7 +2,7 @@ namespace Cdek\Model; -class CoreRequestData +class TaskOutputData { private ?string $status; private ?array $data; diff --git a/src/Uninstaller.php b/src/Uninstaller.php index 87ebf1c..bd94a62 100644 --- a/src/Uninstaller.php +++ b/src/Uninstaller.php @@ -2,12 +2,12 @@ namespace Cdek; -use Cdek\Cache\FileCache; +use Cdek\Actions\FlushTokenCacheAction; class Uninstaller { public function __invoke() { - FileCache::clear(); + (new FlushTokenCacheAction)(); } } From 4bf4e3cf4fbaf2dba0f99eb17f8030f6f6818787 Mon Sep 17 00:00:00 2001 From: Stas Demin Date: Thu, 13 Jun 2024 17:02:35 +0300 Subject: [PATCH 38/50] fix: remove error collection --- src/Contracts/TaskContract.php | 7 ++----- src/Managers/TaskManager.php | 4 ---- 2 files changed, 2 insertions(+), 9 deletions(-) diff --git a/src/Contracts/TaskContract.php b/src/Contracts/TaskContract.php index 55eab6b..4a1b54b 100644 --- a/src/Contracts/TaskContract.php +++ b/src/Contracts/TaskContract.php @@ -12,8 +12,7 @@ abstract class TaskContract { protected cdekCoreApi $cdekCoreApi; - protected static array $errorCollection = []; - protected array $taskMeta = []; + protected ?array $taskMeta = []; protected string $taskId; public function __construct(string $taskId) @@ -79,9 +78,7 @@ protected function initData($response): void return; } - if(empty(self::$errorCollection[$this->taskId])){ - $this->taskMeta = $response['data']['meta']; - } + $this->taskMeta = $response['data']['meta']; } protected function postponeTask(): void diff --git a/src/Managers/TaskManager.php b/src/Managers/TaskManager.php index ca57c37..d8554b8 100644 --- a/src/Managers/TaskManager.php +++ b/src/Managers/TaskManager.php @@ -140,10 +140,6 @@ private function getResponse(): void private function initTasks(): void { - if (!empty(self::$errorCollection)) { - return; - } - foreach ($this->taskData as $data) { $this->taskCollection[] = new TaskData($data); } From 5f82a15a91db2c63b14c781c34442808b299e40c Mon Sep 17 00:00:00 2001 From: Stas Demin Date: Fri, 14 Jun 2024 16:32:40 +0300 Subject: [PATCH 39/50] fix: task manager no more extends from Task Contract, type hints, method docs --- src/Actions/Schedule/CollectOrders.php | 2 +- src/Actions/Schedule/ReindexOrders.php | 2 +- src/Cache/FileCache.php | 9 +-- src/CdekCoreApi.php | 55 +++++++++---------- src/Contracts/TaskContract.php | 9 ++- src/Exceptions/CdekException.php | 3 +- src/Exceptions/CdekScheduledTaskException.php | 1 + src/Managers/TaskManager.php | 49 ++++++++++++++--- 8 files changed, 79 insertions(+), 51 deletions(-) diff --git a/src/Actions/Schedule/CollectOrders.php b/src/Actions/Schedule/CollectOrders.php index 46bef55..71ab6d1 100644 --- a/src/Actions/Schedule/CollectOrders.php +++ b/src/Actions/Schedule/CollectOrders.php @@ -15,7 +15,7 @@ public static function getName(): string return 'collect-orphaned-orders'; } - public function start() + public function start(): void { $query = new \WC_Order_Query( [ diff --git a/src/Actions/Schedule/ReindexOrders.php b/src/Actions/Schedule/ReindexOrders.php index 40482e4..a0e47d1 100644 --- a/src/Actions/Schedule/ReindexOrders.php +++ b/src/Actions/Schedule/ReindexOrders.php @@ -36,7 +36,7 @@ public static function getName(): string * @throws CdekScheduledTaskException * @throws \JsonException */ - public function start() + public function start(): void { if (empty($this->getTaskMeta())) { throw new CdekScheduledTaskException( diff --git a/src/Cache/FileCache.php b/src/Cache/FileCache.php index 660d305..0551fe6 100644 --- a/src/Cache/FileCache.php +++ b/src/Cache/FileCache.php @@ -20,12 +20,12 @@ public static function getVars(): ?array } /** - * @param $vars + * @param array|null $vars * * @return void * @throws CdekApiException */ - public static function putVars($vars): void + public static function putVars(?array $vars): void { if(empty($vars)){ return; @@ -33,7 +33,7 @@ public static function putVars($vars): void if(file_exists(Loader::getPluginPath() . DIRECTORY_SEPARATOR . self::CACHE_FILE_NAME)){ if(!is_writable(Loader::getPluginPath() . DIRECTORY_SEPARATOR . self::CACHE_FILE_NAME)){ - throw new CdekApiException('[CDEKDelivery] Failed check directory rights', + throw new CdekApiException('[CDEKDelivery] Failed check file rights', 'cdek_error.cache.rights', ['path' => Loader::getPluginPath() . DIRECTORY_SEPARATOR . self::CACHE_FILE_NAME], true); @@ -54,9 +54,6 @@ public static function putVars($vars): void fclose($logFile); } - /** - * @return void - */ public static function clear(): void { unlink(Loader::getPluginPath() . DIRECTORY_SEPARATOR . self::CACHE_FILE_NAME); diff --git a/src/CdekCoreApi.php b/src/CdekCoreApi.php index 5fd0274..8d33ba4 100644 --- a/src/CdekCoreApi.php +++ b/src/CdekCoreApi.php @@ -37,7 +37,6 @@ public function __construct( } /** - * @return array * @throws CdekApiException * @throws CdekScheduledTaskException * @throws \JsonException @@ -61,7 +60,7 @@ public function fetchShopToken(): array if (empty($response['body'])) { throw new CdekScheduledTaskException('[CDEKDelivery] Register shop failed', 'cdek_error.register.shop', - $response, + $response ); } @@ -93,33 +92,32 @@ public function fetchShopToken(): array } /** - * @param $data + * @param string|null $next * - * @return array|false|string|\WP_Error * @throws CdekApiException * @throws CdekScheduledTaskException * @throws \JsonException */ - public function taskManager($data = null) + public function taskManager(?string $next = null): array { - $response = $this->coreClient->sendCdekRequest($this->getShopApiUrl() . '/' . self::TASKS, - 'GET', - $this->tokenCoreStorage->getToken(), - $data); + $response = $this->coreClient->sendCdekRequest( + $this->getShopApiUrl() . '/' . self::TASKS . ($next === null ? '' : '?cursor=' . $next), + 'GET', + $this->tokenCoreStorage->getToken(), + ); return $this->initData($response); } /** - * @param $taskId - * @param TaskOutputData $data + * @param string $taskId + * @param TaskOutputData $data * - * @return array|false|string|\WP_Error - * @throws CdekApiException - * @throws CdekScheduledTaskException + * @throws \Cdek\Exceptions\CdekApiException + * @throws \Cdek\Exceptions\CdekScheduledTaskException * @throws \JsonException */ - public function taskInfo($taskId, TaskOutputData $data) + public function taskInfo(string $taskId, TaskOutputData $data): array { $response = $this->coreClient->sendCdekRequest( $this->getShopApiUrl() . '/' . self::TASKS . '/' . $taskId, @@ -135,15 +133,14 @@ public function taskInfo($taskId, TaskOutputData $data) } /** - * @param $taskId - * @param TaskOutputData $data + * @param string $taskId + * @param TaskOutputData $data * - * @return array|false|string|\WP_Error - * @throws CdekApiException - * @throws CdekScheduledTaskException + * @throws \Cdek\Exceptions\CdekApiException + * @throws \Cdek\Exceptions\CdekScheduledTaskException * @throws \JsonException */ - public function sendTaskData($taskId, TaskOutputData $data) + public function sendTaskData(string $taskId, TaskOutputData $data): array { $response = $this->coreClient->sendCdekRequest( $this->getShopApiUrl() . '/' . self::TASKS . '/' . $taskId, @@ -168,7 +165,6 @@ public function isServerError(): bool } /** - * @return mixed|string * @throws CdekApiException * @throws CdekScheduledTaskException * @throws \JsonException @@ -181,14 +177,13 @@ private function getShopApiUrl(): string /** * @param $response * - * @return array * @throws CdekScheduledTaskException */ private function initData($response): array { $decodeResponse = json_decode($response['body'], true); - $this->status = $response['response']['status']; + $this->status = $response['response']['code']; if ( !$this->isSuccessStatus() @@ -204,28 +199,28 @@ private function initData($response): array throw new CdekScheduledTaskException( '[CDEKDelivery] Failed to get core api response', 'cdek_error.core.response', - $response + $response, ); } - return $decodeResponse; + return $decodeResponse ?? []; } private function isSuccessStatus(): bool { - if($this->status === self::SUCCESS_STATUS){ + if ($this->status === self::SUCCESS_STATUS) { return true; } - if($this->status === self::FINISH_STATUS){ + if ($this->status === self::FINISH_STATUS) { return true; } - if($this->status === self::HAS_NEXT_INFO_STATUS){ + if ($this->status === self::HAS_NEXT_INFO_STATUS) { return true; } - if($this->status === self::EMPTY_ANSWER){ + if ($this->status === self::EMPTY_ANSWER) { return true; } diff --git a/src/Contracts/TaskContract.php b/src/Contracts/TaskContract.php index 4a1b54b..4cc13b7 100644 --- a/src/Contracts/TaskContract.php +++ b/src/Contracts/TaskContract.php @@ -23,14 +23,17 @@ public function __construct(string $taskId) abstract protected static function getName(): string; - abstract function start(); + abstract function start(): void; - public static function init($taskId = 'task_manager'): void + public static function init($taskId): void { $taskManager = new static($taskId); $taskManager->start(); } + /** + * @return void + */ public static function registerAction(): void { add_action( @@ -78,7 +81,7 @@ protected function initData($response): void return; } - $this->taskMeta = $response['data']['meta']; + $this->taskMeta = $response['data']['meta'] ?? []; } protected function postponeTask(): void diff --git a/src/Exceptions/CdekException.php b/src/Exceptions/CdekException.php index 66a7014..781a362 100644 --- a/src/Exceptions/CdekException.php +++ b/src/Exceptions/CdekException.php @@ -13,6 +13,7 @@ abstract class CdekException extends Exception { protected $code = 'cdek_error'; + protected bool $isSchedule = false; private ?array $data; public function __construct( @@ -25,7 +26,7 @@ public function __construct( $this->data = $data ?? []; $this->message = $message; - if ($stopPropagation && (defined('REST_REQUEST') || defined('DOING_CRON'))) { + if ($stopPropagation && (defined('REST_REQUEST') || $this->isSchedule)) { wp_die($this->getWpError()); } diff --git a/src/Exceptions/CdekScheduledTaskException.php b/src/Exceptions/CdekScheduledTaskException.php index 8ff64a0..597e9b1 100644 --- a/src/Exceptions/CdekScheduledTaskException.php +++ b/src/Exceptions/CdekScheduledTaskException.php @@ -3,6 +3,7 @@ namespace Cdek\Exceptions; class CdekScheduledTaskException extends \Cdek\Exceptions\CdekException { + protected bool $isSchedule = true; public function __construct( string $message, string $code = 'cdek_error', diff --git a/src/Managers/TaskManager.php b/src/Managers/TaskManager.php index d8554b8..f7a56a3 100644 --- a/src/Managers/TaskManager.php +++ b/src/Managers/TaskManager.php @@ -11,16 +11,15 @@ use Cdek\Exceptions\CdekScheduledTaskException; use Cdek\Model\TaskData; -class TaskManager extends TaskContract +class TaskManager { private const TASK_CLASSES = [ - self::class, ReindexOrders::class, CollectOrders::class, ]; - private array $taskCollection; private array $taskData = []; + private array $taskCursor = []; /** * @param $taskId @@ -29,9 +28,8 @@ class TaskManager extends TaskContract * @throws CdekScheduledTaskException * @throws \JsonException */ - public function __construct($taskId) + public function __construct() { - parent::__construct($taskId); $this->getResponse(); $this->initTasks(); } @@ -47,6 +45,12 @@ public function start(): void } } + public static function init(): void + { + $taskManager = new self(); + $taskManager->start(); + } + public static function getName(): string { return Config::TASK_MANAGER_HOOK_NAME; @@ -59,8 +63,11 @@ public static function registerAction(): void public static function registerTasks(): void { + self::registerAction(); + foreach (self::TASK_CLASSES as $arTaskClass) { if ('\\' . $arTaskClass instanceof TaskContract) { + /** @var TaskContract $arTaskClass */ '\\' . $arTaskClass::registerAction(); } } @@ -69,11 +76,11 @@ public static function registerTasks(): void public static function getTasksHooks(): array { return array_map( - static fn($class) => $class::getName() === static::getName() ? - static::getName() : + /** @var TaskContract $class */ + static fn($class) => sprintf('%s-%s', Config::TASK_MANAGER_HOOK_NAME, - $class::getName(), + $class::getName() ), self::TASK_CLASSES, ); @@ -103,6 +110,7 @@ private function startTask(TaskData $task): void if (!in_array( $task->getName(), array_map( + /** @var TaskContract $class */ static fn($class) => $class::getName(), self::TASK_CLASSES ) @@ -123,7 +131,7 @@ private function startTask(TaskData $task): void private function getResponse(): void { try { - $response = (new CdekCoreApi())->taskManager(); + $response = (new CdekCoreApi())->taskManager($this->taskCursor['next'] ?? null); } catch (CdekScheduledTaskException $e) { static::addPluginScheduleEvents(); @@ -133,8 +141,26 @@ private function getResponse(): void ); } + if( + !isset($response['cursor']) + || + !array_key_exists('current', $response['cursor']) + || + !array_key_exists('previous', $response['cursor']) + || + !array_key_exists('next', $response['cursor']) + || + !array_key_exists('count', $response['cursor']) + ){ + throw new CdekScheduledTaskException('[CDEKDelivery] Not found cursor params', + 'cdek_error.cursor.params', + $response, + ); + } + if (empty($this->errorCollection)) { $this->taskData = $response['data']; + $this->taskCursor = $response['cursor']; } } @@ -143,5 +169,10 @@ private function initTasks(): void foreach ($this->taskData as $data) { $this->taskCollection[] = new TaskData($data); } + + if(!empty($this->taskCursor['next'])){ + $this->getResponse(); + $this->initTasks(); + } } } From edf08a5a77d1e6677389b537d20eaae65d690a68 Mon Sep 17 00:00:00 2001 From: Stas Demin Date: Fri, 14 Jun 2024 16:45:20 +0300 Subject: [PATCH 40/50] fix: response only array + error catch as exception --- src/CdekCoreApi.php | 14 +++++++++++--- src/Transport/HttpCoreClient.php | 19 ++++++++++++++++--- 2 files changed, 27 insertions(+), 6 deletions(-) diff --git a/src/CdekCoreApi.php b/src/CdekCoreApi.php index 8d33ba4..0d665bc 100644 --- a/src/CdekCoreApi.php +++ b/src/CdekCoreApi.php @@ -161,7 +161,7 @@ public function sendTaskData(string $taskId, TaskOutputData $data): array public function isServerError(): bool { - return empty($this->status) || str_starts_with($this->status, self::FATAL_ERRORS_FIRST_NUMBER); + return empty($this->status) || strpos($this->status, self::FATAL_ERRORS_FIRST_NUMBER) === 0; } /** @@ -175,12 +175,20 @@ private function getShopApiUrl(): string } /** - * @param $response + * @param array $response * * @throws CdekScheduledTaskException */ - private function initData($response): array + private function initData(array $response): array { + if($response['error']){ + throw new CdekScheduledTaskException( + '[CDEKDelivery] Failed to get core api response', + 'cdek_error.core.response_error', + $response, + ); + } + $decodeResponse = json_decode($response['body'], true); $this->status = $response['response']['code']; diff --git a/src/Transport/HttpCoreClient.php b/src/Transport/HttpCoreClient.php index ecc8f10..698471e 100644 --- a/src/Transport/HttpCoreClient.php +++ b/src/Transport/HttpCoreClient.php @@ -13,13 +13,20 @@ class HttpCoreClient { + /** + * @param string $url + * @param string $method + * @param string $token + * @param array|null $data + * @param array $headers + */ public function sendCdekRequest( string $url, string $method, string $token, array $data = null, array $headers = [] - ) + ): array { $config = []; @@ -32,7 +39,13 @@ public function sendCdekRequest( return self::sendRequest($url, $method, $config, $headers); } - public function sendRequest(string $url, string $method, array $config = [], array $headers = []) + /** + * @param string $url + * @param string $method + * @param array $config + * @param array $headers + */ + public function sendRequest(string $url, string $method, array $config = [], array $headers = []): array { $resp = wp_remote_request( $url, @@ -60,7 +73,7 @@ public function sendRequest(string $url, string $method, array $config = [], arr header("X-Requester-IP: $ip"); } - return wp_json_encode(['error' => true, 'ip' => $ip]); + return ['error' => true, 'ip' => $ip]; } private static function generateUuid(): string From ce9259b94e87e0453e68e8cdb1874fc8695b4bf0 Mon Sep 17 00:00:00 2001 From: Stas Demin Date: Fri, 14 Jun 2024 16:52:58 +0300 Subject: [PATCH 41/50] fix: type and methods doc --- src/Actions/Schedule/CollectOrders.php | 1 - src/Helpers/DBCoreTokenStorage.php | 4 ---- src/Managers/TaskManager.php | 3 --- src/Model/TaskData.php | 21 ++++++--------------- src/Model/TaskOutputData.php | 4 ++-- 5 files changed, 8 insertions(+), 25 deletions(-) diff --git a/src/Actions/Schedule/CollectOrders.php b/src/Actions/Schedule/CollectOrders.php index 71ab6d1..c2f0ef9 100644 --- a/src/Actions/Schedule/CollectOrders.php +++ b/src/Actions/Schedule/CollectOrders.php @@ -4,7 +4,6 @@ use Cdek\Contracts\TaskContract; use Cdek\Model\TaskOutputData; -use Cdek\Model\Validate; class CollectOrders extends TaskContract { diff --git a/src/Helpers/DBCoreTokenStorage.php b/src/Helpers/DBCoreTokenStorage.php index f6c10a0..f4f1a26 100644 --- a/src/Helpers/DBCoreTokenStorage.php +++ b/src/Helpers/DBCoreTokenStorage.php @@ -18,7 +18,6 @@ class DBCoreTokenStorage extends TokenStorageContract private static string $adminUrlString; /** - * @return string * @throws CdekApiException * @throws CdekScheduledTaskException * @throws \JsonException @@ -39,7 +38,6 @@ final public function getToken(): string } /** - * @return mixed|string * @throws CdekApiException * @throws CdekScheduledTaskException * @throws \JsonException @@ -83,7 +81,6 @@ private function getTokenFromCache(): ?string } /** - * @return string * @throws CdekApiException * @throws CdekScheduledTaskException * @throws \JsonException @@ -106,7 +103,6 @@ final public function updateToken(): string } /** - * @return array * @throws CdekApiException * @throws CdekScheduledTaskException * @throws \JsonException diff --git a/src/Managers/TaskManager.php b/src/Managers/TaskManager.php index f7a56a3..35e3463 100644 --- a/src/Managers/TaskManager.php +++ b/src/Managers/TaskManager.php @@ -22,8 +22,6 @@ class TaskManager private array $taskCursor = []; /** - * @param $taskId - * * @throws CdekApiException * @throws CdekScheduledTaskException * @throws \JsonException @@ -123,7 +121,6 @@ private function startTask(TaskData $task): void } /** - * @return void * @throws CdekApiException * @throws CdekScheduledTaskException * @throws \JsonException diff --git a/src/Model/TaskData.php b/src/Model/TaskData.php index f554b06..2d8ecef 100644 --- a/src/Model/TaskData.php +++ b/src/Model/TaskData.php @@ -11,7 +11,7 @@ class TaskData private $schedule; private int $time; - public function __construct($requestData) + public function __construct(array $requestData) { $this->id = $requestData['id']; $this->name = $requestData['name']; @@ -24,7 +24,7 @@ public function createTaskWork() { $this->time += 5 * 60; - if ($this->isScheduleTask()) { + if ($this->isScheduledTask()) { if (false === as_has_scheduled_action($this->getName())) { as_schedule_cron_action( $this->time, @@ -43,31 +43,22 @@ public function createTaskWork() } } - /** - * @return mixed - */ - public function getId() + public function getId(): string { return $this->id; } - /** - * @return mixed - */ - public function getName() + public function getName(): string { return $this->name; } - /** - * @return mixed - */ - public function getSchedule() + public function getSchedule(): string { return $this->schedule; } - public function isScheduleTask() + public function isScheduledTask(): bool { return !empty($this->schedule); } diff --git a/src/Model/TaskOutputData.php b/src/Model/TaskOutputData.php index 19e8ed7..bb585d9 100644 --- a/src/Model/TaskOutputData.php +++ b/src/Model/TaskOutputData.php @@ -4,13 +4,13 @@ class TaskOutputData { - private ?string $status; + private string $status; private ?array $data; private ?int $currentPage; private ?int $totalPages; public function __construct( - ?string $status, + string $status, ?array $data = null, ?int $currentPage = null, ?int $totalPages = null From b7b52625ccc7409bc0ffab1378d7d1b9f055fdd4 Mon Sep 17 00:00:00 2001 From: Stas Demin Date: Fri, 14 Jun 2024 16:54:45 +0300 Subject: [PATCH 42/50] fix: type hint --- src/Contracts/TaskContract.php | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/src/Contracts/TaskContract.php b/src/Contracts/TaskContract.php index 4cc13b7..b3e29f2 100644 --- a/src/Contracts/TaskContract.php +++ b/src/Contracts/TaskContract.php @@ -45,7 +45,6 @@ public static function registerAction(): void } /** - * @return array * @throws CdekApiException * @throws CdekScheduledTaskException * @throws \JsonException @@ -70,11 +69,11 @@ protected function initTaskData(array $data = null): void } /** - * @param $response + * @param array $response * * @return void */ - protected function initData($response): void + protected function initData(array $response): void { if($this->cdekCoreApi->isServerError()){ $this->postponeTask(); From 3a704dac8d63e5558ec3fe89dc38babc8edc7ced Mon Sep 17 00:00:00 2001 From: Stas Demin Date: Mon, 17 Jun 2024 10:49:32 +0300 Subject: [PATCH 43/50] fix: fixes after review --- src/Actions/Schedule/CollectOrders.php | 87 +++-- src/Actions/Schedule/ReindexOrders.php | 2 - src/Cache/FileCache.php | 92 ++--- src/CdekApi.php | 508 +++++++++++++------------ src/CdekCoreApi.php | 416 ++++++++++---------- src/Contracts/TaskContract.php | 183 ++++----- src/Helpers/DBCoreTokenStorage.php | 194 +++++----- src/Managers/TaskManager.php | 288 +++++++------- src/Model/TaskData.php | 99 ++--- src/Model/TaskOutputData.php | 70 ++-- src/Transport/HttpClient.php | 17 + src/Uninstaller.php | 17 +- 12 files changed, 1020 insertions(+), 953 deletions(-) diff --git a/src/Actions/Schedule/CollectOrders.php b/src/Actions/Schedule/CollectOrders.php index c2f0ef9..0261241 100644 --- a/src/Actions/Schedule/CollectOrders.php +++ b/src/Actions/Schedule/CollectOrders.php @@ -1,53 +1,58 @@ 'id', - 'order' => 'ASC', - 'paginate' => true, - 'limit' => self::ORDERS_LIMIT, - 'return' => 'ids', - ], - ); - - for ($page = 1, $maxPages = 1; $page <= $maxPages; $page++) { - $query->set('page', $page); - $result = $query->get_orders(); - - $maxPages = $result->max_num_pages; - - $response = $this->cdekCoreApi->sendTaskData( - $this->taskId, - new TaskOutputData( - 'success', - [ - 'orders' => array_map( - static fn($order) => (string)$order, - $result->orders - ) - ], - $page, - $maxPages - ) + public static function getName(): string + { + return 'collect-orphaned-orders'; + } + + public function start(): void + { + $query = new \WC_Order_Query( + [ + 'orderby' => 'id', + 'order' => 'ASC', + 'paginate' => true, + 'limit' => self::ORDERS_LIMIT, + 'return' => 'ids', + ], ); - $this->initData($response); + for ($page = 1, $maxPages = 1; $page <= $maxPages; $page++) { + $query->set('page', $page); + $result = $query->get_orders(); + + $maxPages = $result->max_num_pages; + + $response = $this->cdekCoreApi->sendTaskData( + $this->taskId, + new TaskOutputData( + 'success', + [ + 'orders' => array_map( + static fn($order) => (string)$order, + $result->orders, + ) + ], + $page, + $maxPages + ) + ); + + $this->initData($response); + } } } } diff --git a/src/Actions/Schedule/ReindexOrders.php b/src/Actions/Schedule/ReindexOrders.php index a0e47d1..ee46781 100644 --- a/src/Actions/Schedule/ReindexOrders.php +++ b/src/Actions/Schedule/ReindexOrders.php @@ -17,8 +17,6 @@ class ReindexOrders extends TaskContract { - private Validate $error; - public function __construct(string $taskId) { parent::__construct($taskId); diff --git a/src/Cache/FileCache.php b/src/Cache/FileCache.php index 0551fe6..245a98d 100644 --- a/src/Cache/FileCache.php +++ b/src/Cache/FileCache.php @@ -1,61 +1,67 @@ Loader::getPluginPath() . DIRECTORY_SEPARATOR . self::CACHE_FILE_NAME], - true); + /** + * @param array|null $vars + * + * @return void + * @throws CdekApiException + */ + public static function putVars(?array $vars): void + { + if($vars === null){ + return; } - }else{ - if(!is_writable(Loader::getPluginPath())){ - throw new CdekApiException('[CDEKDelivery] Failed check directory rights', - 'cdek_error.cache.rights', - ['path' => Loader::getPluginPath()], - true); + + if(file_exists(Loader::getPluginPath() . DIRECTORY_SEPARATOR . self::CACHE_FILE_NAME)){ + if(!is_writable(Loader::getPluginPath() . DIRECTORY_SEPARATOR . self::CACHE_FILE_NAME)){ + throw new CdekApiException('[CDEKDelivery] Failed check file rights', + 'cdek_error.cache.rights', + ['path' => Loader::getPluginPath() . DIRECTORY_SEPARATOR . self::CACHE_FILE_NAME], + true); + } + }else{ + if(!is_writable(Loader::getPluginPath())){ + throw new CdekApiException('[CDEKDelivery] Failed check directory rights', + 'cdek_error.cache.rights', + ['path' => Loader::getPluginPath()], + true); + } } - } - $logFile = fopen( Loader::getPluginPath() . DIRECTORY_SEPARATOR . self::CACHE_FILE_NAME, 'w+'); + $logFile = fopen( Loader::getPluginPath() . DIRECTORY_SEPARATOR . self::CACHE_FILE_NAME, 'w+'); - fwrite($logFile, 'deliveryMethod = Helper::getActualShippingMethod($shippingInstanceId); - $this->apiUrl = $this->getApiUrl(); - - if (!isset($_ENV['CDEK_REST_API']) && $this->deliveryMethod->get_option('test_mode') === 'yes') { - $this->clientId = Config::TEST_CLIENT_ID; - $this->clientSecret = Config::TEST_CLIENT_SECRET; - } else { - $this->clientId = $this->deliveryMethod->get_option('client_id'); - $this->clientSecret = $this->deliveryMethod->get_option('client_secret'); - } - - $this->tokenStorage = $tokenStorage ?? new DBTokenStorage(); - } +namespace { - private function getApiUrl(): string - { - if ($this->deliveryMethod->get_option('test_mode') === 'yes') { - return $_ENV['CDEK_REST_API'] ?? Config::TEST_API_URL; - } + defined('ABSPATH') or exit; +} - return Config::API_URL; - } +namespace Cdek { - /** - * @throws \Cdek\Exceptions\CdekApiException - */ - final public function checkAuth(): bool - { - return (bool)$this->tokenStorage->getToken(); - } + use Cdek\Contracts\TokenStorageContract; + use Cdek\Enums\BarcodeFormat; + use Cdek\Exceptions\CdekApiException; + use Cdek\Exceptions\RestApiInvalidRequestException; + use Cdek\Helpers\DBTokenStorage; + use Cdek\Transport\HttpClient; + use WC_Shipping_Method; - /** - * @throws \Cdek\Exceptions\CdekApiException - * @throws \JsonException - */ - public function fetchToken(): string + class CdekApi { - $body = json_decode(HttpClient::sendRequest($this->getAuthUrl(), 'POST'), true); - if ($body === null || isset($body['error_description']) || isset($body['error'])) { - throw new CdekApiException('[CDEKDelivery] Failed to get the token', - 'cdek_error.token.auth', - $body, - true); + private const TOKEN_PATH = 'oauth/token'; + private const REGION_PATH = 'location/cities'; + private const ORDERS_PATH = 'orders/'; + private const PVZ_PATH = 'deliverypoints'; + private const CALC_LIST_PATH = 'calculator/tarifflist'; + private const CALC_PATH = 'calculator/tariff'; + private const WAYBILL_PATH = 'print/orders/'; + private const BARCODE_PATH = 'print/barcodes/'; + private const CALL_COURIER = 'intakes'; + + private string $apiUrl; + + private string $clientId; + private string $clientSecret; + private WC_Shipping_Method $deliveryMethod; + + private TokenStorageContract $tokenStorage; + + + public function __construct(?int $shippingInstanceId = null, ?TokenStorageContract $tokenStorage = null) + { + $this->deliveryMethod = Helper::getActualShippingMethod($shippingInstanceId); + $this->apiUrl = $this->getApiUrl(); + + if (!isset($_ENV['CDEK_REST_API']) && $this->deliveryMethod->get_option('test_mode') === 'yes') { + $this->clientId = Config::TEST_CLIENT_ID; + $this->clientSecret = Config::TEST_CLIENT_SECRET; + } else { + $this->clientId = $this->deliveryMethod->get_option('client_id'); + $this->clientSecret = $this->deliveryMethod->get_option('client_secret'); + } + + $this->tokenStorage = $tokenStorage ?? new DBTokenStorage(); } - return $body['access_token']; - } - private function getAuthUrl(): string - { - return sprintf('%s%s?%s', - $this->apiUrl, - self::TOKEN_PATH, - http_build_query([ - 'grant_type' => 'client_credentials', - 'client_id' => $this->clientId, - 'client_secret' => $this->clientSecret, - ])); - } + private function getApiUrl(): string + { + if ($this->deliveryMethod->get_option('test_mode') === 'yes') { + return $_ENV['CDEK_REST_API'] ?? Config::TEST_API_URL; + } - /** - * @throws \JsonException - * @throws \Cdek\Exceptions\CdekApiException - */ - final public function getOrder(string $uuid) - { - $url = $this->apiUrl . self::ORDERS_PATH . $uuid; + return Config::API_URL; + } - return HttpClient::sendCdekRequest($url, 'GET', $this->tokenStorage->getToken()); - } + /** + * @throws \Cdek\Exceptions\CdekApiException + */ + final public function checkAuth(): bool + { + return (bool)$this->tokenStorage->getToken(); + } - /** - * @throws \Cdek\Exceptions\RestApiInvalidRequestException - * @throws \Cdek\Exceptions\CdekApiException - */ - public function createOrder(array $params) - { - $url = $this->apiUrl . self::ORDERS_PATH; - $params['developer_key'] = Config::DEV_KEY; + /** + * @throws \Cdek\Exceptions\CdekApiException + * @throws \JsonException + */ + public function fetchToken(): string + { + $body = json_decode(HttpClient::sendRequest($this->getAuthUrl(), 'POST'), true); + if ($body === null || isset($body['error_description']) || isset($body['error'])) { + throw new CdekApiException('[CDEKDelivery] Failed to get the token', + 'cdek_error.token.auth', + $body, + true); + } + return $body['access_token']; + } - $result = json_decode(HttpClient::sendCdekRequest($url, 'POST', $this->tokenStorage->getToken(), $params), true); + private function getAuthUrl(): string + { + return sprintf('%s%s?%s', + $this->apiUrl, + self::TOKEN_PATH, + http_build_query([ + 'grant_type' => 'client_credentials', + 'client_id' => $this->clientId, + 'client_secret' => $this->clientSecret, + ])); + } - $request = $result['requests'][0]; + /** + * @throws \JsonException + * @throws \Cdek\Exceptions\CdekApiException + */ + final public function getOrder(string $uuid) + { + $url = $this->apiUrl . self::ORDERS_PATH . $uuid; - if ($request['state'] === 'INVALID') { - throw new RestApiInvalidRequestException(self::ORDERS_PATH, $request['errors']); + return HttpClient::sendCdekRequest($url, 'GET', $this->tokenStorage->getToken()); } - return $result; - } + /** + * @throws \Cdek\Exceptions\RestApiInvalidRequestException + * @throws \Cdek\Exceptions\CdekApiException + */ + public function createOrder(array $params) + { + $url = $this->apiUrl . self::ORDERS_PATH; + $params['developer_key'] = Config::DEV_KEY; - /** - * @throws \Cdek\Exceptions\CdekApiException - */ - public function getFileByLink($link) - { - return HttpClient::sendCdekRequest($link, 'GET', $this->tokenStorage->getToken(), null, true)['body']; - } + $result = json_decode(HttpClient::sendCdekRequest($url, 'POST', $this->tokenStorage->getToken(), $params), true); - /** - * @throws \JsonException - * @throws \Cdek\Exceptions\CdekApiException - */ - public function createWaybill($orderUuid) - { - $url = $this->apiUrl . self::WAYBILL_PATH; + $request = $result['requests'][0]; - return HttpClient::sendCdekRequest($url, 'POST', $this->tokenStorage->getToken(), ['orders' => ['order_uuid' => $orderUuid]]); - } + if ($request['state'] === 'INVALID') { + throw new RestApiInvalidRequestException(self::ORDERS_PATH, $request['errors']); + } - /** - * @throws \JsonException - * @throws \Cdek\Exceptions\CdekApiException - */ - public function createBarcode($orderUuid) - { - return HttpClient::sendCdekRequest($this->apiUrl . self::BARCODE_PATH, 'POST', $this->tokenStorage->getToken(), [ - 'orders' => ['order_uuid' => $orderUuid], - 'format' => BarcodeFormat::getByIndex($this->deliveryMethod->get_option('barcode_format', 0)), - ]); - } + return $result; + } - /** - * @throws \JsonException - * @throws \Cdek\Exceptions\CdekApiException - */ - public function getBarcode($uuid) - { - return HttpClient::sendCdekRequest($this->apiUrl . self::BARCODE_PATH . $uuid, 'GET', $this->tokenStorage->getToken()); - } + /** + * @throws \Cdek\Exceptions\CdekApiException + */ + public function getFileByLink($link) + { + return HttpClient::sendCdekRequest($link, 'GET', $this->tokenStorage->getToken(), null, true)['body']; + } - /** - * @throws \JsonException - * @throws \Cdek\Exceptions\CdekApiException - */ - public function getWaybill($uuid) - { - return HttpClient::sendCdekRequest($this->apiUrl . self::WAYBILL_PATH . $uuid, 'GET', $this->tokenStorage->getToken()); - } + /** + * @throws \JsonException + * @throws \Cdek\Exceptions\CdekApiException + */ + public function createWaybill($orderUuid) + { + $url = $this->apiUrl . self::WAYBILL_PATH; - /** - * @throws \JsonException - * @throws \Cdek\Exceptions\CdekApiException - */ - public function deleteOrder($uuid) - { - $url = $this->apiUrl . self::ORDERS_PATH . $uuid; + return HttpClient::sendCdekRequest($url, 'POST', $this->tokenStorage->getToken(), ['orders' => ['order_uuid' => $orderUuid]]); + } - return HttpClient::sendCdekRequest($url, 'DELETE', $this->tokenStorage->getToken()); - } + /** + * @throws \JsonException + * @throws \Cdek\Exceptions\CdekApiException + */ + public function createBarcode($orderUuid) + { + return HttpClient::sendCdekRequest($this->apiUrl . self::BARCODE_PATH, 'POST', $this->tokenStorage->getToken(), [ + 'orders' => ['order_uuid' => $orderUuid], + 'format' => BarcodeFormat::getByIndex($this->deliveryMethod->get_option('barcode_format', 0)), + ]); + } - /** - * @throws \JsonException - * @throws \Cdek\Exceptions\CdekApiException - */ - public function calculateTariffList($deliveryParam) - { - $url = $this->apiUrl . self::CALC_LIST_PATH; + /** + * @throws \JsonException + * @throws \Cdek\Exceptions\CdekApiException + */ + public function getBarcode($uuid) + { + return HttpClient::sendCdekRequest($this->apiUrl . self::BARCODE_PATH . $uuid, 'GET', $this->tokenStorage->getToken()); + } - $request = [ - 'type' => $deliveryParam['type'], - 'from_location' => $deliveryParam['from'], - 'to_location' => $deliveryParam['to'], - 'packages' => $deliveryParam['packages'], - ]; + /** + * @throws \JsonException + * @throws \Cdek\Exceptions\CdekApiException + */ + public function getWaybill($uuid) + { + return HttpClient::sendCdekRequest($this->apiUrl . self::WAYBILL_PATH . $uuid, 'GET', $this->tokenStorage->getToken()); + } - return HttpClient::sendCdekRequest($url, 'POST', $this->tokenStorage->getToken(), $request); - } + /** + * @throws \JsonException + * @throws \Cdek\Exceptions\CdekApiException + */ + public function deleteOrder($uuid) + { + $url = $this->apiUrl . self::ORDERS_PATH . $uuid; - /** - * @throws \Cdek\Exceptions\CdekApiException - * @throws \JsonException - */ - public function calculateTariff($deliveryParam) - { - $url = $this->apiUrl . self::CALC_PATH; - - $request = [ - 'type' => $deliveryParam['type'], - 'from_location' => $deliveryParam['from'], - 'tariff_code' => $deliveryParam['tariff_code'], - 'to_location' => $deliveryParam['to'], - 'packages' => $deliveryParam['packages'], - 'services' => array_key_exists('services', - $deliveryParam) ? $deliveryParam['services'] : [], - ]; - - return HttpClient::sendCdekRequest($url, 'POST', $this->tokenStorage->getToken(), $request); - } + return HttpClient::sendCdekRequest($url, 'DELETE', $this->tokenStorage->getToken()); + } - /** - * @throws \JsonException - * @throws \Cdek\Exceptions\CdekApiException - */ - public function getCityCode(string $city, ?string $postcode): int - { - $url = $this->apiUrl . self::REGION_PATH; + /** + * @throws \JsonException + * @throws \Cdek\Exceptions\CdekApiException + */ + public function calculateTariffList($deliveryParam) + { + $url = $this->apiUrl . self::CALC_LIST_PATH; + + $request = [ + 'type' => $deliveryParam['type'], + 'from_location' => $deliveryParam['from'], + 'to_location' => $deliveryParam['to'], + 'packages' => $deliveryParam['packages'], + ]; - //по запросу к api v2 климовск записан как "климовск микрорайон" поэтому добавляем "микрорайон" - if (mb_strtolower($city) === 'климовск') { - $city .= ' микрорайон'; + return HttpClient::sendCdekRequest($url, 'POST', $this->tokenStorage->getToken(), $request); } - $cityData = json_decode(HttpClient::sendCdekRequest($url, 'GET', $this->tokenStorage->getToken(), - ['city' => $city, 'postal_code' => $postcode]), false, 512, - JSON_THROW_ON_ERROR); + /** + * @throws \Cdek\Exceptions\CdekApiException + * @throws \JsonException + */ + public function calculateTariff($deliveryParam) + { + $url = $this->apiUrl . self::CALC_PATH; + + $request = [ + 'type' => $deliveryParam['type'], + 'from_location' => $deliveryParam['from'], + 'tariff_code' => $deliveryParam['tariff_code'], + 'to_location' => $deliveryParam['to'], + 'packages' => $deliveryParam['packages'], + 'services' => array_key_exists('services', + $deliveryParam) ? $deliveryParam['services'] : [], + ]; - if (empty($cityData)) { - return -1; + return HttpClient::sendCdekRequest($url, 'POST', $this->tokenStorage->getToken(), $request); } - return $cityData[0]->code; - } + /** + * @throws \JsonException + * @throws \Cdek\Exceptions\CdekApiException + */ + public function getCityCode(string $city, ?string $postcode): int + { + $url = $this->apiUrl . self::REGION_PATH; - /** - * @throws \Cdek\Exceptions\CdekApiException - * @throws \JsonException - */ - public function getOffices($filter) - { - $url = $this->apiUrl . self::PVZ_PATH; + //по запросу к api v2 климовск записан как "климовск микрорайон" поэтому добавляем "микрорайон" + if (mb_strtolower($city) === 'климовск') { + $city .= ' микрорайон'; + } - $result = HttpClient::sendCdekRequest($url, 'GET', $this->tokenStorage->getToken(), $filter, true); - if (!$result) { - return [ - 'success' => false, - 'message' => esc_html__("In this locality, delivery is available only for \"door-to-door\" tariffs. Select another locality to gain access to \"from warehouse\" tariffs.", 'cdekdelivery'), - ]; + $cityData = json_decode(HttpClient::sendCdekRequest($url, 'GET', $this->tokenStorage->getToken(), + ['city' => $city, 'postal_code' => $postcode]), false, 512, + JSON_THROW_ON_ERROR); + + if (empty($cityData)) { + return -1; + } + + return $cityData[0]->code; } - return $result; - } + /** + * @throws \Cdek\Exceptions\CdekApiException + * @throws \JsonException + */ + public function getOffices($filter) + { + $url = $this->apiUrl . self::PVZ_PATH; + + $result = HttpClient::sendCdekRequest($url, 'GET', $this->tokenStorage->getToken(), $filter, true); + if (!$result) { + return [ + 'success' => false, + 'message' => esc_html__("In this locality, delivery is available only for \"door-to-door\" tariffs. Select another locality to gain access to \"from warehouse\" tariffs.", 'cdekdelivery'), + ]; + } + + return $result; + } - /** - * @throws \JsonException - * @throws \Cdek\Exceptions\CdekApiException - */ - public function callCourier($param) - { - return HttpClient::sendCdekRequest($this->apiUrl . self::CALL_COURIER, 'POST', $this->tokenStorage->getToken(), $param); - } + /** + * @throws \JsonException + * @throws \Cdek\Exceptions\CdekApiException + */ + public function callCourier($param) + { + return HttpClient::sendCdekRequest($this->apiUrl . self::CALL_COURIER, 'POST', $this->tokenStorage->getToken(), $param); + } - /** - * @throws \Cdek\Exceptions\CdekApiException - * @throws \JsonException - */ - public function courierInfo($uuid) - { - return HttpClient::sendCdekRequest($this->apiUrl . self::CALL_COURIER . '/' . $uuid, 'GET', $this->tokenStorage->getToken()); - } + /** + * @throws \Cdek\Exceptions\CdekApiException + * @throws \JsonException + */ + public function courierInfo($uuid) + { + return HttpClient::sendCdekRequest($this->apiUrl . self::CALL_COURIER . '/' . $uuid, 'GET', $this->tokenStorage->getToken()); + } - /** - * @throws \Cdek\Exceptions\CdekApiException - * @throws \JsonException - */ - public function callCourierDelete($uuid) - { - return HttpClient::sendCdekRequest($this->apiUrl . self::CALL_COURIER . '/' . $uuid, - 'DELETE', - $this->tokenStorage->getToken()); + /** + * @throws \Cdek\Exceptions\CdekApiException + * @throws \JsonException + */ + public function callCourierDelete($uuid) + { + return HttpClient::sendCdekRequest($this->apiUrl . self::CALL_COURIER . '/' . $uuid, + 'DELETE', + $this->tokenStorage->getToken()); + } } } diff --git a/src/CdekCoreApi.php b/src/CdekCoreApi.php index 0d665bc..571d6d1 100644 --- a/src/CdekCoreApi.php +++ b/src/CdekCoreApi.php @@ -1,237 +1,243 @@ coreClient = new HttpCoreClient(); - $this->generalTokenStorage = $tokenStorage ?? new DBTokenStorage(); - $this->tokenCoreStorage = $tokenCoreStorage ?? new DBCoreTokenStorage(); - } - - /** - * @throws CdekApiException - * @throws CdekScheduledTaskException - * @throws \JsonException - */ - public function fetchShopToken(): array - { - $response = $this->coreClient->sendCdekRequest( - Config::API_CORE_URL . self::SHOP, - 'POST', - $this->generalTokenStorage->getToken(), - [ - 'name' => get_bloginfo('name'), - 'url' => [ - 'rest' => rest_url(), - 'home' => home_url(), - 'admin' => admin_url(), - ], - ], - ); +namespace { + defined('ABSPATH') or exit; +} - if (empty($response['body'])) { - throw new CdekScheduledTaskException('[CDEKDelivery] Register shop failed', - 'cdek_error.register.shop', - $response - ); - } +namespace Cdek { - $body = json_decode($response['body'], true); + use Cdek\Contracts\TokenStorageContract; + use Cdek\Exceptions\CdekApiException; + use Cdek\Exceptions\CdekScheduledTaskException; + use Cdek\Helpers\DBCoreTokenStorage; + use Cdek\Helpers\DBTokenStorage; + use Cdek\Model\TaskOutputData; + use Cdek\Transport\HttpCoreClient; - if (empty($body['data']['id'])) { - throw new CdekScheduledTaskException('[CDEKDelivery] Failed to get shop uuid', - 'cdek_error.uuid.auth', - $response, - ); + class CdekCoreApi + { + const SUCCESS_STATUS = 200; + const FINISH_STATUS = 201; + const HAS_NEXT_INFO_STATUS = 202; + const EMPTY_ANSWER = 204; + const UNKNOWN_METHOD = 404; + const FATAL_ERRORS_FIRST_NUMBER = 5; + private const TOKEN_PATH = 'cms/wordpress/shops/%s/token'; + private const SHOP = 'cms/wordpress/shops'; + private const TASKS = 'wordpress/tasks'; + public ?int $status; + private TokenStorageContract $generalTokenStorage; + private TokenStorageContract $tokenCoreStorage; + private HttpCoreClient $coreClient; + + public function __construct( + ?TokenStorageContract $tokenStorage = null, + ?TokenStorageContract $tokenCoreStorage = null + ) + { + $this->coreClient = new HttpCoreClient(); + $this->generalTokenStorage = $tokenStorage ?? new DBTokenStorage(); + $this->tokenCoreStorage = $tokenCoreStorage ?? new DBCoreTokenStorage(); } - $response = $this->coreClient->sendCdekRequest( - sprintf(Config::API_CORE_URL . self::TOKEN_PATH, $body['data']['id']), - 'POST', - $this->generalTokenStorage->getToken(), - ); - - $body = json_decode($response['body'], true); + /** + * @throws CdekApiException + * @throws CdekScheduledTaskException + * @throws \JsonException + */ + public function fetchShopToken(): array + { + $response = $this->coreClient->sendCdekRequest( + Config::API_CORE_URL . self::SHOP, + 'POST', + $this->generalTokenStorage->getToken(), + [ + 'name' => get_bloginfo('name'), + 'url' => [ + 'rest' => rest_url(), + 'home' => home_url(), + 'admin' => admin_url(), + ], + ], + ); - if ($body === null || !$body['success'] || empty($body['data'])) { - throw new CdekScheduledTaskException('[CDEKDelivery] Failed to get shop token', - 'cdek_error.shop_token.auth', - $body, + if (empty($response['body'])) { + throw new CdekScheduledTaskException('[CDEKDelivery] Register shop failed', + 'cdek_error.register.shop', + $response + ); + } + + $body = json_decode($response['body'], true); + + if (empty($body['data']['id'])) { + throw new CdekScheduledTaskException('[CDEKDelivery] Failed to get shop uuid', + 'cdek_error.uuid.auth', + $response, + ); + } + + $response = $this->coreClient->sendCdekRequest( + sprintf(Config::API_CORE_URL . self::TOKEN_PATH, $body['data']['id']), + 'POST', + $this->generalTokenStorage->getToken(), ); - } - return ['tokens' => $body['data']]; - } + $body = json_decode($response['body'], true); - /** - * @param string|null $next - * - * @throws CdekApiException - * @throws CdekScheduledTaskException - * @throws \JsonException - */ - public function taskManager(?string $next = null): array - { - $response = $this->coreClient->sendCdekRequest( - $this->getShopApiUrl() . '/' . self::TASKS . ($next === null ? '' : '?cursor=' . $next), - 'GET', - $this->tokenCoreStorage->getToken(), - ); + if ($body === null || !$body['success'] || empty($body['data'])) { + throw new CdekScheduledTaskException('[CDEKDelivery] Failed to get shop token', + 'cdek_error.shop_token.auth', + $body, + ); + } - return $this->initData($response); - } + return ['tokens' => $body['data']]; + } - /** - * @param string $taskId - * @param TaskOutputData $data - * - * @throws \Cdek\Exceptions\CdekApiException - * @throws \Cdek\Exceptions\CdekScheduledTaskException - * @throws \JsonException - */ - public function taskInfo(string $taskId, TaskOutputData $data): array - { - $response = $this->coreClient->sendCdekRequest( - $this->getShopApiUrl() . '/' . self::TASKS . '/' . $taskId, - 'GET', - $this->tokenCoreStorage->getToken(), - [ - 'status' => $data->getStatus(), - 'result' => $data->getData(), - ], - ); - - return $this->initData($response); - } + /** + * @param string|null $next + * + * @throws CdekApiException + * @throws CdekScheduledTaskException + * @throws \JsonException + */ + public function taskManager(?string $next = null): array + { + $response = $this->coreClient->sendCdekRequest( + $this->getShopApiUrl() . '/' . self::TASKS . ($next === null ? '' : '?cursor=' . $next), + 'GET', + $this->tokenCoreStorage->getToken(), + ); - /** - * @param string $taskId - * @param TaskOutputData $data - * - * @throws \Cdek\Exceptions\CdekApiException - * @throws \Cdek\Exceptions\CdekScheduledTaskException - * @throws \JsonException - */ - public function sendTaskData(string $taskId, TaskOutputData $data): array - { - $response = $this->coreClient->sendCdekRequest( - $this->getShopApiUrl() . '/' . self::TASKS . '/' . $taskId, - 'PUT', - $this->tokenCoreStorage->getToken(), - [ - 'status' => $data->getStatus(), - 'result' => $data->getData(), - ], - [ - 'X-Current-Page' => $data->getCurrentPage(), - 'X-Total-Pages' => $data->getTotalPages(), - ], - ); - - return $this->initData($response); - } + return $this->initData($response); + } - public function isServerError(): bool - { - return empty($this->status) || strpos($this->status, self::FATAL_ERRORS_FIRST_NUMBER) === 0; - } + /** + * @param string $taskId + * @param TaskOutputData $data + * + * @throws \Cdek\Exceptions\CdekApiException + * @throws \Cdek\Exceptions\CdekScheduledTaskException + * @throws \JsonException + */ + public function taskInfo(string $taskId, TaskOutputData $data): array + { + $response = $this->coreClient->sendCdekRequest( + $this->getShopApiUrl() . '/' . self::TASKS . '/' . $taskId, + 'GET', + $this->tokenCoreStorage->getToken(), + [ + 'status' => $data->getStatus(), + 'result' => $data->getData(), + ], + ); - /** - * @throws CdekApiException - * @throws CdekScheduledTaskException - * @throws \JsonException - */ - private function getShopApiUrl(): string - { - return $this->tokenCoreStorage->getPath(); - } + return $this->initData($response); + } - /** - * @param array $response - * - * @throws CdekScheduledTaskException - */ - private function initData(array $response): array - { - if($response['error']){ - throw new CdekScheduledTaskException( - '[CDEKDelivery] Failed to get core api response', - 'cdek_error.core.response_error', - $response, + /** + * @param string $taskId + * @param TaskOutputData $data + * + * @throws \Cdek\Exceptions\CdekApiException + * @throws \Cdek\Exceptions\CdekScheduledTaskException + * @throws \JsonException + */ + public function sendTaskData(string $taskId, TaskOutputData $data): array + { + $response = $this->coreClient->sendCdekRequest( + $this->getShopApiUrl() . '/' . self::TASKS . '/' . $taskId, + 'PUT', + $this->tokenCoreStorage->getToken(), + [ + 'status' => $data->getStatus(), + 'result' => $data->getData(), + ], + [ + 'X-Current-Page' => $data->getCurrentPage(), + 'X-Total-Pages' => $data->getTotalPages(), + ], ); + + return $this->initData($response); } - $decodeResponse = json_decode($response['body'], true); + public function isServerError(): bool + { + return empty($this->status) || strpos($this->status, self::FATAL_ERRORS_FIRST_NUMBER) === 0; + } - $this->status = $response['response']['code']; + /** + * @throws CdekApiException + * @throws CdekScheduledTaskException + * @throws \JsonException + */ + private function getShopApiUrl(): string + { + return $this->tokenCoreStorage->getOrRefreshApiPath(); + } - if ( - !$this->isSuccessStatus() - && - !$this->isServerError() - || - ( - empty($decodeResponse['success']) + /** + * @param array $response + * + * @throws CdekScheduledTaskException + */ + private function initData(array $response): array + { + if($response['error']){ + throw new CdekScheduledTaskException( + '[CDEKDelivery] Failed to get core api response', + 'cdek_error.core.response_error', + $response, + ); + } + + $decodeResponse = json_decode($response['body'], true); + + $this->status = $response['response']['code']; + + if ( + !$this->isSuccessStatus() && - $this->status !== self::EMPTY_ANSWER - ) - ) { - throw new CdekScheduledTaskException( - '[CDEKDelivery] Failed to get core api response', - 'cdek_error.core.response', - $response, - ); + !$this->isServerError() + || + ( + empty($decodeResponse['success']) + && + $this->status !== self::EMPTY_ANSWER + ) + ) { + throw new CdekScheduledTaskException( + '[CDEKDelivery] Failed to get core api response', + 'cdek_error.core.response', + $response, + ); + } + + return $decodeResponse ?? []; } - return $decodeResponse ?? []; - } + private function isSuccessStatus(): bool + { + if ($this->status === self::SUCCESS_STATUS) { + return true; + } - private function isSuccessStatus(): bool - { - if ($this->status === self::SUCCESS_STATUS) { - return true; - } + if ($this->status === self::FINISH_STATUS) { + return true; + } - if ($this->status === self::FINISH_STATUS) { - return true; - } + if ($this->status === self::HAS_NEXT_INFO_STATUS) { + return true; + } - if ($this->status === self::HAS_NEXT_INFO_STATUS) { - return true; - } + if ($this->status === self::EMPTY_ANSWER) { + return true; + } - if ($this->status === self::EMPTY_ANSWER) { - return true; + return false; } - - return false; } + } diff --git a/src/Contracts/TaskContract.php b/src/Contracts/TaskContract.php index b3e29f2..ce08523 100644 --- a/src/Contracts/TaskContract.php +++ b/src/Contracts/TaskContract.php @@ -1,110 +1,115 @@ cdekCoreApi = new CdekCoreApi(); - $this->taskId = $taskId; - } - - abstract protected static function getName(): string; - - abstract function start(): void; +namespace { + defined('ABSPATH') or exit; +} - public static function init($taskId): void - { - $taskManager = new static($taskId); - $taskManager->start(); - } +namespace Cdek\Contracts { - /** - * @return void - */ - public static function registerAction(): void - { - add_action( - sprintf('%s-%s', Config::TASK_MANAGER_HOOK_NAME, static::getName()), - [static::class, 'init'], - 20, - 1, - ); - } + use Cdek\CdekCoreApi; + use Cdek\Config; + use Cdek\Exceptions\CdekApiException; + use Cdek\Exceptions\CdekScheduledTaskException; + use Cdek\Model\TaskOutputData; + use Cdek\Model\TaskData; - /** - * @throws CdekApiException - * @throws CdekScheduledTaskException - * @throws \JsonException - */ - protected function getTaskMeta(): array + abstract class TaskContract { - if(empty($this->taskMeta)){ - $this->initTaskData(); + protected cdekCoreApi $cdekCoreApi; + protected ?array $taskMeta = []; + protected string $taskId; + + public function __construct(string $taskId) + { + $this->cdekCoreApi = new CdekCoreApi(); + $this->taskId = $taskId; } - return $this->taskMeta ?? []; - } + abstract protected static function getName(): string; - /** - * @throws CdekScheduledTaskException - * @throws CdekApiException - * @throws \JsonException - */ - protected function initTaskData(array $data = null): void - { - $this->initData($this->cdekCoreApi->taskInfo($this->taskId, new TaskOutputData('success', $data))); - } + abstract function start(): void; - /** - * @param array $response - * - * @return void - */ - protected function initData(array $response): void - { - if($this->cdekCoreApi->isServerError()){ - $this->postponeTask(); - return; + public static function init(string $taskId): void + { + $taskManager = new static($taskId); + $taskManager->start(); } - $this->taskMeta = $response['data']['meta'] ?? []; - } + /** + * @return void + */ + public static function registerAction(): void + { + add_action( + sprintf('%s-%s', Config::TASK_MANAGER_HOOK_NAME, static::getName()), + [static::class, 'init'], + 20, + 1, + ); + } - protected function postponeTask(): void - { - $hooks = as_get_scheduled_actions( - [ - 'hook' => sprintf('%s-%s', Config::TASK_MANAGER_HOOK_NAME, static::getName()), - 'status' => \ActionScheduler_Store::STATUS_PENDING, - ], - ); - - if(empty($hooks)){ - return; + /** + * @throws CdekApiException + * @throws CdekScheduledTaskException + * @throws \JsonException + */ + protected function getTaskMeta(): array + { + if(empty($this->taskMeta)){ + $this->initTaskData(); + } + + return $this->taskMeta ?? []; + } + + /** + * @throws CdekScheduledTaskException + * @throws CdekApiException + * @throws \JsonException + */ + protected function initTaskData(array $data = null): void + { + $this->initData($this->cdekCoreApi->taskInfo($this->taskId, new TaskOutputData('success', $data))); } - $hook = reset($hooks); + /** + * @param array $response + * + * @return void + */ + protected function initData(array $response): void + { + if($this->cdekCoreApi->isServerError()){ + $this->postponeTask(); + return; + } + + $this->taskMeta = $response['data']['meta'] ?? []; + } - if(!$hook->get_schedule() instanceof \ActionScheduler_CronSchedule){ - (new TaskData( + protected function postponeTask(): void + { + $hooks = as_get_scheduled_actions( [ - 'id' => $this->taskId, - 'name' => sprintf('%s-%s', Config::TASK_MANAGER_HOOK_NAME, static::getName()), + 'hook' => sprintf('%s-%s', Config::TASK_MANAGER_HOOK_NAME, static::getName()), + 'status' => \ActionScheduler_Store::STATUS_PENDING, ], - ))->createTaskWork(); + ); + + if(empty($hooks)){ + return; + } + + $hook = reset($hooks); + + if(!$hook->get_schedule() instanceof \ActionScheduler_CronSchedule){ + (new TaskData( + [ + 'id' => $this->taskId, + 'name' => sprintf('%s-%s', Config::TASK_MANAGER_HOOK_NAME, static::getName()), + ], + ))->createTaskWork(); + } } } } diff --git a/src/Helpers/DBCoreTokenStorage.php b/src/Helpers/DBCoreTokenStorage.php index f4f1a26..0b50c74 100644 --- a/src/Helpers/DBCoreTokenStorage.php +++ b/src/Helpers/DBCoreTokenStorage.php @@ -1,122 +1,128 @@ getTokenFromCache(); - } - if (empty($token)) { - $token = $this->updateToken(); - } +namespace Cdek\Helpers { - return 'Bearer ' . $token; - } + use Cdek\Cache\FileCache; + use Cdek\CdekCoreApi; + use Cdek\Contracts\TokenStorageContract; + use Cdek\Exceptions\CdekApiException; + use Cdek\Exceptions\CdekScheduledTaskException; - /** - * @throws CdekApiException - * @throws CdekScheduledTaskException - * @throws \JsonException - */ - public function getPath(): string + class DBCoreTokenStorage extends TokenStorageContract { - if(isset(static::$apiUrlString)){ - return static::$apiUrlString; + private static ?string $tokenAdmin = null; + private static ?string $tokenStatic = null; + private static ?string $tokenFrontend = null; + private static string $apiUrlString; + private static string $frontendUrlString; + private static string $adminUrlString; + + /** + * @throws CdekApiException + * @throws CdekScheduledTaskException + * @throws \JsonException + */ + final public function getToken(): string + { + $token = self::$tokenStatic; + + if (empty($token)) { + $token = $this->getTokenFromCache(); + } + + if (empty($token)) { + $token = $this->updateToken(); + } + + return 'Bearer ' . $token; } - $cache = FileCache::getVars(); + /** + * @throws CdekApiException + * @throws CdekScheduledTaskException + * @throws \JsonException + */ + public function getOrRefreshApiPath(): string + { + if(isset(static::$apiUrlString)){ + return static::$apiUrlString; + } - if (!empty($cache['endpoint']['common'])) { - return static::$apiUrlString = $cache['endpoint']['common']; - } + $cache = FileCache::getVars(); + + if (!empty($cache['endpoint']['common'])) { + return static::$apiUrlString = $cache['endpoint']['common']; + } + + $this->updateToken(); - $this->updateToken(); + if(!isset(static::$apiUrlString)){ + throw new CdekScheduledTaskException( + '[CDEKDelivery] Failed to get token path', + 'cdek_error.token.path' + ); + } - if(!isset(static::$apiUrlString)){ - throw new CdekScheduledTaskException( - '[CDEKDelivery] Failed to get token path', - 'cdek_error.token.path' - ); + return static::$apiUrlString; } - return static::$apiUrlString; - } + private function getTokenFromCache(): ?string + { + $cache = FileCache::getVars(); - private function getTokenFromCache(): ?string - { - $cache = FileCache::getVars(); + if (empty($cache['tokens'])) { + return null; + } - if (empty($cache['tokens'])) { - return null; + self::$tokenAdmin = $cache['tokens']['admin']; + self::$tokenStatic = $cache['tokens']['common']; + self::$tokenFrontend = $cache['tokens']['frontend']; + return self::$tokenStatic; } - self::$tokenAdmin = $cache['tokens']['admin']; - self::$tokenStatic = $cache['tokens']['common']; - self::$tokenFrontend = $cache['tokens']['frontend']; - return self::$tokenStatic; - } + /** + * @throws CdekApiException + * @throws CdekScheduledTaskException + * @throws \JsonException + */ + final public function updateToken(): string + { + $tokenApi = $this->fetchTokenFromApi(); - /** - * @throws CdekApiException - * @throws CdekScheduledTaskException - * @throws \JsonException - */ - final public function updateToken(): string - { - $tokenApi = $this->fetchTokenFromApi(); + self::$tokenAdmin = $tokenApi['tokens']['admin']; + self::$tokenStatic = $tokenApi['tokens']['common']; + self::$tokenFrontend = $tokenApi['tokens']['frontend']; - self::$tokenAdmin = $tokenApi['tokens']['admin']; - self::$tokenStatic = $tokenApi['tokens']['common']; - self::$tokenFrontend = $tokenApi['tokens']['frontend']; + $tokenApi['endpoint']['admin'] = static::$adminUrlString = $this->getEndPointFromToken(self::$tokenAdmin); + $tokenApi['endpoint']['common'] = static::$apiUrlString = $this->getEndPointFromToken(self::$tokenStatic); + $tokenApi['endpoint']['frontend'] = static::$frontendUrlString = $this->getEndPointFromToken(self::$tokenFrontend); - $tokenApi['endpoint']['admin'] = static::$adminUrlString = $this->getEndPointFromToken(self::$tokenAdmin); - $tokenApi['endpoint']['common'] = static::$apiUrlString = $this->getEndPointFromToken(self::$tokenStatic); - $tokenApi['endpoint']['frontend'] = static::$frontendUrlString = $this->getEndPointFromToken(self::$tokenFrontend); + FileCache::putVars($tokenApi); - FileCache::putVars($tokenApi); + return self::$tokenStatic; + } - return self::$tokenStatic; - } + /** + * @throws CdekApiException + * @throws CdekScheduledTaskException + * @throws \JsonException + */ + final public function fetchTokenFromApi(): array + { + return (new CdekCoreApi)->fetchShopToken(); + } - /** - * @throws CdekApiException - * @throws CdekScheduledTaskException - * @throws \JsonException - */ - final public function fetchTokenFromApi(): array - { - return (new CdekCoreApi)->fetchShopToken(); - } + private function getEndPointFromToken(string $token): ?string + { + $arToken = explode('.', $token); - private function getEndPointFromToken($token) - { - $arToken = explode('.', $token); + return json_decode(base64_decode($arToken[count($arToken) - 1]), true)['endpoint'] ?? null; + } - return json_decode(base64_decode($arToken[count($arToken) - 1]), true)['endpoint']; } - } diff --git a/src/Managers/TaskManager.php b/src/Managers/TaskManager.php index 35e3463..3f18834 100644 --- a/src/Managers/TaskManager.php +++ b/src/Managers/TaskManager.php @@ -1,175 +1,179 @@ getResponse(); - $this->initTasks(); - } +namespace { + defined('ABSPATH') or exit; +} + +namespace Cdek\Managers{ - public function start(): void + use Cdek\Actions\Schedule\CollectOrders; + use Cdek\Actions\Schedule\ReindexOrders; + use Cdek\CdekCoreApi; + use Cdek\Config; + use Cdek\Contracts\TaskContract; + use Cdek\Exceptions\CdekApiException; + use Cdek\Exceptions\CdekScheduledTaskException; + use Cdek\Model\TaskData; + + class TaskManager { - if(!isset($this->taskCollection)){ - return; + private const TASK_CLASSES = [ + ReindexOrders::class, + CollectOrders::class, + ]; + private array $taskCollection; + private array $taskData = []; + private array $taskCursor = []; + + /** + * @throws CdekApiException + * @throws CdekScheduledTaskException + * @throws \JsonException + */ + public function __construct() + { + $this->getResponse(); + $this->initTasks(); } - foreach ($this->taskCollection as $task) { - $this->startTask($task); + public function start(): void + { + if(!isset($this->taskCollection)){ + return; + } + + foreach ($this->taskCollection as $task) { + $this->startTask($task); + } } - } - public static function init(): void - { - $taskManager = new self(); - $taskManager->start(); - } + public static function init(): void + { + $taskManager = new self(); + $taskManager->start(); + } - public static function getName(): string - { - return Config::TASK_MANAGER_HOOK_NAME; - } + public static function getName(): string + { + return Config::TASK_MANAGER_HOOK_NAME; + } - public static function registerAction(): void - { - add_action(static::getName(), [static::class, 'init']); - } + public static function registerAction(): void + { + add_action(static::getName(), [static::class, 'init']); + } - public static function registerTasks(): void - { - self::registerAction(); + public static function registerTasks(): void + { + self::registerAction(); - foreach (self::TASK_CLASSES as $arTaskClass) { - if ('\\' . $arTaskClass instanceof TaskContract) { - /** @var TaskContract $arTaskClass */ - '\\' . $arTaskClass::registerAction(); + foreach (self::TASK_CLASSES as $arTaskClass) { + if (is_callable([$arTaskClass, 'registerAction'])){ + $arTaskClass::registerAction(); + } } } - } - public static function getTasksHooks(): array - { - return array_map( - /** @var TaskContract $class */ - static fn($class) => - sprintf('%s-%s', + public static function getTasksHooks(): array + { + $arNames = []; + + foreach (self::TASK_CLASSES as $class) { + if (is_callable([$class, 'getName'])) { + $arNames[] = sprintf( + '%s-%s', Config::TASK_MANAGER_HOOK_NAME, - $class::getName() - ), - self::TASK_CLASSES, - ); - } + $class::getName(), + ); + } + } - public static function addPluginScheduleEvents(): void - { - if (as_has_scheduled_action(Config::TASK_MANAGER_HOOK_NAME) !== false) { - as_unschedule_action(Config::TASK_MANAGER_HOOK_NAME); + return $arNames; } - $dateTime = new \DateTime('now + 1 hour'); + public static function addPluginScheduleEvents(): void + { + if (as_has_scheduled_action(Config::TASK_MANAGER_HOOK_NAME) !== false) { + as_unschedule_action(Config::TASK_MANAGER_HOOK_NAME); + } - as_schedule_cron_action( - time(), - $dateTime->format('i') . ' ' . $dateTime->format('H') . ' * * *', - Config::TASK_MANAGER_HOOK_NAME, - [], - '', - true, - ); + $dateTime = new \DateTime('now + 1 hour'); - } + as_schedule_cron_action( + time(), + $dateTime->format('i') . ' ' . $dateTime->format('H') . ' * * *', + Config::TASK_MANAGER_HOOK_NAME, + [], + '', + true, + ); - private function startTask(TaskData $task): void - { - if (!in_array( - $task->getName(), - array_map( - /** @var TaskContract $class */ - static fn($class) => $class::getName(), - self::TASK_CLASSES - ) - ) - ) { - return; } - $task->createTaskWork(); - } - - /** - * @throws CdekApiException - * @throws CdekScheduledTaskException - * @throws \JsonException - */ - private function getResponse(): void - { - try { - $response = (new CdekCoreApi())->taskManager($this->taskCursor['next'] ?? null); - } catch (CdekScheduledTaskException $e) { - static::addPluginScheduleEvents(); - - throw new CdekScheduledTaskException( - $e->getMessage(), - 'cdek_error.task.manager' - ); + private function startTask(TaskData $task): void + { + foreach (self::TASK_CLASSES as $class){ + if ( + is_callable([$class, 'getName']) + && + $task->getName() === $class::getName() + ) { + $task->createTaskWork(); + } + } } - if( - !isset($response['cursor']) - || - !array_key_exists('current', $response['cursor']) - || - !array_key_exists('previous', $response['cursor']) - || - !array_key_exists('next', $response['cursor']) - || - !array_key_exists('count', $response['cursor']) - ){ - throw new CdekScheduledTaskException('[CDEKDelivery] Not found cursor params', - 'cdek_error.cursor.params', - $response, - ); - } + /** + * @throws CdekApiException + * @throws CdekScheduledTaskException + * @throws \JsonException + */ + private function getResponse(): void + { + try { + $response = (new CdekCoreApi())->taskManager($this->taskCursor['next'] ?? null); + } catch (CdekScheduledTaskException $e) { + static::addPluginScheduleEvents(); + + throw new CdekScheduledTaskException( + $e->getMessage(), + 'cdek_error.task.manager' + ); + } - if (empty($this->errorCollection)) { - $this->taskData = $response['data']; - $this->taskCursor = $response['cursor']; - } - } + if( + !isset($response['cursor']) + || + !array_key_exists('current', $response['cursor']) + || + !array_key_exists('previous', $response['cursor']) + || + !array_key_exists('next', $response['cursor']) + || + !array_key_exists('count', $response['cursor']) + ){ + throw new CdekScheduledTaskException('[CDEKDelivery] Not found cursor params', + 'cdek_error.cursor.params', + $response, + ); + } - private function initTasks(): void - { - foreach ($this->taskData as $data) { - $this->taskCollection[] = new TaskData($data); + if (empty($this->errorCollection)) { + $this->taskData = $response['data']; + $this->taskCursor = $response['cursor']; + } } - if(!empty($this->taskCursor['next'])){ - $this->getResponse(); - $this->initTasks(); + private function initTasks(): void + { + foreach ($this->taskData as $data) { + $this->taskCollection[] = new TaskData($data); + } + + if(!empty($this->taskCursor['next'])){ + $this->getResponse(); + $this->initTasks(); + } } } } diff --git a/src/Model/TaskData.php b/src/Model/TaskData.php index 2d8ecef..abac114 100644 --- a/src/Model/TaskData.php +++ b/src/Model/TaskData.php @@ -1,66 +1,71 @@ id = $requestData['id']; - $this->name = $requestData['name']; - $this->schedule = $requestData['schedule']; + private string $id; + private string $name; + private ?string $schedule; + private int $time; - $this->time = time(); - } + public function __construct(array $requestData) + { + $this->id = $requestData['id']; + $this->name = $requestData['name']; + $this->schedule = $requestData['schedule']; - public function createTaskWork() - { - $this->time += 5 * 60; + $this->time = time(); + } + + public function createTaskWork(): void + { + $this->time += 5 * 60; - if ($this->isScheduledTask()) { - if (false === as_has_scheduled_action($this->getName())) { - as_schedule_cron_action( - $this->time, - $this->getSchedule(), + if ($this->isScheduledTask()) { + if (false === as_has_scheduled_action($this->getName())) { + as_schedule_cron_action( + $this->time, + $this->getSchedule(), + sprintf('%s-%s', Config::TASK_MANAGER_HOOK_NAME, static::getName()), + [$this->getId()], + '', + true, + ); + } + } else { + as_enqueue_async_action( sprintf('%s-%s', Config::TASK_MANAGER_HOOK_NAME, static::getName()), - [$this->getId()], - '', - true, + [$this->getId()] ); } - } else { - as_enqueue_async_action( - sprintf('%s-%s', Config::TASK_MANAGER_HOOK_NAME, static::getName()), - [$this->getId()] - ); } - } - public function getId(): string - { - return $this->id; - } + public function getId(): string + { + return $this->id; + } - public function getName(): string - { - return $this->name; - } + public function getName(): string + { + return $this->name; + } - public function getSchedule(): string - { - return $this->schedule; - } + public function getSchedule(): ?string + { + return $this->schedule; + } - public function isScheduledTask(): bool - { - return !empty($this->schedule); - } + public function isScheduledTask(): bool + { + return $this->schedule !== null; + } + } } diff --git a/src/Model/TaskOutputData.php b/src/Model/TaskOutputData.php index bb585d9..f756b5a 100644 --- a/src/Model/TaskOutputData.php +++ b/src/Model/TaskOutputData.php @@ -1,43 +1,47 @@ status = $status; - $this->data = $data; - $this->currentPage = $currentPage; - $this->totalPages = $totalPages; - } + public function __construct( + string $status, + ?array $data = null, + ?int $currentPage = null, + ?int $totalPages = null + ){ + $this->status = $status; + $this->data = $data; + $this->currentPage = $currentPage; + $this->totalPages = $totalPages; + } - public function getStatus(): string - { - return $this->status; - } + public function getStatus(): string + { + return $this->status; + } - public function getData(): ?array - { - return $this->data; - } + public function getData(): ?array + { + return $this->data; + } - public function getCurrentPage(): ?int - { - return $this->currentPage; - } + public function getCurrentPage(): ?int + { + return $this->currentPage; + } - public function getTotalPages(): ?int - { - return $this->totalPages; + public function getTotalPages(): ?int + { + return $this->totalPages; + } } } diff --git a/src/Transport/HttpClient.php b/src/Transport/HttpClient.php index 312c4cc..2306cc2 100644 --- a/src/Transport/HttpClient.php +++ b/src/Transport/HttpClient.php @@ -13,6 +13,15 @@ class HttpClient { + /** + * @param string $url + * @param string $method + * @param string $token + * @param array|null $data + * @param bool $plain + * + * @return array|string + */ public static function sendCdekRequest( string $url, string $method, @@ -35,6 +44,14 @@ public static function sendCdekRequest( return self::sendRequest($url, $method, $config, $plain); } + /** + * @param string $url + * @param string $method + * @param array $config + * @param bool $plain + * + * @return array|string + */ public static function sendRequest(string $url, string $method, array $config = [], bool $plain = false) { $pluginVersion = Loader::getPluginVersion(); diff --git a/src/Uninstaller.php b/src/Uninstaller.php index bd94a62..523fdb9 100644 --- a/src/Uninstaller.php +++ b/src/Uninstaller.php @@ -1,13 +1,18 @@ Date: Mon, 17 Jun 2024 11:15:31 +0300 Subject: [PATCH 44/50] fix: exceptions fixed --- src/Exceptions/CdekException.php | 3 +- src/Exceptions/CdekScheduledTaskException.php | 30 ++++++++++++------- 2 files changed, 21 insertions(+), 12 deletions(-) diff --git a/src/Exceptions/CdekException.php b/src/Exceptions/CdekException.php index 781a362..7416a1f 100644 --- a/src/Exceptions/CdekException.php +++ b/src/Exceptions/CdekException.php @@ -13,7 +13,6 @@ abstract class CdekException extends Exception { protected $code = 'cdek_error'; - protected bool $isSchedule = false; private ?array $data; public function __construct( @@ -26,7 +25,7 @@ public function __construct( $this->data = $data ?? []; $this->message = $message; - if ($stopPropagation && (defined('REST_REQUEST') || $this->isSchedule)) { + if ($stopPropagation && defined('REST_REQUEST')) { wp_die($this->getWpError()); } diff --git a/src/Exceptions/CdekScheduledTaskException.php b/src/Exceptions/CdekScheduledTaskException.php index 597e9b1..827e46d 100644 --- a/src/Exceptions/CdekScheduledTaskException.php +++ b/src/Exceptions/CdekScheduledTaskException.php @@ -1,15 +1,25 @@ add($code, $message, $data); + wp_die($error); + } } } From ae7b17bfedd502e845dcfdcc7af50b840c448710 Mon Sep 17 00:00:00 2001 From: Stas Demin Date: Mon, 17 Jun 2024 11:23:51 +0300 Subject: [PATCH 45/50] fix: exception add $stopPropagation --- src/Exceptions/CdekScheduledTaskException.php | 16 +++++++++++----- 1 file changed, 11 insertions(+), 5 deletions(-) diff --git a/src/Exceptions/CdekScheduledTaskException.php b/src/Exceptions/CdekScheduledTaskException.php index 827e46d..f73cba8 100644 --- a/src/Exceptions/CdekScheduledTaskException.php +++ b/src/Exceptions/CdekScheduledTaskException.php @@ -8,18 +8,24 @@ namespace Cdek\Exceptions{ use WP_Error; + use Exception; - class CdekScheduledTaskException + class CdekScheduledTaskException extends Exception { public function __construct( string $message, string $code = 'cdek_error', - ?array $data = null + ?array $data = null, + bool $stopPropagation = true ) { - $error = new WP_Error('cdek_error', 'Error happened at CDEKDelivery'); - $error->add($code, $message, $data); - wp_die($error); + if($stopPropagation){ + $error = new WP_Error('cdek_error', 'Error happened at CDEKDelivery'); + $error->add($code, $message, $data); + wp_die($error); + } + + parent::__construct($message); } } } From 88f038913efa830a7b2993994977709b9d8dd4ba Mon Sep 17 00:00:00 2001 From: Stas Demin Date: Mon, 17 Jun 2024 11:49:58 +0300 Subject: [PATCH 46/50] fix: replace order scripts to meta boxes class --- src/UI/Admin.php | 14 -------------- src/UI/MetaBoxes.php | 19 +++++++++++++------ 2 files changed, 13 insertions(+), 20 deletions(-) diff --git a/src/UI/Admin.php b/src/UI/Admin.php index 715c837..56f576d 100644 --- a/src/UI/Admin.php +++ b/src/UI/Admin.php @@ -63,23 +63,9 @@ public static function registerAdminScripts(): void ]); } - public static function registerOrderScripts(): void - { - global $plugin_page, $pagenow; - - // Not on an Orders page. - if ('admin.php' !== $pagenow || 0 !== strpos($plugin_page, 'wc-orders')) { - return; - } - - Helper::enqueueScript('cdek-admin-create-order', 'cdek-create-order', true); - } - public function __invoke(): void { add_action('load-woocommerce_page_wc-settings', [__CLASS__, 'registerAdminScripts']); - - add_action('admin_enqueue_scripts', [__CLASS__, 'registerOrderScripts']); } } diff --git a/src/UI/MetaBoxes.php b/src/UI/MetaBoxes.php index 250b595..1648742 100644 --- a/src/UI/MetaBoxes.php +++ b/src/UI/MetaBoxes.php @@ -34,6 +34,8 @@ public static function registerMetaBoxes(string $post_type, $post): void return; } + add_action('admin_enqueue_scripts', [__CLASS__, 'registerOrderScripts']); + $cdekMethod = CheckoutHelper::getOrderShippingMethod($order); $selectedTariff = (int) ($cdekMethod->get_meta(MetaKeys::TARIFF_CODE) ?: $cdekMethod->get_meta('tariff_code')); @@ -87,7 +89,7 @@ public static function noAddressMetaBox(): void str_replace('', '', sprintf(esc_html__(/* translators: %s: Name of the plugin */ 'Select the correct sending address in the settings plugin named %s', 'cdekdelivery'), - esc_html($pluginName))). + esc_html($pluginName))). '

'; } @@ -104,7 +106,7 @@ public static function noOfficeMetaBox(): void str_replace('', '', sprintf(esc_html__(/* translators: %s: Name of the plugin */ 'Select the correct sending address in the settings plugin named %s', 'cdekdelivery'), - esc_html($pluginName))). + esc_html($pluginName))). '

'; } @@ -121,7 +123,7 @@ public static function noAuthMetaBox(): void str_replace('', '', sprintf(esc_html__(/* translators: %s: Name of the plugin */ 'Enter the correct client ID and secret key in the settings plugin named %s', 'cdekdelivery'), - esc_html($pluginName))). + esc_html($pluginName))). '

'; } @@ -144,8 +146,8 @@ public static function createOrderMetaBox($post): void $shipping = CheckoutHelper::getOrderShippingMethod($order); $hasPackages - = Helper::getActualShippingMethod($shipping->get_data()['instance_id']) - ->get_option('has_packages_mode') === 'yes'; + = Helper::getActualShippingMethod($shipping->get_data()['instance_id']) + ->get_option('has_packages_mode') === 'yes'; $orderNumber = $orderData['order_number'] ?? null; $orderUuid = $orderData['order_uuid'] ?? null; @@ -180,11 +182,16 @@ public static function notAvailableEditOrderData(): void echo '

CDEKDelivery: '. esc_html__('Editing the order is not available due to a change in the order status in the CDEK system', - 'cdekdelivery'). + 'cdekdelivery'). '

'; } + public static function registerOrderScripts(): void + { + Helper::enqueueScript('cdek-admin-create-order', 'cdek-create-order', true); + } + public function __invoke(): void { add_action('add_meta_boxes', [__CLASS__, 'registerMetaBoxes'], 100, 2); From ed84ca03a4bfcd00bfea2c2295509c6dcdbc253b Mon Sep 17 00:00:00 2001 From: Stas Demin Date: Mon, 17 Jun 2024 12:10:59 +0300 Subject: [PATCH 47/50] fix: global view to constants classes --- src/Managers/TaskManager.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/Managers/TaskManager.php b/src/Managers/TaskManager.php index 3f18834..507dba5 100644 --- a/src/Managers/TaskManager.php +++ b/src/Managers/TaskManager.php @@ -18,8 +18,8 @@ class TaskManager { private const TASK_CLASSES = [ - ReindexOrders::class, - CollectOrders::class, + '\\' . ReindexOrders::class, + '\\' . CollectOrders::class, ]; private array $taskCollection; private array $taskData = []; From afc65ca713c4c60d68eff1bc84174ed283f621b4 Mon Sep 17 00:00:00 2001 From: Stas Demin Date: Mon, 17 Jun 2024 12:34:37 +0300 Subject: [PATCH 48/50] fix: view mode to constants --- src/Actions/Schedule/CollectOrders.php | 2 +- src/Cache/FileCache.php | 2 +- src/CdekCoreApi.php | 14 +++++++------- src/Managers/TaskManager.php | 4 ++-- 4 files changed, 11 insertions(+), 11 deletions(-) diff --git a/src/Actions/Schedule/CollectOrders.php b/src/Actions/Schedule/CollectOrders.php index 0261241..edba458 100644 --- a/src/Actions/Schedule/CollectOrders.php +++ b/src/Actions/Schedule/CollectOrders.php @@ -11,7 +11,7 @@ class CollectOrders extends TaskContract { - const ORDERS_LIMIT = 10000; + private const ORDERS_LIMIT = 10000; public static function getName(): string { diff --git a/src/Cache/FileCache.php b/src/Cache/FileCache.php index 245a98d..7c7b289 100644 --- a/src/Cache/FileCache.php +++ b/src/Cache/FileCache.php @@ -12,7 +12,7 @@ class FileCache { - const CACHE_FILE_NAME = '.cache.php'; + private const CACHE_FILE_NAME = '.cache.php'; private static array $store; public static function getVars(): ?array diff --git a/src/CdekCoreApi.php b/src/CdekCoreApi.php index 571d6d1..bdf1701 100644 --- a/src/CdekCoreApi.php +++ b/src/CdekCoreApi.php @@ -16,16 +16,16 @@ class CdekCoreApi { - const SUCCESS_STATUS = 200; - const FINISH_STATUS = 201; - const HAS_NEXT_INFO_STATUS = 202; - const EMPTY_ANSWER = 204; - const UNKNOWN_METHOD = 404; - const FATAL_ERRORS_FIRST_NUMBER = 5; + private const SUCCESS_STATUS = 200; + private const FINISH_STATUS = 201; + private const HAS_NEXT_INFO_STATUS = 202; + private const EMPTY_ANSWER = 204; + private const UNKNOWN_METHOD = 404; + private const FATAL_ERRORS_FIRST_NUMBER = 5; private const TOKEN_PATH = 'cms/wordpress/shops/%s/token'; private const SHOP = 'cms/wordpress/shops'; private const TASKS = 'wordpress/tasks'; - public ?int $status; + private ?int $status; private TokenStorageContract $generalTokenStorage; private TokenStorageContract $tokenCoreStorage; private HttpCoreClient $coreClient; diff --git a/src/Managers/TaskManager.php b/src/Managers/TaskManager.php index 507dba5..3f18834 100644 --- a/src/Managers/TaskManager.php +++ b/src/Managers/TaskManager.php @@ -18,8 +18,8 @@ class TaskManager { private const TASK_CLASSES = [ - '\\' . ReindexOrders::class, - '\\' . CollectOrders::class, + ReindexOrders::class, + CollectOrders::class, ]; private array $taskCollection; private array $taskData = []; From a1a17f4978cbab1cb90f723293545f0d5abea17f Mon Sep 17 00:00:00 2001 From: Stas Demin Date: Mon, 17 Jun 2024 15:29:48 +0300 Subject: [PATCH 49/50] fix: merge insert services instead to rewrite services by get services from delivery settings --- src/Helpers/DeliveryCalc.php | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/src/Helpers/DeliveryCalc.php b/src/Helpers/DeliveryCalc.php index a556a31..d6d9483 100644 --- a/src/Helpers/DeliveryCalc.php +++ b/src/Helpers/DeliveryCalc.php @@ -156,11 +156,14 @@ static function ($carry, $item) use ($package) { $api = $this->api; $deliveryMethod = $this->method; + $servicesParams = $deliveryParam['services']; + $this->rates = array_map(static function ($tariff) use ( $priceRules, $api, $deliveryParam, - $deliveryMethod + $deliveryMethod, + $servicesParams ) { $rule = Tariff::isTariffToOffice($tariff['meta_data'][MetaKeys::TARIFF_CODE]) ? $priceRules['office'] : $priceRules['door']; @@ -181,8 +184,9 @@ static function ($carry, $item) use ($package) { $deliveryParam['type'] = Tariff::getTariffType($deliveryParam['tariff_code']); $serviceList = Helper::getServices($deliveryMethod, $deliveryParam['tariff_code']); + if (!empty($serviceList)) { - $deliveryParam['services'] = $serviceList; + $deliveryParam['services'] = array_merge($serviceList, $servicesParams); } $tariffInfo = $api->calculateTariff($deliveryParam); From e5683a1e3eba108ff2643594adeeb2f77ace72cf Mon Sep 17 00:00:00 2001 From: Stas Demin Date: Mon, 17 Jun 2024 15:29:48 +0300 Subject: [PATCH 50/50] fix: remove not necessary variables --- src/Helpers/DeliveryCalc.php | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/Helpers/DeliveryCalc.php b/src/Helpers/DeliveryCalc.php index a556a31..d8aec52 100644 --- a/src/Helpers/DeliveryCalc.php +++ b/src/Helpers/DeliveryCalc.php @@ -181,8 +181,9 @@ static function ($carry, $item) use ($package) { $deliveryParam['type'] = Tariff::getTariffType($deliveryParam['tariff_code']); $serviceList = Helper::getServices($deliveryMethod, $deliveryParam['tariff_code']); + if (!empty($serviceList)) { - $deliveryParam['services'] = $serviceList; + $deliveryParam['services'] = array_merge($serviceList, $deliveryParam['services']); } $tariffInfo = $api->calculateTariff($deliveryParam);