PluginProbe
Fluent Booking – The Ultimate Appointments Scheduling, Events Booking, Events Calendar Solution / 1.5.21
Fluent Booking – The Ultimate Appointments Scheduling, Events Booking, Events Calendar Solution v1.5.21
2.4.0 2.3.0 2.2.5 2.2.0 2.1.2 2.1.1 trunk 1.10.0 1.10.01 1.10.02 1.5.0 1.5.01 1.5.02 1.5.1 1.5.10 1.5.20 1.5.21 1.5.22 1.5.23 1.5.24 1.5.25 1.6.0 1.7.0 1.7.1 1.7.2 All 33 releases
fluent-booking / app / Services / Integrations / FluentCRM / Bootstrap.php

Bootstrap.php in Fluent Booking – The Ultimate Appointments Scheduling, Events Booking, Events Calendar Solution 1.5.21, at app/Services/Integrations/FluentCRM/Bootstrap.php

443 lines 15.7 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2
3 namespace FluentBooking\App\Services\Integrations\FluentCRM;
4
5 use FluentCrm\App\Models\Tag;
6 use FluentCrm\App\Models\Lists;
7 use FluentCrm\App\Models\Subscriber;
8 use FluentBooking\Framework\Support\Arr;
9 use FluentCrm\App\Models\CustomContactField;
10 use FluentBooking\App\Http\Controllers\IntegrationManagerController;
11
12 class Bootstrap extends IntegrationManagerController
13 {
14 public $hasGlobalMenu = false;
15
16 public $disableGlobalSettings = 'yes';
17
18 public function __construct()
19 {
20 parent::__construct(
21 __('FluentCRM', 'fluent-booking'),
22 'fluentcrm',
23 '_fluent_booking_fluentcrm_settings',
24 'fluentcrm_feeds',
25 10
26 );
27
28 $this->logo = FLUENTCRM_PLUGIN_URL . 'assets/images/fluentcrm-logo.svg';
29
30 $this->description = __('Connect FluentCRM with Fluent Booking and subscribe a contact when a booking is created.', 'fluent-booking');
31
32 $this->registerAdminHooks();
33
34 add_filter('fluent_booking/notifying_async_fluentcrm', '__return_false');
35 }
36
37 public function pushIntegration($integrations, $calendarEventId)
38 {
39 $integrations[$this->integrationKey] = [
40 'title' => $this->title . ' ' . __('Integration', 'fluent-booking'),
41 'logo' => $this->logo,
42 'is_active' => $this->isConfigured(),
43 'configure_title' => __('Configuration required!', 'fluent-booking'),
44 'global_configure_url' => '#',
45 'configure_message' => __('FluentCRM is not configured yet! Please configure your FluentCRM api first', 'fluent-booking'),
46 'configure_button_text' => __('Set FluentCRM', 'fluent-booking'),
47 ];
48
49 return $integrations;
50 }
51
52 public function getIntegrationDefaults($settings, $calendarEventId)
53 {
54 return [
55 'name' => '',
56 'first_name' => '{{guest.first_name}}',
57 'last_name' => '{{guest.last_name}}',
58 'email' => '{{guest.email}}',
59 'other_fields' => [
60 [
61 'item_value' => '',
62 'label' => '',
63 ],
64 ],
65 'list_ids' => '',
66 'tag_ids' => [],
67 'skip_if_exists' => false,
68 'double_opt_in' => false,
69 'force_subscribe' => false,
70 'skip_primary_data' => false,
71 'conditionals' => [
72 'conditions' => [],
73 'status' => false,
74 'type' => 'all',
75 ],
76 'run_events_only' => [],
77 'remove_tags' => [],
78 'enabled' => true,
79 ];
80 }
81
82 public function getSettingsFields($settings, $slotId)
83 {
84 $fieldOptions = [];
85
86 foreach (Subscriber::mappables() as $key => $column) {
87 $fieldOptions[$key] = $column;
88 }
89
90 foreach ((new CustomContactField)->getGlobalFields()['fields'] as $field) {
91 $fieldOptions[$field['slug']] = $field['label'];
92 }
93
94 $fieldOptions['avatar'] = __('Profile Photo', 'fluent-booking');
95
96 unset($fieldOptions['email']);
97 unset($fieldOptions['first_name']);
98 unset($fieldOptions['last_name']);
99 unset($fieldOptions['prefix']);
100 unset($fieldOptions['full_name']);
101 unset($fieldOptions['company_id']);
102
103 $fields = [
104 [
105 'key' => 'name',
106 'label' => __('Feed Name', 'fluent-booking'),
107 'required' => true,
108 'placeholder' => __('Your Feed Name', 'fluent-booking'),
109 'component' => 'text',
110 ],
111 [
112 'key' => 'CustomFields',
113 'require_list' => false,
114 'label' => __('Map Primary Fields', 'fluent-booking'),
115 'tips' => __('Associate your FluentCRM merge tags to the appropriate Fluent Form fields by selecting the appropriate form field from the list.', 'fluent-booking'),
116 'component' => 'map_fields',
117 'field_label_remote' => __('FluentCRM Field', 'fluent-booking'),
118 'field_label_local' => __('Booking Field', 'fluent-booking'),
119 'primary_fields' => [
120 [
121 'key' => 'email',
122 'label' => __('Email Address', 'fluent-booking'),
123 'required' => true,
124 'input_options' => 'emails',
125 ],
126 [
127 'key' => 'first_name',
128 'label' => __('First Name', 'fluent-booking'),
129 ],
130 [
131 'key' => 'last_name',
132 'label' => __('Last Name', 'fluent-booking'),
133 ]
134 ],
135 ],
136 [
137 'key' => 'other_fields',
138 'require_list' => false,
139 'label' => __('Other Fields', 'fluent-booking'),
140 'tips' => __('Select which Fluent Form fields pair with their<br /> respective FlunentCRM fields.', 'fluent-booking'),
141 'component' => 'dropdown_many_fields',
142 'field_label_remote' => __('FluentCRM Field', 'fluent-booking'),
143 'field_label_local' => __('Form Field', 'fluent-booking'),
144 'options' => $fieldOptions,
145 ],
146 [
147 'key' => 'list_ids',
148 'label' => __('FluentCRM Lists', 'fluent-booking'),
149 'placeholder' => __('Select FluentCRM Lists', 'fluent-booking'),
150 'tips' => __('Select the FluentCRM Lists you would like to add your contacts to.', 'fluent-booking'),
151 'component' => 'select',
152 'is_multiple' => true,
153 'required' => false,
154 'options' => $this->getLists(),
155 ],
156 [
157 'key' => 'tag_ids',
158 'require_list' => false,
159 'label' => __('Contact Tags', 'fluent-booking'),
160 'placeholder' => __('Select Tags', 'fluent-booking'),
161 'component' => 'select',
162 'is_multiple' => true,
163 'options' => $this->getTags(),
164 ],
165 [
166 'key' => 'skip_if_exists',
167 'require_list' => false,
168 'checkbox_label' => __('Skip if contact already exist in FluentCRM', 'fluent-booking'),
169 'component' => 'checkbox-single',
170 ],
171 [
172 'key' => 'skip_primary_data',
173 'require_list' => false,
174 'checkbox_label' => __('Skip name update if existing contact have old data (per primary field)', 'fluent-booking'),
175 'component' => 'checkbox-single',
176 ],
177 [
178 'key' => 'double_opt_in',
179 'require_list' => false,
180 'checkbox_label' => __('Enable Double opt-in for new contacts', 'fluent-booking'),
181 'component' => 'checkbox-single',
182 ],
183 [
184 'key' => 'force_subscribe',
185 'require_list' => false,
186 'checkbox_label' => __('Enable Force Subscribe if contact is not in subscribed status (Existing contact only)', 'fluent-booking'),
187 'component' => 'checkbox-single',
188 'inline_tip' => __('If you enable this then contact will forcefully subscribed no matter in which status that contact had', 'fluent-booking'),
189 ],
190 [
191 'require_list' => false,
192 'required' => true,
193 'key' => 'event_trigger',
194 'options' => [
195 'after_booking_scheduled' => __('Booking Confirmed', 'fluent-booking'),
196 'booking_schedule_completed' => __('Booking Completed', 'fluent-booking'),
197 'booking_schedule_cancelled' => __('Booking Canceled', 'fluent-booking'),
198 ],
199 'tips' => __('Select in which booking stage you want to trigger this feed', 'fluent-booking'),
200 'label' => __('Event Trigger', 'fluent-booking'),
201 'component' => 'checkbox-multiple-text',
202 'checkbox_label' => __('Event Trigger For This Feed', 'fluent-booking'),
203 ]
204 ];
205
206 $fields[] = [
207 'require_list' => false,
208 'key' => 'remove_tags',
209 'label' => __('Remove Contact Tags', 'fluent-booking'),
210 'placeholder' => __('Select Tags (remove from contact)', 'fluent-booking'),
211 'tips' => __('(Optional) The selected tags will be removed from the contact (if exist)', 'fluent-booking'),
212 'component' => 'select',
213 'is_multiple' => true,
214 'required' => false,
215 'options' => $this->getTags(),
216 ];
217
218 $fields[] = [
219 'require_list' => false,
220 'key' => 'enabled',
221 'label' => __('Status', 'fluent-booking'),
222 'component' => 'checkbox-single',
223 'checkbox_label' => __('Enable This feed', 'fluent-booking'),
224 ];
225
226 return [
227 'fields' => $fields,
228 'button_require_list' => false,
229 'integration_title' => $this->title,
230 ];
231 }
232
233 public function getMergeFields($list, $listId, $slotId)
234 {
235 return [];
236 }
237
238 public function getConfigFieldOptions($settings, $slotId)
239 {
240 return [];
241 }
242
243 protected function getLists()
244 {
245 $lists = Lists::orderBy('title', 'ASC')->get();
246 $formattedLists = [];
247 foreach ($lists as $list) {
248 $formattedLists[$list->id] = $list->title;
249 }
250
251 return $formattedLists;
252 }
253
254 protected function getTags()
255 {
256 $tags = Tag::orderBy('title', 'ASC')->get();
257 $formattedTags = [];
258 foreach ($tags as $tag) {
259 $formattedTags[strval($tag->id)] = $tag->title;
260 }
261
262 return $formattedTags;
263 }
264
265 /*
266 * Submission Hooks Here
267 */
268 public function notify($feed, $booking, $calendarEvent)
269 {
270 $data = $feed['processedValues'];
271 $contact = Arr::only($data, ['first_name', 'last_name', 'email']);
272
273 if (empty($contact['email'])) {
274 return false;
275 }
276
277 foreach (Arr::get($data, 'other_fields') as $field) {
278 if ($field['item_value']) {
279 $contact[$field['label']] = $field['item_value'];
280 }
281 }
282
283 if ($booking->ip_address) {
284 $contact['ip'] = $booking->ip_address;
285 }
286
287 if (!is_email($contact['email'])) {
288 $this->addLog(
289 $feed['settings']['name'],
290 __('FluentCRM API called skipped because no valid email available', 'fluent-booking'),
291 $booking->id,
292 'failed'
293 );
294 return false;
295 }
296
297 $subscriber = Subscriber::where('email', $contact['email'])->first();
298 if ($subscriber && Arr::isTrue($data, 'skip_if_exists')) {
299 $this->addLog(
300 $feed['settings']['name'],
301 __('Contact creation has been skipped because contact already exist in the database', 'fluent-booking'),
302 $booking->id,
303 'failed'
304 );
305 return false;
306 }
307
308 if (!empty($contact['avatar'])) {
309 // validate the avatar photo
310 $validUrl = '';
311 if (false !== filter_var($contact['avatar'], FILTER_VALIDATE_URL)) {
312 $url = $contact['avatar'];
313 $dots = explode('.', $url);
314 $ext = strtolower(end($dots));
315
316 if (in_array($ext, ['png', 'jpg', 'jpeg', 'webp', 'gif'])) {
317 $validUrl = $contact['avatar'];
318 }
319 }
320
321 if (!$validUrl) {
322 unset($contact['avatar']);
323 }
324 }
325
326 if ($subscriber) {
327 if ($subscriber->ip && isset($contact['ip'])) {
328 unset($contact['ip']);
329 }
330
331 if (Arr::isTrue($data, 'skip_primary_data')) {
332 if ($subscriber->first_name) {
333 unset($contact['first_name']);
334 unset($contact['last_name']);
335 }
336 }
337 } else {
338 if (empty($contact['source'])) {
339 $contact['source'] = 'FluentBooking';
340 }
341 if (Arr::isTrue($data, 'double_opt_in')) {
342 $contact['status'] = 'pending';
343 } else {
344 $contact['status'] = 'subscribed';
345 }
346 }
347
348 $user = get_user_by('email', $contact['email']);
349 if ($user) {
350 $contact['user_id'] = $user->ID;
351 }
352
353 if (!empty($data['tag_ids'])) {
354 $contact['tags'] = $data['tag_ids'];
355 }
356
357 if (!empty($data['list_ids'])) {
358 $contact['lists'] = $data['list_ids'];
359 }
360
361 if (!$subscriber) {
362 if (Arr::isTrue($data, 'double_opt_in')) {
363 $contact['status'] = 'pending';
364 } else {
365 $contact['status'] = 'subscribed';
366 }
367
368 $subscriber = FluentCrmApi('contacts')->createOrUpdate($contact, false, false);
369
370 if (!$subscriber) {
371 return false;
372 }
373
374 if ($subscriber->status == 'pending') {
375 $subscriber->sendDoubleOptinEmail();
376 }
377
378 if ($removeTags = Arr::get($feed, 'settings.remove_tags', [])) {
379 $subscriber->detachTags($removeTags);
380 }
381
382 $this->addLog(
383 $feed['settings']['name'],
384 __('Contact has been created in FluentCRM. Contact ID: ', 'fluent-booking') . $subscriber->id,
385 $booking->id,
386 'success'
387 );
388
389 do_action('fluent_crm/contact_added_by_fluent_booking', $subscriber, $booking, $calendarEvent, $feed);
390 return true;
391 }
392
393 // We have subscriber here
394
395 $hasDouBleOptIn = Arr::isTrue($data, 'double_opt_in');
396
397 $forceSubscribed = !$hasDouBleOptIn && ($subscriber->status != 'subscribed');
398
399 if (!$forceSubscribed) {
400 $forceSubscribed = Arr::isTrue($data, 'force_subscribe');
401 }
402
403 if ($forceSubscribed) {
404 $contact['status'] = 'subscribed';
405 }
406
407 $subscriber = FluentCrmApi('contacts')->createOrUpdate($contact, $forceSubscribed, false);
408
409 if (!$subscriber) {
410 return false;
411 }
412
413 if ($hasDouBleOptIn && ($subscriber->status == 'pending' || $subscriber->status == 'unsubscribed')) {
414 $subscriber->sendDoubleOptinEmail();
415 }
416
417 do_action('fluent_crm/contact_added_by_fluent_booking', $subscriber, $booking, $calendarEvent, $feed);
418
419 if ($removeTags = Arr::get($feed, 'settings.remove_tags', [])) {
420 $subscriber->detachTags($removeTags);
421 }
422
423 $this->addLog(
424 $feed['settings']['name'],
425 __('Contact has been updated in FluentCRM. Contact ID: ', 'fluent-booking') . $subscriber->id,
426 $booking->id,
427 'success'
428 );
429
430 return true;
431 }
432
433 public function isConfigured()
434 {
435 return true;
436 }
437
438 public function isEnabled()
439 {
440 return true;
441 }
442 }
443