WordPress Online Booking and Scheduling Plugin – Bookly - Version 17.0

Version Description

Download this release

Release Info

Developer Ladela
Plugin Icon 128x128 WordPress Online Booking and Scheduling Plugin – Bookly
Version 17.0
Comparing to
See all releases

Code changes from version 16.9 to 17.0

backend/components/dialogs/appointment/edit/resources/js/ng-appointment.js CHANGED
@@ -667,7 +667,7 @@
667
  notes : item.notes,
668
  status : item.status,
669
  payment_id : item.payment_id,
670
- payment_create : item.payment_create,
671
  payment_price : item.payment_price,
672
  payment_tax : item.payment_tax
673
  });
667
  notes : item.notes,
668
  status : item.status,
669
  payment_id : item.payment_id,
670
+ payment_create : item.payment_create||false,
671
  payment_price : item.payment_price,
672
  payment_tax : item.payment_tax
673
  });
backend/components/dialogs/customer/edit/resources/js/ng-customer.js CHANGED
@@ -67,6 +67,7 @@
67
 
68
  // Init select2 for wp_users.
69
  jQuery('#wp_user')
 
70
  .on('select2:unselecting', function(e) {
71
  e.preventDefault();
72
  jQuery(this).val(null).trigger('change');
67
 
68
  // Init select2 for wp_users.
69
  jQuery('#wp_user')
70
+ .val(null)
71
  .on('select2:unselecting', function(e) {
72
  e.preventDefault();
73
  jQuery(this).val(null).trigger('change');
backend/components/dialogs/sms/resources/js/notification-dialog.js CHANGED
@@ -64,17 +64,13 @@ jQuery(function ($) {
64
 
65
  switch (notification_type) {
66
  case 'appointment_reminder':
67
- hideServices = false;
68
- break;
69
  case 'ca_status_changed':
70
  case 'ca_status_changed_recurring':
71
  hideStatuses = false;
72
  hideServices = false;
73
  break;
74
  case 'customer_birthday':
75
- break;
76
  case 'customer_new_wp_user':
77
- break;
78
  case 'last_appointment':
79
  break;
80
  case 'new_booking':
@@ -86,7 +82,6 @@ jQuery(function ($) {
86
  $helpType.filter('.' + notification_type).show();
87
  break;
88
  case 'new_package':
89
- break;
90
  case 'package_deleted':
91
  break;
92
  case 'staff_day_agenda':
64
 
65
  switch (notification_type) {
66
  case 'appointment_reminder':
 
 
67
  case 'ca_status_changed':
68
  case 'ca_status_changed_recurring':
69
  hideStatuses = false;
70
  hideServices = false;
71
  break;
72
  case 'customer_birthday':
 
73
  case 'customer_new_wp_user':
 
74
  case 'last_appointment':
75
  break;
76
  case 'new_booking':
82
  $helpType.filter('.' + notification_type).show();
83
  break;
84
  case 'new_package':
 
85
  case 'package_deleted':
86
  break;
87
  case 'staff_day_agenda':
backend/components/dialogs/sms/templates/_settings.php CHANGED
@@ -7,9 +7,9 @@ $service_dropdown_data = \Bookly\Lib\Utils\Common::getServiceDataForDropDown( 's
7
  <div class="row">
8
  <div class="col-md-12">
9
  <div class="form-group">
10
- <label for="notification_status_1"><?php esc_attr_e( 'Appointment status', 'bookly' ) ?></label>
11
  <p class="help-block"><?php esc_html_e( 'Select what status an appointment should have for the notification to be sent.', 'bookly' ) ?></p>
12
- <select class="form-control" name="notification[settings][status]" id="notification_status_1">
13
  <option value="any"><?php esc_attr_e( 'Any', 'bookly' ) ?></option>
14
  <?php foreach ( $statuses as $status ) : ?>
15
  <option value="<?php echo $status ?>"><?php echo CustomerAppointment::statusToString( $status ) ?></option>
7
  <div class="row">
8
  <div class="col-md-12">
9
  <div class="form-group">
10
+ <label for="notification_status"><?php esc_attr_e( 'Appointment status', 'bookly' ) ?></label>
11
  <p class="help-block"><?php esc_html_e( 'Select what status an appointment should have for the notification to be sent.', 'bookly' ) ?></p>
12
+ <select class="form-control" name="notification[settings][status]" id="notification_status">
13
  <option value="any"><?php esc_attr_e( 'Any', 'bookly' ) ?></option>
14
  <?php foreach ( $statuses as $status ) : ?>
15
  <option value="<?php echo $status ?>"><?php echo CustomerAppointment::statusToString( $status ) ?></option>
backend/modules/customers/resources/js/customers.js CHANGED
@@ -1,5 +1,5 @@
1
  jQuery(function($) {
2
-
3
  var
4
  $customersList = $('#bookly-customers-list'),
5
  $mergeListContainer = $('#bookly-merge-list'),
@@ -45,7 +45,7 @@ jQuery(function($) {
45
 
46
  if (BooklyL10n.proEnabled == 1){
47
  columns = columns.concat([
48
- {data: 'address', responsivePriority: 3, orderable: false},
49
  {
50
  data: 'facebook_id',
51
  responsivePriority: 2,
1
  jQuery(function($) {
2
+ 'use strict';
3
  var
4
  $customersList = $('#bookly-customers-list'),
5
  $mergeListContainer = $('#bookly-merge-list'),
45
 
46
  if (BooklyL10n.proEnabled == 1){
47
  columns = columns.concat([
48
+ {data: 'address', render: $.fn.dataTable.render.text(), responsivePriority: 3, orderable: false},
49
  {
50
  data: 'facebook_id',
51
  responsivePriority: 2,
backend/modules/debug/Ajax.php CHANGED
@@ -143,6 +143,365 @@ class Ajax extends Page
143
  exit ( 0 );
144
  }
145
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
146
  public static function getConstraintData()
147
  {
148
  /** @global \wpdb */
143
  exit ( 0 );
144
  }
145
 
146
+ public static function getFieldData()
147
+ {
148
+ /** @global \wpdb */
149
+ global $wpdb;
150
+
151
+ $table = self::parameter( 'table' );
152
+ $column = self::parameter( 'column' );
153
+
154
+ /** SELECT CONCAT ( '\'', CONCAT_WS( '.', SUBSTR(TABLE_NAME,4), COLUMN_NAME ), '\' => "' , COLUMN_TYPE, ' ', IF(IS_NULLABLE = 'YES','null', 'not null') ,
155
+ IF ( EXTRA = 'auto_increment', ' auto_increment primary key',
156
+ CONCAT ( IF (COLUMN_DEFAULT is NULL, IF(IS_NULLABLE = 'NO', '', ' default null' ), CONCAT(' default \'',COLUMN_DEFAULT, '\'')))) , '",') AS data
157
+ FROM INFORMATION_SCHEMA.COLUMNS
158
+ WHERE TABLE_SCHEMA = SCHEMA()
159
+ AND TABLE_NAME LIKE 'wp_bookly_%'
160
+ ORDER BY TABLE_NAME, COLUMN_NAME
161
+ */
162
+
163
+ $fields = array(
164
+ 'bookly_appointments.created' => "datetime not null",
165
+ 'bookly_appointments.created_from' => "enum('bookly','google','outlook') not null default 'bookly'",
166
+ 'bookly_appointments.custom_service_name' => "varchar(255) null default null",
167
+ 'bookly_appointments.custom_service_price' => "decimal(10,2) null default null",
168
+ 'bookly_appointments.end_date' => "datetime null default null",
169
+ 'bookly_appointments.extras_duration' => "int(11) not null default '0'",
170
+ 'bookly_appointments.google_event_etag' => "varchar(255) null default null",
171
+ 'bookly_appointments.google_event_id' => "varchar(255) null default null",
172
+ 'bookly_appointments.id' => "int(10) unsigned not null auto_increment primary key",
173
+ 'bookly_appointments.internal_note' => "text null default null",
174
+ 'bookly_appointments.location_id' => "int(10) unsigned null default null",
175
+ 'bookly_appointments.outlook_event_change_key' => "varchar(255) null default null",
176
+ 'bookly_appointments.outlook_event_id' => "varchar(255) null default null",
177
+ 'bookly_appointments.outlook_event_series_id' => "varchar(255) null default null",
178
+ 'bookly_appointments.service_id' => "int(10) unsigned null default null",
179
+ 'bookly_appointments.staff_any' => "tinyint(1) not null default '0'",
180
+ 'bookly_appointments.staff_id' => "int(10) unsigned not null",
181
+ 'bookly_appointments.start_date' => "datetime null default null",
182
+ 'bookly_categories.id' => "int(10) unsigned not null auto_increment primary key",
183
+ 'bookly_categories.name' => "varchar(255) not null",
184
+ 'bookly_categories.position' => "int(11) not null default '9999'",
185
+ 'bookly_coupons.code' => "varchar(255) not null default ''",
186
+ 'bookly_coupons.date_limit_end' => "date null default null",
187
+ 'bookly_coupons.date_limit_start' => "date null default null",
188
+ 'bookly_coupons.deduction' => "decimal(10,2) not null default '0.00'",
189
+ 'bookly_coupons.discount' => "decimal(3,0) not null default '0'",
190
+ 'bookly_coupons.id' => "int(10) unsigned not null auto_increment primary key",
191
+ 'bookly_coupons.max_appointments' => "int(10) unsigned null default null",
192
+ 'bookly_coupons.min_appointments' => "int(10) unsigned not null default '1'",
193
+ 'bookly_coupons.once_per_customer' => "tinyint(1) not null default '0'",
194
+ 'bookly_coupons.usage_limit' => "int(10) unsigned not null default '1'",
195
+ 'bookly_coupons.used' => "int(10) unsigned not null default '0'",
196
+ 'bookly_coupon_customers.coupon_id' => "int(10) unsigned not null",
197
+ 'bookly_coupon_customers.customer_id' => "int(10) unsigned not null",
198
+ 'bookly_coupon_customers.id' => "int(10) unsigned not null auto_increment primary key",
199
+ 'bookly_coupon_services.coupon_id' => "int(10) unsigned not null",
200
+ 'bookly_coupon_services.id' => "int(10) unsigned not null auto_increment primary key",
201
+ 'bookly_coupon_services.service_id' => "int(10) unsigned not null",
202
+ 'bookly_coupon_staff.coupon_id' => "int(10) unsigned not null",
203
+ 'bookly_coupon_staff.id' => "int(10) unsigned not null auto_increment primary key",
204
+ 'bookly_coupon_staff.staff_id' => "int(10) unsigned not null",
205
+ 'bookly_customers.additional_address' => "varchar(255) null default null",
206
+ 'bookly_customers.birthday' => "date null default null",
207
+ 'bookly_customers.city' => "varchar(255) null default null",
208
+ 'bookly_customers.country' => "varchar(255) null default null",
209
+ 'bookly_customers.created' => "datetime not null",
210
+ 'bookly_customers.email' => "varchar(255) not null default ''",
211
+ 'bookly_customers.facebook_id' => "bigint(20) unsigned null default null",
212
+ 'bookly_customers.first_name' => "varchar(255) not null default ''",
213
+ 'bookly_customers.full_name' => "varchar(255) not null default ''",
214
+ 'bookly_customers.group_id' => "int(10) unsigned null default null",
215
+ 'bookly_customers.id' => "int(10) unsigned not null auto_increment primary key",
216
+ 'bookly_customers.info_fields' => "text null default null",
217
+ 'bookly_customers.last_name' => "varchar(255) not null default ''",
218
+ 'bookly_customers.notes' => "text not null",
219
+ 'bookly_customers.phone' => "varchar(255) not null default ''",
220
+ 'bookly_customers.postcode' => "varchar(255) null default null",
221
+ 'bookly_customers.state' => "varchar(255) null default null",
222
+ 'bookly_customers.street' => "varchar(255) null default null",
223
+ 'bookly_customers.street_number' => "varchar(255) null default null",
224
+ 'bookly_customers.wp_user_id' => "bigint(20) unsigned null default null",
225
+ 'bookly_customer_appointments.appointment_id' => "int(10) unsigned not null",
226
+ 'bookly_customer_appointments.collaborative_service_id' => "int(10) unsigned null default null",
227
+ 'bookly_customer_appointments.collaborative_token' => "varchar(255) null default null",
228
+ 'bookly_customer_appointments.compound_service_id' => "int(10) unsigned null default null",
229
+ 'bookly_customer_appointments.compound_token' => "varchar(255) null default null",
230
+ 'bookly_customer_appointments.created' => "datetime not null",
231
+ 'bookly_customer_appointments.created_from' => "enum('frontend','backend') not null default 'frontend'",
232
+ 'bookly_customer_appointments.customer_id' => "int(10) unsigned not null",
233
+ 'bookly_customer_appointments.custom_fields' => "text null default null",
234
+ 'bookly_customer_appointments.extras' => "text null default null",
235
+ 'bookly_customer_appointments.extras_consider_duration' => "tinyint(1) not null default '1'",
236
+ 'bookly_customer_appointments.extras_multiply_nop' => "tinyint(1) not null default '1'",
237
+ 'bookly_customer_appointments.id' => "int(10) unsigned not null auto_increment primary key",
238
+ 'bookly_customer_appointments.locale' => "varchar(8) null default null",
239
+ 'bookly_customer_appointments.notes' => "text null default null",
240
+ 'bookly_customer_appointments.number_of_persons' => "int(10) unsigned not null default '1'",
241
+ 'bookly_customer_appointments.package_id' => "int(10) unsigned null default null",
242
+ 'bookly_customer_appointments.payment_id' => "int(10) unsigned null default null",
243
+ 'bookly_customer_appointments.rating' => "int(11) null default null",
244
+ 'bookly_customer_appointments.rating_comment' => "text null default null",
245
+ 'bookly_customer_appointments.series_id' => "int(10) unsigned null default null",
246
+ 'bookly_customer_appointments.status' => "varchar(255) not null default 'approved'",
247
+ 'bookly_customer_appointments.status_changed_at' => "datetime null default null",
248
+ 'bookly_customer_appointments.time_zone' => "varchar(255) null default null",
249
+ 'bookly_customer_appointments.time_zone_offset' => "int(11) null default null",
250
+ 'bookly_customer_appointments.token' => "varchar(255) null default null",
251
+ 'bookly_customer_appointments.units' => "int(10) unsigned not null default '1'",
252
+ 'bookly_customer_appointment_files.customer_appointment_id' => "int(10) unsigned not null",
253
+ 'bookly_customer_appointment_files.file_id' => "int(10) unsigned not null",
254
+ 'bookly_customer_appointment_files.id' => "int(10) unsigned not null auto_increment primary key",
255
+ 'bookly_customer_groups.appointment_status' => "varchar(255) not null default ''",
256
+ 'bookly_customer_groups.description' => "text not null",
257
+ 'bookly_customer_groups.discount' => "varchar(100) not null default '0'",
258
+ 'bookly_customer_groups.id' => "int(10) unsigned not null auto_increment primary key",
259
+ 'bookly_customer_groups.name' => "varchar(255) not null",
260
+ 'bookly_customer_groups_services.group_id' => "int(10) unsigned not null",
261
+ 'bookly_customer_groups_services.id' => "int(10) unsigned not null auto_increment primary key",
262
+ 'bookly_customer_groups_services.service_id' => "int(10) unsigned not null",
263
+ 'bookly_custom_statuses.busy' => "tinyint(1) not null default '1'",
264
+ 'bookly_custom_statuses.id' => "int(10) unsigned not null auto_increment primary key",
265
+ 'bookly_custom_statuses.name' => "varchar(255) null default null",
266
+ 'bookly_custom_statuses.position' => "int(11) not null default '9999'",
267
+ 'bookly_custom_statuses.slug' => "varchar(255) not null",
268
+ 'bookly_files.custom_field_id' => "int(11) null default null",
269
+ 'bookly_files.id' => "int(10) unsigned not null auto_increment primary key",
270
+ 'bookly_files.name' => "text not null",
271
+ 'bookly_files.path' => "text not null",
272
+ 'bookly_files.slug' => "varchar(32) not null",
273
+ 'bookly_holidays.date' => "date not null",
274
+ 'bookly_holidays.id' => "int(10) unsigned not null auto_increment primary key",
275
+ 'bookly_holidays.parent_id' => "int(10) unsigned null default null",
276
+ 'bookly_holidays.repeat_event' => "tinyint(1) not null default '0'",
277
+ 'bookly_holidays.staff_id' => "int(10) unsigned null default null",
278
+ 'bookly_locations.id' => "int(10) unsigned not null auto_increment primary key",
279
+ 'bookly_locations.info' => "text null default null",
280
+ 'bookly_locations.name' => "varchar(255) null default ''",
281
+ 'bookly_locations.position' => "int(11) not null default '9999'",
282
+ 'bookly_messages.body' => "text null default null",
283
+ 'bookly_messages.created' => "datetime not null",
284
+ 'bookly_messages.id' => "int(10) unsigned not null auto_increment primary key",
285
+ 'bookly_messages.message_id' => "int(10) unsigned not null",
286
+ 'bookly_messages.seen' => "tinyint(1) not null default '0'",
287
+ 'bookly_messages.subject' => "text null default null",
288
+ 'bookly_messages.type' => "varchar(255) not null",
289
+ 'bookly_notifications.active' => "tinyint(1) not null default '0'",
290
+ 'bookly_notifications.attach_ics' => "tinyint(1) not null default '0'",
291
+ 'bookly_notifications.attach_invoice' => "tinyint(1) not null default '0'",
292
+ 'bookly_notifications.gateway' => "enum('email','sms') not null default 'email'",
293
+ 'bookly_notifications.id' => "int(10) unsigned not null auto_increment primary key",
294
+ 'bookly_notifications.message' => "text null default null",
295
+ 'bookly_notifications.name' => "varchar(255) not null default ''",
296
+ 'bookly_notifications.settings' => "text null default null",
297
+ 'bookly_notifications.subject' => "varchar(255) not null default ''",
298
+ 'bookly_notifications.to_admin' => "tinyint(1) not null default '0'",
299
+ 'bookly_notifications.to_customer' => "tinyint(1) not null default '0'",
300
+ 'bookly_notifications.to_staff' => "tinyint(1) not null default '0'",
301
+ 'bookly_notifications.type' => "varchar(255) not null default ''",
302
+ 'bookly_packages.created' => "datetime not null",
303
+ 'bookly_packages.customer_id' => "int(10) unsigned not null",
304
+ 'bookly_packages.id' => "int(10) unsigned not null auto_increment primary key",
305
+ 'bookly_packages.internal_note' => "text null default null",
306
+ 'bookly_packages.location_id' => "int(10) unsigned null default null",
307
+ 'bookly_packages.service_id' => "int(10) unsigned not null",
308
+ 'bookly_packages.staff_id' => "int(10) unsigned null default null",
309
+ 'bookly_payments.coupon_id' => "int(10) unsigned null default null",
310
+ 'bookly_payments.created' => "datetime not null",
311
+ 'bookly_payments.details' => "text null default null",
312
+ 'bookly_payments.gateway_price_correction' => "decimal(10,2) null default '0.00'",
313
+ 'bookly_payments.id' => "int(10) unsigned not null auto_increment primary key",
314
+ 'bookly_payments.paid' => "decimal(10,2) not null default '0.00'",
315
+ 'bookly_payments.paid_type' => "enum('in_full','deposit') not null default 'in_full'",
316
+ 'bookly_payments.status' => "enum('pending','completed','rejected') not null default 'completed'",
317
+ 'bookly_payments.tax' => "decimal(10,2) not null default '0.00'",
318
+ 'bookly_payments.total' => "decimal(10,2) not null default '0.00'",
319
+ 'bookly_payments.type' => "enum('local','coupon','paypal','authorize_net','stripe','2checkout','payu_biz','payu_latam','payson','mollie','woocommerce') not null default 'local'",
320
+ 'bookly_schedule_item_breaks.end_time' => "time null default null",
321
+ 'bookly_schedule_item_breaks.id' => "int(10) unsigned not null auto_increment primary key",
322
+ 'bookly_schedule_item_breaks.staff_schedule_item_id' => "int(10) unsigned not null",
323
+ 'bookly_schedule_item_breaks.start_time' => "time null default null",
324
+ 'bookly_sent_notifications.created' => "datetime not null",
325
+ 'bookly_sent_notifications.id' => "int(10) unsigned not null auto_increment primary key",
326
+ 'bookly_sent_notifications.notification_id' => "int(10) unsigned not null",
327
+ 'bookly_sent_notifications.ref_id' => "int(10) unsigned not null",
328
+ 'bookly_series.id' => "int(10) unsigned not null auto_increment primary key",
329
+ 'bookly_series.repeat' => "varchar(255) null default null",
330
+ 'bookly_series.token' => "varchar(255) not null",
331
+ 'bookly_services.appointments_limit' => "int(11) null default null",
332
+ 'bookly_services.capacity_max' => "int(11) not null default '1'",
333
+ 'bookly_services.capacity_min' => "int(11) not null default '1'",
334
+ 'bookly_services.category_id' => "int(10) unsigned null default null",
335
+ 'bookly_services.collaborative_equal_duration' => "tinyint(1) not null default '0'",
336
+ 'bookly_services.color' => "varchar(255) not null default '#FFFFFF'",
337
+ 'bookly_services.deposit' => "varchar(100) not null default '100%'",
338
+ 'bookly_services.duration' => "int(11) not null default '900'",
339
+ 'bookly_services.end_time_info' => "varchar(255) null default ''",
340
+ 'bookly_services.id' => "int(10) unsigned not null auto_increment primary key",
341
+ 'bookly_services.info' => "text null default null",
342
+ 'bookly_services.limit_period' => "enum('off','day','week','month','year','upcoming','calendar_day','calendar_week','calendar_month','calendar_year') not null default 'off'",
343
+ 'bookly_services.one_booking_per_slot' => "tinyint(1) not null default '0'",
344
+ 'bookly_services.package_life_time' => "int(11) null default null",
345
+ 'bookly_services.package_size' => "int(11) null default null",
346
+ 'bookly_services.package_unassigned' => "tinyint(1) not null default '0'",
347
+ 'bookly_services.padding_left' => "int(11) not null default '0'",
348
+ 'bookly_services.padding_right' => "int(11) not null default '0'",
349
+ 'bookly_services.position' => "int(11) not null default '9999'",
350
+ 'bookly_services.price' => "decimal(10,2) not null default '0.00'",
351
+ 'bookly_services.recurrence_enabled' => "tinyint(1) not null default '1'",
352
+ 'bookly_services.recurrence_frequencies' => "set('daily','weekly','biweekly','monthly') not null default 'daily,weekly,biweekly,monthly'",
353
+ 'bookly_services.slot_length' => "varchar(255) not null default 'default'",
354
+ 'bookly_services.staff_preference' => "enum('order','least_occupied','most_occupied','least_occupied_for_period','most_occupied_for_period','least_expensive','most_expensive') not null default 'most_expensive'",
355
+ 'bookly_services.staff_preference_settings' => "text null default null",
356
+ 'bookly_services.start_time_info' => "varchar(255) null default ''",
357
+ 'bookly_services.time_requirements' => "enum('required','optional','off') not null default 'required'",
358
+ 'bookly_services.title' => "varchar(255) null default ''",
359
+ 'bookly_services.type' => "enum('simple','collaborative','compound','package') not null default 'simple'",
360
+ 'bookly_services.units_max' => "int(10) unsigned not null default '1'",
361
+ 'bookly_services.units_min' => "int(10) unsigned not null default '1'",
362
+ 'bookly_services.visibility' => "enum('public','private','group') not null default 'public'",
363
+ 'bookly_service_extras.attachment_id' => "int(10) unsigned null default null",
364
+ 'bookly_service_extras.duration' => "int(11) not null default '0'",
365
+ 'bookly_service_extras.id' => "int(10) unsigned not null auto_increment primary key",
366
+ 'bookly_service_extras.max_quantity' => "int(11) not null default '1'",
367
+ 'bookly_service_extras.position' => "int(11) not null default '9999'",
368
+ 'bookly_service_extras.price' => "decimal(10,2) not null default '0.00'",
369
+ 'bookly_service_extras.service_id' => "int(10) unsigned not null",
370
+ 'bookly_service_extras.title' => "varchar(255) null default ''",
371
+ 'bookly_service_schedule_breaks.end_time' => "time null default null",
372
+ 'bookly_service_schedule_breaks.id' => "int(10) unsigned not null auto_increment primary key",
373
+ 'bookly_service_schedule_breaks.service_schedule_day_id' => "int(10) unsigned not null",
374
+ 'bookly_service_schedule_breaks.start_time' => "time null default null",
375
+ 'bookly_service_schedule_days.day_index' => "smallint(6) null default null",
376
+ 'bookly_service_schedule_days.end_time' => "time null default null",
377
+ 'bookly_service_schedule_days.id' => "int(10) unsigned not null auto_increment primary key",
378
+ 'bookly_service_schedule_days.service_id' => "int(10) unsigned not null",
379
+ 'bookly_service_schedule_days.start_time' => "time null default null",
380
+ 'bookly_service_special_days.date' => "date null default null",
381
+ 'bookly_service_special_days.end_time' => "time null default null",
382
+ 'bookly_service_special_days.id' => "int(10) unsigned not null auto_increment primary key",
383
+ 'bookly_service_special_days.service_id' => "int(10) unsigned not null",
384
+ 'bookly_service_special_days.start_time' => "time null default null",
385
+ 'bookly_service_special_days_breaks.end_time' => "time null default null",
386
+ 'bookly_service_special_days_breaks.id' => "int(10) unsigned not null auto_increment primary key",
387
+ 'bookly_service_special_days_breaks.service_special_day_id' => "int(10) unsigned not null",
388
+ 'bookly_service_special_days_breaks.start_time' => "time null default null",
389
+ 'bookly_service_taxes.id' => "int(10) unsigned not null auto_increment primary key",
390
+ 'bookly_service_taxes.service_id' => "int(10) unsigned not null",
391
+ 'bookly_service_taxes.tax_id' => "int(10) unsigned not null",
392
+ 'bookly_shop.created' => "datetime not null",
393
+ 'bookly_shop.demo_url' => "varchar(255) null default null",
394
+ 'bookly_shop.description' => "text not null",
395
+ 'bookly_shop.highlighted' => "tinyint(1) not null default '0'",
396
+ 'bookly_shop.icon' => "varchar(255) not null",
397
+ 'bookly_shop.id' => "int(10) unsigned not null auto_increment primary key",
398
+ 'bookly_shop.plugin_id' => "int(10) unsigned not null",
399
+ 'bookly_shop.price' => "decimal(10,2) not null",
400
+ 'bookly_shop.priority' => "int(10) unsigned null default '0'",
401
+ 'bookly_shop.published' => "datetime not null",
402
+ 'bookly_shop.rating' => "decimal(10,2) not null",
403
+ 'bookly_shop.reviews' => "int(10) unsigned not null",
404
+ 'bookly_shop.sales' => "int(10) unsigned not null",
405
+ 'bookly_shop.seen' => "tinyint(1) not null default '0'",
406
+ 'bookly_shop.slug' => "varchar(255) not null",
407
+ 'bookly_shop.title' => "varchar(255) not null",
408
+ 'bookly_shop.type' => "enum('plugin','bundle') not null default 'plugin'",
409
+ 'bookly_shop.url' => "varchar(255) not null",
410
+ 'bookly_special_days_breaks.end_time' => "time null default null",
411
+ 'bookly_special_days_breaks.id' => "int(10) unsigned not null auto_increment primary key",
412
+ 'bookly_special_days_breaks.staff_special_day_id' => "int(10) unsigned not null",
413
+ 'bookly_special_days_breaks.start_time' => "time null default null",
414
+ 'bookly_staff.attachment_id' => "int(10) unsigned null default null",
415
+ 'bookly_staff.category_id' => "int(10) unsigned null default null",
416
+ 'bookly_staff.email' => "varchar(255) null default null",
417
+ 'bookly_staff.full_name' => "varchar(255) null default null",
418
+ 'bookly_staff.google_data' => "text null default null",
419
+ 'bookly_staff.id' => "int(10) unsigned not null auto_increment primary key",
420
+ 'bookly_staff.info' => "text null default null",
421
+ 'bookly_staff.outlook_data' => "text null default null",
422
+ 'bookly_staff.phone' => "varchar(255) null default null",
423
+ 'bookly_staff.position' => "int(11) not null default '9999'",
424
+ 'bookly_staff.visibility' => "enum('public','private','archive') not null default 'public'",
425
+ 'bookly_staff.working_time_limit' => "int(10) unsigned null default null",
426
+ 'bookly_staff.wp_user_id' => "bigint(20) unsigned null default null",
427
+ 'bookly_staff_categories.id' => "int(10) unsigned not null auto_increment primary key",
428
+ 'bookly_staff_categories.name' => "varchar(255) not null",
429
+ 'bookly_staff_categories.position' => "int(11) not null default '9999'",
430
+ 'bookly_staff_locations.custom_schedule' => "tinyint(1) not null default '0'",
431
+ 'bookly_staff_locations.custom_services' => "tinyint(1) not null default '0'",
432
+ 'bookly_staff_locations.id' => "int(10) unsigned not null auto_increment primary key",
433
+ 'bookly_staff_locations.location_id' => "int(10) unsigned not null",
434
+ 'bookly_staff_locations.staff_id' => "int(10) unsigned not null",
435
+ 'bookly_staff_preference_orders.id' => "int(10) unsigned not null auto_increment primary key",
436
+ 'bookly_staff_preference_orders.position' => "int(11) not null default '9999'",
437
+ 'bookly_staff_preference_orders.service_id' => "int(10) unsigned not null",
438
+ 'bookly_staff_preference_orders.staff_id' => "int(10) unsigned not null",
439
+ 'bookly_staff_schedule_items.day_index' => "int(10) unsigned not null",
440
+ 'bookly_staff_schedule_items.end_time' => "time null default null",
441
+ 'bookly_staff_schedule_items.id' => "int(10) unsigned not null auto_increment primary key",
442
+ 'bookly_staff_schedule_items.location_id' => "int(10) unsigned null default null",
443
+ 'bookly_staff_schedule_items.staff_id' => "int(10) unsigned not null",
444
+ 'bookly_staff_schedule_items.start_time' => "time null default null",
445
+ 'bookly_staff_services.capacity_max' => "int(11) not null default '1'",
446
+ 'bookly_staff_services.capacity_min' => "int(11) not null default '1'",
447
+ 'bookly_staff_services.deposit' => "varchar(100) not null default '100%'",
448
+ 'bookly_staff_services.id' => "int(10) unsigned not null auto_increment primary key",
449
+ 'bookly_staff_services.location_id' => "int(10) unsigned null default null",
450
+ 'bookly_staff_services.price' => "decimal(10,2) not null default '0.00'",
451
+ 'bookly_staff_services.service_id' => "int(10) unsigned not null",
452
+ 'bookly_staff_services.staff_id' => "int(10) unsigned not null",
453
+ 'bookly_staff_special_days.date' => "date null default null",
454
+ 'bookly_staff_special_days.end_time' => "time null default null",
455
+ 'bookly_staff_special_days.id' => "int(10) unsigned not null auto_increment primary key",
456
+ 'bookly_staff_special_days.staff_id' => "int(10) unsigned not null",
457
+ 'bookly_staff_special_days.start_time' => "time null default null",
458
+ 'bookly_staff_special_hours.end_time' => "time null default null",
459
+ 'bookly_staff_special_hours.id' => "int(10) unsigned not null auto_increment primary key",
460
+ 'bookly_staff_special_hours.location_id' => "int(10) unsigned null default null",
461
+ 'bookly_staff_special_hours.price' => "decimal(10,2) not null default '0.00'",
462
+ 'bookly_staff_special_hours.service_id' => "int(10) unsigned not null",
463
+ 'bookly_staff_special_hours.staff_id' => "int(10) unsigned not null",
464
+ 'bookly_staff_special_hours.start_time' => "time null default null",
465
+ 'bookly_stats.created' => "datetime not null",
466
+ 'bookly_stats.id' => "int(10) unsigned not null auto_increment primary key",
467
+ 'bookly_stats.name' => "varchar(255) not null",
468
+ 'bookly_stats.value' => "text null default null",
469
+ 'bookly_sub_services.duration' => "int(11) null default null",
470
+ 'bookly_sub_services.id' => "int(10) unsigned not null auto_increment primary key",
471
+ 'bookly_sub_services.position' => "int(11) not null default '9999'",
472
+ 'bookly_sub_services.service_id' => "int(10) unsigned not null",
473
+ 'bookly_sub_services.sub_service_id' => "int(10) unsigned null default null",
474
+ 'bookly_sub_services.type' => "enum('service','spare_time') not null default 'service'",
475
+ 'bookly_taxes.id' => "int(10) unsigned not null auto_increment primary key",
476
+ 'bookly_taxes.rate' => "decimal(10,3) not null default '0.000'",
477
+ 'bookly_taxes.title' => "varchar(255) null default ''",
478
+ );
479
+
480
+ $prefix_len = strlen( $wpdb->prefix );
481
+ $key = substr( $table, $prefix_len ) . '.' . $column;
482
+ if ( isset( $fields[ $key ] ) ) {
483
+ wp_send_json_success( $fields[ $key ] );
484
+ } else {
485
+ wp_send_json_error();
486
+ }
487
+ }
488
+
489
+ public static function executeQuery()
490
+ {
491
+ /** @global \wpdb */
492
+ global $wpdb;
493
+
494
+ ob_start();
495
+ $result = $wpdb->query( self::parameter( 'query' ) );
496
+ ob_end_clean();
497
+
498
+ if ( $result ) {
499
+ wp_send_json_success( array( 'message' => 'Query completed successfully' ) );
500
+ } else {
501
+ wp_send_json_error( array( 'message' => $wpdb->last_error ) );
502
+ }
503
+ }
504
+
505
  public static function getConstraintData()
506
  {
507
  /** @global \wpdb */
backend/modules/debug/resources/js/debug.js CHANGED
@@ -1,6 +1,9 @@
1
  jQuery(function($) {
2
- var $constraintModal = $('#bookly-js-add-constraint'),
3
- $status;
 
 
 
4
 
5
  $('.collapse').collapse('hide');
6
 
@@ -14,7 +17,7 @@ jQuery(function($) {
14
  .on('click', function (e) {
15
  e.preventDefault();
16
  $status = $(this).closest('td');
17
- var $tr = $(this).closest('tr'),
18
  table = $tr.closest('.panel-collapse').attr('id'),
19
  column = $tr.find('td:eq(0)').html(),
20
  ref_table = $tr.find('td:eq(1)').html(),
@@ -55,7 +58,7 @@ jQuery(function($) {
55
 
56
  $constraintModal
57
  .on('click', '.bookly-js-save', function () {
58
- var ladda = Ladda.create(this);
59
  ladda.start();
60
  $.ajax({
61
  url : ajaxurl,
@@ -90,7 +93,7 @@ jQuery(function($) {
90
  })
91
  .on('click', '[data-action=fix-consistency]', function (e) {
92
  e.preventDefault();
93
- var $button = $(this),
94
  table = $('#bookly-js-table', $constraintModal).html(),
95
  column = $('#bookly-js-column', $constraintModal).html(),
96
  ref_table = $('#bookly-js-ref_table', $constraintModal).html(),
@@ -125,10 +128,10 @@ jQuery(function($) {
125
  booklyAlert({success: ['No manipulation actions were performed']});
126
  return false;
127
  case 'CASCADE':
128
- query = 'DELETE FROM `' + table + '`' + "\n" + ' WHERE `' + column + '` NOT IN ( SELECT `' + ref_column + '` FROM `' + ref_table + '` )';
129
  break;
130
  case 'SET NULL':
131
- query = 'UPDATE TABLE `' + table + '`' + "\n" + ' SET `' + column + '` = NULL' + "\n" + ' WHERE `' + column + '` NOT IN ( SELECT `' + ref_column + '` FROM `' + ref_table + '` )';
132
  break;
133
  }
134
 
@@ -151,4 +154,133 @@ jQuery(function($) {
151
  });
152
  }
153
  });
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
154
  });
1
  jQuery(function($) {
2
+ let $constraintModal = $('#bookly-js-add-constraint'),
3
+ $columnModal = $('#bookly-js-add-field'),
4
+ $tableModal = $('#bookly-js-create-table'),
5
+ $status,
6
+ $create;
7
 
8
  $('.collapse').collapse('hide');
9
 
17
  .on('click', function (e) {
18
  e.preventDefault();
19
  $status = $(this).closest('td');
20
+ let $tr = $(this).closest('tr'),
21
  table = $tr.closest('.panel-collapse').attr('id'),
22
  column = $tr.find('td:eq(0)').html(),
23
  ref_table = $tr.find('td:eq(1)').html(),
58
 
59
  $constraintModal
60
  .on('click', '.bookly-js-save', function () {
61
+ let ladda = Ladda.create(this);
62
  ladda.start();
63
  $.ajax({
64
  url : ajaxurl,
93
  })
94
  .on('click', '[data-action=fix-consistency]', function (e) {
95
  e.preventDefault();
96
+ let $button = $(this),
97
  table = $('#bookly-js-table', $constraintModal).html(),
98
  column = $('#bookly-js-column', $constraintModal).html(),
99
  ref_table = $('#bookly-js-ref_table', $constraintModal).html(),
128
  booklyAlert({success: ['No manipulation actions were performed']});
129
  return false;
130
  case 'CASCADE':
131
+ query = 'DELETE FROM `' + table + "`\n" + ' WHERE `' + column + '` NOT IN ( SELECT `' + ref_column + '` FROM `' + ref_table + '` )';
132
  break;
133
  case 'SET NULL':
134
+ query = 'UPDATE TABLE `' + table + "`\n" + ' SET `' + column + '` = NULL' + "\n" + ' WHERE `' + column + '` NOT IN ( SELECT `' + ref_column + '` FROM `' + ref_table + '` )';
135
  break;
136
  }
137
 
154
  });
155
  }
156
  });
157
+
158
+ $('[data-action=fix-column]')
159
+ .on('click', function (e) {
160
+ e.preventDefault();
161
+ $status = $(this).closest('td');
162
+ let $tr = $(this).closest('tr'),
163
+ table = $tr.closest('.panel-collapse').attr('id'),
164
+ column = $tr.find('td:eq(0)').html()
165
+ ;
166
+ $('.bookly-js-loading:first-child', $columnModal).addClass('bookly-loading').removeClass('collapse');
167
+ $('.bookly-js-loading:last-child', $columnModal).addClass('collapse');
168
+ $('.bookly-js-fix-consistency', $columnModal).hide();
169
+ $columnModal.modal();
170
+ $.ajax({
171
+ url: ajaxurl,
172
+ type: 'POST',
173
+ data: {
174
+ action : 'bookly_get_field_data',
175
+ table : table,
176
+ column : column,
177
+ csrf_token: BooklyL10n.csrfToken
178
+ },
179
+ dataType: 'json',
180
+ success: function (response) {
181
+ if (response.success) {
182
+ let sql = 'ALTER TABLE `' + table + '`' +
183
+ "\n ADD COLUMN `" + column + '` ' + response.data;
184
+ $('pre', $columnModal).html(sql);
185
+ } else {
186
+ $('pre', $columnModal).html('');
187
+ }
188
+ $('.bookly-js-loading', $columnModal).toggleClass('collapse');
189
+ }
190
+ });
191
+ });
192
+
193
+ $columnModal
194
+ .on('click', '.bookly-js-save', function () {
195
+ let ladda = Ladda.create(this);
196
+ ladda.start();
197
+ $.ajax({
198
+ url : ajaxurl,
199
+ type : 'POST',
200
+ data : {
201
+ action : 'bookly_execute_query',
202
+ query : $('pre', $columnModal).html(),
203
+ csrf_token : BooklyL10n.csrfToken
204
+ },
205
+ dataType : 'json',
206
+ success : function (response) {
207
+ if (response.success) {
208
+ booklyAlert({success: [response.data.message]});
209
+ $columnModal.modal('hide');
210
+ $status.html('OK');
211
+ } else {
212
+ booklyAlert({error : [response.data.message]});
213
+ }
214
+ ladda.stop();
215
+ },
216
+ error: function () {
217
+ booklyAlert({error: ['Error: in query execution.']});
218
+ ladda.stop();
219
+ }
220
+ });
221
+ });
222
+
223
+ $('[data-action=fix-create-table]')
224
+ .on('click', function (e) {
225
+ e.preventDefault();
226
+ $create = $(this);
227
+ let table = $create.closest('.panel').find('.panel-collapse').attr('id');
228
+ $('.bookly-js-loading:first-child', $tableModal).addClass('bookly-loading').removeClass('collapse');
229
+ $('.bookly-js-loading:last-child', $tableModal).addClass('collapse');
230
+ $tableModal.modal();
231
+ $.ajax({
232
+ url: ajaxurl,
233
+ type: 'POST',
234
+ data: {
235
+ action : 'bookly_get_field_data',
236
+ table : table,
237
+ column : 'id',
238
+ csrf_token: BooklyL10n.csrfToken
239
+ },
240
+ dataType: 'json',
241
+ success: function (response) {
242
+ if (response.success) {
243
+ let field = response.data.replace(' primary key', ','),
244
+ sql = 'CREATE TABLE `' + table + '` (' +
245
+ "\n `id` " + field +
246
+ "\n PRIMARY KEY (`id`));";
247
+ $('pre', $tableModal).html(sql);
248
+ } else {
249
+ $('pre', $tableModal).html('');
250
+ }
251
+ $('.bookly-js-loading', $tableModal).toggleClass('collapse');
252
+ }
253
+ });
254
+ });
255
+
256
+ $tableModal
257
+ .on('click', '.bookly-js-save', function () {
258
+ let ladda = Ladda.create(this);
259
+ ladda.start();
260
+ $.ajax({
261
+ url : ajaxurl,
262
+ type : 'POST',
263
+ data : {
264
+ action : 'bookly_execute_query',
265
+ query : $('pre', $tableModal).html(),
266
+ csrf_token : BooklyL10n.csrfToken
267
+ },
268
+ dataType : 'json',
269
+ success : function (response) {
270
+ if (response.success) {
271
+ booklyAlert({success: [response.data.message]});
272
+ $tableModal.modal('hide');
273
+ $create.closest('.panel').find('.panel-body').html('Refresh the current page');
274
+ $create.remove();
275
+ } else {
276
+ booklyAlert({error : [response.data.message]});
277
+ }
278
+ ladda.stop();
279
+ },
280
+ error: function () {
281
+ booklyAlert({error: ['Error: in query execution.']});
282
+ ladda.stop();
283
+ }
284
+ });
285
+ });
286
  });
backend/modules/debug/templates/index.php CHANGED
@@ -47,6 +47,9 @@ use Bookly\Backend\Components\Controls\Buttons;
47
  <a class="collapsed" role="button" data-toggle="collapse" data-parent="#accordion" href="#<?php echo $tableName ?>" aria-expanded="true" aria-controls="<?php echo $tableName ?>">
48
  <?php echo $tableName ?>
49
  </a>
 
 
 
50
  </h4>
51
  </div>
52
  <div id="<?php echo $tableName ?>" class="panel-collapse collapse" role="tabpanel" aria-labelledby="<?php echo $tableName ?>">
@@ -64,7 +67,7 @@ use Bookly\Backend\Components\Controls\Buttons;
64
  <?php foreach ( $table['fields'] as $field => $status ) : ?>
65
  <tr class="<?php echo $status ? 'default' : 'danger' ?>">
66
  <td><?php echo $field ?></td>
67
- <td><?php echo $status ? 'OK' : 'ERROR' ?></td>
68
  </tr>
69
  <?php endforeach ?>
70
  </tbody>
@@ -153,4 +156,40 @@ ADD CONSTRAINT
153
  </div>
154
  </div>
155
  </div>
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
156
  </div>
47
  <a class="collapsed" role="button" data-toggle="collapse" data-parent="#accordion" href="#<?php echo $tableName ?>" aria-expanded="true" aria-controls="<?php echo $tableName ?>">
48
  <?php echo $tableName ?>
49
  </a>
50
+ <?php if ( ! $table['status'] ) : ?>
51
+ <button class="btn btn-success btn-xs pull-right" type="button" data-action="fix-create-table">create</button>
52
+ <?php endif ?>
53
  </h4>
54
  </div>
55
  <div id="<?php echo $tableName ?>" class="panel-collapse collapse" role="tabpanel" aria-labelledby="<?php echo $tableName ?>">
67
  <?php foreach ( $table['fields'] as $field => $status ) : ?>
68
  <tr class="<?php echo $status ? 'default' : 'danger' ?>">
69
  <td><?php echo $field ?></td>
70
+ <td><?php echo $status ? 'OK' : '<button class="btn btn-success btn-xs" type="button" data-action="fix-column">FIX…</button>' ?></td>
71
  </tr>
72
  <?php endforeach ?>
73
  </tbody>
156
  </div>
157
  </div>
158
  </div>
159
+ <div id="bookly-js-add-field" class="modal fade" tabindex="-1" role="dialog">
160
+ <div class="modal-dialog" role="document">
161
+ <div class="modal-content">
162
+ <div class="modal-header">
163
+ <button type="button" class="close" data-dismiss="modal" aria-label="Close"><span aria-hidden="true">&times;</span></button>
164
+ <h4 class="modal-title">Add column</h4>
165
+ </div>
166
+ <div class="modal-body">
167
+ <div class="bookly-js-loading" style="height: 120px;"></div>
168
+ <div class="bookly-js-loading"><pre></pre></div>
169
+ </div>
170
+ <div class="modal-footer">
171
+ <?php Buttons::renderCustom( null, 'bookly-js-save btn-lg btn-success', 'Add column' ) ?>
172
+ <?php Buttons::renderCustom( null, 'btn-lg btn-default', 'Close', array( 'data-dismiss' => 'modal' ) ) ?>
173
+ </div>
174
+ </div>
175
+ </div>
176
+ </div>
177
+ <div id="bookly-js-create-table" class="modal fade" tabindex="-1" role="dialog">
178
+ <div class="modal-dialog" role="document">
179
+ <div class="modal-content">
180
+ <div class="modal-header">
181
+ <button type="button" class="close" data-dismiss="modal" aria-label="Close"><span aria-hidden="true">&times;</span></button>
182
+ <h4 class="modal-title">Create table</h4>
183
+ </div>
184
+ <div class="modal-body">
185
+ <div class="bookly-js-loading" style="height: 120px;"></div>
186
+ <div class="bookly-js-loading"><pre></pre></div>
187
+ </div>
188
+ <div class="modal-footer">
189
+ <?php Buttons::renderCustom( null, 'bookly-js-save btn-lg btn-success', 'Create table' ) ?>
190
+ <?php Buttons::renderCustom( null, 'btn-lg btn-default', 'Close', array( 'data-dismiss' => 'modal' ) ) ?>
191
+ </div>
192
+ </div>
193
+ </div>
194
+ </div>
195
  </div>
frontend/modules/booking/Ajax.php CHANGED
@@ -94,6 +94,7 @@ class Ajax extends Lib\Base\Ajax
94
  'location' => (int) ( Lib\Config::locationsActive() && ( get_option( 'bookly_app_required_location' ) || get_option( 'bookly_locations_allow_services_per_location' ) ) ),
95
  ),
96
  );
 
97
  } else {
98
  $response = array( 'success' => false, 'error' => Errors::FORM_ID_ERROR );
99
  }
@@ -150,6 +151,7 @@ class Ajax extends Lib\Base\Ajax
150
  } else {
151
  $response = array( 'success' => false, 'error' => Errors::SESSION_ERROR );
152
  }
 
153
 
154
  // Output JSON response.
155
  wp_send_json( $response );
@@ -250,6 +252,7 @@ class Ajax extends Lib\Base\Ajax
250
  } else {
251
  $response = array( 'success' => false, 'error' => Errors::SESSION_ERROR );
252
  }
 
253
 
254
  // Output JSON response.
255
  wp_send_json( $response );
@@ -300,6 +303,7 @@ class Ajax extends Lib\Base\Ajax
300
  } else {
301
  $response = array( 'success' => false, 'error' => Errors::SESSION_ERROR );
302
  }
 
303
 
304
  // Output JSON response.
305
  wp_send_json( $response );
@@ -366,6 +370,7 @@ class Ajax extends Lib\Base\Ajax
366
  } else {
367
  $response = array( 'success' => false, 'error' => Errors::SESSION_ERROR );
368
  }
 
369
 
370
  // Output JSON response.
371
  wp_send_json( $response );
@@ -402,6 +407,7 @@ class Ajax extends Lib\Base\Ajax
402
  } else {
403
  $response = array( 'success' => false, 'error' => Errors::SESSION_ERROR );
404
  }
 
405
 
406
  // Output JSON response.
407
  wp_send_json( $response );
@@ -476,6 +482,7 @@ class Ajax extends Lib\Base\Ajax
476
  } else {
477
  $response = array( 'success' => false, 'error' => Errors::SESSION_ERROR );
478
  }
 
479
 
480
  // Output JSON response.
481
  wp_send_json( $response );
@@ -570,6 +577,7 @@ class Ajax extends Lib\Base\Ajax
570
  } else {
571
  $response = array( 'success' => false, 'error' => Errors::SESSION_ERROR );
572
  }
 
573
 
574
  // Output JSON response.
575
  wp_send_json( $response );
@@ -619,6 +627,7 @@ class Ajax extends Lib\Base\Ajax
619
  } else {
620
  $response = array( 'success' => false, 'error' => Errors::SESSION_ERROR );
621
  }
 
622
 
623
  // Output JSON response.
624
  wp_send_json( $response );
@@ -674,8 +683,10 @@ class Ajax extends Lib\Base\Ajax
674
  }
675
  $userData->fillData( $parameters );
676
  }
 
677
  }
678
  $errors['success'] = empty( $errors );
 
679
  wp_send_json( $errors );
680
  }
681
 
@@ -980,6 +991,7 @@ class Ajax extends Lib\Base\Ajax
980
  } else {
981
  $response = array( 'success' => false, 'error' => Errors::SESSION_ERROR );
982
  }
 
983
 
984
  // Output JSON response.
985
  wp_send_json( $response );
94
  'location' => (int) ( Lib\Config::locationsActive() && ( get_option( 'bookly_app_required_location' ) || get_option( 'bookly_locations_allow_services_per_location' ) ) ),
95
  ),
96
  );
97
+ $userData->sessionSave();
98
  } else {
99
  $response = array( 'success' => false, 'error' => Errors::FORM_ID_ERROR );
100
  }
151
  } else {
152
  $response = array( 'success' => false, 'error' => Errors::SESSION_ERROR );
153
  }
154
+ $userData->sessionSave();
155
 
156
  // Output JSON response.
157
  wp_send_json( $response );
252
  } else {
253
  $response = array( 'success' => false, 'error' => Errors::SESSION_ERROR );
254
  }
255
+ $userData->sessionSave();
256
 
257
  // Output JSON response.
258
  wp_send_json( $response );
303
  } else {
304
  $response = array( 'success' => false, 'error' => Errors::SESSION_ERROR );
305
  }
306
+ $userData->sessionSave();
307
 
308
  // Output JSON response.
309
  wp_send_json( $response );
370
  } else {
371
  $response = array( 'success' => false, 'error' => Errors::SESSION_ERROR );
372
  }
373
+ $userData->sessionSave();
374
 
375
  // Output JSON response.
376
  wp_send_json( $response );
407
  } else {
408
  $response = array( 'success' => false, 'error' => Errors::SESSION_ERROR );
409
  }
410
+ $userData->sessionSave();
411
 
412
  // Output JSON response.
413
  wp_send_json( $response );
482
  } else {
483
  $response = array( 'success' => false, 'error' => Errors::SESSION_ERROR );
484
  }
485
+ $userData->sessionSave();
486
 
487
  // Output JSON response.
488
  wp_send_json( $response );
577
  } else {
578
  $response = array( 'success' => false, 'error' => Errors::SESSION_ERROR );
579
  }
580
+ $userData->sessionSave();
581
 
582
  // Output JSON response.
583
  wp_send_json( $response );
627
  } else {
628
  $response = array( 'success' => false, 'error' => Errors::SESSION_ERROR );
629
  }
630
+ $userData->sessionSave();
631
 
632
  // Output JSON response.
633
  wp_send_json( $response );
683
  }
684
  $userData->fillData( $parameters );
685
  }
686
+ $userData->sessionSave();
687
  }
688
  $errors['success'] = empty( $errors );
689
+
690
  wp_send_json( $errors );
691
  }
692
 
991
  } else {
992
  $response = array( 'success' => false, 'error' => Errors::SESSION_ERROR );
993
  }
994
+ $userData->sessionSave();
995
 
996
  // Output JSON response.
997
  wp_send_json( $response );
lib/Cart.php CHANGED
@@ -182,6 +182,7 @@ class Cart
182
  if ( $order->hasItem( $series_unique_id ) ) {
183
  $series = $order->getItem( $series_unique_id );
184
  } else {
 
185
  $series_entity = new Entities\Series();
186
  $series_entity
187
  ->setRepeat( '{}' )
@@ -332,7 +333,7 @@ class Cart
332
  $item = $collaborative->addItem( $item );
333
  }
334
  if ( $series ) {
335
- $series->addItem( $i, $item );
336
  } else {
337
  $order->addItem( $i, $item );
338
  }
182
  if ( $order->hasItem( $series_unique_id ) ) {
183
  $series = $order->getItem( $series_unique_id );
184
  } else {
185
+ $series_item_id = 0;
186
  $series_entity = new Entities\Series();
187
  $series_entity
188
  ->setRepeat( '{}' )
333
  $item = $collaborative->addItem( $item );
334
  }
335
  if ( $series ) {
336
+ $series->addItem( $series_item_id++, $item );
337
  } else {
338
  $order->addItem( $i, $item );
339
  }
lib/UserBookingData.php CHANGED
@@ -257,6 +257,14 @@ class UserBookingData
257
  * Destructor used in register_shutdown_function.
258
  */
259
  public function destruct()
 
 
 
 
 
 
 
 
260
  {
261
  Session::setFormVar( $this->form_id, 'data', $this->getData() );
262
  Session::setFormVar( $this->form_id, 'cart', $this->cart->getItemsData() );
257
  * Destructor used in register_shutdown_function.
258
  */
259
  public function destruct()
260
+ {
261
+ $this->sessionSave();
262
+ }
263
+
264
+ /**
265
+ * Save data to session.
266
+ */
267
+ public function sessionSave()
268
  {
269
  Session::setFormVar( $this->form_id, 'data', $this->getData() );
270
  Session::setFormVar( $this->form_id, 'cart', $this->cart->getItemsData() );
lib/data_holders/booking/Collaborative.php CHANGED
@@ -249,7 +249,7 @@ class Collaborative extends Item
249
  $query = Lib\Entities\CustomerAppointment::query( 'ca' )
250
  ->leftJoin( 'Appointment', 'a', 'a.id = ca.appointment_id' )
251
  ->where( 'ca.collaborative_token', $token );
252
- if ( $statuses ){
253
  $query->whereIn( 'ca.status', $statuses );
254
  }
255
 
249
  $query = Lib\Entities\CustomerAppointment::query( 'ca' )
250
  ->leftJoin( 'Appointment', 'a', 'a.id = ca.appointment_id' )
251
  ->where( 'ca.collaborative_token', $token );
252
+ if ( $statuses ) {
253
  $query->whereIn( 'ca.status', $statuses );
254
  }
255
 
lib/data_holders/notification/Settings.php CHANGED
@@ -56,6 +56,9 @@ class Settings
56
  $this->services = $this->_handleService( $this->settings );
57
  break;
58
  case Notification::TYPE_APPOINTMENT_REMINDER:
 
 
 
59
  case Notification::TYPE_LAST_CUSTOMER_APPOINTMENT:
60
  if ( $this->settings['option'] == 1 ) {
61
  // offset_hours [ 1h .. 30d ] & perform [ after | before ]
@@ -68,9 +71,6 @@ class Settings
68
  $this->at_hour = $this->settings['at_hour'];
69
  $this->offset_hours = $this->settings['offset_bidirectional_hours'];
70
  }
71
- if ( $type != Notification::TYPE_LAST_CUSTOMER_APPOINTMENT ) {
72
- $this->services = $this->_handleService( $this->settings );
73
- }
74
  break;
75
  case Notification::TYPE_STAFF_DAY_AGENDA:
76
  $this->at_hour = $this->settings['before_at_hour'];
56
  $this->services = $this->_handleService( $this->settings );
57
  break;
58
  case Notification::TYPE_APPOINTMENT_REMINDER:
59
+ $this->status = $this->settings['status'];
60
+ $this->services = $this->_handleService( $this->settings );
61
+ // no need to break here
62
  case Notification::TYPE_LAST_CUSTOMER_APPOINTMENT:
63
  if ( $this->settings['option'] == 1 ) {
64
  // offset_hours [ 1h .. 30d ] & perform [ after | before ]
71
  $this->at_hour = $this->settings['at_hour'];
72
  $this->offset_hours = $this->settings['offset_bidirectional_hours'];
73
  }
 
 
 
74
  break;
75
  case Notification::TYPE_STAFF_DAY_AGENDA:
76
  $this->at_hour = $this->settings['before_at_hour'];
lib/notifications/Routine.php CHANGED
@@ -49,11 +49,18 @@ abstract class Routine
49
  if ( ! $settings->getInstant() ) {
50
  $ca_list = array();
51
  $customers = array();
 
 
 
 
52
 
53
  switch ( $notification->getType() ) {
54
  // Appointment start date add time.
55
  case Notification::TYPE_APPOINTMENT_REMINDER:
56
  $ca_list = self::getCustomerAppointments( $notification, $settings );
 
 
 
57
  break;
58
 
59
  // Last appointment.
@@ -80,17 +87,11 @@ abstract class Routine
80
  foreach ( $ca_list as $ca ) {
81
  if ( $token = $ca->getCompoundToken() ) {
82
  if ( ! isset ( $compounds[ $token ] ) ) {
83
- $compounds[ $token ] = Compound::createByToken( $token, Lib\Proxy\CustomStatuses::prepareBusyStatuses( array(
84
- Lib\Entities\CustomerAppointment::STATUS_PENDING,
85
- Lib\Entities\CustomerAppointment::STATUS_APPROVED,
86
- ) ) );
87
  }
88
  } elseif ( $token = $ca->getCollaborativeToken() ) {
89
  if ( ! isset ( $collaboratives[ $token ] ) ) {
90
- $collaboratives[ $token ] = Collaborative::createByToken( $token, Lib\Proxy\CustomStatuses::prepareBusyStatuses( array(
91
- Lib\Entities\CustomerAppointment::STATUS_PENDING,
92
- Lib\Entities\CustomerAppointment::STATUS_APPROVED,
93
- ) ) );
94
  }
95
  } else {
96
  $simple = Simple::create( $ca );
@@ -170,13 +171,6 @@ abstract class Routine
170
  );
171
  if ( $settings->getStatus() != 'any' ) {
172
  $query .= sprintf( ' AND `ca`.`status` = "%s"', $settings->getStatus() );
173
- } elseif ( $notification->getType() == Notification::TYPE_APPOINTMENT_REMINDER || $notification->getType() == Notification::TYPE_LAST_CUSTOMER_APPOINTMENT ) {
174
- $busy = Lib\Proxy\CustomStatuses::prepareBusyStatuses( array(
175
- Lib\Entities\CustomerAppointment::STATUS_PENDING,
176
- Lib\Entities\CustomerAppointment::STATUS_APPROVED,
177
- ) );
178
- array_walk( $busy, array( $wpdb, 'escape_by_ref' ) );
179
- $query .= sprintf( ' AND `ca`.`status` IN (%s)', implode( ',', array_map( function ( $status ) { return sprintf( "'%s'", $status ); }, $busy ) ) );
180
  }
181
 
182
  $query .= self::getAndWhereServiceType( $settings );
49
  if ( ! $settings->getInstant() ) {
50
  $ca_list = array();
51
  $customers = array();
52
+ $statuses = Lib\Proxy\CustomStatuses::prepareBusyStatuses( array(
53
+ Lib\Entities\CustomerAppointment::STATUS_PENDING,
54
+ Lib\Entities\CustomerAppointment::STATUS_APPROVED,
55
+ ) );
56
 
57
  switch ( $notification->getType() ) {
58
  // Appointment start date add time.
59
  case Notification::TYPE_APPOINTMENT_REMINDER:
60
  $ca_list = self::getCustomerAppointments( $notification, $settings );
61
+ if ( $settings->getStatus() === 'any' ) {
62
+ $statuses = array();
63
+ }
64
  break;
65
 
66
  // Last appointment.
87
  foreach ( $ca_list as $ca ) {
88
  if ( $token = $ca->getCompoundToken() ) {
89
  if ( ! isset ( $compounds[ $token ] ) ) {
90
+ $compounds[ $token ] = Compound::createByToken( $token, $statuses );
 
 
 
91
  }
92
  } elseif ( $token = $ca->getCollaborativeToken() ) {
93
  if ( ! isset ( $collaboratives[ $token ] ) ) {
94
+ $collaboratives[ $token ] = Collaborative::createByToken( $token, $statuses );
 
 
 
95
  }
96
  } else {
97
  $simple = Simple::create( $ca );
171
  );
172
  if ( $settings->getStatus() != 'any' ) {
173
  $query .= sprintf( ' AND `ca`.`status` = "%s"', $settings->getStatus() );
 
 
 
 
 
 
 
174
  }
175
 
176
  $query .= self::getAndWhereServiceType( $settings );
main.php CHANGED
@@ -3,7 +3,7 @@
3
  Plugin Name: Bookly
4
  Plugin URI: https://www.booking-wp-plugin.com/?utm_source=bookly_admin&utm_medium=plugins_page&utm_campaign=plugins_page
5
  Description: Bookly Plugin – is a great easy-to-use and easy-to-manage booking tool for service providers who think about their customers. The plugin supports a wide range of services provided by business and individuals who offer reservations through websites. Set up any reservation quickly, pleasantly and easily with Bookly!
6
- Version: 16.9
7
  Author: Bookly
8
  Author URI: https://www.booking-wp-plugin.com/?utm_source=bookly_admin&utm_medium=plugins_page&utm_campaign=plugins_page
9
  Text Domain: bookly
3
  Plugin Name: Bookly
4
  Plugin URI: https://www.booking-wp-plugin.com/?utm_source=bookly_admin&utm_medium=plugins_page&utm_campaign=plugins_page
5
  Description: Bookly Plugin – is a great easy-to-use and easy-to-manage booking tool for service providers who think about their customers. The plugin supports a wide range of services provided by business and individuals who offer reservations through websites. Set up any reservation quickly, pleasantly and easily with Bookly!
6
+ Version: 17.0
7
  Author: Bookly
8
  Author URI: https://www.booking-wp-plugin.com/?utm_source=bookly_admin&utm_medium=plugins_page&utm_campaign=plugins_page
9
  Text Domain: bookly
readme.txt CHANGED
@@ -3,9 +3,9 @@ Contributors: Ladela
3
  Tags: Booking, booking system, appointment booking, Booking calendar, reservation calendar, appointment scheduler, appointment calendar
4
  Donate link: https://www.booking-wp-plugin.com/
5
  Requires at least: 3.7
6
- Tested up to: 5.0.3
7
  Requires PHP: 5.3.7
8
- Stable tag: 16.9
9
  License: GPLv3
10
  License URI: http://www.gnu.org/licenses/gpl-3.0.html
11
 
3
  Tags: Booking, booking system, appointment booking, Booking calendar, reservation calendar, appointment scheduler, appointment calendar
4
  Donate link: https://www.booking-wp-plugin.com/
5
  Requires at least: 3.7
6
+ Tested up to: 5.1
7
  Requires PHP: 5.3.7
8
+ Stable tag: 17.0
9
  License: GPLv3
10
  License URI: http://www.gnu.org/licenses/gpl-3.0.html
11