PluginProbe
Fluent Support – Helpdesk & Customer Support Ticket System / 1.10.2
Fluent Support – Helpdesk & Customer Support Ticket System v1.10.2
2.4.0 2.3.2 2.3.1 2.3.0 2.2.1 2.2.0 trunk 1.10.0 1.10.1 1.10.2 1.10.3 1.10.4 1.10.5 1.4.0 1.4.1 1.4.2 1.4.5 1.4.6 1.4.7 1.5.0 1.5.1 1.5.2 1.5.3 1.5.4 1.5.5 All 68 releases
fluent-support / app / Services / Tickets / Importer / BaseImporter.php

BaseImporter.php in Fluent Support – Helpdesk & Customer Support Ticket System 1.10.2, at app/Services/Tickets/Importer/BaseImporter.php

416 lines 12.9 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2
3 namespace FluentSupport\App\Services\Tickets\Importer;
4
5 use FluentSupport\App\Models\Agent;
6 use FluentSupport\App\Models\Attachment;
7 use FluentSupport\App\Models\Customer;
8 use FluentSupport\App\Models\Person;
9 use FluentSupport\App\Models\Ticket;
10 use FluentSupport\App\Services\Helper;
11 use FluentSupport\Framework\Support\Arr;
12
13 abstract class BaseImporter
14 {
15 protected $db;
16 protected $handler = '';
17 protected $mailbox;
18 protected $limit = 20;
19 protected $ticketUpdatedSince;
20
21 public function __construct()
22 {
23 $this->db = Helper::FluentSupport('db');
24 $this->mailbox = Helper::getDefaultMailBox();
25 $this->limit = apply_filters('fluent_support/ticket_import_chunk_limit', 20);
26 $this->ticketUpdatedSince = apply_filters('fluent_support/fs_tickets_updated_since', '2010-01-19T02:00:00Z');
27 }
28 /**
29 * This method `stats` returns an array of ticket stats of targeted helpdesk system
30 *
31 * @return array
32 */
33 abstract public function stats();
34
35 /**
36 * This method `doMigration` is responsible for migrating tickets from targeted helpdesk system
37 * and it returns an array with migration response
38 *
39 * @param int $page
40 * @param string $handler
41 * @return array
42 */
43 abstract public function doMigration($page, $handler);
44
45 /**
46 * This method `deleteTickets` delete tickets and related data from targeted helpdesk once the
47 * migration process done succesfully
48 *
49 * @param int $page // this will be migrated ticket page number
50 * @return array
51 */
52 abstract public function deleteTickets($page);
53
54 /**
55 * This method `migrateTickets` migrate tickets on Fluent Support with the help of `migrateTicket` method
56 *
57 * @param array $tickets // array of tickets with all required data
58 * @return array
59 */
60 public function migrateTickets($tickets)
61 {
62 $insertIds = [];
63 $skips = [];
64 foreach ($tickets as $ticket) {
65 $createdTicket = $this->migrateTicket($ticket);
66 if ($createdTicket) {
67 $insertIds[] = $createdTicket->id;
68 } else {
69 $skips[] = $ticket;
70 }
71 }
72
73 return [
74 'inserts' => $insertIds,
75 'skips' => $skips
76 ];
77 }
78
79 /**
80 * This method `migrateTicket` is responsible for migrating a single ticket in Fluent Support
81 *
82 * @param array $ticketData
83 * @return \FluentSupport\App\Models\Ticket $createdTicket
84 */
85 public function migrateTicket($ticketData)
86 {
87 if ($this->isMigrated($ticketData['origin_id'])) {
88 return false;
89 }
90
91 $fillables = (new Ticket())->getFillable();
92 $fillables[] = 'created_at';
93 $fillables[] = 'updated_at';
94
95 $data = array_filter(Arr::only($ticketData, $fillables));
96
97 if (!isset($data['content'])) {
98 $data['content'] = '';
99 }
100
101 $data['customer_id'] = $ticketData['customer']['id'];
102
103 if (!empty($ticketData['agent'])) {
104 $data['agent_id'] = $ticketData['agent']['id'];
105 }
106
107 if (empty($ticketData['mailbox_id'])) {
108 $data['mailbox_id'] = $this->mailbox->id;
109 }
110
111 $data = $this->addMetaData($data);
112
113 $createdTicketId = $this->db->table('fs_tickets')
114 ->insertGetId($data);
115
116 if (!$createdTicketId) {
117 return false;
118 }
119
120 $createdTicket = Ticket::find($createdTicketId);
121
122
123 if (!empty($ticketData['attachments'])) {
124 foreach ($ticketData['attachments'] as $attachmentData) {
125 $attachmentData['person_id'] = $createdTicket->customer_id;
126 $attachmentData['ticket_id'] = $createdTicket->id;
127 Attachment::create($attachmentData);
128 }
129 }
130
131 if (!$createdTicket) {
132 return false;
133 }
134
135 Helper::updateTicketMeta($createdTicket->id, '_' . $this->handler . '_origin_id', $ticketData['origin_id']);
136
137 if (empty($ticketData['replies'])) {
138 return $createdTicket;
139 }
140
141 // Let's migrate the replies
142 $lastAgentResponseTime = $createdTicket->last_customer_response;
143 $lastCustomerResponseTime = $createdTicket->waiting_since;
144 $waitingSince = $createdTicket->waiting_since;
145 $responseCount = 0;
146 $firstResponseTimestamp = false;
147
148 $defualtAgentId = false;
149
150 foreach ($ticketData['replies'] as $reply) {
151
152 $replyData = Arr::only($reply, [
153 'content',
154 'conversation_type',
155 'created_at',
156 'updated_at'
157 ]);
158
159 if (!isset($replyData['content']) || empty($replyData['content'])) {
160 continue;
161 }
162
163 $replyData['ticket_id'] = $createdTicket->id;
164 $replyData['source'] = $this->handler;
165 $replyData['content_hash'] = md5($replyData['content']);
166
167 $person = ($reply['is_customer_reply']) ? $this->getPerson($reply['user']) : $this->getPerson($reply['user'], 'agent');
168
169 if (!$person) {
170 continue; // person could not be found
171 }
172
173 $replyData['person_id'] = intval($person->id);
174
175 if ($replyData['conversation_type'] == 'response') {
176 $responseCount++;
177 }
178
179 if ($reply['is_customer_reply']) {
180 if (strtotime($lastCustomerResponseTime) < strtotime($replyData['created_at'])) {
181 $lastCustomerResponseTime = $replyData['created_at'];
182 }
183 } else if ($replyData['conversation_type'] == 'response') {
184
185 if (!$firstResponseTimestamp) {
186 $firstResponseTimestamp = $replyData['created_at'];
187 }
188
189 if (strtotime($lastAgentResponseTime) < strtotime($replyData['created_at'])) {
190 $lastAgentResponseTime = $replyData['created_at'];
191 $waitingSince = $replyData['created_at'];
192 }
193
194 $defualtAgentId = $person->id;
195 }
196
197 $conversionId = $this->db->table('fs_conversations')
198 ->insertGetId($replyData);
199
200 if (!empty($reply['attachments'])) {
201 foreach ($reply['attachments'] as $attachmentData) {
202 $attachmentData['ticket_id'] = $createdTicket->id;
203 $attachmentData['person_id'] = $person->id;
204 $attachmentData['conversation_id'] = $conversionId;
205 Attachment::create($attachmentData);
206 }
207 }
208 }
209
210 $ticketUpdateData = array_filter([
211 'last_customer_response' => $lastAgentResponseTime,
212 'waiting_since' => $waitingSince,
213 'response_count' => $responseCount
214 ]);
215
216 if(!$createdTicket->agent_id && $defualtAgentId) {
217 $ticketUpdateData['agent_id'] = $defualtAgentId;
218 }
219
220 if ($firstResponseTimestamp && $createdTicket->crerated_at) {
221 $ticketUpdateData['first_response_time'] = strtotime($firstResponseTimestamp) - strtotime($createdTicket->crerated_at);
222 }
223
224 if ($createdTicket->status == 'closed' && $createdTicket->resolved_at && $createdTicket->crerated_at) {
225 $ticketUpdateData['total_close_time'] = strtotime($createdTicket->resolved_at) - strtotime($createdTicket->crerated_at);
226 }
227
228 if ($ticketUpdateData) {
229 $createdTicket->fill($ticketUpdateData);
230 $createdTicket->save();
231 }
232
233 return $createdTicket;
234 }
235
236 /**
237 * This `getPerson` method will get associated person with a tickets or conversation
238 * @param array $personData
239 * @param string $type user type default is `customer`
240 * @return object|false $person
241 */
242 protected function getPerson($personData, $type = 'customer')
243 {
244
245 static $cachedPerson = [];
246
247 $personData = (array) $personData;
248
249 if (!empty($personData['user_id'])) {
250 if (isset($personData[$personData['user_id'] . '_' . $type])) {
251 return $personData[$personData['user_id'] . '_' . $type];
252 }
253 }
254
255 if ($type == 'customer') {
256 if (!empty($personData['user_id']) || !empty($personData['email'])) {
257 $person = Customer::maybeCreateCustomer($personData);
258 if ($person) {
259 $cachedPerson[$person->user_id . '_' . $type] = $person;
260 }
261 return $person;
262 }
263 return false;
264 }
265
266 if (!empty($personData['user_id'])) {
267 $person = Person::where('user_id', $personData['user_id'])
268 ->where('person_type', $type)
269 ->first();
270 if ($person) {
271 $cachedPerson[$person->user_id . '_' . $type] = $person;
272
273 return $person;
274 }
275 }
276
277 if (!empty($personData['email'])) {
278 $person = Person::where('email', $personData['email'])
279 ->where('person_type', $type)
280 ->first();
281 if ($person) {
282 $cachedPerson[$person->user_id . '_' . $type] = $person;
283 return $person;
284 }
285 }
286
287 $user = false;
288
289 if (!empty($personData['user_id'])) {
290 $user = get_user_by('ID', $personData['user_id']);
291 } else if (!empty($personData['email'])) {
292 $user = get_user_by('email', $personData['email']);
293 }
294
295 if (!$user && 'agent' == $type) {
296 $person = Agent::updateOrCreate(
297 [
298 'email' => $personData['email']
299 ],
300 [
301 'first_name' => $personData['first_name'] ?? '',
302 'last_name' => $personData['last_name'] ?? '',
303 'email' => $personData['email'],
304 'type' => $type
305 ]
306 );
307
308 return $person;
309 }
310
311
312 if ($user){
313 $personData['user_id'] = $user->ID;
314 $personData['first_name'] = $user->first_name;
315 $personData['last_name'] = $user->last_name;
316 $personData['last_name'] = $user->last_name;
317 $personData['email'] = $user->user_email;
318
319 if (empty($personData['full_name'])) {
320 $personData['full_name'] = $user->display_name;
321 }
322
323 }
324
325 if (empty($personData['first_name']) && $personData['last_name'] && !empty($personData['name'])) {
326 $fullNameArray = explode(' ', $personData['name']);
327 $personData['first_name'] = array_shift($fullNameArray);
328 if ($fullNameArray) {
329 $personData['last_name'] = implode(' ', $fullNameArray);
330 }
331 unset($personData['name']);
332 }
333
334
335 $personData['person_type'] = $type;
336
337 $person = Person::create($personData);
338 $cachedPerson[$person->user_id . '_' . $type] = $person;
339 return $person;
340 }
341
342 protected function fallbackAgentId()
343 {
344 $agent = Person::where('person_type', 'agent')
345 ->oldest('id')
346 ->select(['id'])
347 ->first();
348
349 return (int)$agent->id;
350 }
351
352 protected function isMigrated($originId)
353 {
354 $exist = $this->db->table('fs_meta')
355 ->where('object_type', 'ticket_meta')
356 ->where('key', '_' . $this->handler . '_origin_id')
357 ->where('value', $originId)
358 ->first();
359
360 return !!$exist;
361 }
362
363 protected function addMetaData($ticketData)
364 {
365 if (empty($ticketData['slug'])) {
366 $ticketData['slug'] = Ticket::slugify($ticketData['title']);
367 }
368
369 $ticketData['hash'] = substr(md5(time() . wp_generate_uuid4()), 0, 8) . mt_rand(1, 99);
370
371 $ticketData['content_hash'] = md5($ticketData['content']);
372
373 if (empty($ticketData['last_customer_response'])) {
374 $ticketData['last_customer_response'] = current_time('mysql');
375 }
376
377 if (empty($ticketData['created_at'])) {
378 $ticketData['created_at'] = current_time('mysql');
379 }
380 if (empty($ticketData['updated_at'])) {
381 $ticketData['updated_at'] = current_time('mysql');
382 }
383
384 if (empty($ticketData['waiting_since'])) {
385 $ticketData['waiting_since'] = current_time('mysql');
386 }
387
388 return $ticketData;
389 }
390
391
392 public function resolvePerson($personUserId)
393 {
394 $person = get_user_by('ID', $personUserId);
395
396 if (!$person) {
397 return false;
398 }
399
400 return [
401 'user_id' => $personUserId,
402 'full_name' => $person->first_name . ' ' . $person->last_name,
403 'email' => $person->user_email
404 ];
405 }
406
407 public function getUnknownCustomerData($authorId): array
408 {
409 return [
410 'user_id' => 0,
411 'full_name' => 'Unknown User',
412 'email' => 'unknown-' . $authorId . '@example.com',
413 ];
414 }
415 }
416