PluginProbe
ووسلام – همگام سازی ووکامرس و باسلام / 1.10.28
ووسلام – همگام سازی ووکامرس و باسلام v1.10.28
1.10.28 1.1.26 1.10.27 1.10.24 1.10.25 1.10.23 1.10.22 1.10.21 1.10.19 1.10.20 1.10.18 1.10.17 1.10.15 1.10.14 1.10.13 1.10.12 1.10.10 1.10.9 1.10.8 1.10.7 1.10.6 1.10.5 1.10.4 1.10.3 1.10.2 All 61 releases
sync-basalam / includes / Services / Products / CreateSingleProductService.php

CreateSingleProductService.php in ووسلام – همگام سازی ووکامرس و باسلام 1.10.28, at includes/Services/Products/CreateSingleProductService.php

256 lines 9.9 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2
3 namespace SyncBasalam\Services\Products;
4
5 use SyncBasalam\Admin\Product\Data\Validators\CreateProductDataValidator;
6 use SyncBasalam\Admin\Product\Data\Services\VariantService;
7 use SyncBasalam\Admin\Settings\SettingsConfig;
8 use SyncBasalam\Config\Endpoints;
9 use SyncBasalam\Services\ApiServiceManager;
10 use SyncBasalam\Jobs\Exceptions\RetryableException;
11 use SyncBasalam\Jobs\Exceptions\NonRetryableException;
12 use SyncBasalam\Utilities\ProductMetaKey;
13 use SyncBasalam\Services\VendorSyncPolicy;
14
15 defined('ABSPATH') || exit;
16
17 class CreateSingleProductService
18 {
19 private $apiservice;
20 private $validator;
21
22 public function __construct($validator = null)
23 {
24 $this->apiservice = syncBasalamContainer()->get(ApiServiceManager::class);
25 $this->validator = $validator ?: new CreateProductDataValidator();
26 }
27
28 public function createProductInBasalam($productData, $productId)
29 {
30 $vendorSyncPolicy = syncBasalamContainer()->get(VendorSyncPolicy::class);
31 if (!$vendorSyncPolicy->canCreate()) {
32 throw NonRetryableException::invalidData($vendorSyncPolicy->getRestrictionMessage(false));
33 }
34
35 $productData = apply_filters('sync_basalam_product_data_before_create', $productData, $productId);
36 $this->ValidCreateProductData($productData, $productId);
37
38 do_action('sync_basalam_before_create_product_api', $productId, $productData);
39
40 $vendorId = syncBasalamSettings()->getSettings(SettingsConfig::VENDOR_ID);
41
42 $url = sprintf(Endpoints::PRODUCT_CREATE, $vendorId);
43
44 $maxDescriptionRetries = 3;
45 $descriptionRetry = 0;
46 $skuRetry = false;
47
48 while (true) {
49 try {
50 $request = $this->apiservice->post($url, $productData);
51 } catch (RetryableException $e) {
52 if ($this->retryWithoutDuplicateSku($productData, $e, $skuRetry)) {
53 continue;
54 }
55
56 throw $e;
57 } catch (NonRetryableException $e) {
58 if ($this->retryWithoutDuplicateSku($productData, $e, $skuRetry)) {
59 continue;
60 }
61
62 if ($descriptionRetry < $maxDescriptionRetries && $this->stripForbiddenDescription($e, $productData, $productId, $descriptionRetry)) {
63 $descriptionRetry++;
64 continue;
65 }
66 throw $e;
67 } catch (\Exception $e) {
68 if ($this->retryWithoutDuplicateSku($productData, $e, $skuRetry)) {
69 continue;
70 }
71
72 throw new \Exception(esc_html($e->getMessage()));
73 }
74
75 // Some API adapters return a non-2xx response instead of throwing it.
76 if ($this->retryWithoutDuplicateSku($productData, $request, $skuRetry)) {
77 continue;
78 }
79
80 break;
81 }
82
83 if ($request['status_code'] != 201 && isset($request['status_code'])) {
84
85 $body = $request['body'] ?? '';
86
87 if (is_string($body))
88 $responseData = json_decode($body, true);
89 else $responseData = $body;
90
91 if (!is_array($responseData)) $responseData = [];
92
93 if ($responseData && isset($responseData['messages'][0])) {
94 $message = $responseData['messages'][0]['message'] ?? 'خطای نا�
95 شخص';
96 $field = $responseData['messages'][0]['fields'][0] ?? '';
97 } else {
98 $message = 'درخواست با تای�
99 اوت �
100 واجه شد.';
101 $field = '';
102 }
103
104 $errorMessage = 'فرایند اضافه کردن �
105 حصول نا�
106 وفق بود: ' . esc_html($message);
107 if ($field) $errorMessage .= ' (فیلد: ' . esc_html($field) . ')';
108
109 throw new \Exception(esc_html($errorMessage));
110 }
111
112 if (is_wp_error($request)) {
113 $body = $request['body'] ?? '';
114
115 if (is_string($body))
116 $responseData = json_decode($body, true);
117 else $responseData = $body;
118
119 $message = $responseData[0]['message'] ?? 'خطای نا�
120 شخص';
121 throw new \Exception('درخواست �
122 وفقیت آ�
123 یز نبود: ' . esc_html($message));
124 }
125
126 $responseData = json_decode($request['body'], true);
127 if (isset($responseData['id'])) {
128 if (isset($responseData['variants'])) {
129 $product = wc_get_product($productId);
130
131 if ($product && $product->is_type('variable')) {
132 $wcVariations = [];
133 $attributes = $product->get_attributes();
134
135 foreach ($product->get_children() as $variationId) {
136 $variation = wc_get_product($variationId);
137 $attributeValues = [];
138
139 foreach ($attributes as $attributeName => $attribute) {
140 if ($attribute->get_variation()) {
141 $cleanAttributeName = str_replace('attribute_', '', $attributeName);
142 $value = $variation->get_attribute($cleanAttributeName);
143
144 $value = urldecode($value);
145 $value = trim($value);
146 $value = mb_strtolower($value, 'UTF-8');
147 $value = str_replace(['ي', 'ك'], ['ی', 'ک'], $value);
148 $value = str_replace(['-', '_', '–', '—'], ' ', $value);
149 $value = preg_replace('/\s+/', ' ', $value);
150
151 if (!empty($value)) {
152 $attributeValues[] = $value;
153 }
154 }
155 }
156
157 if (!empty($attributeValues)) {
158 $key = implode("_", $attributeValues);
159 $wcVariations[$key] = $variationId;
160 }
161 }
162
163 $syncBasalamVariations = [];
164 foreach ($responseData['variants'] as $variant) {
165 $attributeValues = [];
166 if (!empty($variant['properties'])) {
167 foreach ($variant['properties'] as $property) {
168 $val = trim($property['value']['title']);
169 $val = mb_strtolower($val, 'UTF-8');
170 $val = str_replace(['ي', 'ك'], ['ی', 'ک'], $val);
171 $val = str_replace(['-', '_', '–', '—'], ' ', $val);
172 $val = preg_replace('/\s+/', ' ', $val);
173 if (!empty($val)) {
174 $attributeValues[] = $val;
175 }
176 }
177 }
178
179 if (!empty($attributeValues)) {
180 $key = implode("_", $attributeValues);
181 $syncBasalamVariations[$key] = $variant['id'];
182 }
183 }
184
185 $variationMapping = [];
186 foreach ($wcVariations as $key => $wcVarId) {
187 if (isset($syncBasalamVariations[$key])) {
188 $variationMapping[$wcVarId] = $syncBasalamVariations[$key];
189 update_post_meta($wcVarId, 'sync_basalam_variation_id', $syncBasalamVariations[$key]);
190 }
191 }
192
193 (new VariantService())->syncExpandedVariationIds($product, $responseData['variants']);
194 }
195 }
196
197 update_post_meta($productId, ProductMetaKey::basalamProductId(), $responseData['id']);
198 update_post_meta($productId, ProductMetaKey::basalamProductStatus(), 2976);
199 update_post_meta($productId, ProductMetaKey::basalamProductSyncStatus(), 'synced');
200
201 $result = [
202 'success' => true,
203 'message' => '�
204 حصول با �
205 وفقیت به باسلا�
206 اضافه شد.',
207 'status_code' => 200,
208 'basalam_id' => $responseData['id'],
209 ];
210
211 do_action('sync_basalam_after_create_product_api', $productId, $responseData, $result);
212
213 return $result;
214 }
215
216 throw new \Exception("فرایند اضافه کردن �
217 حصول نا�
218 وفق بود");
219 }
220
221 private function stripForbiddenDescription(NonRetryableException $e, array &$productData, int $productId, int $attempt): bool
222 {
223 if (!isset($productData['description']) || !is_string($productData['description'])) return false;
224
225 $values = DescriptionErrorSanitizer::extractDescriptionValues($e->getResponseData());
226 if (empty($values)) return false;
227
228 $cleaned = DescriptionErrorSanitizer::sanitize($productData['description'], $values);
229 if ($cleaned === $productData['description']) return false;
230
231 $productData['description'] = $cleaned;
232
233 return true;
234 }
235
236 private function retryWithoutDuplicateSku(array &$productData, $error, bool &$retried): bool
237 {
238 if ($retried || !ProductSkuRetry::hasSku($productData)) return false;
239 if (!ProductSkuRetry::isDuplicateSkuError($error)) return false;
240
241 $productData = ProductSkuRetry::withoutSkus($productData);
242 $retried = true;
243
244 return true;
245 }
246
247 private function ValidCreateProductData(array $productData, int $productId): void
248 {
249 $validation = $this->validator->validate($productData, $productId);
250
251 if (!$validation['valid']) {
252 throw NonRetryableException::invalidData(esc_html($validation['message']));
253 }
254 }
255 }
256