PluginProbe ʕ •ᴥ•ʔ
LatePoint – Calendar Booking Plugin for Appointments and Events / 5.6.3
LatePoint – Calendar Booking Plugin for Appointments and Events v5.6.3
5.6.5 5.6.4 5.6.3 5.6.2 5.6.1 5.6.0 5.5.2 5.5.1 5.5.0 5.4.2 trunk 5.1.0 5.1.1 5.1.2 5.1.3 5.1.4 5.1.5 5.1.6 5.1.7 5.1.8 5.1.9 5.1.91 5.1.92 5.1.93 5.1.94 5.2.0 5.2.1 5.2.10 5.2.11 5.2.2 5.2.3 5.2.4 5.2.5 5.2.6 5.2.7 5.2.8 5.2.9 5.3.0 5.3.1 5.3.2 5.4.0 5.4.1
latepoint / lib / misc / process_action.php
latepoint / lib / misc Last commit date
blocked_period.php 3 months ago booked_period.php 3 months ago booking_request.php 3 months ago booking_resource.php 3 months ago booking_slot.php 3 months ago filter.php 3 months ago process_action.php 1 month ago process_event.php 1 month ago role.php 2 weeks ago router.php 3 months ago step.php 3 months ago stripe_connect_customer.php 3 months ago time_period.php 3 months ago user.php 3 months ago work_period.php 3 months ago
process_action.php
755 lines
1 <?php
2 /*
3 * Copyright (c) 2022 LatePoint LLC. All rights reserved.
4 */
5
6 namespace LatePoint\Misc;
7
8 class ProcessAction {
9 public string $id;
10 public string $type = 'send_email';
11 public string $status = 'active';
12 public ?array $settings = [];
13 public array $prepared_data_for_run = [];
14 public array $replacement_vars = [];
15 public array $selected_data_objects = []; // example ['model' => 'booking', 'id' => INT]
16 public ProcessEvent $event;
17
18 function __construct( $args = [] ) {
19 $allowed_props = self::allowed_props();
20 foreach ( $args as $key => $arg ) {
21 if ( in_array( $key, $allowed_props ) ) {
22 $this->$key = $arg;
23 }
24 }
25 if ( empty( $this->id ) ) {
26 $this->id = self::generate_id();
27 }
28 switch ( $this->type ) {
29 case 'send_email':
30 $this->settings['to_email'] = $this->settings['to_email'] ?? '';
31 $this->settings['subject'] = $this->settings['subject'] ?? '';
32 $this->settings['content'] = $this->settings['content'] ?? '';
33 break;
34 case 'send_sms':
35 $this->settings['to_phone'] = $this->settings['to_phone'] ?? '';
36 $this->settings['content'] = $this->settings['content'] ?? '';
37 break;
38 case 'send_whatsapp':
39 $this->settings['to_phone'] = $this->settings['to_phone'] ?? '';
40 $this->settings['content'] = $this->settings['content'] ?? '';
41 break;
42 }
43 }
44
45 public function is_attach_calendar() {
46 return ! empty( $this->settings['attach_calendar'] ) && \OsUtilHelper::is_on( $this->settings['attach_calendar'] );
47 }
48
49 public function get_ics_filename_prefix(): string {
50 return isset( $this->settings['ics_filename_prefix'] )
51 ? trim( (string) $this->settings['ics_filename_prefix'] )
52 : '';
53 }
54
55 private function resolve_ics_filename_basename(): string {
56 $raw = $this->get_ics_filename_prefix();
57 if ( $raw === '' ) {
58 return '';
59 }
60 $resolved = \OsReplacerHelper::replace_all_vars( $raw, $this->replacement_vars );
61 // Strip any leftover {{...}} placeholders that the workflow context didn't supply.
62 $resolved = (string) preg_replace( '/\{\{[^}]*\}\}/', '', $resolved );
63 $resolved = sanitize_file_name( trim( $resolved ) );
64 // User typed `.ics` themselves — drop it; we always append our own extension.
65 if ( strtolower( substr( $resolved, -4 ) ) === '.ics' ) {
66 $resolved = substr( $resolved, 0, -4 );
67 }
68 return $resolved;
69 }
70
71 public function get_nice_type_name() {
72 return self::get_action_name_for_type( $this->type );
73 }
74
75 public function get_descriptive_setting() {
76 switch ( $this->type ) {
77 case 'send_email':
78 return $this->settings['to_email'] ?? '';
79 case 'send_sms':
80 return $this->settings['to_phone'] ?? '';
81 case 'send_whatsapp':
82 return $this->settings['to_phone'] ?? '';
83 }
84 }
85
86 public function generate_replacement_vars() {
87 $this->replacement_vars = \OsReplacerHelper::generate_replacement_vars_from_data_objects( $this->selected_data_objects );
88 }
89
90 public function set_from_params( $params ) {
91 if ( ! empty( $params['id'] ) ) {
92 $this->id = $params['id'];
93 }
94 if ( ! empty( $params['type'] ) ) {
95 $this->type = $params['type'];
96 }
97 if ( ! empty( $params['settings'] ) ) {
98 $this->settings = $params['settings'];
99 }
100 if ( ! empty( $params['event'] ) ) {
101 $this->event = new ProcessEvent( [ 'type' => $params['event']['type'] ] );
102 }
103 }
104
105 public function load_settings_from_template( $template_id ) {
106 $templates = \OsNotificationsHelper::load_templates_for_action_type( $this->type );
107 foreach ( $templates as $template ) {
108 if ( $template['id'] == $template_id ) {
109 switch ( $this->type ) {
110 case 'send_email':
111 $this->settings['to_email'] = $template['to_email'];
112 $this->settings['subject'] = $template['subject'];
113 $this->settings['content'] = $template['content'];
114 break;
115 case 'send_sms':
116 $this->settings['to_phone'] = $template['to_phone'];
117 $this->settings['content'] = $template['content'];
118 break;
119 case 'send_whatsapp':
120 $this->settings['to_phone'] = $template['to_phone'];
121 $this->settings['content'] = $template['content'];
122 break;
123 }
124
125 /**
126 * Returns an array of process action settings, based on a selected template
127 *
128 * @since 4.7.0
129 * @hook latepoint_process_action_settings
130 *
131 * @param {array} $settings Array of settings to filter
132 * @param {array} $template Array of data representing selected template
133 * @param {ProcessAction} $action Instance of <code>ProcessAction</code> for which settings are being generated
134 *
135 * @returns {array} Filtered array of process action settings
136 */
137 $this->settings = apply_filters( 'latepoint_process_action_settings', $this->settings, $template, $this );
138 break;
139 }
140 }
141 }
142
143 public static function generate_form( ProcessAction $action, string $process_id = '' ): string {
144 $descriptive_setting = $action->get_descriptive_setting() ? '<div class="process-action-descriptive-setting">' . $action->get_descriptive_setting() . '</div>' : '';
145 $html = '<div class="process-action-form pa-type-' . $action->type . ' pa-status-' . $action->status . '" data-id="' . $action->id . '">';
146 $html .= '<div class="process-action-heading">
147 <div class="process-action-status"></div>
148 <div class="process-action-icon"></div>
149 <div class="process-action-name">' . self::get_action_name_for_type( $action->type ) . '</div>
150 ' . $descriptive_setting . '
151 <div class="process-action-chevron"><i class="latepoint-icon latepoint-icon-chevron-down"></i></div>
152 <a href="#" class="process-action-remove os-remove-process-action"
153 data-os-prompt="' . __( 'Are you sure you want to delete this action?', 'latepoint' ) . '"><i class="latepoint-icon latepoint-icon-cross"></i></a>
154 </div>';
155 $html .= '<div class="process-action-content">';
156 $html .= '<div class="os-row">';
157 $html .= \OsFormHelper::select_field(
158 'process[actions][' . $action->id . '][type]',
159 __( 'Action Type', 'latepoint' ),
160 \LatePoint\Misc\ProcessAction::get_action_types_for_select(),
161 $action->type,
162 [
163 'class' => 'process-action-type',
164 'data-action-id' => $action->id,
165 'data-process-id' => $process_id,
166 'data-route' => \OsRouterHelper::build_route_name( 'processes', 'load_action_settings' ),
167 ],
168 [ 'class' => 'os-col-10' ]
169 );
170 $html .= \OsFormHelper::select_field(
171 'process[actions][' . $action->id . '][status]',
172 __( 'Status', 'latepoint' ),
173 [
174 LATEPOINT_STATUS_ACTIVE => __( 'Active', 'latepoint' ),
175 LATEPOINT_STATUS_DISABLED => __( 'Disabled', 'latepoint' ),
176 ],
177 $action->status,
178 false,
179 [ 'class' => 'os-col-2' ]
180 );
181 $html .= '</div>';
182 $html .= '<div class="process-action-settings">';
183 $html .= self::generate_settings_fields( $action, $process_id );
184 $html .= '</div>';
185 $html .= '<div class="process-buttons">
186 <a href="#" class="latepoint-btn latepoint-btn-danger pull-left os-remove-process-action"
187 data-os-prompt="' . __( 'Are you sure you want to delete this action?', 'latepoint' ) . '" >' . __( 'Delete', 'latepoint' ) . '</a>
188 <a href="#" data-route="' . \OsRouterHelper::build_route_name( 'processes', 'action_test_preview' ) . '" class="latepoint-btn latepoint-btn-secondary os-run-process-action" ><i class="latepoint-icon latepoint-icon-play-circle"></i><span>' . __( 'Test this action', 'latepoint' ) . '</span></a>
189 </div>';
190 $html .= '</div>';
191 $html .= '</div>';
192 return $html;
193 }
194
195
196 public static function generate_settings_fields( ProcessAction $action, string $process_id = '' ) {
197 $html = '';
198
199 if ( in_array( $action->type, [ 'send_email', 'send_sms' ] ) ) {
200 $html .= '<div class="process-action-controls-wrapper">';
201 $html .= '<a href="#" data-os-after-call="latepoint_init_template_library" data-os-params="' . \OsUtilHelper::build_os_params(
202 [
203 'action_id' => $action->id,
204 'action_type' => $action->type,
205 'process_id' => $process_id,
206 ]
207 ) . '" data-os-lightbox-classes="width-1000" data-os-action="' . \OsRouterHelper::build_route_name( 'notifications', 'templates_index' ) . '" href="#" data-os-output-target="side-panel" class="latepoint-btn latepoint-btn-outline latepoint-btn-sm"><i class="latepoint-icon latepoint-icon-book"></i><span>' . __( 'Load from template', 'latepoint' ) . '</span></a>';
208 $html .= '<a href="#" class="latepoint-btn latepoint-btn-outline latepoint-btn-sm open-template-variables-panel"><i class="latepoint-icon latepoint-icon-zap"></i><span>' . __( 'Show smart variables', 'latepoint' ) . '</span></a>';
209 $html .= '</div>';
210 }
211
212 switch ( $action->type ) {
213 case 'send_email':
214 $html .= '<div class="os-row">';
215 $html .= \OsFormHelper::text_field(
216 'process[actions][' . $action->id . '][settings][to_email]',
217 __( 'To Email', 'latepoint' ),
218 $action->settings['to_email'],
219 [
220 'theme' => 'simple',
221 'placeholder' => __( 'To email address', 'latepoint' ),
222 ],
223 [ 'class' => 'os-col-6' ]
224 );
225 $html .= \OsFormHelper::text_field(
226 'process[actions][' . $action->id . '][settings][subject]',
227 __( 'Email Subject', 'latepoint' ),
228 $action->settings['subject'],
229 [
230 'theme' => 'simple',
231 'placeholder' => __( 'Email Subject', 'latepoint' ),
232 ],
233 [ 'class' => 'os-col-6' ]
234 );
235 $html .= '</div>';
236 $html .= \OsFormHelper::textarea_field(
237 'process[actions][' . $action->id . '][settings][content]',
238 false,
239 $action->settings['content'],
240 [
241 'id' => 'process_actions_' . $action->id . '_settings_content',
242 'class' => 'os-wp-editor-textarea',
243 ]
244 );
245
246 $attach_calendar_settings_id = 'process_action_' . $action->id . '_attach_calendar_settings';
247
248 $html .= '<div class="os-row pa-attach-calendar-row">';
249 $html .= '<div class="os-col-4">';
250 $html .= \OsFormHelper::toggler_field(
251 'process[actions][' . $action->id . '][settings][attach_calendar]',
252 __( 'Attach Booking Calendar', 'latepoint' ),
253 $action->is_attach_calendar(),
254 $attach_calendar_settings_id
255 );
256 $html .= '</div>';
257 $html .= '<div class="os-col-8" id="' . esc_attr( $attach_calendar_settings_id ) . '"' . ( $action->is_attach_calendar() ? '' : ' style="display:none"' ) . '>';
258 $html .= \OsFormHelper::text_field(
259 'process[actions][' . $action->id . '][settings][ics_filename_prefix]',
260 __( 'Calendar attachment filename', 'latepoint' ),
261 $action->settings['ics_filename_prefix'] ?? '',
262 [
263 'theme' => 'simple',
264 'placeholder' => __( 'e.g. MyBusiness_{{service_name}}_{{booking_id}}', 'latepoint' ),
265 'sub_label' => __( 'Optional. Use the "Show smart variables" button above to insert placeholders. Leave blank to use the default.', 'latepoint' ),
266 ]
267 );
268 $html .= '</div>';
269 $html .= '</div>';
270 $html .= \OsFormHelper::multiple_files_uploader_field( 'process[actions][' . $action->id . '][settings][attachments]', esc_html__( '+ Attach File', 'latepoint' ), esc_html__( 'Remove File', 'latepoint' ), $action->get_attachments() );
271 break;
272 case 'send_sms':
273 if ( \OsSmsHelper::get_sms_processors() ) {
274 $html .= \OsFormHelper::text_field(
275 'process[actions][' . $action->id . '][settings][to_phone]',
276 __( 'To Phone Number', 'latepoint' ),
277 $action->settings['to_phone'],
278 [
279 'theme' => 'simple',
280 'placeholder' => __( 'Phone Number', 'latepoint' ),
281 ]
282 );
283 $html .= \OsFormHelper::textarea_field(
284 'process[actions][' . $action->id . '][settings][content]',
285 __( 'Message Content', 'latepoint' ),
286 $action->settings['content'],
287 [
288 'theme' => 'simple',
289 'placeholder' => __( 'Message', 'latepoint' ),
290 'rows' => 4,
291 ]
292 );
293 } else {
294 $html = \OsUtilHelper::generate_missing_addon_link( __( 'You have to enable an SMS processor to send text messages. Available in a premium version.', 'latepoint' ) );
295 }
296 break;
297 case 'send_whatsapp':
298 if ( \OsWhatsappHelper::get_whatsapp_processors() ) {
299 $html .= '<div class="latepoint-whatsapp-templates-loader" data-route="' . esc_attr( \OsRouterHelper::build_route_name( 'whatsapp', 'load_templates_for_action' ) ) . '" data-selected-template-id="' . esc_attr( $action->settings['template_id'] ?? '' ) . '" data-process-id="' . esc_attr( $process_id ) . '" data-process-action-id="' . esc_attr( $action->id ) . '"></div>';
300 $html .= '<div class="latepoint-whatsapp-templates-holder">' . \OsFormHelper::get_hidden_fields_for_array( $action->settings, 'process[actions][' . $action->id . ']' ) . '</div>';
301
302 } else {
303 $html = \OsUtilHelper::generate_missing_addon_link( __( 'You have to enable a WhatsApp processor to send messages. Available in a premium version.', 'latepoint' ) );
304 }
305 break;
306 case 'trigger_webhook':
307 $html = \OsUtilHelper::generate_missing_addon_link( __( 'Requires upgrade to a premium version', 'latepoint' ) );
308 break;
309 }
310
311 /**
312 * Filters HTML code (after) for Process Action settings form
313 *
314 * @since 4.7.0
315 * @hook latepoint_process_action_settings_fields_html_after
316 *
317 * @param {string} $html HTML content of the settings form
318 * @param {ProcessAction} $action ProcessAction object for which this settings form is being generated
319 *
320 * @returns {string} HTML content of the settings form
321 */
322 return apply_filters( 'latepoint_process_action_settings_fields_html_after', $html, $action );
323 }
324
325 public static function generate_id(): string {
326 return 'pa_' . \OsUtilHelper::random_text( 'alnum', 6 );
327 }
328
329 public function settings_form() {
330 $html = '';
331 switch ( $this->type ) {
332 case 'send_email':
333 $html .= \OsFormHelper::text_field(
334 'action[actions][' . $this->id . '][to]',
335 '',
336 $this->settings['to'],
337 [
338 'theme' => 'simple',
339 'placeholder' => __( 'Email To', 'latepoint' ),
340 ]
341 );
342 break;
343 case 'send_sms':
344 $html .= \OsFormHelper::text_field(
345 'action[actions][' . $this->id . '][to]',
346 '',
347 $this->settings['to'],
348 [
349 'theme' => 'simple',
350 'placeholder' => __( 'SMS To', 'latepoint' ),
351 ]
352 );
353 break;
354 case 'send_whatsapp':
355 $html .= \OsFormHelper::text_field(
356 'action[actions][' . $this->id . '][to]',
357 '',
358 $this->settings['to'],
359 [
360 'theme' => 'simple',
361 'placeholder' => __( 'WhatsApp Message To', 'latepoint' ),
362 ]
363 );
364 break;
365 case 'trigger_webhook':
366 $html .= \OsFormHelper::text_field(
367 'action[actions][' . $this->id . '][url]',
368 '',
369 $this->settings['url'],
370 [
371 'theme' => 'simple',
372 'placeholder' => __( 'Webhook URL', 'latepoint' ),
373 ]
374 );
375 break;
376 }
377
378 return apply_filters( 'latepoint_process_action_settings_form_html', $html, $this );
379 }
380
381
382 public static function get_action_types() {
383 $action_types = [ 'send_email', 'send_sms', 'trigger_webhook', 'send_whatsapp' ];
384
385 /**
386 * Returns an array of process action types that can be executed when an event is triggered
387 *
388 * @since 4.7.0
389 * @hook latepoint_process_action_types
390 *
391 * @param {array} $action_types Array of action types to filter
392 *
393 * @returns {array} Filtered array of action types
394 */
395 return apply_filters( 'latepoint_process_action_types', $action_types );
396 }
397
398 public static function get_action_name_for_type( $type ) {
399 $names = [
400 'send_email' => __( 'Send Email', 'latepoint' ),
401 'send_sms' => __( 'Send SMS', 'latepoint' ),
402 'trigger_webhook' => __( 'HTTP Request (Webhook)', 'latepoint' ),
403 'send_whatsapp' => __( 'Send WhatsApp Message', 'latepoint' ),
404 ];
405
406 /**
407 * Returns an array of process action types mapped to their displayable names
408 *
409 * @since 4.7.0
410 * @hook latepoint_process_action_names
411 *
412 * @param {array} $names Array of action types/names to filter
413 *
414 * @returns {array} Filtered array of action types/names
415 */
416 $names = apply_filters( 'latepoint_process_action_names', $names );
417
418 return $names[ $type ] ?? __( 'n/a', 'latepoint' );
419 }
420
421 public static function get_action_types_for_select() {
422 $types = self::get_action_types();
423 $types_for_select = [];
424 foreach ( $types as $type ) {
425 $types_for_select[ $type ] = self::get_action_name_for_type( $type );
426 }
427 return $types_for_select;
428 }
429
430 public function prepare_data_for_run() {
431 $this->generate_replacement_vars();
432 foreach ( $this->selected_data_objects as $data_object ) {
433 switch ( $data_object['model'] ) {
434 case 'order':
435 $this->prepared_data_for_run['activity_data']['order_id'] = $data_object['id'];
436 if ( ! empty( $data_object['model_ready'] ) ) {
437 $this->prepared_data_for_run['activity_data']['customer_id'] = $data_object['model_ready']->customer_id;
438 }
439 break;
440 case 'booking':
441 $this->prepared_data_for_run['activity_data']['booking_id'] = $data_object['id'];
442 if ( ! empty( $data_object['model_ready'] ) ) {
443 $this->prepared_data_for_run['activity_data']['agent_id'] = $data_object['model_ready']->agent_id;
444 $this->prepared_data_for_run['activity_data']['service_id'] = $data_object['model_ready']->service_id;
445 $this->prepared_data_for_run['activity_data']['customer_id'] = $data_object['model_ready']->customer_id;
446 }
447 break;
448 case 'customer':
449 $this->prepared_data_for_run['activity_data']['customer_id'] = $data_object['id'];
450 break;
451 case 'transaction':
452 $this->prepared_data_for_run['activity_data']['transaction_id'] = $data_object['id'];
453 break;
454 case 'payment_request':
455 $this->prepared_data_for_run['activity_data']['payment_request_id'] = $data_object['id'];
456 break;
457 }
458 }
459
460 $this->replacement_vars['sender_type'] = $this->type;
461
462 switch ( $this->type ) {
463 case 'send_email':
464 $this->prepared_data_for_run['to'] = \OsReplacerHelper::replace_all_vars( $this->settings['to_email'], $this->replacement_vars );
465 $this->prepared_data_for_run['subject'] = \OsReplacerHelper::replace_all_vars( $this->settings['subject'], $this->replacement_vars );
466 $this->prepared_data_for_run['content'] = \OsReplacerHelper::replace_all_vars( $this->settings['content'], $this->replacement_vars );
467 $this->prepared_data_for_run['attachments'] = [];
468
469 if ( $this->is_attach_calendar() ) {
470 $booking = $this->find_booking_from_selected_data();
471
472 if ( $booking ) {
473 $ical_temp_file = $this->create_ical_temp_file( $booking );
474
475 if ( $ical_temp_file ) {
476 $this->prepared_data_for_run['attachments'][] = $ical_temp_file;
477 $this->prepared_data_for_run['_attachments_temp_files'] = [ $ical_temp_file ];
478 }
479 }
480 }
481 $attachments = $this->get_attachments();
482 if ( ! empty( $attachments ) ) {
483 foreach ( $attachments as $attachment_id ) {
484 $file_path = get_attached_file( $attachment_id );
485 if ( $file_path && file_exists( $file_path ) ) {
486 $this->prepared_data_for_run['attachments'][] = $file_path;
487 } else {
488 \OsDebugHelper::log( 'Attachment file not found: ' . $file_path, 'error' );
489 }
490 }
491 }
492
493 break;
494 case 'send_sms':
495 $this->prepared_data_for_run['to'] = \OsReplacerHelper::replace_all_vars( $this->settings['to_phone'], $this->replacement_vars );
496 $this->prepared_data_for_run['content'] = \OsReplacerHelper::replace_all_vars( $this->settings['content'], $this->replacement_vars );
497 break;
498 case 'send_whatsapp':
499 $this->prepared_data_for_run['to'] = \OsReplacerHelper::replace_all_vars( $this->settings['to_phone'], $this->replacement_vars );
500 $this->prepared_data_for_run['data']['type'] = 'template';
501 $this->prepared_data_for_run['data']['template_id'] = $this->settings['template_id'];
502 $this->prepared_data_for_run['data']['template_language'] = $this->settings['template_language'];
503 $this->prepared_data_for_run['data']['template_parameter_format'] = $this->settings['template_parameter_format'];
504 $this->prepared_data_for_run['data']['template_category'] = $this->settings['template_category'];
505 $this->prepared_data_for_run['data']['template_name'] = $this->settings['template_name'];
506
507 $selected_template = \OsWhatsappHelper::get_template( $this->settings['template_id'] );
508
509 $this->prepared_data_for_run['data']['variables'] = $this->settings['variables'] ?? [];
510 if ( ! empty( $this->settings['variables'] ) ) {
511 foreach ( $this->settings['variables'] as $type => $variables ) {
512 $parameters = [];
513 foreach ( $variables as $key => $value ) {
514 $clean_key = str_replace( [ '{{', '}}' ], '', $key );
515 $replaced_value = \OsReplacerHelper::replace_all_vars( $value, $this->replacement_vars );
516 if ( is_numeric( $clean_key ) ) {
517 $parameters[] = [
518 'type' => 'text',
519 'text' => $replaced_value,
520 ];
521 } else {
522 $parameters[] = [
523 'type' => 'text',
524 'text' => $replaced_value,
525 'parameter_name' => $clean_key,
526 ];
527 }
528 }
529 if ( strtolower( $type ) == 'buttons' ) {
530 // each button has to have a separate component element, only URL typed buttons have variables in them
531 foreach ( $parameters as $index => $parameter ) {
532 $this->prepared_data_for_run['data']['components'][] = [
533 'type' => 'button',
534 'index' => $index,
535 'sub_type' => 'url',
536 'parameters' => $parameters,
537 ];
538 }
539 } else {
540 $this->prepared_data_for_run['data']['components'][] = [
541 'type' => $type,
542 'parameters' => $parameters,
543 ];
544 }
545 }
546 }
547
548 $content_by_type['header'] = \OsWhatsappHelper::get_template_component_value_by_key( $selected_template, 'HEADER', 'text' );
549 $content_by_type['body'] = \OsWhatsappHelper::get_template_component_value_by_key( $selected_template, 'BODY', 'text' );
550 $content_by_type['buttons'] = \OsWhatsappHelper::get_template_component_value_by_key( $selected_template, 'BUTTONS', 'buttons' );
551
552
553 foreach ( $content_by_type as $content_type => $content ) {
554 if ( $content_type == 'buttons' ) {
555 if ( ! empty( $content ) ) {
556 foreach ( $content as $button ) {
557 // only URL can have variables
558 if ( $button['type'] == 'URL' ) {
559 $button['url'] = empty( $this->settings['variables'][ $content_type ] ) ? $button['url'] : \OsReplacerHelper::replace_all_vars( str_replace( array_keys( $this->settings['variables'][ $content_type ] ), array_values( $this->settings['variables'][ $content_type ] ), $button['url'] ), $this->replacement_vars );
560 }
561 $this->prepared_data_for_run[ 'content_for_' . $content_type ][] = $button;
562 }
563 } else {
564 $this->prepared_data_for_run[ 'content_for_' . $content_type ] = [];
565 }
566 } else {
567 $this->prepared_data_for_run[ 'content_for_' . $content_type ] = empty( $this->settings['variables'][ $content_type ] ) ? $content : \OsReplacerHelper::replace_all_vars( str_replace( array_keys( $this->settings['variables'][ $content_type ] ), array_values( $this->settings['variables'][ $content_type ] ), $content ), $this->replacement_vars );
568 }
569 }
570 break;
571 }
572
573 /**
574 * Prepare data for action run
575 *
576 * @since 4.7.0
577 * @hook latepoint_process_prepare_data_for_run
578 *
579 * @param {ProcessAction} $action ProcessAction that was executed
580 *
581 * @returns {ProcessAction} $action ProcessAction with prepared data for action run
582 */
583 return apply_filters( 'latepoint_process_prepare_data_for_run', $this );
584 }
585
586
587 /**
588 * @param $prepare_data
589 * @return array [status => '', 'message' => '']
590 */
591 public function run( $prepare_data = true ) {
592 $result = [
593 'status' => LATEPOINT_STATUS_SUCCESS,
594 'message' => __( 'Nothing to run', 'latepoint' ),
595 ];
596 if ( $prepare_data ) {
597 $this->prepare_data_for_run();
598 }
599
600 switch ( $this->type ) {
601 case 'send_email':
602 $notification_type = 'email';
603 $result = \OsNotificationsHelper::send( $notification_type, $this->prepared_data_for_run );
604 break;
605 case 'send_sms':
606 $notification_type = 'sms';
607 $result = \OsNotificationsHelper::send( $notification_type, $this->prepared_data_for_run );
608 break;
609 case 'send_whatsapp':
610 $notification_type = 'whatsapp';
611 $result = \OsNotificationsHelper::send( $notification_type, $this->prepared_data_for_run );
612 break;
613 }
614
615 $tmp_files = $this->prepared_data_for_run['_attachments_temp_files'] ?? [];
616 foreach ( $tmp_files as $tmp_file ) {
617 if ( file_exists( $tmp_file ) ) {
618 @unlink( $tmp_file );
619 };
620 }
621
622 /**
623 * ProcessAction run result
624 *
625 * @since 4.7.0
626 * @hook latepoint_process_action_run
627 *
628 * @param {array} $result The array of data describing the status of the action run
629 * @param {ProcessAction} $action ProcessAction that was executed
630 *
631 * @returns {array} The array of descriptive data, possibly transformed by additional hooked ProcessAction handlers
632 */
633 return apply_filters( 'latepoint_process_action_run', $result, $this );
634 }
635
636
637 /**
638 * @return string
639 */
640 public function generate_preview() {
641 if ( empty( $this->prepared_data_for_run ) ) {
642 $this->prepare_data_for_run();
643 // nothing was generated, probably because there is no object attached
644 if ( empty( $this->prepared_data_for_run ) ) {
645 return '<div class="action-preview-error">' . __( 'You have to create a booking to be able to test this action.', 'latepoint' ) . '</div>';
646 }
647 }
648 $html = '<div class="action-preview-content-wrapper">';
649 $preview_content_html = '';
650 switch ( $this->type ) {
651 case 'send_email':
652 $preview_content_html .= '<div class="action-preview-subject"><span class="os-label">' . __( 'Subject:', 'latepoint' ) . '</span> ' . esc_html( $this->prepared_data_for_run['subject'] ) . '</div>';
653 $preview_content_html .= '<div class="action-preview-to"><span class="os-label">' . __( 'To:', 'latepoint' ) . '</span><span class="os-value">' . esc_html( $this->prepared_data_for_run['to'] ) . '</div>';
654 $preview_content_html .= '<div class="action-preview-content">' . wp_kses_post( $this->prepared_data_for_run['content'] ) . '</div>';
655 break;
656 case 'send_sms':
657 $preview_content_html .= '<div class="action-preview-to"><span class="os-label">' . __( 'To:', 'latepoint' ) . '</span><span class="os-value">' . esc_html( $this->prepared_data_for_run['to'] ) . '</span></div>';
658 $preview_content_html .= '<div class="action-preview-content">' . wp_kses_post( $this->prepared_data_for_run['content'] ) . '</div>';
659 break;
660 case 'send_whatsapp':
661 $preview_content_html .= '<div class="action-preview-to"><span class="os-label">' . __( 'To:', 'latepoint' ) . '</span><span class="os-value">' . esc_html( $this->prepared_data_for_run['to'] ) . '</span></div>';
662 $preview_content_html .= '<div class="action-preview-content">';
663 $preview_content_html .= '<div class="latepoint-whatsapp-template-preview-messages">';
664 $preview_content_html .= '<div class="latepoint-whatsapp-template-preview-message">';
665 $preview_content_html .= '<div class="latepoint-whatsapp-template-preview-message-header">' . wp_kses_post( $this->prepared_data_for_run['content_for_header'] ) . '</div>';
666 $preview_content_html .= '<div class="latepoint-whatsapp-template-preview-message-body">' . wp_kses_post( $this->prepared_data_for_run['content_for_body'] ) . '</div>';
667 if ( $this->prepared_data_for_run['content_for_buttons'] ) {
668 $preview_content_html .= '<div class="latepoint-whatsapp-template-preview-message-buttons">';
669 foreach ( $this->prepared_data_for_run['content_for_buttons'] as $button ) {
670 switch ( $button['type'] ) {
671 case 'PHONE_NUMBER':
672 $preview_content_html .= '<a href="tel:' . esc_url( $button['phone_number'] ) . '" class="latepoint-whatsapp-template-preview-message-button"><i class="latepoint-icon latepoint-icon-phone"></i>' . esc_html( $button['text'] ) . '</a>';
673 break;
674 case 'URL':
675 $preview_content_html .= '<a href="' . esc_url( $button['url'] ) . '" class="latepoint-whatsapp-template-preview-message-button"><i class="latepoint-icon latepoint-icon-external-link"></i>' . esc_html( $button['text'] ) . '</a>';
676 break;
677 }
678 }
679 $preview_content_html .= '</div>';
680 }
681 $preview_content_html .= '</div>';
682 $preview_content_html .= '</div>';
683 $preview_content_html .= '</div>';
684 break;
685 }
686
687 /**
688 * Generates a preview html for ProcessAction testing
689 *
690 * @since 4.7.0
691 * @hook latepoint_process_action_generate_preview
692 *
693 * @param {string} $preview_content_html HTML that goes inside of a preview
694 * @param {ProcessAction} $action ProcessAction that is being tested
695 *
696 * @returns {string} HTML that goes inside of a preview
697 */
698 $preview_content_html = apply_filters( 'latepoint_process_action_generate_preview', $preview_content_html, $this );
699 $html .= $preview_content_html;
700 $html .= '</div>';
701 return $html;
702 }
703
704 private function find_booking_from_selected_data() {
705 foreach ( $this->selected_data_objects as $data_object ) {
706 if ( $data_object['model'] === 'booking' && ! empty( $data_object['model_ready'] ) ) {
707 return $data_object['model_ready'];
708 }
709 }
710 return null;
711 }
712
713 private function create_ical_temp_file( $booking ) {
714 try {
715 $ical_content = \OsBookingHelper::generate_ical_event_string( $booking );
716 if ( empty( $ical_content ) ) {
717 throw new \Exception( 'iCal content is empty' );
718 }
719
720 $resolved_basename = $this->resolve_ics_filename_basename();
721
722 if ( $resolved_basename !== '' ) {
723 $temp_file = tempnam( sys_get_temp_dir(), $resolved_basename . '_' );
724 $ical_temp_file = $temp_file . '.ics';
725 rename( $temp_file, $ical_temp_file );
726 } else {
727 $temp_file = tempnam( sys_get_temp_dir(), 'latepoint_ical_' );
728 $ical_temp_file = $temp_file . '.ics';
729 rename( $temp_file, $ical_temp_file );
730 }
731
732 if ( file_put_contents( $ical_temp_file, $ical_content ) !== false ) {
733 return $ical_temp_file;
734 } else {
735 throw new \Exception( 'Failed to write iCal content to file' );
736 }
737 } catch ( \Exception $e ) {
738 \OsDebugHelper::log( 'Failed to create iCal file: ' . $e->getMessage(), 'error' );
739 }
740
741 return null;
742 }
743
744 public static function replace_variables( $test ) {
745 }
746
747 public static function allowed_props(): array {
748 return [ 'id', 'type', 'settings', 'status' ];
749 }
750
751 public function get_attachments() {
752 return ! empty( $this->settings['attachments'] ) ? explode( ',', $this->settings['attachments'] ) : [];
753 }
754 }
755