14Loc::loadMessages(__FILE__);
35 "USER_TYPE_ID" => static::USER_TYPE_ID,
36 "CLASS_NAME" => __CLASS__,
37 "DESCRIPTION" => Loc::getMessage(
"USER_TYPE_RESOURCEBOOKING_DESCRIPTION"),
38 "BASE_TYPE" => \CUserTypeManager::BASE_TYPE_STRING,
39 "EDIT_CALLBACK" =>
array(__CLASS__,
'getPublicEdit'),
40 "VIEW_CALLBACK" =>
array(__CLASS__,
'getPublicView')
48 'SELECTED_RESOURCES' => $userField[
'SETTINGS'][
'SELECTED_RESOURCES'] ??
null,
49 'SELECTED_USERS' => $userField[
'SETTINGS'][
'SELECTED_USERS'] ??
null,
50 'USE_USERS' => $userField[
'SETTINGS'][
'USE_USERS'] ??
null,
51 'USE_RESOURCES' => $userField[
'SETTINGS'][
'USE_RESOURCES'] ??
null,
52 'FULL_DAY' => $userField[
'SETTINGS'][
'FULL_DAY'] ??
null,
53 'ALLOW_OVERBOOKING' => $userField[
'SETTINGS'][
'ALLOW_OVERBOOKING'] ??
null,
54 'USE_SERVICES' => $userField[
'SETTINGS'][
'USE_SERVICES'] ??
null,
55 'SERVICE_LIST' => $userField[
'SETTINGS'][
'SERVICE_LIST'] ??
null,
56 'TIMEZONE' => $userField[
'SETTINGS'][
'TIMEZONE'] ??
null,
57 'USE_USER_TIMEZONE' => $userField[
'SETTINGS'][
'USE_USER_TIMEZONE'] ??
null,
61 $selectedResources = [];
63 if (is_array($userField[
"SETTINGS"][
"SELECTED_RESOURCES"]))
65 $selectedResources = self::handleResourceList($userField[
"SETTINGS"][
"SELECTED_RESOURCES"]);
68 if (is_array($userField[
"SETTINGS"][
"SELECTED_USERS"]))
70 foreach($userField[
"SETTINGS"][
"SELECTED_USERS"] as
$user)
72 if (intval(
$user) > 0)
74 $selectedUsers[] = intval(
$user);
80 "USE_USERS" => $userField[
"SETTINGS"][
"USE_USERS"] ===
'N' ?
'N' :
'Y',
81 "USE_RESOURCES" => $userField[
"SETTINGS"][
"USE_RESOURCES"] ===
'N' ?
'N' :
'Y',
82 "RESOURCES" => self::getDefaultResourcesList(),
83 "SELECTED_RESOURCES" => $selectedResources,
84 "SELECTED_USERS" => $selectedUsers,
85 "FULL_DAY" => $userField[
"SETTINGS"][
"FULL_DAY"] ===
'Y' ?
'Y' :
'N',
86 "ALLOW_OVERBOOKING" => $userField[
"SETTINGS"][
"ALLOW_OVERBOOKING"] ===
'N' ?
'N' :
'Y',
87 "USE_SERVICES" => $userField[
"SETTINGS"][
"USE_SERVICES"] ===
'N' ?
'N' :
'Y',
88 "SERVICE_LIST" => is_array($userField[
"SETTINGS"][
"SERVICE_LIST"]) ? $userField[
"SETTINGS"][
"SERVICE_LIST"] : self::getDefaultServiceList(),
89 "RESOURCE_LIMIT" => self::getBitrx24Limitation(),
90 "TIMEZONE" => $userField[
"SETTINGS"][
"TIMEZONE"],
91 "USE_USER_TIMEZONE" => $userField[
"SETTINGS"][
"USE_USER_TIMEZONE"] ===
'Y' ?
'Y' :
'N'
104 if($userField[
"MANDATORY"] ===
"Y" && ($value ===
'empty' || !$value))
107 "id" => $userField[
'FIELD_NAME'],
108 "text"=>str_replace(
"#FIELD_NAME#", $userField[
'EDIT_FORM_LABEL'],
109 Loc::getMessage(
"USER_TYPE_FIELD_VALUE_IS_MISSING"))
119 $currentUserId = \CCalendar::getCurUserId();
127 $resourseList = Internals\ResourceTable::query()
129 ->where(
'PARENT_TYPE', $userField[
'ENTITY_ID'])
130 ->where(
'PARENT_ID', $userField[
'VALUE_ID'])
131 ->where(
'UF_ID', $userField[
'ID'])
135 $currentEntriesIndex = [];
136 while ($resourse = $resourseList->fetch())
138 $currentEntriesIndex[$resourse[
'CAL_TYPE'].$resourse[
'RESOURCE_ID']] = $resourse;
141 if (self::isCrmEntity($userField[
'ENTITY_ID']) && Loader::includeModule(
'crm'))
143 if ($userField[
'ENTITY_ID'] === self::CRM_DEAL_ENTITY_ID)
145 $dealResult = \CCrmDeal::GetListEx(
147 [
'=ID' => $userField[
'VALUE_ID'],
'CHECK_PERMISSIONS' =>
'N'],
153 if (!empty($dealResult))
155 $entity = $dealResult->Fetch();
160 $entityTitle = Loc::getMessage(
"USER_TYPE_RESOURCE_EVENT_TITLE").
': '.
$entity[
'TITLE'];
163 elseif ($userField[
'ENTITY_ID'] === self::CRM_LEAD_ENTITY_ID)
165 $leadResult = \CCrmLead::GetListEx(
167 [
'=ID' => $userField[
'VALUE_ID'],
'CHECK_PERMISSIONS' =>
'N'],
173 if (!empty($leadResult))
175 $entity = $leadResult->Fetch();
180 $entityTitle = Loc::getMessage(
"USER_TYPE_RESOURCE_EVENT_TITLE").
': '.
$entity[
'TITLE'];
185 $userField[
'ENTITY_ID'] === self::CRM_SUSPENDED_DEAL_ENTITY_ID
186 || $userField[
'ENTITY_ID'] === self::CRM_SUSPENDED_LEAD_ENTITY_ID
189 $entityTitle = Loc::getMessage(
"USER_TYPE_RESOURCE_EVENT_TITLE").
" (Deleted)";
195 $entityTitle = Loc::getMessage(
"USER_TYPE_RESOURCE_EVENT_TITLE");
199 foreach ($values as $value)
201 if ((
string)$value === (
string)((
int)$value))
203 $currentValue = static::fetchFieldValue($value);
204 $skipTime = is_array($userField[
'SETTINGS']) && $userField[
'SETTINGS'][
'FULL_DAY'] ===
'Y';
205 $fromTs = \CCalendar::timestamp($currentValue[
'DATE_FROM'],
true, !$skipTime);
206 $toTs = \CCalendar::timestamp($currentValue[
'DATE_TO'],
true, !$skipTime);
208 foreach ($currentValue[
'ENTRIES'] as $entry)
212 foreach ($values as $iValue)
214 $str = $entry[
'TYPE'].
'|'.$entry[
'RESOURCE_ID'];
215 if (str_starts_with($iValue,
$str))
226 $entry[
'RESOURCE_ID'],
227 $currentValue[
'DATE_FROM'],
229 $currentValue[
'SERVICE_NAME']
236 $values = array_merge($values, $valuesToMerge);
238 foreach ($values as $value)
242 if (!is_array($value))
247 if (!$dateFrom || !$dateTo)
249 $dateFromTimestamp = \CCalendar::timestamp($value[
'from']);
250 $skipTime = isset($userField[
'SETTINGS']) && $userField[
'SETTINGS'][
'FULL_DAY'] ===
'Y';
251 $dateFrom = \CCalendar::date($dateFromTimestamp, !$skipTime);
252 $duration = (int)$value[
'duration'];
253 $dateTo = \CCalendar::date($dateFromTimestamp + ($skipTime ? $duration - \CCalendar::DAY_LENGTH : $duration), !$skipTime);
254 $serviceName = trim($value[
'serviceName']);
257 "DATE_FROM" => $dateFrom,
258 "DATE_TO" => $dateTo,
259 "SKIP_TIME" => $skipTime,
260 "NAME" => $entityTitle
264 $userField[
'ENTITY_ID'] === self::CRM_SUSPENDED_DEAL_ENTITY_ID
265 || $userField[
'ENTITY_ID'] === self::CRM_SUSPENDED_LEAD_ENTITY_ID
271 if ($serviceName !==
'')
273 $fields[
"DESCRIPTION"] = Loc::getMessage(
"USER_TYPE_RESOURCE_SERVICE_LABEL").
': '.$serviceName;
278 if ($userField[
'SETTINGS'][
'USE_USER_TIMEZONE'] ===
'Y')
280 $timezoneName = \CCalendar::getUserTimezoneName($currentUserId,
true);
282 else if($userField[
'SETTINGS'][
'TIMEZONE'])
284 $timezoneName = $userField[
'SETTINGS'][
'TIMEZONE'];
288 $timezoneName = \CCalendar::GetGoodTimezoneForOffset((
int)date(
"Z"));
293 $fields[
'TZ_FROM'] = $timezoneName;
294 $fields[
'TZ_TO'] = $timezoneName;
300 if (isset($currentEntriesIndex[$value[
'type'] . $value[
'id']]))
302 $fields[
'ID'] = $currentEntriesIndex[$value[
'type'].$value[
'id']][
'EVENT_ID'];
303 $entryId = $currentEntriesIndex[$value[
'type'].$value[
'id']][
'ID'];
316 'userField' => $userField,
317 'serviceName' => $serviceName
321 if ($resourceBookingId)
323 $valuesToSave[] = $resourceBookingId;
327 foreach ($currentEntriesIndex as $resourceEntry)
329 if (!in_array($resourceEntry[
'ID'], $valuesToSave))
335 return $valuesToSave;
340 $resourseList = Internals\ResourceTable::getList(
343 "=PARENT_TYPE" => $userField[
'ENTITY_ID'],
344 "=PARENT_ID" => $userField[
'ENTITY_VALUE_ID'],
345 "=UF_ID" => $userField[
'ID'],
350 while ($resourse = $resourseList->fetch())
371 $currentUserId = \CCalendar::getCurUserId();
373 $eventFields[
"EVENT_TYPE"] =
'#resourcebooking#';
374 if ($resourceType ===
'user')
376 $eventFields[
"CAL_TYPE"] = $resourceType;
379 if (
$params[
'userField'][
'ENTITY_ID'] ===
'CRM_DEAL' ||
$params[
'userField'][
'ENTITY_ID'] ===
'CRM_LEAD')
381 $sectionId = \CCalendar::getCrmSection(
$resourceId,
true);
385 $sectionId = \CCalendar::getMeetingSection(
$resourceId,
true);
389 $eventFields[
'SECTIONS'] = [$sectionId];
394 if (
$params[
'userField'][
'ENTITY_ID'] ===
'CRM_DEAL')
396 $userFields[
'UF_CRM_CAL_EVENT'] = [
"D_".$params[
'userField'][
'VALUE_ID']];
400 $userFields[
'UF_CRM_CAL_EVENT'] = [
"L_".$params[
'userField'][
'VALUE_ID']];
403 $entryId = \CCalendar::saveEvent([
404 'arFields' => $eventFields,
406 'silentErrorMode' =>
false,
407 'autoDetectSection' =>
true,
408 'autoCreateSection' =>
true,
409 'checkPermission' =>
false
414 $eventFields[
"CAL_TYPE"] = $resourceType;
416 $entryId = \CCalendarEvent::edit([
417 'arFields' => $eventFields
423 if ($eventFields[
'TZ_FROM'] ??
null)
427 $fromUtc =
new Type\DateTime($eventFields[
"DATE_FROM"],
null,
new \DateTimeZone(
'UTC'));
428 $toUtc =
new Type\DateTime($eventFields[
"DATE_TO"],
null,
new \DateTimeZone(
'UTC'));
438 \CTimeZone::Disable();
440 $resourceTableFields = [
441 'EVENT_ID' => $entryId,
442 'CAL_TYPE' => $eventFields[
"CAL_TYPE"],
444 'PARENT_TYPE' =>
$params[
'bindingEntityType'] ??
$params[
'userField'][
'ENTITY_ID'],
445 'PARENT_ID' =>
$params[
'bindingEntityId'] ??
$params[
'userField'][
'VALUE_ID'],
446 'UF_ID' =>
$params[
'bindingUserfieldId'] ??
$params[
'userField'][
'ID'],
447 'DATE_FROM' => $from,
449 'SKIP_TIME' => $eventFields[
'SKIP_TIME'] ??
null,
450 'DATE_FROM_UTC' => $fromUtc,
451 'DATE_TO_UTC' => $toUtc,
452 'TZ_FROM' => $eventFields[
'TZ_FROM'] ??
null,
453 'TZ_TO' => $eventFields[
'TZ_TO'] ??
null,
454 'TZ_OFFSET_FROM' => \CCalendar::getTimezoneOffset(
455 $eventFields[
'TZ_FROM'] ??
null,
456 \CCalendar::timestamp($eventFields[
"DATE_FROM"])
458 'TZ_OFFSET_TO' => \CCalendar::getTimezoneOffset(
459 $eventFields[
'TZ_TO'] ??
null,
460 \CCalendar::timestamp($eventFields[
"DATE_TO"])
462 'CREATED_BY' => $currentUserId,
463 'SERVICE_NAME' =>
$params[
'serviceName'] ?? null
468 $result = Internals\ResourceTable::update($id, $resourceTableFields);
472 $result = Internals\ResourceTable::add($resourceTableFields);
477 $valueToSave =
$result->getId();
481 \CCalendar::deleteEvent((
int)$entryId,
false);
487 'userFieldValueId' => $valueToSave,
488 'bookingEventId' => $entryId,
489 'resourceType' => $resourceType,
491 'serviceName' =>
$params[
'serviceName'] ??
null,
494 'skipTime' => $eventFields[
'SKIP_TIME'],
495 'timezoneFrom' => $eventFields[
'TZ_FROM'] ??
null,
496 'timezoneTo' => $eventFields[
'TZ_TO'] ??
null,
500 \CTimeZone::Enable();
506 private static function isCrmEntity(
$entityId)
508 return in_array(
$entityId, [self::CRM_LEAD_ENTITY_ID, self::CRM_SUSPENDED_LEAD_ENTITY_ID,self::CRM_DEAL_ENTITY_ID, self::CRM_SUSPENDED_DEAL_ENTITY_ID]);
511 private static function isResourceAvailable()
518 \CCalendar::deleteEvent((
int)$entry[
'EVENT_ID'],
true,
array(
'checkPermissions' =>
false));
519 Internals\ResourceTable::delete($entry[
'ID']);
522 private static function handleResourceList($resources)
525 foreach($resources as $resource)
527 if (is_array($resource))
529 if (($resource[
'id'] ??
null) && (($resource[
'deleted'] ??
null) || ($resource[
'title'] ??
null) ==
''))
531 $sectionList = Internals\SectionTable::getList(
533 "filter" =>
array(
"ID" => $resource[
'id'],
"CAL_TYPE" => $resource[
'type'] ??
null),
534 "select" =>
array(
"ID",
"CAL_TYPE",
"NAME")
537 if ($sectionList->fetch())
539 Internals\SectionTable::delete(
array(
'ID' => $resource[
'id']));
542 else if ($resource[
'id'] ??
null)
544 $sectionList = Internals\SectionTable::getList(
546 "filter" =>
array(
"ID" => $resource[
'id'],
"CAL_TYPE" => $resource[
'type'] ??
null),
547 "select" =>
array(
"ID",
"CAL_TYPE",
"NAME")
550 if ($section = $sectionList->fetch())
552 if ($section[
'NAME'] != ($resource[
'title'] ??
null))
554 \CCalendarSect::edit(
array(
556 'ID' => $resource[
'id'],
557 'CAL_TYPE' => $resource[
'type'] ??
null,
558 'NAME' => $resource[
'title'] ??
null,
566 elseif (!($resource[
'id'] ??
null) && ($resource[
'title'] ??
null) !==
'')
568 $resource[
'id'] = \CCalendarSect::edit(
array(
570 'CAL_TYPE' => $resource[
'type'] ??
null,
571 'NAME' => $resource[
'title'] ??
null,
585 $id = (int)$id > 0 ? $id : 1;
586 $duration = (int)$duration > 0 ? $duration : 60;
587 return $type.
'|'.$id.
'|'.$from.
'|'.$duration.
'|'.$serviceName;
593 if(mb_strpos($value,
'|') >= 0)
595 $list = explode(
'|', $value);
596 $type = $list[0] ??
null;
597 $id = $list[1] ??
null;
598 $from = $list[2] ??
null;
599 $duration = $list[3] ??
null;
600 $serviceName = $list[4] ??
null;
601 if (
$type ===
'user' || (
$type ===
'resource' && (
int)$id > 0))
607 'duration' => $duration,
608 'serviceName' => $serviceName ? $serviceName :
''
615 function getSettingsHTML($userField =
false, $htmlControl = [], $varsFromForm =
false)
617 \Bitrix\Main\UI\Extension::load([
'uf',
'calendar.resourcebookinguserfield',
'calendar_planner',
'socnetlogdest',
'helper',
'main',
'ui',
'ui.selector']);
621 $settingsValue =
$GLOBALS[$htmlControl[
"NAME"]];
623 elseif(is_array($userField))
625 $settingsValue = $userField[
"SETTINGS"];
632 $controlId = $userField[
'FIELD_NAME'].
'_'.rand();
634 'controlId' => $controlId,
635 'settings' => $settingsValue,
636 'userField' => $userField,
637 'htmlControl' => $htmlControl,
638 'outerWrapId' => $controlId.
'-settings-outer-wrap',
639 'formName' =>
'post_form'
642 if ($settingsValue[
'USE_USERS'] ===
'Y')
644 $params[
'socnetDestination'] = \CCalendar::getSocNetDestination(
false, [], $settingsValue[
'SELECTED_USERS']);
650 <div id="'.HtmlFilter::encode(
$params[
'outerWrapId']).
'"></div>
651 <script>(function(){new BX.Calendar.AdminSettingsViewer('.
653 ').showLayout();})();</script>
662 return static::getPublicEdit($userField, $htmlControl);
669 $fieldName = static::getFieldName($userField, $additionalParams);
670 $userField[
'VALUE'] = static::getFieldValue($userField, $additionalParams);
672 $value = static::fetchFieldValue($userField[
"VALUE"]);
675 $userField[
'SETTINGS'][
'USE_RESOURCES'] ===
'Y'
676 && (!is_array($userField[
'SETTINGS'][
'SELECTED_RESOURCES']) || empty($userField[
'SETTINGS'][
'SELECTED_RESOURCES']))
679 $userField[
'SETTINGS'][
'USE_RESOURCES'] =
'N';
682 $controlId = $userField[
'FIELD_NAME'].
'_'.rand();
684 'controlId' => $controlId,
685 'inputName' => $fieldName,
687 'plannerId' => $controlId.
'_planner',
688 'userSelectorId' =>
'resource_booking_user_selector',
689 'useUsers' => $userField[
'SETTINGS'][
'USE_USERS'] ===
'Y',
690 'useResources' => $userField[
'SETTINGS'][
'USE_RESOURCES'] ===
'Y',
691 'fullDay' => $userField[
'SETTINGS'][
'FULL_DAY'] ===
'Y',
692 'allowOverbooking' => $userField[
'SETTINGS'][
'ALLOW_OVERBOOKING'] !==
'N',
693 'useServices' => $userField[
'SETTINGS'][
'USE_SERVICES'] ===
'Y',
694 'serviceList' => $userField[
'SETTINGS'][
'SERVICE_LIST'],
695 'resourceList' => $userField[
'SETTINGS'][
'SELECTED_RESOURCES'],
696 'userList' => $userField[
'SETTINGS'][
'SELECTED_USERS'],
697 'userfieldId' => $userField[
'ID'],
699 'workTime' => [\COption::getOptionString(
'calendar',
'work_time_start', 9), \COption::getOptionString(
'calendar',
'work_time_end', 19)]
704 $params[
'socnetDestination'] = \CCalendar::getSocNetDestination(
false, [], $userField[
'SETTINGS'][
'SELECTED_USERS']);
710 <div
id=
"<?= HtmlFilter::encode($params['controlId'])?>" class=
"crm-entity-widget-resourcebook-container"></div>
714 BX.Runtime.loadExtension(
'calendar.resourcebookinguserfield').then(
function(exports)
716 if (exports && BX.type.isFunction(exports.ResourcebookingUserfield))
718 exports.ResourcebookingUserfield.initEditFieldController(<?= \
Bitrix\
Main\
Web\Json::encode(
$params)?>);
725 $html = ob_get_clean();
727 return static::getHelper()->wrapDisplayResult($html);
732 $context = $additionalParams[
'CONTEXT'] ??
'';
733 $value = static::fetchFieldValue($userField[
"VALUE"] ??
null);
734 $skipTime = is_array($userField[
'SETTINGS'] ??
null) && ($userField[
'SETTINGS'][
'FULL_DAY'] ??
null) ==
'Y';
735 $fromTs = \CCalendar::timestamp($value[
'DATE_FROM'] ??
null,
true, !$skipTime);
736 $toTs = \CCalendar::timestamp($value[
'DATE_TO'] ??
null,
true, !$skipTime);
742 $resourceIdList = [];
744 foreach($value[
'ENTRIES'] as $entry)
746 if ($entry[
'TYPE'] ===
'user')
748 $userIdList[] = (int) $entry[
'RESOURCE_ID'];
752 $resourceIdList[] = (int) $entry[
'RESOURCE_ID'];
756 $userIdList = array_unique($userIdList);
757 $resourceIdList = array_unique($resourceIdList);
759 if (!empty($userIdList))
761 $orm = UserTable::getList([
763 '=ID' => $userIdList,
766 'select' => [
'ID',
'LOGIN',
'NAME',
'LAST_NAME',
'SECOND_NAME',
'TITLE',
'PERSONAL_PHOTO']
769 while (
$user = $orm->fetch())
771 $user[
'URL'] = \CCalendar::getUserUrl(
$user[
"ID"]);
776 if (!empty($resourceIdList))
778 $sectionList = Internals\SectionTable::getList(
782 "!=CAL_TYPE" => [
'user',
'group',
'company_calendar',
'company',
'calendar_company'],
783 "ID" => $resourceIdList
785 "select" =>
array(
"ID",
"CAL_TYPE",
"NAME")
789 while ($section = $sectionList->fetch())
791 $resources[$section[
'ID']] = $section;
792 $resourceNames[] = HtmlFilter::encode($section[
'NAME']);
803 \Bitrix\Main\Page\Asset::getInstance()->addCss(
'/bitrix/js/calendar/userfield/resourcebooking.css');
807 foreach($users as
$user)
809 $resListItems[] =
'<span>'.HtmlFilter::encode(\CCalendar::getUserName(
$user)).
'</span>';
812 if (!empty($resourceNames))
814 foreach($resourceNames as $resourceName)
816 $resListItems[] =
'<span>'.$resourceName.
'</span>';
820 if (!empty($resListItems))
822 $html =
'<span>'.\CCalendar::getFromToHtml($fromTs, $toTs, $skipTime, $toTs - $fromTs).
'</span>: ';
823 if(!empty($value[
'SERVICE_NAME']))
825 $html .=
'<span>'.HtmlFilter::encode($value[
'SERVICE_NAME']).
'</span>, ';
827 $html .=
'<span>'.implode(
', ', $resListItems).
'</span>';
831 $html =
'<span class="calendar-resbook-field-empty">'.Loc::getMessage(
"USER_TYPE_RESOURCE_EMPTY").
'</span>';
837 if (empty($users) && empty($resourceNames))
839 $html = Loc::getMessage(
"USER_TYPE_RESOURCE_EMPTY");
845 <div
class=
"calendar-res-book-public-view-outer-wrap">
846 <div
class=
"calendar-res-book-public-view-inner-wrap">
847 <div
class=
"crm-entity-widget-content-block crm-entity-widget-content-block-field-select">
848 <div
class=
"crm-entity-widget-content-block-title">
850 class=
"crm-entity-widget-content-block-title-text"><?= ($skipTime ? Loc::getMessage(
"USER_TYPE_RESOURCE_DATE_BLOCK_TITLE") : Loc::getMessage(
"USER_TYPE_RESOURCE_DATETIME_BLOCK_TITLE")) ?></span>
853 class=
"crm-entity-widget-content-block-inner"><?= \CCalendar::getFromToHtml($fromTs, $toTs, $skipTime, $toTs - $fromTs) ?></div>
856 <?
if(!empty($value[
'SERVICE_NAME'])): ?>
857 <div
class=
"crm-entity-widget-content-block crm-entity-widget-content-block-field-select">
858 <div
class=
"crm-entity-widget-content-block-title">
860 class=
"crm-entity-widget-content-block-title-text"><?= Loc::getMessage(
"USER_TYPE_RESOURCE_SERVICE_PLACEHOLDER") ?></span>
863 class=
"crm-entity-widget-content-block-inner"><?= HtmlFilter::encode($value[
'SERVICE_NAME']) ?></div>
867 <?
if (!empty($users)): ?>
868 <div
class=
"crm-entity-widget-content-block crm-entity-widget-content-block-field-select">
869 <div
class=
"crm-entity-widget-content-block-title">
871 class=
"crm-entity-widget-content-block-title-text"><?= Loc::getMessage(
"USER_TYPE_RESOURCE_USERS_CONTROL_DEFAULT_NAME") ?></span>
873 <?
foreach($users as
$user): ?>
874 <div
class=
"crm-widget-employee-container">
875 <a
class=
"crm-widget-employee-avatar-container" href=
"<?= $user['URL'] ?>" target=
"_blank" style=
"background-image: url('<?= \CCalendar::getUserAvatarSrc($user) ?>'); background-size: 30px;"></a>
876 <span
class=
"crm-widget-employee-info"><a
class=
"crm-widget-employee-name" href=
"<?= $user['URL']?>" target=
"_blank"><?= HtmlFilter::encode(\CCalendar::getUserName(
$user))?></a><span
class=
"crm-widget-employee-position"></span></span>
882 <?
if (!empty($resourceNames)): ?>
883 <div
class=
"crm-entity-widget-content-block crm-entity-widget-content-block-field-select">
884 <div
class=
"crm-entity-widget-content-block-title">
886 class=
"crm-entity-widget-content-block-title-text"><?= Loc::getMessage(
"USER_TYPE_RESOURCE_RESOURCE_CONTROL_DEFAULT_NAME") ?></span>
888 <div
class=
"crm-entity-widget-content-block-inner"><?= implode(
', ', $resourceNames) ?></div>
894 $html = ob_get_clean();
900 $html =
'<span class="field-item">' . $html .
'</span>';
903 return static::getHelper()->wrapDisplayResult($html);
909 $value = static::fetchFieldValue($userField[
"VALUE"]);
915 $resourseIdList = [];
917 foreach($value[
'ENTRIES'] as $entry)
919 if ($entry[
'TYPE'] ===
'user')
921 $userIdList[] = (int) $entry[
'RESOURCE_ID'];
925 $resourseIdList[] = (int) $entry[
'RESOURCE_ID'];
929 $userIdList = array_unique($userIdList);
930 $resourseIdList = array_unique($resourseIdList);
932 if (!empty($userIdList))
934 $orm = UserTable::getList([
936 '=ID' => $userIdList,
939 'select' => [
'ID',
'LOGIN',
'NAME',
'LAST_NAME',
'SECOND_NAME',
'TITLE',
'PERSONAL_PHOTO']
942 while (
$user = $orm->fetch())
944 $user[
'URL'] = \CCalendar::getUserUrl(
$user[
"ID"]);
949 if (!empty($resourseIdList))
951 $sectionList = Internals\SectionTable::getList(
955 "!=CAL_TYPE" => [
'user',
'group',
'company_calendar',
'company',
'calendar_company'],
956 "ID" => $resourseIdList
958 "select" =>
array(
"ID",
"CAL_TYPE",
"NAME")
962 while ($section = $sectionList->fetch())
964 $resources[$section[
'ID']] = $section;
965 $resourceNames[] = $section[
'NAME'];
972 foreach($users as
$user)
974 $resListItems[] = \CCalendar::getUserName(
$user);
977 if (!empty($resourceNames))
979 foreach($resourceNames as $resourceName)
981 $resListItems[] = $resourceName;
985 if (!empty($resListItems))
987 $skipTime = is_array($userField[
'SETTINGS']) && $userField[
'SETTINGS'][
'FULL_DAY'] ===
'Y';
988 $fromTs = isset($value[
'DATE_FROM']) ? \CCalendar::timestamp($value[
'DATE_FROM'],
true, !$skipTime) : 0;
989 $toTs = isset($value[
'DATE_TO']) ? \CCalendar::timestamp($value[
'DATE_TO'],
true, !$skipTime) : 0;
991 $resultText = \CCalendar::getFromToHtml($fromTs, $toTs, $skipTime, $toTs - $fromTs).
': ';
992 $resultText = str_replace(
"–",
'-', $resultText);
993 if(!empty($value[
'SERVICE_NAME']))
995 $resultText .= $value[
'SERVICE_NAME'].
', ';
997 $resultText .= implode(
', ', $resListItems);
1006 $typeList = Internals\TypeTable::getList(
1009 "XML_ID" => self::RESOURCE_CALENDAR_TYPE
1011 "select" =>
array(
"XML_ID",
"NAME")
1015 while (
$type = $typeList->fetch())
1017 $type[
'SECTIONS'] = [];
1021 if (empty(
$result[self::RESOURCE_CALENDAR_TYPE] ??
null))
1023 Internals\TypeTable::add([
1024 'XML_ID' => self::RESOURCE_CALENDAR_TYPE,
1025 'NAME' => self::RESOURCE_CALENDAR_TYPE,
1028 \CCalendar::ClearCache(
'type_list');
1030 $result[self::RESOURCE_CALENDAR_TYPE] = [
1031 'XML_ID' => self::RESOURCE_CALENDAR_TYPE,
1032 'NAME' => self::RESOURCE_CALENDAR_TYPE
1036 $sectionList = Internals\SectionTable::getList(
1040 "CAL_TYPE" => [self::RESOURCE_CALENDAR_TYPE],
1043 "select" =>
array(
"ID",
"CAL_TYPE",
"NAME")
1047 while ($section = $sectionList->fetch())
1049 if (is_array(
$result[$section[
'CAL_TYPE']][
'SECTIONS']))
1051 $result[$section[
'CAL_TYPE']][
'SECTIONS'][] = $section;
1060 $resourseList = Internals\ResourceTable::getList(
1072 while ($resourse = $resourseList->fetch())
1074 if (!isset(
$result[
'DATE_FROM']))
1076 \CTimeZone::Disable();
1077 $result[
'DATE_FROM'] = $resourse[
'DATE_FROM']->toString();
1078 $result[
'DATE_TO'] = $resourse[
'DATE_TO']->toString();
1079 $result[
'SERVICE_NAME'] = $resourse[
'SERVICE_NAME'];
1080 \CTimeZone::Enable();
1082 $fromTs = \CCalendar::timestamp(
$result[
'DATE_FROM']);
1083 $toTs = \CCalendar::timestamp(
$result[
'DATE_TO']);
1085 if (!$resourse[
'SKIP_TIME'])
1087 $currentUserID = \CCalendar::getCurUserId();
1089 $userOffsetFrom = \CCalendar::getTimezoneOffset($resourse[
'TZ_FROM'], $fromTs) - \CCalendar::getCurrentOffsetUTC($currentUserID);
1090 $userOffsetTo = \CCalendar::getTimezoneOffset($resourse[
'TZ_TO'], $toTs) - \CCalendar::getCurrentOffsetUTC($currentUserID);
1092 $result[
'DATE_FROM'] = \CCalendar::date($fromTs - $userOffsetFrom);
1093 $result[
'DATE_TO'] = \CCalendar::date($toTs - $userOffsetTo);
1097 $result[
'DATE_TO'] = \CCalendar::date($toTs + \CCalendar::DAY_LENGTH);
1102 'ID' => $resourse[
'ID'],
1103 'EVENT_ID' => $resourse[
'EVENT_ID'],
1104 'TYPE' => $resourse[
'CAL_TYPE'],
1105 'RESOURCE_ID' => $resourse[
'RESOURCE_ID']
1115 array(
'name' =>
'',
'duration' => 60)
1122 if (\
Bitrix\
Main\Loader::includeModule(
'bitrix24'))
1124 $b24limit = Bitrix24\Feature::getVariable(
'calendar_resourcebooking_limit');
1125 if ($b24limit !==
null)
1131 $licenseType = \CBitrix24::getLicenseType();
1133 if ($licenseType ===
'project' || $licenseType ===
'self')
1137 elseif ($licenseType ===
'tf' || $licenseType ===
'retail')
1141 elseif ($licenseType ===
'team' || $licenseType ===
'start_2019')
1152 return array(
'CRM_LEAD',
'CRM_DEAL');
1157 if ($userTypeFields[
'USER_TYPE_ID'] ===
'resourcebooking')
1159 $userTypeFields[
'MULTIPLE'] =
'Y';
1174 $r = \CUserTypeEntity::getList(
array(
"ID" =>
"ASC"),
array(
"FIELD_NAME" => $fieldName));
1177 $resultData = $r->fetch();
1181 if (!is_array($selectedUsers))
1183 $selectedUsers = [];
1185 if (is_array($resultData) && isset($resultData[
'SETTINGS'][
'SELECTED_USERS']))
1187 $selectedUsers = array_merge($selectedUsers, $resultData[
'SETTINGS'][
'SELECTED_USERS']);
1190 array_walk($selectedUsers,
'intval');
1191 $selectedUsers = array_unique($selectedUsers);
1193 if (!empty($selectedUsers))
1195 $orm = UserTable::getList([
1197 '=ID' => $selectedUsers,
1200 'select' => [
'ID',
'LOGIN',
'NAME',
'LAST_NAME',
'SECOND_NAME',
'EMAIL']
1203 $resultData[
'SETTINGS'][
'USER_INDEX'] = [];
1204 while(
$user = $orm->fetch())
1206 $resultData[
'SETTINGS'][
'USER_INDEX'][
$user[
'ID']] = [
1207 'id' =>
$user[
'ID'],
1208 'displayName' => \CCalendar::getUserName(
$user)
1220 $curUserId =
$USER->GetID();
1227 $from =
$params[
'from']->toString();
1228 $to =
$params[
'to']->toString();
1232 $fromTs = (isset(
$params[
'from']) &&
$params[
'from']) ? \CCalendar::timestamp(
$params[
'from']) : time();
1233 $from = \CCalendar::date($fromTs,
false);
1235 ? \CCalendar::date(\CCalendar::timestamp(
$params[
'to']),
false)
1236 : \CCalendar::date($fromTs + \CCalendar::DAY_LENGTH * 60,
false);
1239 if (isset(
$params[
'timezone']))
1241 $deltaOffset = \CCalendar::GetTimezoneOffset(
$params[
'timezone']) - \CCalendar::GetCurrentOffsetUTC($curUserId);
1247 $resultData[
'timezoneOffset'] = 0;
1252 $r = \CUserTypeEntity::getList(
array(
"ID" =>
"ASC"),
array(
"FIELD_NAME" =>
$params[
'fieldName']));
1255 $fieldProperties = $r->fetch();
1256 $resultData[
'fieldSettings'] = $fieldProperties[
'SETTINGS'];
1258 if ($resultData[
'fieldSettings'][
'USE_USER_TIMEZONE'] ===
'N')
1260 $resultData[
'timezoneOffset'] = $resultData[
'fieldSettings'][
'TIMEZONE'] ? \CCalendar::GetTimezoneOffset($resultData[
'fieldSettings'][
'TIMEZONE']) : intval(date(
"Z"));
1261 $resultData[
'timezoneOffsetLabel'] =
'UTC'.($resultData[
'timezoneOffset'] <> 0 ?
' '.($resultData[
'timezoneOffset'] < 0?
'-':
'+').sprintf(
"%02d", ($h = floor(abs($resultData[
'timezoneOffset'])/3600))).
':'.sprintf(
"%02d", abs($resultData[
'timezoneOffset']) / 60 - $h * 60) :
'');
1266 if (isset(
$data[
'users']))
1268 $userIdList = is_array(
$data[
'users'][
'value'])
1269 ?
$data[
'users'][
'value']
1270 : explode(
'|',
$data[
'users'][
'value']);
1271 array_walk($userIdList,
'intval');
1273 $resultData[
'usersAccessibility'] = [];
1274 $accessibility = \CCalendar::getAccessibilityForUsers(
array(
1275 'users' => $userIdList,
1278 'getFromHR' =>
true,
1279 'checkPermissions' =>
false
1282 foreach($accessibility as
$userId => $entries)
1284 $resultData[
'usersAccessibility'][
$userId] = [];
1286 foreach($entries as $entry)
1288 if (isset($entry[
'DT_FROM']) && !isset($entry[
'DATE_FROM']))
1291 'id' => $entry[
'ID'],
1292 'dateFrom' => $entry[
'DT_FROM'],
1293 'dateTo' => $entry[
'DT_TO'],
1298 $fromTs = \CCalendar::Timestamp($entry[
'DATE_FROM']);
1299 $toTs = \CCalendar::Timestamp($entry[
'DATE_TO']);
1301 if ($entry[
'DT_SKIP_TIME'] !==
"Y")
1303 if ($resultData[
'fieldSettings'][
'USE_USER_TIMEZONE'] ===
'N')
1305 $fromTs -= \CCalendar::GetTimezoneOffset($entry[
'TZ_FROM']) - $resultData[
'timezoneOffset'];
1306 $toTs -= \CCalendar::GetTimezoneOffset($entry[
'TZ_TO']) - $resultData[
'timezoneOffset'];
1310 $fromTs -= $entry[
'~USER_OFFSET_FROM'];
1311 $toTs -= $entry[
'~USER_OFFSET_TO'];
1312 $fromTs += $deltaOffset;
1313 $toTs += $deltaOffset;
1318 'id' => $entry[
'ID'],
1319 'dateFrom' => \CCalendar::Date($fromTs, $entry[
'DT_SKIP_TIME'] !=
'Y'),
1320 'dateTo' => \CCalendar::Date($toTs, $entry[
'DT_SKIP_TIME'] !=
'Y'),
1321 'fullDay' => $entry[
'DT_SKIP_TIME'] ===
"Y"
1328 $orm = UserTable::getList(
1331 '=ID' => $userIdList,
1334 'select' => [
'ID',
'LOGIN',
'NAME',
'LAST_NAME',
'SECOND_NAME',
'EMAIL']
1338 $resultData[
'SETTINGS'][
'USER_INDEX'] = [];
1339 while(
$user = $orm->fetch())
1341 $resultData[
'userIndex'][
$user[
'ID']] = [
1342 'id' =>
$user[
'ID'],
1343 'displayName' => \CCalendar::getUserName(
$user)
1348 if (isset(
$data[
'resources']))
1350 $resultData[
'resourcesAccessibility'] = [];
1352 $resourceIdList = is_array(
$data[
'resources'][
'value'])
1353 ?
$data[
'resources'][
'value']
1354 : explode(
'|',
$data[
'resources'][
'value']);
1356 array_walk($resourceIdList,
'intval');
1358 $resEntries = \CCalendarEvent::getList(
1360 'arFilter' =>
array(
1361 "FROM_LIMIT" => $from,
1363 "CAL_TYPE" =>
'resource',
1364 "ACTIVE_SECTION" =>
"Y",
1365 "SECTION" => $resourceIdList
1367 'parseRecursion' =>
true,
1368 'setDefaultLimit' =>
false
1372 foreach($resEntries as $row)
1374 $fromTs = \CCalendar::timestamp($row[
"DATE_FROM"]);
1375 $toTs = \CCalendar::timestamp($row[
'DATE_TO']);
1377 if ($row[
'DT_SKIP_TIME'] !==
"Y" && $resultData[
'fieldSettings'][
'USE_USER_TIMEZONE'] !==
'N')
1379 if ($resultData[
'fieldSettings'][
'USE_USER_TIMEZONE'] ===
'N')
1381 $fromTs -= \CCalendar::GetTimezoneOffset($entry[
'TZ_FROM']) - $resultData[
'timezoneOffset'];
1382 $toTs -= \CCalendar::GetTimezoneOffset($entry[
'TZ_TO']) - $resultData[
'timezoneOffset'];
1386 $fromTs -= $row[
'~USER_OFFSET_FROM'];
1387 $toTs -= $row[
'~USER_OFFSET_TO'];
1388 $fromTs += $deltaOffset;
1389 $toTs += $deltaOffset;
1393 $resultData[
'resourcesAccessibility'][$row[
'SECT_ID']][] =
array(
1395 'dateFrom' => \CCalendar::date($fromTs, $row[
'DT_SKIP_TIME'] !==
'Y'),
1396 'dateTo' => \CCalendar::date($toTs, $row[
'DT_SKIP_TIME'] !==
'Y'),
1397 'fullDay' => $row[
'DT_SKIP_TIME'] ===
"Y"
1402 $resultData[
'workTimeStart'] = floor(floatVal(\COption::GetOptionString(
'calendar',
'work_time_start', 9)));
1403 $resultData[
'workTimeEnd'] = ceil(floatVal(\COption::GetOptionString(
'calendar',
'work_time_end', 19)));
1418 $to->add(
$options[
'dateInterval'] ??
'P5D');
1424 'fieldName' => $fieldName,
1431 $accessibility = [];
1432 if ($formData[
'fieldSettings'][
'USE_USERS'] ===
'Y'
1433 && isset(
$options[
'settingsData'][
'users'][
'value']))
1435 $selectedUser =
$options[
'settingsData'][
'users'][
'value'];
1437 isset($formData[
'usersAccessibility'])
1438 && isset($formData[
'usersAccessibility'][$selectedUser])
1441 $accessibility = array_merge($accessibility, $formData[
'usersAccessibility'][$selectedUser]);
1445 if ($formData[
'fieldSettings'][
'USE_RESOURCES'] ===
'Y'
1446 && isset(
$options[
'settingsData'][
'resources'][
'value']))
1448 $selectedResource =
$options[
'settingsData'][
'resources'][
'value'];
1450 isset($formData[
'resourcesAccessibility'])
1451 && isset($formData[
'resourcesAccessibility'][$selectedResource])
1454 $accessibility = array_merge($accessibility, $formData[
'resourcesAccessibility'][$selectedResource]);
1459 if ($selectedUser || $selectedResource)
1462 foreach ($accessibility as
$i => $item)
1464 $accessibility[
$i][
'fromTs'] = (
new DateTime($item[
'dateFrom'], $format))->getTimestamp();
1465 $accessibility[
$i][
'toTs'] = (
new DateTime($item[
'dateTo'], $format))->getTimestamp();
1468 $result = self::getAvailableTimeSlots($accessibility, [
1471 'scale' =>
$options[
'settingsData'][
'time'][
'scale']
1478 private static function getAvailableTimeSlots($accessibility,
$options)
1485 $workTimeStart = (int)\COption::getOptionString(
'calendar',
'work_time_start', 9);
1486 $workTimeEnd = (int)\COption::getOptionString(
'calendar',
'work_time_end', 19);
1492 while ($currentDate->getTimestamp() < $to->getTimestamp())
1494 $currentDate->setTime($workTimeStart, 0, 0);
1495 while ((
int)$currentDate->format(
'H') < $workTimeEnd)
1497 if ($currentDate->getTimestamp() > time())
1500 $slotStart = $currentDate->getTimestamp();
1501 $slotEnd = $slotStart + $scale * 60;
1503 foreach ($accessibility as
$i => $item)
1505 if ($item[
'toTs'] > $slotStart && $item[
'fromTs'] < $slotEnd)
1514 $slots[] = clone $currentDate;
1517 $currentDate->add(
'PT'.$scale.
'M');
1525 $currentDate->add(
'P1D');
1534 if (!isset($dateFrom) || !($dateFrom instanceof
DateTime))
1536 throw new \Bitrix\Main\SystemException(
'Wrong dateFrom value type. DateTime expected');
1538 if (empty($fieldName))
1540 throw new \Bitrix\Main\SystemException(
'Wrong fieldName given');
1544 if (!empty(
$options[
'settingsData'][
'duration'][
'value']))
1546 $duration =
$options[
'settingsData'][
'duration'][
'value'];
1548 else if (!empty(
$options[
'settingsData'][
'duration'][
'defaultValue']))
1550 $duration =
$options[
'settingsData'][
'duration'][
'defaultValue'];
1553 $r = \CUserTypeEntity::getList([
"ID" =>
"ASC"], [
"FIELD_NAME" => $fieldName]);
1556 $fieldProperties = $r->fetch();
1557 $fieldSettings = $fieldProperties[
'SETTINGS'];
1559 if ($fieldSettings[
'USE_USERS'] ===
'Y'
1560 && isset(
$options[
'settingsData'][
'users'][
'value']))
1565 if ($fieldSettings[
'USE_RESOURCES'] ===
'Y'
1566 && isset(
$options[
'settingsData'][
'resources'][
'value']))
if(!is_object($USER)||! $USER->IsAuthorized()) $userId
static getDefaultResourcesList()
static getUserTypeDescription()
static saveResource($id, $resourceType, $resourceId, $eventFields=[], $params=[])
const CRM_SUSPENDED_DEAL_ENTITY_ID
static getResourceEntriesList($idList=[])
static getDefaultServiceList()
getEditFormHTML($userField, $htmlControl)
static getPublicEdit($userField, $additionalParams=[])
static prepareFormDateValues($dateFrom=null, $fieldName='', $options=[])
getSettingsHTML($userField=false, $htmlControl=[], $varsFromForm=false)
static fetchFieldValue($value)
static onBeforeUserTypeAdd(&$userTypeFields)
static getAvailableEntriesList()
static releaseResource($entry)
static getUserFieldByFieldName($fieldName='', $selectedUsers=[])
static onBeforeSaveAll($userField, $values, $userId=false)
static getFillFormData($data=[], $params=[])
static onDelete($userField, $values, $userId=false)
const CRM_SUSPENDED_LEAD_ENTITY_ID
static getPublicView($userField, $additionalParams=[])
static parseValue($value)
static getBitrx24Limitation()
static prepareSettings($userField=[])
const BITRIX24_RESTRICTION
static checkFields($userField, $value)
static getPublicText($userField)
const RESOURCE_CALENDAR_TYPE
const BITRIX24_RESTRICTION_CODE
static prepareValue($type, $id, $from, $duration, $serviceName='')
static getFormDateTimeSlots($fieldName='', $options=[])
static getConnection($name="")
static encode($data, $options=null)
</td ></tr ></table ></td ></tr >< tr >< td class="bx-popup-label bx-width30"><?=GetMessage("PAGE_NEW_TAGS")?> array( $site)
ExecuteModuleEventEx($arEvent, $arParams=[])
$GLOBALS['____1690880296']
global_menu_<?echo $menu["menu_id"]?> adm main menu item icon adm main menu item text text adm main menu hover adm submenu menucontainer menu_id menu_id items_id items_id desktop menu_id block none adm global submenu<?=($subMenuDisplay=="block" ? " adm-global-submenu-active" :"")?> global_submenu_<?echo $menu["menu_id"]?> text MAIN_PR_ADMIN_FAV items adm submenu items wrap adm submenu items stretch wrap BX adminMenu itemsStretchScroll()"> <table class if (!empty( $menu["items"])) elseif ( $menu[ 'menu_id']=='desktop') if ( $menu[ 'menu_id']=='desktop') endforeach
if( $daysToExpire >=0 &&$daysToExpire< 60 elseif)( $daysToExpire< 0)
if($inWords) echo htmlspecialcharsbx(Number2Word_Rus(roundEx($totalVatSum $params['CURRENCY']