PluginProbe
Fluent Support – Helpdesk & Customer Support Ticket System / trunk
Fluent Support – Helpdesk & Customer Support Ticket System vtrunk
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 / EmailNotification / Settings.php

Settings.php in Fluent Support – Helpdesk & Customer Support Ticket System trunk, at app/Services/EmailNotification/Settings.php

713 lines 36.8 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\EmailNotification;
4 use FluentSupportPro\Database\Migrations\TimeTrackMigrator;
5
6 use FluentSupport\App\Services\Helper;
7 use FluentSupport\App\Services\Notifications\NotificationSettings;
8 use FluentSupport\Framework\Support\Arr;
9
10 class Settings
11 {
12 public function getEmailSettingsKeys()
13 {
14 $key = apply_filters('fluent_support/email_setting_keys', [
15 'ticket_created_email_to_customer',
16 'ticket_replied_by_agent_email_to_customer',
17 'ticket_closed_by_agent_email_to_customer',
18 'ticket_created_email_to_admin',
19 'ticket_replied_by_customer_email_to_admin',
20 'ticket_agent_on_change',
21 'ticket_created_by_agent_email_to_customer',
22 'ticket_created_by_agent_on_behalf_email_to_customer'
23 ]);
24 return $key;
25 }
26
27 public function get($settingsKey)
28 {
29 if ($settingsKey == 'global_business_settings') {
30 return [
31 'settings' => $this->globalBusinessSettings(),
32 'fields' => $this->getGlobalBusinessSettingsFields()
33 ];
34 }
35
36 if ($settingsKey == NotificationSettings::OPTION_KEY) {
37 $notificationSettings = new NotificationSettings();
38
39 return [
40 'settings' => $notificationSettings->get(false),
41 'fields' => $notificationSettings->getFields()
42 ];
43 }
44
45 return [
46 'settings' => [],
47 'fields' => []
48 ];
49 }
50
51 /**
52 * save method will save the requested settings by settings key
53 * @param $settingsKey
54 * @param $settings
55 * @return mixed
56 */
57 public function save($settingsKey, $settings)
58 {
59 if ($settingsKey == 'global_business_settings' && is_array($settings) && array_key_exists('internal_notifications_enabled', $settings)) {
60 $notificationSettings = new NotificationSettings();
61 $savedNotificationSettings = $notificationSettings->get(false);
62 $savedNotificationSettings['enabled'] = $settings['internal_notifications_enabled'];
63 $notificationSettings->save($savedNotificationSettings);
64 }
65
66 if ($settingsKey == 'global_business_settings' && empty($settings['accepted_file_types'])) {
67 $settings['accepted_file_types'] = [];
68 }
69
70 if ($settingsKey == 'global_business_settings') {
71 $settings['ticket_link_portal_migrated'] = 'yes';
72 if (isset($settings['min_serial_number'])) {
73 $settings['min_serial_number'] = max(1, (int) $settings['min_serial_number']);
74 }
75 // The frontend only ever offers 3/7/15 — reject anything else
76 // (a tampered request, or a stale/unexpected value) back to the
77 // 15-day default rather than trusting the submitted value as-is.
78 if (isset($settings['report_snapshot_retention']) && !in_array($settings['report_snapshot_retention'], ['3', '7', '15'], true)) {
79 $settings['report_snapshot_retention'] = '15';
80 }
81 }
82
83 if ($settingsKey == 'global_business_settings' && !empty($settings['agent_time_tracking'])) {
84 if (class_exists(TimeTrackMigrator::class) && $settings['agent_time_tracking'] === 'yes') {
85 TimeTrackMigrator::migrate();
86 }
87 }
88
89 if ($settingsKey == NotificationSettings::OPTION_KEY) {
90 return (new NotificationSettings())->save($settings);
91 }
92
93 $result = Helper::updateOption($settingsKey, $settings);
94
95 return $result;
96 }
97
98 /**
99 * globalBusinessSettings method will fetch global settings from database, parse and return
100 * @param bool $cached
101 * @return array|mixed
102 */
103 public function globalBusinessSettings($cached = true)
104 {
105 static $settings;
106
107 if($cached && $settings) {
108 return $settings;
109 }
110
111 $defaults = [
112 'portal_page_id' => '',
113 'ticket_link_portal' => 'default',
114 'ticket_link_portal_migrated' => 'no',
115 // translators: %1$s is opening paragraph tag, %2$s is closing paragraph tag
116 'login_message' => sprintf(__('%1$sPlease login or create an account to access the Customer Support Portal%2$s [fluent_support_auth]', 'fluent-support'), '<p>', '</p>'),
117 'disable_public_ticket' => 'no',
118 'accepted_file_types' => ['images', 'csv', 'documents', 'zip', 'json'],
119 'max_file_size' => 2,
120 'max_file_upload' => 3,
121 'del_files_on_close' => 'no',
122 'enable_admin_bar_summary' => 'no',
123 'internal_notifications_enabled' => 'no',
124 'enable_draft_mode' => 'no',
125 'agent_feedback_rating' => 'no',
126 'keyboard_shortcuts' => 'yes',
127 'enable_min_serial_number' => 'no',
128 'ticket_prefix' => '',
129 'min_serial_number' => 1,
130 'enable_fluent_booking_integration' => 'no',
131 'report_snapshot_retention' => '15',
132 ];
133
134 //Get default/existing settings from database using the key global_business_settings
135 $existingSettings = Helper::getOption('global_business_settings', []);
136
137 if (!$existingSettings) {
138 $settings = $defaults;
139 return $settings;
140 }
141
142 $settings = wp_parse_args($existingSettings, $defaults);
143 $settings['ticket_link_portal'] = $settings['ticket_link_portal'] ?: 'default';
144
145 if (Arr::get($settings, 'ticket_link_portal_migrated') !== 'yes') {
146 $settings['ticket_link_portal'] = $this->resolveLegacyTicketLinkPortal($settings);
147 $settings['ticket_link_portal_migrated'] = 'yes';
148 Helper::updateOption('global_business_settings', $settings);
149 }
150
151 return $settings;
152 }
153
154 private function resolveLegacyTicketLinkPortal($settings)
155 {
156 $selectedPortal = Arr::get($settings, 'ticket_link_portal', 'default');
157
158 if ($selectedPortal && $selectedPortal !== 'default') {
159 return $selectedPortal;
160 }
161
162 $ticketFormSettings = Helper::getOption('_ticket_form_settings', []);
163
164 if (Arr::get($settings, 'enable_fc_menu') === 'yes') {
165 return 'fluent_cart';
166 }
167
168 // The legacy pro plugin defaulted enable_woo_menu to 'yes', so treat an
169 // absent value the same as 'yes' — only skip migration if explicitly 'no'.
170 // WC portal was always Pro-only, so require Pro to be active as well.
171 if (defined('FLUENTSUPPORTPRO_PLUGIN_VERSION') && defined('WC_PLUGIN_FILE') && Arr::get($ticketFormSettings, 'enable_woo_menu', 'yes') !== 'no') {
172 return 'woocommerce';
173 }
174
175 return 'default';
176 }
177
178
179 /**
180 * getGlobalBusinessSettingsFields method will prepare the list of field, and it's property that will be used in global settings form
181 * @return array
182 */
183 private function getGlobalBusinessSettingsFields()
184 {
185 $nextSerialNumber = \FluentSupport\App\Models\Ticket::getNextSerialNumber();
186
187 $mimeGroups = Helper::getMimeGroups();
188
189 $formattedMimeGroups = [];
190
191 foreach ($mimeGroups as $mimeGroup => $mime) {
192 $formattedMimeGroups[$mimeGroup] = $mime['title'];
193 }
194
195 $customRegistrationFormOptions = array(
196 'address_line_1' => 'Address Line 1',
197 'address_line_2' => 'Address Line 2',
198 'city' => 'City',
199 'zip' => 'Zip Code',
200 'state' => 'State',
201 'country' => 'Country',
202 );
203
204 $fields = [
205 'ticket_link_portal_description' => [
206 'type' => 'html-viewer',
207 'label' => __('Customer Portal', 'fluent-support'),
208 'wrapper_class' => 'fs_portal_destination_description',
209 ],
210 'ticket_link_portal' => [
211 'type' => 'input-radio',
212 'wrapper_class' => 'fs_portal_destination_options',
213 'options' => $this->getTicketLinkPortalOptions(),
214 ],
215 'fluent_community_portal_link' => [
216 'type' => 'html-viewer',
217 'wrapper_class' => 'fs_fluent_community_portal_link',
218 'html' => $this->getFluentCommunityPortalLinkHtml(),
219 'dependency' => [
220 'depends_on' => 'ticket_link_portal',
221 'operator' => '=',
222 'value' => 'fluent_community'
223 ],
224 ],
225 'portal_page_id' => [
226 'type' => 'input-options',
227 'label' => __('Select a Page', 'fluent-support'),
228 'wrapper_class' => 'fs_portal_page_selector',
229 'show_id' => true,
230 'placeholder' => __('Select Portal Page', 'fluent-support'),
231 'options' => Helper::getWPPages(),//Get list of published pages
232 'inline_help' => __('Please provide the page id where you want to show the tickets for your customers. Use shortcode <code>[fluent_support_portal]</code> in that page', 'fluent-support'),
233 'admin_url' => admin_url(),
234 'home_url' => home_url('/'),
235 'dependency' => [
236 'depends_on' => 'ticket_link_portal',
237 'operator' => '=',
238 'value' => 'default'
239 ],
240 ],
241 'login_message' => [
242 'type' => 'wp-editor',
243 'label' => __('Message for non logged in users', 'fluent-support'),
244 'inline_help' => __('Please provide message for not logged in users. You can place login shortcode too. Use shortcode <code>[fluent_support_login]</code> to show built-in login form. For the user registration use this shortcode <code>[fluent_support_signup]</code> and for both form please use <code>[fluent_support_auth]</code>', 'fluent-support')
245 ],
246 'disable_public_ticket' => [
247 'wrapper_class' => '',
248 'type' => 'inline-checkbox',
249 'label' => __('Public Ticket Interaction', 'fluent-support'),
250 'true_label' => 'yes',
251 'false-label' => 'no',
252 'checkbox_label' => __('Disable Public Ticket interaction', 'fluent-support'),
253 'inline_help' => __('If you enable this then only logged in user can reply the tickets. Otherwise, url will be signed and intended user can reply without logging in', 'fluent-support')
254 ],
255 'accepted_file_types' => [
256 'wrapper_class' => '',
257 'type' => 'checkbox-group',
258 'label' => __('Accepted File Types', 'fluent-support'),
259 'options' => $formattedMimeGroups
260 ],
261 'max_file_size' => [
262 'wrapper_class' => 'fs_settings_half_field',
263 'type' => 'input-text',
264 'data_type' => 'number',
265 'label' => __('Max File Size (in MegaByte)', 'fluent-support'),
266 ],
267 'max_file_upload' => [
268 'wrapper_class' => 'fs_settings_half_field',
269 'type' => 'input-text',
270 'data_type' => 'number',
271 'label' => __('Maximum File Upload', 'fluent-support'),
272 ],
273 'del_files_on_close' => [
274 'wrapper_class' => '',
275 'type' => 'inline-checkbox',
276 'true_label' => 'yes',
277 'false-label' => 'no',
278 'checkbox_label' => __('Delete all attachments on ticket close', 'fluent-support'),
279 'inline_help' => __('If you enable this feature, all attachments associated with a ticket will be deleted when the ticket is closed.', 'fluent-support')
280 ],
281 'enable_admin_bar_summary' => [
282 'wrapper_class' => '',
283 'type' => 'inline-checkbox',
284 'true_label' => 'yes',
285 'false-label' => 'no',
286 'checkbox_label' => __('Enable Fluent Summary In Admin Bar', 'fluent-support'),
287 'inline_help' => __('If you enable this, logged in user can see the ticket summary from top nav bar.', 'fluent-support')
288 ],
289 'internal_notifications_enabled' => [
290 'wrapper_class' => '',
291 'type' => 'inline-checkbox',
292 'true_label' => 'yes',
293 'false-label' => 'no',
294 'checkbox_label' => __('Enable Internal Notifications', 'fluent-support'),
295 'inline_help' => sprintf(
296 '<ul><li>%1$s</li><li>%2$s</li></ul>',
297 __('Enable the in-app notification bell, unread counts, and notification event storage for agents.', 'fluent-support'),
298 __('Notification data older than 15 days will be removed automatically.', 'fluent-support')
299 )
300 ],
301 'enable_draft_mode' => [
302 'wrapper_class' => '',
303 'type' => 'inline-checkbox',
304 'true_label' => 'yes',
305 'false-label' => 'no',
306 'checkbox_label' => __('Enable Draft Mode', 'fluent-support'),
307 'inline_help' => __('If you enable this setting, any written response will be saved as a draft if an agent accidentally closes a ticket.', 'fluent-support')
308 ],
309 'custom_registration_form_field' => [
310 'wrapper_class' => '',
311 'type' => 'checkbox-group',
312 'label' => __('Custom Registration Form Field', 'fluent-support'),
313 'options' => $customRegistrationFormOptions
314 ],
315 'enable_two_fa' => [
316 'wrapper_class' => '',
317 'type' => 'inline-checkbox',
318 'true_label' => 'yes',
319 'false-label' => 'no',
320 'checkbox_label' => __('Enable Two-Factor Authentication', 'fluent-support'),
321 'inline_help' => __('If you enable this setting, users will be required to submit a second form of authentication, such as a code sent to their email, to login.', 'fluent-support')
322 ],
323 'keyboard_shortcuts' => [
324 'wrapper_class' => '',
325 'type' => 'inline-checkbox',
326 'true_label' => 'yes',
327 'false-label' => 'no',
328 'checkbox_label' => __('Enable Keyboard Shortcuts', 'fluent-support'),
329 'inline_help' => __("If you enable this, agents can use keyboard shortcuts for faster actions.", 'fluent-support'),
330 'shortcut_modal' => $this->getKeyboardShortcutModalData()
331 ],
332 'enable_min_serial_number' => [
333 'wrapper_class' => '',
334 'type' => 'inline-checkbox',
335 'true_label' => 'yes',
336 'false-label' => 'no',
337 'checkbox_label' => __('Enable Minimum Ticket Number', 'fluent-support'),
338 'inline_help' => __('Enable this to start public ticket numbers from a custom minimum number.', 'fluent-support')
339 ],
340 'min_serial_number' => [
341 'wrapper_class' => 'fs_settings_half_field',
342 'type' => 'input-text',
343 'data_type' => 'number',
344 'label' => __('Minimum Ticket Number', 'fluent-support'),
345 'help' => __('Once a ticket is created, you cannot lower this value below the current highest ticket number. Set this carefully — raising it is easy, but lowering it below an existing ticket number is not allowed.', 'fluent-support'),
346 'inline_help' => sprintf(
347 __('Next Ticket Number: %d', 'fluent-support'),
348 $nextSerialNumber
349 ),
350 'next_serial_number' => $nextSerialNumber,
351 'dependency' => [
352 'depends_on' => 'enable_min_serial_number',
353 'operator' => '=',
354 'value' => 'yes'
355 ]
356 ],
357 'ticket_prefix' => [
358 'wrapper_class' => 'fs_settings_half_field',
359 'type' => 'input-text',
360 'data_type' => 'text',
361 'label' => __('Ticket Prefix', 'fluent-support'),
362 'inline_help' => __('Optional prefix for newly created public ticket numbers.', 'fluent-support'),
363 'dependency' => [
364 'depends_on' => 'enable_min_serial_number',
365 'operator' => '=',
366 'value' => 'yes'
367 ]
368 ],
369 'report_snapshot_retention' => [
370 'wrapper_class' => '',
371 'type' => 'input-radio',
372 'label' => __('Snapshot Retention', 'fluent-support'),
373 'options' => [
374 ['id' => '3', 'label' => __('3 days', 'fluent-support')],
375 ['id' => '7', 'label' => __('7 days', 'fluent-support')],
376 ['id' => '15', 'label' => __('15 days', 'fluent-support')],
377 ],
378 'inline_help' => __('Advanced Reports saves a snapshot of each report every 6 hours. Snapshots older than this many days are automatically deleted.', 'fluent-support'),
379 ]
380 ];
381 if (defined('FLUENT_BOOKING_VERSION')) {
382 $fields['enable_fluent_booking_integration'] = [
383 'wrapper_class' => '',
384 'type' => 'inline-checkbox',
385 'true_label' => 'yes',
386 'false-label' => 'no',
387 'checkbox_label' => __('Enable Fluent Booking Integration', 'fluent-support'),
388 'inline_help' => __('If you enable this, agents can create booking links and view meeting details inside tickets.', 'fluent-support')
389 ];
390 }
391
392 if (defined('FLUENTSUPPORTPRO_PLUGIN_VERSION')) {
393 $fields['agent_feedback_rating'] = [
394 'wrapper_class' => '',
395 'type' => 'inline-checkbox',
396 'true_label' => 'yes',
397 'false-label' => 'no',
398 'checkbox_label' => __('Agent Feedback Rating', 'fluent-support'),
399 'inline_help' => __("If you enable this setting, users will have the option to provide feedback on an agent's response.", 'fluent-support')
400 ];
401
402 $fields['agent_time_tracking'] = [
403 'wrapper_class' => '',
404 'type' => 'inline-checkbox',
405 'true_label' => 'yes',
406 'false-label' => 'no',
407 'checkbox_label' => __('Agent Time Tracking', 'fluent-support'),
408 'inline_help' => __("If you enable this setting, the agent can specify the amount of time needed to complete a ticket.", 'fluent-support')
409 ];
410
411 }
412
413 return $fields;
414 }
415
416 private function getTicketLinkPortalOptions()
417 {
418 $options = [
419 [
420 'id' => 'default',
421 'label' => __('Default Portal Page', 'fluent-support'),
422 ],
423 ];
424
425 if (Helper::isPortalActive('fluent_cart')) {
426 $options[] = [
427 'id' => 'fluent_cart',
428 'label' => __('FluentCart Account Navigation', 'fluent-support'),
429 ];
430 }
431
432 if (Helper::isPortalActive('woocommerce')) {
433 $options[] = [
434 'id' => 'woocommerce',
435 'label' => __('WooCommerce Account Navigation', 'fluent-support'),
436 ];
437 }
438
439 if (Helper::isPortalActive('fluent_community')) {
440 $options[] = [
441 'id' => 'fluent_community',
442 'label' => __('FluentCommunity Portal', 'fluent-support'),
443 ];
444 }
445
446 return apply_filters('fluent_support/ticket_link_portal_options', $options);
447 }
448
449 private function getFluentCommunityPortalLinkHtml()
450 {
451 if (!defined('FLUENT_COMMUNITY_PLUGIN_VERSION') || !class_exists('\FluentCommunity\App\Services\Helper')) {
452 return '';
453 }
454
455 $portalLink = rtrim(\FluentCommunity\App\Services\Helper::baseUrl('support/'), '/\\') . '/';
456
457 return '<div class="fs_portal_link_content">'
458 . '<span class="fs_portal_link_label">' . esc_html__('FluentCommunity Portal URL', 'fluent-support') . '</span>'
459 . '<button type="button" class="fs_portal_link_token" data-portal-link="' . esc_attr($portalLink) . '">'
460 . '<span class="fs_portal_link_text">' . esc_html($portalLink) . '</span>'
461 . '<span class="fs_portal_link_action">' . esc_html__('Copy', 'fluent-support') . '</span>'
462 . '</button>'
463 . '<p class="fc_inline_help">' . esc_html__('Copy this URL and add it to your FluentCommunity menu.', 'fluent-support') . '</p>'
464 . '</div>';
465 }
466
467 /**
468 * Returns translatable keyboard shortcut modal data for the settings form.
469 *
470 * @return array{title: string, mac_label: string, win_label: string, action_label: string, shortcut_label: string, mac_shortcuts: array, win_shortcuts: array}
471 */
472 public function getKeyboardShortcutModalData()
473 {
474 $actionLabel = __('Action', 'fluent-support');
475 $shortcutLabel = __('Shortcut', 'fluent-support');
476
477 $macShortcuts = [
478 ['action' => __('Tickets – Advanced filter toggle', 'fluent-support'), 'shortcut' => '⌘ + ⌥ + f'],
479 ['action' => __('Tickets – Refresh', 'fluent-support'), 'shortcut' => '⌘ + ⌥ + q'],
480 ['action' => __('Tickets – Create Ticket', 'fluent-support'), 'shortcut' => '⌘ + ⌥ + n'],
481 ['action' => __('Tickets – Reset filter', 'fluent-support'), 'shortcut' => '⌘ + ⌥ + r'],
482 ['action' => __('Tickets – All Tickets', 'fluent-support'), 'shortcut' => '⌘ + ⇧ + a'],
483 ['action' => __('Tickets – My Tickets', 'fluent-support'), 'shortcut' => '⌘ + ⇧ + m'],
484 ['action' => __('Tickets – Unassigned', 'fluent-support'), 'shortcut' => '⌘ + ⇧ + u'],
485 ['action' => __('Tickets – Waiting for reply', 'fluent-support'), 'shortcut' => '⌘ + ⌥ + w'],
486 ['action' => __('Tickets – Bookmarks', 'fluent-support'), 'shortcut' => '⌘ + ⇧ + b'],
487 ['action' => __('Tickets – Toggle (Open, active, close, all)', 'fluent-support'), 'shortcut' => '⌘ + ⇧ + → / ←'],
488 ['action' => __('Ticket Reply – Reply', 'fluent-support'), 'shortcut' => '⌘ + ⌥ + r'],
489 ['action' => __('Ticket Reply – Personal note', 'fluent-support'), 'shortcut' => '⌘ + ⌥ + n'],
490 ['action' => __('Ticket Reply – Merge', 'fluent-support'), 'shortcut' => '⌘ + ⌥ + m'],
491 ['action' => __('Ticket Reply – Bookmarks', 'fluent-support'), 'shortcut' => '⌘ + ⌥ + b'],
492 ['action' => __('Ticket Reply – Refresh', 'fluent-support'), 'shortcut' => '⌘ + ⌥ + q'],
493 ];
494
495 $winShortcuts = [
496 ['action' => __('Tickets – Advanced filter toggle', 'fluent-support'), 'shortcut' => 'Alt + Win + Shift + f'],
497 ['action' => __('Tickets – Refresh', 'fluent-support'), 'shortcut' => 'Alt + Win + q'],
498 ['action' => __('Tickets – Create Ticket', 'fluent-support'), 'shortcut' => 'Alt + Win + n'],
499 ['action' => __('Tickets – Reset filter', 'fluent-support'), 'shortcut' => 'Alt + Win + Shift + r'],
500 ['action' => __('Tickets – All Tickets', 'fluent-support'), 'shortcut' => 'Win + Shift + a'],
501 ['action' => __('Tickets – My Tickets', 'fluent-support'), 'shortcut' => 'Alt + Win + Shift + m'],
502 ['action' => __('Tickets – Unassigned', 'fluent-support'), 'shortcut' => 'Win + Shift + u'],
503 ['action' => __('Tickets – Waiting for reply', 'fluent-support'), 'shortcut' => 'Alt + Win + Shift + w'],
504 ['action' => __('Tickets – Bookmarks', 'fluent-support'), 'shortcut' => 'Win + Shift + b'],
505 ['action' => __('Ticket Reply – Reply', 'fluent-support'), 'shortcut' => 'Alt + Win + Shift + r'],
506 ['action' => __('Ticket Reply – Personal note', 'fluent-support'), 'shortcut' => 'Alt + Win + n'],
507 ['action' => __('Ticket Reply – Merge', 'fluent-support'), 'shortcut' => 'Ctrl + Alt + Win + m'],
508 ['action' => __('Ticket Reply – Bookmarks', 'fluent-support'), 'shortcut' => 'Ctrl + Alt + Win + b'],
509 ['action' => __('Ticket Reply – Refresh', 'fluent-support'), 'shortcut' => 'Alt + Win + q'],
510 ];
511
512 return [
513 'title' => __('Keyboard Shortcuts', 'fluent-support'),
514 'mac_label' => __('macOS', 'fluent-support'),
515 'win_label' => __('Windows', 'fluent-support'),
516 'action_label' => $actionLabel,
517 'shortcut_label'=> $shortcutLabel,
518 'mac_shortcuts' => $macShortcuts,
519 'win_shortcuts' => $winShortcuts,
520 ];
521 }
522
523 public function saveBoxEmailSettings($box, $emailKey, $settings)
524 {
525 return $box->saveMeta('_email_' . $emailKey, $settings);
526 }
527
528 /**
529 * getBoxEmailSettings method will reply the email settings
530 * @param $box
531 * @param $emailKey
532 * @return array|false
533 */
534 public function getBoxEmailSettings($box, $emailKey)
535 {
536 if (!$box) {
537 return false;
538 }
539
540 #ticket_closed_by_agent_email_to_customer 2 times, is it wrong or right!!!
541 $strictSubjectKeys = apply_filters('fluent_support/strict_subjects', [
542 'ticket_replied_by_agent_email_to_customer',
543 'ticket_closed_by_agent_email_to_customer',
544 'ticket_created_email_to_customer'
545 ]);
546
547 $settingsDefaults = [
548 'ticket_created_email_to_customer' => [
549 'key' => 'ticket_created_email_to_customer',
550 'title' => __('Ticket Created (To Customer)', 'fluent-support'),
551 'description' => __('This email will be sent when a customer submit a support ticket', 'fluent-support'),
552 'email_subject' => 'Re: {{ticket.title}} #{{ticket.id}}',
553 'default_status' => 'no',
554 'send_attachments'=> 'no'
555 ],
556 'ticket_replied_by_agent_email_to_customer' => [
557 'key' => 'ticket_replied_by_agent_email_to_customer',
558 'title' => __('Replied by Agent (To Customer)', 'fluent-support'),
559 'description' => __('This email will be sent when an agent reply to a ticket', 'fluent-support'),
560 'email_subject' => 'Re: {{ticket.title}} #{{ticket.id}}',
561 'default_status' => 'yes',
562 'send_attachments'=> 'no'
563 ],
564 'ticket_closed_by_agent_email_to_customer' => [
565 'key' => 'ticket_closed_by_agent_email_to_customer',
566 'title' => __('Ticket Closed by Agent (To Customer)', 'fluent-support'),
567 'description' => __('This email will be sent when an agent close a ticket', 'fluent-support'),
568 'email_subject' => 'Re: {{ticket.title}} #{{ticket.id}}',
569 'default_status' => 'no',
570 'send_attachments'=> 'no'
571 ],
572 'ticket_created_email_to_admin' => [
573 'key' => 'ticket_created_email_to_admin',
574 'title' => __('Ticket Created (To Admin)', 'fluent-support'),
575 'description' => __('This email will be sent when the business when a new ticket has been submitted', 'fluent-support'),
576 'email_subject' => 'New Ticket: {{ticket.title}} #{{ticket.id}}',
577 'default_status' => 'yes',
578 'send_attachments'=> 'no'
579 ],
580 'ticket_replied_by_customer_email_to_admin' => [
581 'key' => 'ticket_replied_by_customer_email_to_admin',
582 'title' => __('Replied by Customer (To Agent/Admin)', 'fluent-support'),
583 'description' => __('This email will be sent to Assigned Agent or Admin when a customer reply to a ticket', 'fluent-support'),
584 'email_subject' => 'New Response: {{ticket.title}} #{{ticket.id}}',
585 'default_status' => 'yes',
586 'send_attachments'=> 'no'
587 ],
588 'ticket_agent_on_change' => [
589 'key' => 'ticket_agent_on_change',
590 'title' => __('Ticket Agent Change (To Agent)', 'fluent-support'),
591 'description' => __('This email will be sent to newly assigned agent', 'fluent-support'),
592 'email_subject' => 'Ticket Agent Change: {{ticket.title}} #{{ticket.id}}',
593 'default_status' => 'yes',
594 'send_attachments'=> 'no'
595 ],
596 'ticket_created_by_agent_email_to_customer' => [
597 'key' => 'ticket_created_by_agent_email_to_customer',
598 'title' => __('Ticket Logged by Agent (To Customer)', 'fluent-support'),
599 'description' => __('This email will be sent when an agent logs a ticket on behalf of a customer (e.g. from a phone call or email received outside the system)', 'fluent-support'),
600 'email_subject' => 'Re: {{ticket.title}} #{{ticket.id}}',
601 'default_status' => 'no',
602 'send_attachments'=> 'no'
603 ],
604 'ticket_created_by_agent_on_behalf_email_to_customer' => [
605 'key' => 'ticket_created_by_agent_on_behalf_email_to_customer',
606 'title' => __('Agent Outreach Ticket (To Customer)', 'fluent-support'),
607 'description' => __('This email will be sent when an agent creates a ticket using the "Agent Initiated" option to proactively reach out to a customer — includes the agent\'s message content', 'fluent-support'),
608 'email_subject' => 'Your ticket has been created (#{{ticket.id}})',
609 'default_status' => 'yes',
610 'send_attachments'=> 'no'
611 ]
612 ];
613
614 if (!isset($settingsDefaults[$emailKey])) {
615 return false;
616 }
617
618 $savedSettings = (array)$box->getMeta('_email_' . $emailKey, []);
619
620
621 if (!$savedSettings) {
622 $savedSettings = [
623 'key' => $settingsDefaults[$emailKey]['key'],
624 'title' => $settingsDefaults[$emailKey]['title'],
625 'email_subject' => $settingsDefaults[$emailKey]['email_subject'],
626 'email_body' => $this->getDefaultEmailBody($emailKey, $box->box_type),
627 'status' => $settingsDefaults[$emailKey]['default_status'],
628 'can_edit_subject' => (in_array($emailKey, $strictSubjectKeys) && $box->box_type == 'email') ? 'no' : 'yes',
629 'send_attachments' => $settingsDefaults[$emailKey]['send_attachments']
630 ];
631
632 if ($box->box_type == 'email' && in_array($emailKey, $strictSubjectKeys)) {
633 $savedSettings['email_subject'] = 'Re: {{ticket.title}}';
634 $savedSettings['can_edit_subject'] = 'no';
635 }
636
637 return $savedSettings;
638 }
639
640 $savedSettings['key'] = $settingsDefaults[$emailKey]['key'];
641 $savedSettings['title'] = $settingsDefaults[$emailKey]['title'];
642 $savedSettings['description'] = $settingsDefaults[$emailKey]['description'];
643
644 if ($box->box_type == 'email' && in_array($emailKey, $strictSubjectKeys)) {
645 $savedSettings['email_subject'] = 'Re: {{ticket.title}}';
646 $savedSettings['can_edit_subject'] = 'no';
647 }
648
649 if (empty($savedSettings['email_subject'])) {
650 $savedSettings['email_subject'] = $settingsDefaults[$emailKey]['email_subject'];
651 }
652
653 if (empty($savedSettings['status'])) {
654 $savedSettings['status'] = $settingsDefaults[$emailKey]['default_status'];
655 }
656
657 if (empty($savedSettings['email_body'])) {
658 $savedSettings['email_body'] = $this->getDefaultEmailBody($emailKey, $box->box_type);
659 }
660
661 if (empty($savedSettings['send_attachments'])) {
662 $savedSettings['send_attachments'] = $settingsDefaults[$emailKey]['send_attachments'];
663 }
664
665 return $savedSettings;
666 }
667
668 /**
669 * getDefaultEmailBody method will return html for email body
670 * @param $emailKey
671 * @param string $type
672 * @return string
673 */
674 private function getDefaultEmailBody($emailKey, $type = 'web')
675 {
676 if ($emailKey == 'ticket_created_email_to_customer') {
677 if ($type == 'web') {
678 return '<p>Hi <strong><em>{{customer.full_name}}</em>,</strong></p><p>Your request (<a href="{{ticket.public_url}}">#{{ticket.id}}</a>) has been received, and is being reviewed by our support staff.</p><p>To add additional comments, follow the link below:</p><h4><a href="{{ticket.public_url}}">View Ticket</a></h4><p>&nbsp;</p><p>or follow this link: {{ticket.public_url}}</p><hr /><p>{{business.name}}</p>';
679 } else {
680 return '<p>Hi <strong><em>{{customer.full_name}}</em>,</strong></p><p>Your request has been received, and is being reviewed by our support staff.</p><p>Our support staff will reply back to you soon</p>';
681 }
682 } else if ($emailKey == 'ticket_replied_by_agent_email_to_customer') {
683 if ($type == 'web') {
684 return '<p>Hi <strong><em>{{customer.full_name}}</em>,</strong></p><p>An agent just replied to your ticket "<strong>{{ticket.title}}</strong>" (<a href="{{ticket.public_url}}">#{{ticket.id}}</a>). To view his reply or add additional comments, click the button below:</p><h4><a href="{{ticket.public_url}}">View Ticket</a></h4><p>or follow this link: {{ticket.public_url}}</p><hr /><p>Regards,<br />{{business.name}}</p>';
685 } else {
686 return '{{response.full_content}}<p>Regards,<br />{{agent.full_name}}</p>';
687 }
688 } else if ($emailKey == 'ticket_closed_by_agent_email_to_customer') {
689 if ($type == 'web') {
690 return '<p>Hi <strong><em>{{customer.full_name}},</strong></p><p>Your ticket - {{ticket.title}}</p><p>We hope that the ticket was resolved to your satisfaction. If you feel that the ticket should not be closed or if the ticket has not been resolved, please reopen the ticket (<a href="{{ticket.public_url}}">#{{ticket.id}}</a>)</p><p>Regards,<br />{{business.name}}</p>';
691 } else {
692 return '<p>Hi <strong><em>{{customer.full_name}},</strong></p><p>Your ticket - {{ticket.title}}</p><p>We hope that the ticket was resolved to your satisfaction. If you feel that the ticket should not be closed or if the ticket has not been resolved, please feel free to reply back.<p>Regards,<br />{{business.name}}</p>';
693 }
694 } else if ($emailKey == 'ticket_created_email_to_admin') {
695 return '<p>A new ticket (<a href="{{ticket.admin_url}}">{{ticket.title}}</a>) as been submitted by {{customer.full_name}}</p><h4>Ticket Body</h4><p>{{ticket.content}}</p><p><b><a href="{{ticket.admin_url}}">View Ticket</a></b></p>';
696 } else if ($emailKey == 'ticket_replied_by_customer_email_to_admin') {
697 return '<p>A new response has been added to "<a href="{{ticket.admin_url}}">{{ticket.title}}</a>" by {{customer.full_name}}</p><h4>Response Body</h4><p>{{response.content}}</p><p><b><a href="{{ticket.admin_url}}">View Ticket</a></b></p>';
698 } else if($emailKey == 'ticket_agent_on_change') {
699 return '<p>Hi <strong><em>{{agent.full_name}}</em>,</strong></p><p>Ticket "<a href="{{ticket.admin_url}}">#{{ticket.id}}</a>" assigned to you.</p>';
700 } else if($emailKey == 'ticket_created_by_agent_email_to_customer') {
701 return '<p>Hi <strong><em>{{customer.full_name}}</em>,</strong></p><p>{{agent.full_name}} created a ticket on behalf of you, you can check it <a href="{{ticket.public_url}}">here</a></p>.';
702 } else if($emailKey == 'ticket_created_by_agent_on_behalf_email_to_customer') {
703 if ($type == 'web') {
704 return '<p>Hi <strong><em>{{customer.full_name}}</em>,</strong></p><p>A support agent has created a new ticket on your behalf titled "{{ticket.title}}" (#{{ticket.id}}).</p><p>You can review the details, track progress, or add additional comments by clicking the button below:</p><h4><a href="{{ticket.public_url}}">View Ticket</a></h4><p>Or follow this link: {{ticket.public_url}}</p><p>Best regards,<br />{{agent.full_name}}</p>';
705 } else {
706 return '{{response.full_content}}<p>Regards,<br />{{agent.full_name}}</p>';
707 }
708 }
709
710 return '';
711 }
712 }
713