PluginProbe
Fluent Support – Helpdesk & Customer Support Ticket System / 2.3.0
Fluent Support – Helpdesk & Customer Support Ticket System v2.3.0
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 / Models / Traits / CustomerTrait.php

CustomerTrait.php in Fluent Support – Helpdesk & Customer Support Ticket System 2.3.0, at app/Models/Traits/CustomerTrait.php

495 lines 16.0 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\Models\Traits;
4
5 use Exception;
6 use FluentSupport\App\Models\Ticket;
7 use FluentSupport\App\Services\Helper;
8 use FluentSupport\Framework\Support\Arr;
9 use FluentSupport\App\Services\ProfileInfoService;
10
11 trait CustomerTrait
12 {
13
14 /**
15 * This getCustomers method will return all customers
16 * @param string $search
17 * @param string $status
18 * @return object
19 */
20 public function getCustomers($search, $status=false)
21 {
22 $customersQuery = static::latest();
23
24 if ( $search ) {
25 $customersQuery = $customersQuery->searchBy($search);
26 }
27
28 if ($status && $status != 'all') {
29 $customersQuery->filterByStatues([$status]);
30 }
31
32 $customers = $customersQuery->paginate();
33
34 if ( defined( 'FLUENTCRM' ) && $customers->isEmpty() && !$status ) {
35 $customers = $this->findInCrmAndMakeCustomer ( $search );
36 ! is_null( $customers ) ? $customers : $customers = $customersQuery->paginate();
37 }
38
39 if ( defined('FLUENT_SUPPORT_PRO_DIR_FILE') && $customers->isEmpty() && !$status ) {
40 $customers = $this->findUserInWPAndMakeCustomer( $search );
41 ! is_null( $customers ) ? $customers : $customers = $customersQuery->paginate();
42 }
43
44 return $this->attachCustomersMetaData( $customers );
45 }
46
47 public function getCustomerField($customer_id,$userID = null)
48 {
49 $basicFields = [
50 'first_name' => [
51 'label' => __('First Name', 'fluent-support'),
52 'data_type' => 'text',
53 'placeholder' => __('First Name', 'fluent-support'),
54 'type' => 'input-text',
55 'wrapper_class' => 'fs_half_field required',
56 ],
57 'last_name' => [
58 'label' => __('Last Name', 'fluent-support'),
59 'data_type' => 'text',
60 'placeholder' => __('Last Name', 'fluent-support'),
61 'type' => 'input-text',
62 'wrapper_class' => 'fs_half_field',
63 ],
64 'email' => [
65 'label' => __('Email', 'fluent-support'),
66 'data_type' => 'email',
67 'placeholder' => __('Email', 'fluent-support'),
68 'type' => 'input-text',
69 'wrapper_class' => 'fs_half_field required',
70 'disabled' => !empty($customer_id),
71 ],
72 'title' => [
73 'label' => __('Job Title', 'fluent-support'),
74 'data_type' => 'text',
75 'placeholder' => __('Job Title', 'fluent-support'),
76 'type' => 'input-text',
77 'wrapper_class' => 'fs_half_field',
78 ],
79 'note' => [
80 'label' => __('Note', 'fluent-support'),
81 'data_type' => 'textarea',
82 'placeholder' => __('Note', 'fluent-support'),
83 'type' => 'input-text',
84 ],
85 'status' => [
86 'label' => __('Status', 'fluent-support'),
87 'data_type' => 'text',
88 'type' => 'input-radio',
89 'options' => [
90 'active' => ['id' => 'active', 'value' => 'active', 'label' => __('Active', 'fluent-support')],
91 'inactive' => ['id' => 'inactive', 'value' => 'inactive', 'label' => __('Blocked', 'fluent-support')],
92 ],
93 ],
94 'status_html' => [
95 'dependency' => [
96 'depends_on' => 'status',
97 'operator' => '=',
98 'value' => 'inactive',
99 ],
100 'type' => 'html-viewer',
101 'wrapper_class' => 'fs_warn_alert_wrapper',
102 'html' => __('If you select the <b>Blocked</b> status, this customer will not be able to submit a ticket or any response.', 'fluent-support'),
103 ],
104 ];
105
106 $addressFields = [
107 'address_line_1' => [
108 'label' => __('Address Line 1', 'fluent-support'),
109 'data_type' => 'text',
110 'placeholder' => __('Address Line 1', 'fluent-support'),
111 'type' => 'input-text',
112 'wrapper_class' => 'fs_half_field',
113 ],
114 'address_line_2' => [
115 'label' => __('Address Line 2', 'fluent-support'),
116 'data_type' => 'text',
117 'placeholder' => __('Address Line 2', 'fluent-support'),
118 'type' => 'input-text',
119 'wrapper_class' => 'fs_half_field',
120 ],
121 'city' => [
122 'label' => __('City', 'fluent-support'),
123 'data_type' => 'text',
124 'placeholder' => __('City', 'fluent-support'),
125 'type' => 'input-text',
126 'wrapper_class' => 'fs_half_field',
127 ],
128 'state' => [
129 'label' => __('State', 'fluent-support'),
130 'data_type' => 'text',
131 'placeholder' => __('State', 'fluent-support'),
132 'type' => 'input-text',
133 'wrapper_class' => 'fs_half_field',
134 ],
135 'zip' => [
136 'label' => __('Zip Code', 'fluent-support'),
137 'data_type' => 'text',
138 'placeholder' => __('Zip Code', 'fluent-support'),
139 'type' => 'input-text',
140 'wrapper_class' => 'fs_half_field',
141 ],
142 'country' => [
143 'label' => __('Country', 'fluent-support'),
144 'placeholder' => __('Country', 'fluent-support'),
145 'type' => 'country-selector',
146 'wrapper_class' => 'fs_half_field',
147 ],
148 ];
149
150 if ($userID) {
151 $addressFields = apply_filters('fluent_support/custom_registration_form_fields',$addressFields);
152
153 foreach ($addressFields as $key => $field) {
154 if (isset($field['type']) && $field['type'] === 'country-selector') {
155 continue; // Skip conversion for country-selector
156 }
157
158 //To create a custom field using _formBuilder.vue, the 'type' should be 'input-text', and the 'data_type' may vary, such as (text, number, date...).
159 $addressFields[$key]['data_type'] = $addressFields[$key]['type'];
160 $addressFields[$key]['type'] = 'input-text';
161 }
162 }
163
164 $loading = false;
165
166 $state = [
167 'basic_fields' => $basicFields,
168 'address_fields' => $addressFields,
169 'loading' => $loading,
170 ];
171
172 return $state;
173
174 }
175
176 /**
177 * This `findUserInWPAndMakeCustomer` method will find customer in WP Users and make it as a customer
178 * @param string $search
179 * @return object
180 */
181 public function findUserInWPAndMakeCustomer ( $search )
182 {
183 if ( is_email( $search ) ){
184 $user = get_user_by( 'email', $search );
185
186 if( $user ) {
187 unset( $user->user_pass );
188 $customerData = [
189 'user_id' => $user->ID,
190 'email' => $user->user_email,
191 'first_name' => $user->first_name,
192 'last_name' => $user->last_name
193 ];
194 $customer = static::maybeCreateCustomer( $customerData );
195 return static::where('email', $user->user_email)->paginate();
196 }
197 }
198 }
199
200 /**
201 * This `findInCrmAndMakeCustomer` method will find customer in Fluent CRM and make it as a customer
202 * @param string $search
203 * @return object
204 */
205 public function findInCrmAndMakeCustomer ( $search )
206 {
207 $customer = \FluentCrm\App\Models\Subscriber::where( 'email', $search )->first();
208 if( $customer ) {
209 $customerData = [
210 'email' => $customer->email,
211 'first_name' => $customer->first_name,
212 'last_name' => $customer->last_name
213 ];
214 $customer = static::maybeCreateCustomer( $customerData );
215 return static::where('email', $customer->email)->paginate();
216 }
217 }
218
219 /**
220 * This getCustomer method will return a single customer
221 * @param int $id
222 * @param array $with
223 * @return object
224 */
225
226 public function getCustomer($id, $with)
227 {
228 $customer = static::find($id);
229
230 $data = [
231 'customer' => $customer
232 ];
233
234 if (!$with) {
235 return $data;
236 }
237
238 return $this->getCustomerAdditionalData($with, $customer, $data);
239 }
240
241 /**
242 * This createCustomer method will create a new customer
243 * @param array $data
244 * @return object
245 */
246
247 public function createCustomer($data)
248 {
249 $data = Arr::only($data, $this->getFillable());
250
251 $user = get_user_by('email', $data['email']);
252
253 if ($user) {
254 $data['user_id'] = $user->ID;
255 if (empty($data['first_name'])) {
256 $data['first_name'] = $user->first_name;
257 }
258 if (empty($data['last_name'])) {
259 $data['last_name'] = $user->last_name;
260 }
261 }
262
263 return static::create($data);
264 }
265
266 /**
267 * This updateCustomer method will update a customer
268 * @since 1.5.7
269 * @param int $customerId
270 * @param array $data
271 * @return object
272 */
273
274 public function updateCustomer($customerId, $data)
275 {
276 $customFieldsKeys = apply_filters('fluent_support/custom_registration_form_fields_key', Helper::getBusinessSettings('custom_registration_form_field'));
277 $customFieldsKeys = is_array($customFieldsKeys) ? $customFieldsKeys : [];
278 $customFormValue = Arr::only($data, $customFieldsKeys);
279
280 $data = $this->takeValidKeysForUpdate($data);
281
282 if (isset($data['last_response_at']) && empty($data['last_response_at'])) {
283 unset($data['last_response_at']);
284 }
285
286 $customer = static::findOrFail($customerId);
287
288 if($this->customerExists($customerId, $data['email']))
289 {
290 throw new \Exception('Another Customer has same email address');
291 }
292
293 $user = get_user_by('email', $data['email']);
294
295 if ($user && !empty($customFieldsKeys)) {
296 $data['user_id'] = $user->ID;
297
298 //Update Custom field data for user
299 foreach ($customFieldsKeys as $key) {
300 if (isset($customFormValue[$key])) {
301 $fieldValue = $customFormValue[$key];
302 update_user_meta($user->ID, $key, $fieldValue);
303 }
304 }
305 }
306
307 static::where('id', $customer->id)->update($data);
308
309 return static::findOrFail($customerId);
310 }
311
312 /**
313 * deleteCustomer method will delete a customer and all tickets by that customer
314 * @since 1.5.7
315 * @param int $customerId
316 * @return array
317 */
318
319 public function deleteCustomer($customerId)
320 {
321 $customer = static::findOrFail($customerId);
322
323 $tickets = Ticket::where('customer_id', $customer->id)->get();
324
325 foreach ($tickets as $ticket) {
326 $ticket->deleteTicket();
327 }
328
329 $customer->delete();
330
331 return [
332 'message' => __('Customer Deleted Successfully', 'fluent-support')
333 ];
334 }
335
336 /**
337 * bulkDeleteCustomers method will delete multiple customers and all their tickets
338 * @since 1.9.3
339 * @param array $customerIds
340 * @return array
341 */
342 public function bulkDeleteCustomers($customerIds)
343 {
344 if (empty($customerIds) || !is_array($customerIds)) {
345 return [
346 'message' => __('No customers selected for deletion', 'fluent-support')
347 ];
348 }
349
350 $deletedCount = 0;
351 $errors = [];
352
353 foreach ($customerIds as $customerId) {
354 try {
355 $customer = static::findOrFail($customerId);
356
357 $tickets = Ticket::where('customer_id', $customer->id)->get();
358
359 foreach ($tickets as $ticket) {
360 $ticket->deleteTicket();
361 }
362
363 $customer->delete();
364 $deletedCount++;
365
366 } catch (\Exception $e) {
367 /* translators: %1$d: customer ID, %2$s: error message */
368 $errors[] = sprintf(__('Failed to delete customer ID %1$d: %2$s', 'fluent-support'), $customerId, $e->getMessage());
369 }
370 }
371
372 if ($deletedCount > 0) {
373 /* translators: %1$d: number of customers deleted */
374 $message = $deletedCount === 1
375 ? __('Customer deleted successfully', 'fluent-support')
376 : sprintf(__('%1$d customers deleted successfully', 'fluent-support'), $deletedCount);
377 } else {
378 $message = __('No customers were deleted', 'fluent-support');
379 }
380
381 $response = [
382 'message' => $message,
383 'deleted_count' => $deletedCount,
384 'total_requested' => count($customerIds)
385 ];
386
387 if (!empty($errors)) {
388 $response['errors'] = $errors;
389 }
390
391 return $response;
392 }
393
394 /**
395 * This attachCustomersMetaData method will attach meta data to customers
396 * @since 1.5.7
397 * @param object $customers
398 * @return object
399 */
400 private function attachCustomersMetaData($customers)
401 {
402 foreach ($customers as $customer) {
403 $customer->total_tickets = $customer->getTicketCounts();
404 $customer->total_responses = $customer->getResponseCounts();
405 if ($customer->user_id) {
406 //Get profile link, if they are WP user
407 $customer->user_profile = admin_url('user-edit.php?user_id=' . $customer->user_id);
408 }
409 }
410
411 return $customers;
412 }
413
414 /**
415 * This getCustomerAdditionalData method will return additional data for a customer
416 * @since 1.5.7
417 * @param array $with
418 * @param object $customer
419 * @param array $data
420 * @return array
421 */
422
423 private function getCustomerAdditionalData($with, $customer, $data)
424 {
425 $customFieldKeys = apply_filters('fluent_support/custom_registration_form_fields_key', []);
426
427 $userMetaData = get_user_meta($customer['user_id']);
428
429 //Custom field data from wp user_meta
430 foreach ($customFieldKeys as $fieldKey) {
431 if (isset($userMetaData[$fieldKey][0])) {
432 $customer[$fieldKey] = $userMetaData[$fieldKey][0];
433 }
434 }
435
436 if (in_array('widgets', $with)) {
437 $data['widgets'] = ProfileInfoService::getProfileExtraWidgets($customer);
438 }
439
440 if (in_array('tickets', $with)) {
441 /*
442 * Filter ticket limit to show ticket in customer page sidebar
443 * @since 1.5.6
444 * @param int $limit
445 */
446 $limit = apply_filters('fluent_support/customer_page_ticket_widgets_limit', 20);
447
448 $data['tickets'] = Ticket::select(['id', 'title', 'status', 'customer_id', 'created_at'])
449 ->where('customer_id', $customer->id)
450 ->latest('id')
451 ->limit($limit)
452 ->get();
453 }
454
455 if(in_array('fluentcrm_profile', $with)) {
456 $data['fluentcrm_profile'] = Helper::getFluentCrmContactData($customer);
457 }
458
459 return $data;
460 }
461
462 /**
463 * This customerExists method will check if customer exists
464 * @since 1.5.7
465 * @param int $customerId
466 * @param string $email
467 * @return mixed
468 */
469
470 private function customerExists($customerId, $email)
471 {
472 $customer = static::where('id','!=', $customerId)->where('email', $email)->first();
473 if ($customer) {
474 return $customer;
475 }
476 return false;
477 }
478
479
480 /**
481 * This takeValidKeysForUpdate method will take valid keys data for update
482 * @since 1.5.7
483 * @param array $data
484 * @return array
485 */
486 private function takeValidKeysForUpdate($data)
487 {
488 $validKeys = $this->getFillable();
489 unset($validKeys['hash']);
490 unset($validKeys['user_id']);
491
492 return Arr::only($data, $validKeys);
493 }
494 }
495