← All changes
|
includes/Services/Products/UpdateSingleProductService.php
+60
-1
1.10.13
→
1.10.20
View file →
| @@ -53,24 +53,44 @@ | ||
| 53 | 53 | $url = sprintf(Endpoints::PRODUCT_UPDATE, $syncBasalamProductId); |
| 54 | 54 | |
| 55 | 55 | $maxDescriptionRetries = 3; |
| 56 | 56 | $descriptionRetry = 0; |
| 57 | + $skuRetry = false; | |
| 57 | 58 | |
| 58 | 59 | while (true) { |
| 59 | 60 | try { |
| 60 | 61 | $request = $this->apiservice->patch($url, $productData); |
| 61 | - break; | |
| 62 | 62 | } catch (RetryableException $e) { |
| 63 | + if ($this->retryWithoutDuplicateSku($productData, $e, $skuRetry)) { | |
| 64 | + continue; | |
| 65 | + } | |
| 66 | + | |
| 63 | 67 | throw $e; |
| 64 | 68 | } catch (NonRetryableException $e) { |
| 69 | + if ($this->retryWithoutDuplicateSku($productData, $e, $skuRetry)) { | |
| 70 | + continue; | |
| 71 | + } | |
| 72 | + | |
| 65 | 73 | if ($descriptionRetry < $maxDescriptionRetries && $this->stripForbiddenDescription($e, $productData, $productId, $descriptionRetry)) { |
| 66 | 74 | $descriptionRetry++; |
| 67 | 75 | continue; |
| 68 | 76 | } |
| 77 | + | |
| 69 | 78 | throw $e; |
| 70 | 79 | } catch (\Exception $e) { |
| 80 | + if ($this->retryWithoutDuplicateSku($productData, $e, $skuRetry)) { | |
| 81 | + continue; | |
| 82 | + } | |
| 83 | + | |
| 71 | 84 | throw new \Exception(esc_html('خطا در ارتباط با API باسلام: ' . $e->getMessage())); |
| 72 | 85 | } |
| 86 | + | |
| 87 | + // Some API adapters return a non-2xx response instead of throwing it. | |
| 88 | + if ($this->retryWithoutDuplicateSku($productData, $request, $skuRetry)) { | |
| 89 | + continue; | |
| 90 | + } | |
| 91 | + | |
| 92 | + break; | |
| 73 | 93 | } |
| 74 | 94 | |
| 75 | 95 | $body = $request['body'] ?? ''; |
| 76 | 96 | |
| @@ -96,8 +116,17 @@ | ||
| 96 | 116 | } |
| 97 | 117 | |
| 98 | 118 | if (is_wp_error($request)) throw NonRetryableException::permanent('خطایی در ارتباط با سرور رخ داد.'); |
| 99 | 119 | |
| 120 | + // Basalam may return a successful response with a stale/null product SKU | |
| 121 | + // when another product field (most commonly a long description) is | |
| 122 | + // present in the same patch. Send the SKU on its own when the response | |
| 123 | + // does not contain the value we requested, so the product-level SKU is | |
| 124 | + // not lost for variable products. | |
| 125 | + // When the duplicate-SKU fallback was used, deliberately keep the | |
| 126 | + // second request SKU-free; do not issue a follow-up SKU-only patch. | |
| 127 | + if (!$skuRetry) $this->ensureProductSkuUpdated($url, $productData, $body); | |
| 128 | + | |
| 100 | 129 | $product = \wc_get_product($productId); |
| 101 | 130 | if ($product && $product->is_type('variable')) { |
| 102 | 131 | $variations = $product->get_children(); |
| 103 | 132 | if (isset($body['variants'])) { |
| @@ -210,8 +239,19 @@ | ||
| 210 | 239 | |
| 211 | 240 | return true; |
| 212 | 241 | } |
| 213 | 242 | |
| 243 | + private function retryWithoutDuplicateSku(array &$productData, $error, bool &$retried): bool | |
| 244 | + { | |
| 245 | + if ($retried || !ProductSkuRetry::hasSku($productData)) return false; | |
| 246 | + if (!ProductSkuRetry::isDuplicateSkuError($error)) return false; | |
| 247 | + | |
| 248 | + $productData = ProductSkuRetry::withoutSkus($productData); | |
| 249 | + $retried = true; | |
| 250 | + | |
| 251 | + return true; | |
| 252 | + } | |
| 253 | + | |
| 214 | 254 | public function updateProductStatus($productId, $status) |
| 215 | 255 | { |
| 216 | 256 | $vendorSyncPolicy = syncBasalamContainer()->get(VendorSyncPolicy::class); |
| 217 | 257 | if (!$vendorSyncPolicy->canUpdateProductStatus()) { |
| @@ -255,6 +295,25 @@ | ||
| 255 | 295 | return $result; |
| 256 | 296 | } |
| 257 | 297 | |
| 258 | 298 | throw NonRetryableException::permanent("تغییر وضعیت محصول در باسلام ناموفق بود."); |
| 299 | + } | |
| 300 | + | |
| 301 | + private function ensureProductSkuUpdated(string $url, array $productData, $responseBody): void | |
| 302 | + { | |
| 303 | + if (!array_key_exists('sku', $productData) || $productData['sku'] === null) return; | |
| 304 | + | |
| 305 | + $requestedSku = (string) $productData['sku']; | |
| 306 | + $responseSku = null; | |
| 307 | + | |
| 308 | + if (is_array($responseBody) && array_key_exists('sku', $responseBody)) { | |
| 309 | + $responseSku = $responseBody['sku']; | |
| 310 | + } | |
| 311 | + | |
| 312 | + if ($responseSku !== null && (string) $responseSku === $requestedSku) return; | |
| 313 | + | |
| 314 | + $skuRequest = $this->apiservice->patch($url, ['sku' => $productData['sku']]); | |
| 315 | + if (!is_array($skuRequest) || (int) ($skuRequest['status_code'] ?? 0) !== 200) { | |
| 316 | + throw NonRetryableException::permanent('بروزرسانی شناسه محصول (SKU) در باسلام ناموفق بود.'); | |
| 317 | + } | |
| 259 | 318 | } |
| 260 | 319 | } |