PluginProbe ʕ •ᴥ•ʔ
Booking for Appointments and Events Calendar – Amelia / 2.4.6
Booking for Appointments and Events Calendar – Amelia v2.4.6
2.4.7 2.4.6 2.4.5 2.4.4 2.4.3 2.4.2 2.4.1 2.4 trunk 1.2.1 1.2.10 1.2.11 1.2.12 1.2.13 1.2.14 1.2.15 1.2.16 1.2.17 1.2.18 1.2.19 1.2.2 1.2.20 1.2.21 1.2.22 1.2.23 1.2.24 1.2.25 1.2.26 1.2.27 1.2.28 1.2.29 1.2.3 1.2.30 1.2.31 1.2.32 1.2.33 1.2.34 1.2.35 1.2.36 1.2.37 1.2.38 1.2.4 1.2.5 1.2.6 1.2.7 1.2.8 1.2.9 2.0 2.0.1 2.0.2 2.1 2.1.1 2.1.2 2.1.3 2.2 2.2.1 2.3
ameliabooking / v3 / src / assets / js / common / employee.js
ameliabooking / v3 / src / assets / js / common Last commit date
appointments.js 1 month ago attendees.js 1 month ago colorManipulation.js 1 month ago customer.js 1 month ago date.js 3 weeks ago defaultCustomize.js 3 weeks ago employee.js 6 days ago events.js 1 month ago formFieldsTemplates.js 1 month ago formatting.js 1 month ago helper.js 6 days ago image.js 1 month ago integrationApple.js 1 month ago integrationGoogle.js 1 month ago integrationOutlook.js 1 month ago integrationStripe.js 1 month ago integrationZoom.js 1 month ago licence.js 1 month ago liveAnnouncer.js 3 weeks ago phone.js 3 weeks ago pricing.js 1 month ago recurring.js 6 days ago responsive.js 1 month ago scrollElements.js 1 month ago settings.js 1 month ago translationsElementPlus.js 1 month ago utilHeaderHeight.js 1 month ago
employee.js
655 lines
1 import moment from 'moment'
2 import { settings } from '../../../plugins/settings'
3 import { useTimeInSeconds } from './date'
4 import { useAppointmentServicePrice } from './appointments'
5
6 function useParsedCustomPricing(service) {
7 if (!('customPricing' in service) || service.customPricing === null) {
8 service.customPricing = {
9 enabled: null,
10 durations: {},
11 persons: {},
12 periods: { default: [], custom: [] },
13 }
14
15 service.customPricing.durations[service.duration] = { price: service.price, rules: [] }
16 } else {
17 let customPricing =
18 typeof service.customPricing === 'object'
19 ? service.customPricing
20 : JSON.parse(service.customPricing)
21
22 service.customPricing = {
23 enabled: null,
24 durations: {},
25 persons: {},
26 periods: 'periods' in customPricing ? customPricing.periods : { default: [], custom: [] },
27 }
28
29 service.customPricing.durations[service.duration] = { price: service.price, rules: [] }
30
31 service.customPricing.durations = Object.assign(
32 service.customPricing.durations,
33 customPricing.durations,
34 )
35
36 customPricing.persons = 'persons' in customPricing ? customPricing.persons : {}
37
38 let persons = {}
39
40 if (Object.keys(customPricing.persons).length) {
41 let range = Object.keys(customPricing.persons)[0] - 1
42
43 persons[range] = {
44 from: 1,
45 range: range,
46 price: service.price,
47 rules: [],
48 }
49
50 Object.keys(customPricing.persons).forEach((person, index) => {
51 range =
52 index !== Object.keys(customPricing.persons).length - 1
53 ? Object.keys(customPricing.persons)[index + 1] - 1
54 : service.maxCapacity
55
56 persons[range] = {
57 from: parseInt(person),
58 range: range,
59 price: customPricing.persons[person].price,
60 rules: customPricing.persons[person].rules,
61 }
62 })
63 }
64
65 service.customPricing.persons = persons
66
67 if (customPricing.enabled === 'duration' || customPricing.enabled === true) {
68 service.customPricing.enabled = 'duration'
69 } else if (customPricing.enabled === 'person') {
70 service.customPricing.enabled = 'person'
71 } else if (customPricing.enabled === 'period') {
72 service.customPricing.enabled = 'period'
73 }
74 }
75
76 return service.customPricing
77 }
78
79 function getEmployeeServicePrice(store, providerId, serviceId) {
80 let employeeService = store.getters['entities/getEmployeeService'](providerId, serviceId)
81
82 let duration = store.getters['booking/getBookingDuration']
83 ? store.getters['booking/getBookingDuration']
84 : employeeService.duration
85
86 let persons = store.getters['booking/getBookingPersons']
87
88 return useAppointmentServicePrice(employeeService, persons, duration)
89 }
90
91 function sortForEmployeeSelection(store, employeesIds, serviceId) {
92 switch (settings.appointments.employeeSelection) {
93 case 'roundRobin': {
94 let lastBookedProviderId = store.getters['booking/getLastBookedProviderId']
95 employeesIds = employeesIds.map((e) => parseInt(e)).sort((a, b) => a - b)
96
97 for (let i = 0; i < employeesIds.length; i++) {
98 if (parseInt(employeesIds[0]) > parseInt(lastBookedProviderId)) {
99 break
100 }
101 employeesIds.push(employeesIds.shift())
102 }
103
104 return employeesIds
105 }
106 case 'lowestPrice':
107 return employeesIds.sort((emp1, emp2) => {
108 let price1 = getEmployeeServicePrice(store, emp1, serviceId)
109 let price2 = getEmployeeServicePrice(store, emp2, serviceId)
110 if (price1 < price2) {
111 return -1
112 } else if (price1 === price2) {
113 return emp1 < emp2 ? -1 : 1
114 } else {
115 return 1
116 }
117 })
118 case 'highestPrice':
119 return employeesIds.sort((emp1, emp2) => {
120 let price1 = getEmployeeServicePrice(store, emp1, serviceId)
121 let price2 = getEmployeeServicePrice(store, emp2, serviceId)
122 if (price1 < price2) {
123 return 1
124 } else if (price1 === price2) {
125 return emp1 < emp2 ? -1 : 1
126 } else {
127 return -1
128 }
129 })
130 case 'random':
131 default:
132 return employeesIds
133 }
134 }
135
136 function checkLimitPerEmployee(
137 employeesIds,
138 bookingIndex,
139 bookings,
140 booking,
141 appCount,
142 chosenEmployees,
143 serviceId,
144 ) {
145 let filteredEmployeeIds = []
146 for (let employeeId of employeesIds) {
147 let count =
148 appCount && appCount[employeeId] && appCount[employeeId][booking.date]
149 ? appCount[employeeId][booking.date]
150 : 0
151
152 let otherServiceBookings = chosenEmployees.filter(
153 (e) =>
154 e.providerId === employeeId &&
155 e.date === booking.date &&
156 e.serviceId !== serviceId &&
157 !e.existingApp,
158 )
159 let otherBookings = bookings.filter(
160 (e, index) =>
161 e.providerId === employeeId &&
162 e.date === booking.date &&
163 bookingIndex !== index &&
164 !e.existingApp,
165 )
166
167 if (
168 otherBookings.length + otherServiceBookings.length + count <
169 settings.roles.limitPerEmployee.numberOfApp
170 ) {
171 filteredEmployeeIds.push(employeeId)
172 }
173 }
174 if (filteredEmployeeIds.length === 0) {
175 return { employeeIds: filteredEmployeeIds, bookingFailed: bookingIndex }
176 }
177 return { employeeIds: filteredEmployeeIds, bookingFailed: null }
178 }
179
180 function getFrontendPeriodList(periodList) {
181 periodList.forEach((period) => {
182 period.startTime = period.startTime.substring(0, 5)
183 period.endTime = period.endTime.substring(0, 5)
184 period.locationId = period.locationId ? period.locationId : null
185 period.periodServiceList = period.periodServiceList.map((i) => i.serviceId)
186 period.periodLocationList = period.periodLocationList.map((i) => i.locationId)
187 })
188
189 return periodList.sort((a, b) => {
190 return useTimeInSeconds(a.startTime) - useTimeInSeconds(b.startTime)
191 })
192 }
193
194 function useFrontendEmployeeServiceList(store, employeeServiceList) {
195 let serviceList = {}
196
197 store.getters['entities/getCategories'].forEach((category) => {
198 category.serviceList.forEach((service) => {
199 let employeeService = employeeServiceList.find((s) => s.id === service.id)
200
201 if (!(service.categoryId in serviceList)) {
202 serviceList[service.categoryId] = {}
203 }
204
205 if (!(service.id in serviceList[service.categoryId])) {
206 serviceList[service.categoryId][service.id] = {}
207 }
208
209 serviceList[service.categoryId][service.id] =
210 typeof employeeService === 'undefined'
211 ? {
212 enabled: false,
213 price: parseFloat(service.price),
214 minCapacity: service.minCapacity,
215 maxCapacity: service.maxCapacity,
216 customPricing: service.customPricing,
217 }
218 : {
219 enabled: true,
220 price: parseFloat(employeeService.price),
221 minCapacity: employeeService.minCapacity,
222 maxCapacity: employeeService.maxCapacity,
223 customPricing: employeeService.customPricing,
224 }
225 })
226 })
227
228 return serviceList
229 }
230
231 function useFrontendEmployee(store, employee) {
232 let weekDayList = []
233
234 settings.weekSchedule.forEach((weekDay, index) => {
235 let employeeWeekDay = employee.weekDayList.find((i) => parseInt(i.dayIndex) === index + 1)
236
237 let timeOutList = []
238
239 if (typeof employeeWeekDay !== 'undefined') {
240 employeeWeekDay.timeOutList.forEach((timeOut) => {
241 timeOutList.push({
242 startTime: timeOut.startTime.substring(0, 5),
243 endTime: timeOut.endTime.substring(0, 5),
244 })
245 })
246 }
247
248 weekDayList.push(
249 typeof employeeWeekDay === 'undefined'
250 ? {
251 enabled: false,
252 id: null,
253 dayIndex: index + 1,
254 startTime: '',
255 endTime: '',
256 periodList: [],
257 timeOutList: [],
258 }
259 : Object.assign({}, employeeWeekDay, {
260 enabled: true,
261 startTime: employeeWeekDay.startTime.substring(0, 5),
262 endTime: employeeWeekDay.endTime.substring(0, 5),
263 periodList: getFrontendPeriodList(employeeWeekDay.periodList),
264 timeOutList: timeOutList,
265 }),
266 )
267 })
268
269 let specialDayList = []
270
271 employee.specialDayList.forEach((specialDay) => {
272 specialDayList.push({
273 id: specialDay.id,
274 range: [moment(specialDay.startDate).toDate(), moment(specialDay.endDate).toDate()],
275 periodList: getFrontendPeriodList(specialDay.periodList),
276 })
277 })
278
279 let dayOffList = []
280
281 employee.dayOffList.forEach((dayOff) => {
282 dayOffList.push({
283 id: dayOff.id,
284 name: dayOff.name,
285 repeat: dayOff.repeat,
286 range: [moment(dayOff.startDate).toDate(), moment(dayOff.endDate).toDate()],
287 })
288 })
289
290 let descriptionMode =
291 !employee.description || employee.description.startsWith('<!-- Content -->') ? 'text' : 'html'
292
293 let description = employee.description ? employee.description.replace('<!-- Content -->', '') : ''
294
295 return {
296 id: employee.id,
297 firstName: employee.firstName,
298 lastName: employee.lastName,
299 email: employee.email,
300 phone: employee.phone,
301 description: description,
302 descriptionMode: descriptionMode,
303 externalId: employee.externalId,
304 googleCalendar: employee.googleCalendar,
305 outlookCalendar: employee.outlookCalendar,
306 appleCalendarId: employee.appleCalendarId,
307 googleCalendarId: employee.googleCalendarId,
308 outlookCalendarId: employee.outlookCalendarId,
309 employeeAppleCalendar: employee.employeeAppleCalendar
310 ? employee.employeeAppleCalendar
311 : {
312 iCloudId: null,
313 appSpecificPassword: null,
314 },
315 stripeConnect: employee.stripeConnect,
316 zoomUserId: employee.zoomUserId,
317 locationId: employee.locationId ? employee.locationId : '',
318 serviceList: employee.serviceList,
319 weekDayList: weekDayList,
320 specialDayList: specialDayList,
321 dayOffList: dayOffList,
322 badgeId: employee.badgeId,
323 }
324 }
325
326 function getBackendPeriodList(store, periodList) {
327 let dayPeriodList = []
328
329 let servicesIds = useEmployeeServices(store).map((i) => i.id)
330
331 periodList.forEach((period) => {
332 dayPeriodList.push({
333 id: period.id,
334 locationId: period.locationId ? period.locationId : null,
335 startTime: period.startTime + ':00',
336 endTime: period.endTime + ':00',
337 periodServiceList: period.periodServiceList
338 .filter((id) => servicesIds.indexOf(id) !== -1)
339 .map((id) => new Object({ id: null, serviceId: id })),
340 periodLocationList: period.periodLocationList.map(
341 (id) => new Object({ id: null, locationId: id }),
342 ),
343 })
344 })
345
346 return dayPeriodList
347 }
348
349 function getBackendTimeOutList(store, timeOutList) {
350 let dayTimeOutList = []
351
352 timeOutList.forEach((timeOut) => {
353 dayTimeOutList.push({
354 id: timeOut.id,
355 startTime: timeOut.startTime + ':00',
356 endTime: timeOut.endTime + ':00',
357 })
358 })
359
360 return dayTimeOutList
361 }
362
363 function haveSameUniqueSortedValues(arr1, arr2) {
364 const unique1 = [...new Set(arr1)].sort()
365 const unique2 = [...new Set(arr2)].sort()
366
367 return unique1.length === unique2.length && unique1.every((v, i) => v === unique2[i])
368 }
369
370 function isChangedDayOff(savedDayOff, dayOff) {
371 return (
372 savedDayOff.name !== dayOff.name ||
373 savedDayOff.startDate !== dayOff.startDate ||
374 savedDayOff.endDate !== dayOff.endDate ||
375 savedDayOff.repeat !== dayOff.repeat
376 )
377 }
378
379 function isChangedSpecialDay(savedSpecialDay, specialDay) {
380 let savedPeriods = {}
381
382 savedSpecialDay.periodList.forEach((period) => {
383 savedPeriods[period.startTime + '-' + period.endTime] = {
384 locationId: period.locationId,
385 servicesIds: period.periodServiceList.map((s) => s.serviceId),
386 locationsIds: period.periodLocationList.map((l) => l.locationId),
387 }
388 })
389
390 let periods = {}
391
392 specialDay.periodList.forEach((period) => {
393 periods[period.startTime + '-' + period.endTime] = {
394 locationId: period.locationId,
395 servicesIds: period.periodServiceList.map((s) => s.serviceId),
396 locationsIds: period.periodLocationList.map((l) => l.locationId),
397 }
398 })
399
400 let changedSpecialDay =
401 savedSpecialDay.startDate !== specialDay.startDate ||
402 savedSpecialDay.endDate !== specialDay.endDate ||
403 !haveSameUniqueSortedValues(Object.keys(savedPeriods), Object.keys(periods))
404
405 if (!changedSpecialDay) {
406 Object.keys(savedPeriods).forEach((key) => {
407 if (
408 !(key in periods) ||
409 savedPeriods[key].locationId !== periods[key].locationId ||
410 !haveSameUniqueSortedValues(savedPeriods[key].servicesIds, periods[key].servicesIds) ||
411 !haveSameUniqueSortedValues(savedPeriods[key].locationsIds, periods[key].locationsIds)
412 ) {
413 changedSpecialDay = true
414 }
415 })
416 }
417
418 return changedSpecialDay
419 }
420
421 function modifyDayList(store, employee) {
422 let modifiedDayOffList = []
423
424 let removedDayOffList = []
425
426 store.getters['employee/getSavedDayOffList'].forEach((savedDay) => {
427 let index = employee.dayOffList.findIndex((i) => i.id === savedDay.id)
428
429 if (index === -1) {
430 removedDayOffList.push({ id: savedDay.id })
431 } else if (isChangedDayOff(savedDay, employee.dayOffList[index])) {
432 modifiedDayOffList.push(employee.dayOffList[index])
433 }
434 })
435
436 employee.dayOffList.forEach((day) => {
437 if (day.id === null) {
438 modifiedDayOffList.push(day)
439 }
440 })
441
442 employee.dayOffList = modifiedDayOffList
443
444 employee.removedDayOffList = removedDayOffList
445
446 let modifiedSpecialDayList = []
447
448 let removedSpecialDayList = []
449
450 store.getters['employee/getSavedSpecialDayList'].forEach((savedDay) => {
451 let index = employee.specialDayList.findIndex((i) => i.id === savedDay.id)
452
453 if (index === -1) {
454 removedSpecialDayList.push({ id: savedDay.id })
455 } else if (isChangedSpecialDay(savedDay, employee.specialDayList[index])) {
456 modifiedSpecialDayList.push(employee.specialDayList[index])
457 }
458 })
459
460 employee.specialDayList.forEach((day) => {
461 if (day.id === null) {
462 modifiedSpecialDayList.push(day)
463 }
464 })
465
466 employee.specialDayList = modifiedSpecialDayList
467
468 employee.removedSpecialDayList = removedSpecialDayList
469
470 delete employee.savedSpecialDayList
471
472 delete employee.savedDayOffList
473 }
474
475 function useBackendEmployee(store, timeZone) {
476 let employee = store.getters['employee/getEmployee']
477
478 let serviceList = []
479
480 Object.keys(employee.serviceList).forEach((categoryId) => {
481 Object.keys(employee.serviceList[categoryId]).forEach((serviceId) => {
482 if (employee.serviceList[categoryId][serviceId].enabled) {
483 let service = store.getters['entities/getCategory'](categoryId).serviceList.find(
484 (i) => i.id === parseInt(serviceId),
485 )
486
487 let price =
488 employee.serviceList[categoryId][serviceId].customPricing.enabled === 'duration'
489 ? parseFloat(
490 employee.serviceList[categoryId][serviceId].customPricing.durations[
491 service.duration
492 ].price,
493 )
494 : parseFloat(employee.serviceList[categoryId][serviceId].price)
495
496 let employeeService = {
497 id: parseInt(serviceId),
498 minCapacity: parseInt(employee.serviceList[categoryId][serviceId].minCapacity),
499 maxCapacity: parseInt(employee.serviceList[categoryId][serviceId].maxCapacity),
500 price: price,
501 customPricing: {
502 enabled: employee.serviceList[categoryId][serviceId].customPricing.enabled,
503 durations: {},
504 persons: {},
505 periods: employee.serviceList[categoryId][serviceId].customPricing.periods,
506 },
507 }
508
509 Object.keys(employee.serviceList[categoryId][serviceId].customPricing.durations).forEach(
510 (duration) => {
511 employeeService.customPricing.durations[duration] = {
512 price: parseFloat(
513 employee.serviceList[categoryId][serviceId].customPricing.durations[duration].price,
514 ),
515 rules: [],
516 }
517 },
518 )
519
520 Object.keys(employee.serviceList[categoryId][serviceId].customPricing.persons).forEach(
521 (range, index) => {
522 if (index !== 0) {
523 employeeService.customPricing.persons[
524 employee.serviceList[categoryId][serviceId].customPricing.persons[range].from
525 ] = {
526 price: parseFloat(
527 employee.serviceList[categoryId][serviceId].customPricing.persons[range].price,
528 ),
529 rules: [],
530 }
531 }
532 },
533 )
534
535 delete employeeService.customPricing.durations[service.duration]
536
537 employeeService.customPricing = JSON.stringify(employeeService.customPricing)
538
539 serviceList.push(employeeService)
540 }
541 })
542 })
543
544 let weekDayList = []
545
546 employee.weekDayList.forEach((weekDay) => {
547 if (weekDay.enabled) {
548 let periodList = getBackendPeriodList(store, weekDay.periodList)
549
550 if (periodList.length) {
551 let timeOutList = getBackendTimeOutList(store, weekDay.timeOutList)
552
553 weekDayList.push({
554 id: weekDay.id,
555 dayIndex: weekDay.dayIndex,
556 startTime: periodList.length ? periodList[0].startTime : weekDay.startTime,
557 endTime: periodList.length ? periodList[periodList.length - 1].endTime : weekDay.endTime,
558 periodList: periodList,
559 timeOutList: timeOutList,
560 })
561 }
562 }
563 })
564
565 let specialDayList = []
566
567 employee.specialDayList.forEach((specialDay) => {
568 let periodList = getBackendPeriodList(store, specialDay.periodList)
569
570 if (periodList.length) {
571 specialDayList.push({
572 id: specialDay.id,
573 startDate: moment(specialDay.range[0]).format('YYYY-MM-DD'),
574 endDate: moment(specialDay.range[1]).format('YYYY-MM-DD'),
575 periodList: periodList,
576 })
577 }
578 })
579
580 let dayOffList = []
581
582 employee.dayOffList.forEach((dayOff) => {
583 dayOffList.push({
584 id: dayOff.id,
585 name: dayOff.name,
586 startDate: moment(dayOff.range[0]).format('YYYY-MM-DD'),
587 endDate: moment(dayOff.range[1]).format('YYYY-MM-DD'),
588 repeat: dayOff.repeat,
589 })
590 })
591
592 let result = Object.assign({}, employee, {
593 description:
594 store.getters['employee/getDescription'] &&
595 store.getters['employee/getDescriptionMode'] === 'text'
596 ? '<!-- Content -->' + store.getters['employee/getDescription']
597 : store.getters['employee/getDescription'],
598 serviceList: serviceList,
599 weekDayList: weekDayList,
600 specialDayList: specialDayList,
601 dayOffList: dayOffList,
602 timeZone:
603 store.getters['cabinet/getTimeZone'] === timeZone ? '' : store.getters['cabinet/getTimeZone'],
604 })
605
606 modifyDayList(store, result)
607
608 delete result.descriptionMode
609
610 return result
611 }
612
613 function useEmployeeServices(store) {
614 let serviceIds = []
615
616 Object.keys(store.getters['employee/getServiceList']).forEach((categoryId) => {
617 Object.keys(store.getters['employee/getServiceList'][categoryId]).forEach((serviceId) => {
618 if (store.getters['employee/getServiceList'][categoryId][serviceId].enabled) {
619 serviceIds.push(parseInt(serviceId))
620 }
621 })
622 })
623
624 return store.getters['entities/getServices'].filter((i) => serviceIds.indexOf(i.id) !== -1)
625 }
626
627 function useFeaturesAndIntegrations(service, isPanel) {
628 if (!isPanel && !settings.featuresIntegrations.extras.enabled) {
629 service.extras = []
630 }
631
632 if (!settings.featuresIntegrations.customPricing.enabled) {
633 service.customPricing = null
634 }
635
636 if (!settings.featuresIntegrations.depositPayment.enabled) {
637 service.depositPayment = 'disabled'
638 }
639
640 if (!settings.featuresIntegrations.recurringAppointments.enabled) {
641 service.recurringCycle = 'disabled'
642 }
643 }
644
645 export {
646 useEmployeeServices,
647 useParsedCustomPricing,
648 sortForEmployeeSelection,
649 checkLimitPerEmployee,
650 useFrontendEmployee,
651 useBackendEmployee,
652 useFrontendEmployeeServiceList,
653 useFeaturesAndIntegrations,
654 }
655