PluginProbe
ووسلام – همگام سازی ووکامرس و باسلام / 1.10.18
ووسلام – همگام سازی ووکامرس و باسلام v1.10.18
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 1.8.7 1.8.4 All 51 releases
sync-basalam / includes / Services / TicketServiceManager.php

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

257 lines 8.1 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;
4
5 use SyncBasalam\Admin\Settings\SettingsConfig;
6 use SyncBasalam\Services\Hamsalam\FetchHamsalamToken;
7 use SyncBasalam\Services\Hamsalam\FetchHamsalamBusinessId;
8
9 use SyncBasalam\Services\Ticket\FetchAllTickets;
10 use SyncBasalam\Services\Ticket\FetchTicket;
11 use SyncBasalam\Services\Ticket\FetchTicketSubjects;
12 use SyncBasalam\Services\Ticket\CreateTicket;
13 use SyncBasalam\Services\Ticket\CreateTicketItem;
14 use SyncBasalam\Services\Ticket\UploadTicketMedia;
15 use SyncBasalam\Services\Ticket\UpsertTicketSiteAccess;
16
17 use SyncBasalam\Jobs\Exceptions\RetryableException;
18 use SyncBasalam\Jobs\Exceptions\NonRetryableException;
19
20 class TicketServiceManager
21 {
22 private $hamsalamToken;
23 private $hamsalamBusinessId;
24 private $tokenFetcher;
25 private $businessIdFetcher;
26
27 private const MAX_RETRY_ATTEMPTS = 2;
28
29 public static function isUnauthorized($response): bool
30 {
31 return is_array($response) && isset($response['status_code']) && intval($response['status_code']) === 401;
32 }
33
34 public static function isSuccessful($response): bool
35 {
36 if (!is_array($response)) return false;
37 $statusCode = intval($response['status_code'] ?? 0);
38 return $statusCode >= 200 && $statusCode < 300;
39 }
40
41 public static function ticketStatuses(): array
42 {
43 return [
44 'pending_response' => 'در انتظار پاسخ',
45 'under_review' => 'در حال بررسی',
46 'closed' => 'بسته شده',
47 'answered' => 'پاسخ داده شده',
48 ];
49 }
50
51 public static function resolveTicketStatus(array $ticket): string
52 {
53 $status = $ticket['data']['status'] ?? $ticket['status'] ?? '';
54
55 if (is_array($status)) {
56 $status = $status['slug'] ?? $status['name'] ?? '';
57 }
58
59 return strtolower(trim((string) $status));
60 }
61
62 public static function isTicketClosed(array $ticket): bool
63 {
64 return in_array(self::resolveTicketStatus($ticket), ['closed', 'بسته شده'], true);
65 }
66
67 public static function resolveTicketSiteAccessStatus(array $ticket): string
68 {
69 $siteAccess = $ticket['data']['site_access'] ?? $ticket['site_access'] ?? null;
70 if (!is_array($siteAccess)) return '';
71
72 $status = $siteAccess['status'] ?? '';
73 if (is_array($status)) {
74 $status = $status['slug'] ?? $status['name'] ?? '';
75 }
76
77 return strtolower(trim((string) $status));
78 }
79
80 public static function isTicketSiteAccessRejected(array $ticket): bool
81 {
82 return in_array(self::resolveTicketSiteAccessStatus($ticket), ['invalid', 'rejected'], true);
83 }
84
85 public function __construct()
86 {
87 $settings = (array) syncBasalamSettings()->getSettings();
88
89 $this->hamsalamToken = $settings[SettingsConfig::HAMSALAM_TOKEN] ?? null;
90 $this->hamsalamBusinessId = $settings[SettingsConfig::HAMSALAM_BUSINESS_ID] ?? null;
91 $this->tokenFetcher = new FetchHamsalamToken();
92 $this->businessIdFetcher = new FetchHamsalamBusinessId();
93 }
94
95 private function executeWithRetry(callable $callback, array $callbackArgs = []): array
96 {
97 $attempt = 0;
98
99 while ($attempt < self::MAX_RETRY_ATTEMPTS) {
100 $attempt++;
101
102 try {
103 $token = $this->getHamsalamToken();
104 if (!$this->hasValue($token)) return $this->buildErrorResponse('توکن ه�
105 سلا�
106 در دسترس نیست.', 401);
107
108 $data = call_user_func_array($callback, array_merge([$token], $callbackArgs));
109 } catch (RetryableException $e) {
110 return $this->buildErrorResponse($e->getMessage(), $e->getCode() ?: 400);
111 } catch (NonRetryableException $e) {
112 return $this->buildErrorResponse($e->getMessage(), $e->getCode() ?: 400);
113 } catch (\Exception $e) {
114 return $this->buildErrorResponse($e->getMessage(), 500);
115 }
116
117 if (!is_array($data) || !isset($data['status_code'])) {
118 return $this->buildErrorResponse('پاسخ دریافتی از سرویس نا�
119 عتبر است.', 500);
120 }
121
122 if (!self::isUnauthorized($data)) return $data;
123
124 if ($attempt >= self::MAX_RETRY_ATTEMPTS) return $data;
125
126 $this->refreshHamsalamToken();
127 }
128
129 return $this->buildErrorResponse('خطای ناشناخته در پردازش درخواست.', 500);
130 }
131
132 private function buildErrorResponse(string $message, int $statusCode = 500): array
133 {
134 return [
135 'status_code' => $statusCode,
136 'error' => true,
137 'message' => $message,
138 ];
139 }
140
141 private function getHamsalamToken()
142 {
143 if ($this->hasValue($this->hamsalamToken)) return $this->hamsalamToken;
144
145 $this->hamsalamToken = $this->tokenFetcher->fetch();
146 return $this->hamsalamToken;
147 }
148
149 private function refreshHamsalamToken(): void
150 {
151 $this->hamsalamToken = $this->tokenFetcher->fetch();
152 }
153
154 private function getHamsalamBusinessId()
155 {
156 if ($this->hasValue($this->hamsalamBusinessId)) return $this->hamsalamBusinessId;
157
158 $this->hamsalamBusinessId = $this->businessIdFetcher->fetch();
159 return $this->hamsalamBusinessId;
160 }
161
162 private function hasValue($value): bool
163 {
164 return !($value === null || $value === '');
165 }
166
167 private function isValidTicketPayload($title, $subject, $content): bool
168 {
169 if (!isset($title, $subject, $content)) return false;
170
171 $title = trim((string) $title);
172 $content = trim((string) $content);
173
174 return mb_strlen($title) >= 3
175 && mb_strlen($title) <= 255
176 && mb_strlen($content) >= 10;
177 }
178
179 public function CheckHamsalamAccess($page = 1): array
180 {
181 return $this->fetchAllTickets($page);
182 }
183
184 public function fetchTicketSubjects(): array
185 {
186 $service = new FetchTicketSubjects();
187 return $this->executeWithRetry([$service, 'execute']);
188 }
189
190 public function fetchAllTickets($page = 1): array
191 {
192 $service = new FetchAllTickets();
193 $page = max(1, intval($page));
194
195 return $this->executeWithRetry([$service, 'execute'], [$page]);
196 }
197
198 public function fetchTicket($ticket_id): array
199 {
200 $service = new FetchTicket($ticket_id);
201 return $this->executeWithRetry([$service, 'execute']);
202 }
203
204 public function uploadTicketMedia($filePath): array
205 {
206 $service = new UploadTicketMedia();
207 return $this->executeWithRetry([$service, 'execute'], [$filePath]);
208 }
209
210 public function createTicket($title, $subject, $content, $fileIds = []): array
211 {
212 if (!$this->isValidTicketPayload($title, $subject, $content)) {
213 return $this->buildErrorResponse('اطلاعات وارد شده �
214 عتبر نیست', 400);
215 }
216
217 $service = new CreateTicket();
218
219 $data = [
220 'title' => $title,
221 'subject' => $subject,
222 'content' => $content,
223 'file_ids' => is_array($fileIds) ? $fileIds : [],
224 'business_id' => $this->getHamsalamBusinessId(),
225 ];
226
227 return $this->executeWithRetry([$service, 'execute'], [$data]);
228 }
229
230 public function createTicketItem($ticket_id, $content, $fileIds = []): array
231 {
232 $service = new CreateTicketItem($ticket_id);
233
234 $data = [
235 'type' => 'content',
236 'content' => $content,
237 'file_ids' => is_array($fileIds) ? $fileIds : [],
238 ];
239
240 return $this->executeWithRetry([$service, 'execute'], [$data]);
241 }
242
243 public function upsertTicketSiteAccess($ticketId, array $accessData): array
244 {
245 $businessId = intval($this->getHamsalamBusinessId());
246 $ticketId = intval($ticketId);
247 if ($businessId <= 0 || $ticketId <= 0 || empty($accessData)) {
248 return $this->buildErrorResponse('اطلاعات دسترسی �
249 عتبر نیست.', 400);
250 }
251
252 $accessData['ticket_id'] = $ticketId;
253 $service = new UpsertTicketSiteAccess($businessId);
254 return $this->executeWithRetry([$service, 'execute'], [$accessData]);
255 }
256 }
257