PluginProbe
ووسلام – همگام سازی ووکامرس و باسلام / 1.10.12
ووسلام – همگام سازی ووکامرس و باسلام v1.10.12
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 1.10.1 1.10.0 1.9.2 1.9.1 1.9.0 1.8.8 1.8.5 1.8.6 All 53 releases
sync-basalam / includes / Services / Products / Discount / DiscountTaskProcessor.php

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

323 lines 11.8 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\Discount;
4
5 use SyncBasalam\JobManager;
6 use SyncBasalam\Admin\Settings\SettingsConfig;
7 use SyncBasalam\Services\Products\ProductConnection;
8 use SyncBasalam\Utilities\ProductMetaKey;
9
10 defined('ABSPATH') || exit;
11
12 class DiscountTaskProcessor
13 {
14 private $discountManager;
15 private $taskModel;
16 private $jobManager;
17 private $settingsAccessor;
18
19 public function __construct(
20 $discountManager = null,
21 $taskModel = null,
22 $jobManager = null
23 ) {
24 $this->discountManager = $discountManager ?: syncBasalamContainer()->get(DiscountManager::class);
25 $this->taskModel = $taskModel ?: syncBasalamContainer()->get(DiscountTaskModel::class);
26 $this->jobManager = $jobManager ?: syncBasalamContainer()->get(JobManager::class);
27 $this->settingsAccessor = syncBasalamSettings();
28 }
29
30 public function processDiscountTasks()
31 {
32 $job = $this->jobManager->getJob(['job_type' => 'sync_basalam_discount_tasks', 'status' => 'pending']);
33
34 if (!$job) return;
35
36 $this->jobManager->updateJob(['status' => 'processing', 'started_at' => time()], ['id' => $job->id]);
37
38 try {
39 $runnableTasks = $this->taskModel->getRunnableTasks();
40
41 if (!$runnableTasks) {
42 $this->jobManager->deleteJob(['id' => $job->id]);
43 return;
44 }
45
46 $this->processTaskGroup($runnableTasks);
47
48 $remainingTasks = $this->taskModel->getTasksCountByStatus(DiscountTaskModel::STATUS_PENDING);
49
50 if ($remainingTasks > 0) {
51 $this->jobManager->updateJob(
52 ['status' => 'pending', 'started_at' => 0],
53 ['id' => $job->id]
54 );
55 } else $this->jobManager->deleteJob(['id' => $job->id]);
56 } catch (\Exception $e) {
57 $this->jobManager->updateJob(
58 ['status' => 'failed', 'error_message' => $e->getMessage()],
59 ['id' => $job->id]
60 );
61 }
62 }
63
64 private function processTaskGroup($group)
65 {
66 $taskIds = !empty($group->task_ids) ? explode(',', $group->task_ids) : [];
67 $rawProductIds = !empty($group->product_ids) ? array_filter(explode(',', $group->product_ids)) : [];
68
69 $rawVariationIds = !empty($group->variation_ids) ? array_filter(explode(',', $group->variation_ids)) : [];
70
71 $productIds = array_filter($rawProductIds, function ($id) {
72 return !empty($id) && $id !== 'NULL' && $id !== null;
73 });
74
75 $variationIds = array_filter($rawVariationIds, function ($id) {
76 return !empty($id) && $id !== 'NULL' && $id !== null;
77 });
78
79 if (empty($productIds) && empty($variationIds)) {
80 $this->taskModel->updateMultipleStatus(
81 $taskIds,
82 DiscountTaskModel::STATUS_FAILED,
83 'No valid product or variation IDs found'
84 );
85 return;
86 }
87
88 $this->taskModel->updateMultipleStatus($taskIds, DiscountTaskModel::STATUS_PROCESSING);
89
90 if ($group->action === 'remove') $result = $this->discountManager->remove($productIds, $variationIds);
91 else {
92 $result = $this->discountManager->apply(
93 $group->discount_percent,
94 $productIds,
95 $variationIds,
96 $group->active_days
97 );
98 }
99
100 if ($result && isset($result['status_code']) && $result['status_code'] === 202) {
101 $this->taskModel->deleteMultipleTasks($taskIds);
102 } else {
103 $errorMessage = 'خطای ناشناخته';
104 if ($result) {
105 $decodedBody = is_string($result['body']) ? json_decode($result['body'], true) : $result['body'];
106 if (isset($decodedBody['message'])) {
107 $errorMessage = $decodedBody['message'];
108 } elseif (isset($decodedBody['error'])) {
109 $errorMessage = $decodedBody['error'];
110 } elseif (isset($result['status_code'])) {
111 $errorMessage = sprintf('API returned status code: %d', $result['status_code']);
112 }
113 }
114
115 $this->taskModel->updateMultipleStatus($taskIds, DiscountTaskModel::STATUS_FAILED, $errorMessage);
116 }
117 }
118
119 public function addDiscountTasks($items)
120 {
121 $jobExists = $this->jobManager->getCountJobs(['job_type' => 'sync_basalam_discount_tasks', 'status' => ['pending', 'processing']]);
122 $discountReductionPercent = absint($this->settingsAccessor->getSettings(SettingsConfig::DISCOUNT_REDUCTION_PERCENT));
123
124 if ($jobExists === 0) $this->jobManager->createJob('sync_basalam_discount_tasks', 'pending');
125
126 $createdCount = 0;
127 foreach ($items as $item) {
128 $wcProductId = $item['product_id'] ?? null;
129 $wcVariationId = $item['variation_id'] ?? null;
130 $action = $item['action'] ?? 'apply';
131 $discountPercent = $item['discount_percent'] ?? 0;
132
133 if ($action === 'apply') {
134 $discountPercent = $this->getAdjustedDiscountPercent($discountPercent, $discountReductionPercent);
135 }
136
137 $activeDays = $item['active_days'] ?? $this->settingsAccessor->getSettings(SettingsConfig::DISCOUNT_DURATION) ?? 7;
138
139 $basalamProductId = null;
140 $basalamVariationId = null;
141
142 if ($wcProductId) $basalamProductId = get_post_meta($wcProductId, ProductMetaKey::basalamProductId(), true);
143 if ($wcVariationId) $basalamVariationId = get_post_meta($wcVariationId, 'sync_basalam_variation_id', true);
144
145 if ($basalamProductId || $basalamVariationId) {
146 $taskData = [
147 'product_id' => $basalamProductId,
148 'variation_id' => $basalamVariationId,
149 'discount_percent' => $discountPercent,
150 'active_days' => $activeDays,
151 'action' => $action,
152 'status' => DiscountTaskModel::STATUS_PENDING,
153 ];
154
155 $taskId = $this->taskModel->create($taskData);
156
157 if ($taskId) {
158 $createdCount++;
159 $this->markProductsAsDiscounted([$wcProductId], [$wcVariationId], $action);
160 }
161 }
162 }
163
164 return $createdCount > 0;
165 }
166
167 private function getAdjustedDiscountPercent($discountPercent, int $discountReductionPercent): float
168 {
169 $discountPercent = (float) $discountPercent;
170
171 if ($discountReductionPercent > 0 && $discountPercent > $discountReductionPercent) {
172 return $discountPercent - $discountReductionPercent;
173 }
174
175 return $discountPercent;
176 }
177
178 public function handleProductDiscount($productId)
179 {
180 $priceField = $this->settingsAccessor->getSettings(SettingsConfig::PRODUCT_PRICE_FIELD);
181
182 $product = wc_get_product($productId);
183
184 if (!$product) return;
185
186 // اتصال �
187 شترک با �
188 حصول دیگر یعنی تخفیف روی �
189 حصول اشتباهی در باسلا�
190 اع�
191 ال �
192 ی‌شود.
193 if (ProductConnection::hasConflict($productId)) return;
194
195 $items = [];
196
197 if ($priceField !== 'sale_strikethrough_price') {
198 $this->handleNonSalePriceMode($product);
199 return;
200 }
201
202 if ($product->is_type('simple')) {
203 $basalamProductId = get_post_meta($productId, ProductMetaKey::basalamProductId(), true);
204
205 if (!$basalamProductId) return;
206
207 $salePrice = $product->get_sale_price();
208 $regularPrice = $product->get_regular_price();
209
210 if ($salePrice && $regularPrice) {
211 $discountPercent = DiscountManager::calculateDiscountPercent($regularPrice, $salePrice);
212 if ($discountPercent > 0) {
213 $items[] = [
214 'product_id' => $productId,
215 'discount_percent' => $discountPercent,
216 'action' => 'apply'
217 ];
218 }
219 } else {
220 $items[] = [
221 'product_id' => $productId,
222 'action' => 'remove'
223 ];
224 }
225 } elseif ($product->is_type('variable')) {
226 $basalamProductId = get_post_meta($productId, ProductMetaKey::basalamProductId(), true);
227 if (!$basalamProductId) return;
228
229 foreach ($product->get_children() as $variationId) {
230 $variation = wc_get_product($variationId);
231 if (!$variation) continue;
232
233 $basalamVariationId = get_post_meta($variationId, 'sync_basalam_variation_id', true);
234 if (!$basalamVariationId) continue;
235
236 $salePrice = $variation->get_sale_price();
237 $regularPrice = $variation->get_regular_price();
238
239 if ($salePrice && $regularPrice) {
240 $discountPercent = DiscountManager::calculateDiscountPercent($regularPrice, $salePrice);
241 if ($discountPercent > 0) {
242 $items[] = [
243 'product_id' => $productId,
244 'variation_id' => $variationId,
245 'discount_percent' => $discountPercent,
246 'action' => 'apply'
247 ];
248 }
249 } else {
250 $items[] = [
251 'product_id' => $productId,
252 'variation_id' => $variationId,
253 'action' => 'remove'
254 ];
255 }
256 }
257 }
258
259 if (!empty($items)) {
260 $this->addDiscountTasks($items);
261 }
262 }
263
264 private function markProductsAsDiscounted(array $wcProductIds, array $wcVariationIds, string $action)
265 {
266 foreach ($wcProductIds as $wcProductId) {
267 if ($wcProductId) {
268 if ($action === 'apply') update_post_meta($wcProductId, 'sync_basalam_discounted', 'true');
269 else delete_post_meta($wcProductId, 'sync_basalam_discounted');
270 }
271 }
272
273 foreach ($wcVariationIds as $wcVariationId) {
274 if ($wcVariationId) {
275 if ($action === 'apply') update_post_meta($wcVariationId, 'sync_basalam_discounted', 'true');
276 else delete_post_meta($wcVariationId, 'sync_basalam_discounted');
277 }
278 }
279 }
280
281 private function handleNonSalePriceMode($product)
282 {
283 $productId = $product->get_id();
284 $items = [];
285
286 if ($product->is_type('simple')) {
287 $basalamProductId = get_post_meta($productId, ProductMetaKey::basalamProductId(), true);
288 if (!$basalamProductId) return;
289
290 $isDiscounted = get_post_meta($productId, 'sync_basalam_discounted', true);
291
292 if ($isDiscounted === 'true') {
293 $items[] = [
294 'product_id' => $productId,
295 'action' => 'remove'
296 ];
297 }
298 } elseif ($product->is_type('variable')) {
299 $basalamProductId = get_post_meta($productId, ProductMetaKey::basalamProductId(), true);
300
301 if (!$basalamProductId) return;
302
303 foreach ($product->get_children() as $variationId) {
304 $basalamVariationId = get_post_meta($variationId, 'sync_basalam_variation_id', true);
305
306 if (!$basalamVariationId) continue;
307
308 $isDiscounted = get_post_meta($variationId, 'sync_basalam_discounted', true);
309
310 if ($isDiscounted === 'true') {
311 $items[] = [
312 'product_id' => $productId,
313 'variation_id' => $variationId,
314 'action' => 'remove'
315 ];
316 }
317 }
318 }
319
320 if (!empty($items)) $this->addDiscountTasks($items);
321 }
322 }
323