Перейти к основному содержимому

Календарь и встречи

Календарь позволяет планировать встречи с кандидатами: собеседования, звонки и другие события. Со встречей можно связать кандидатов, вакансии и менеджеров, а также создать внешнюю видеоконференцию (Telemost, Zoom, Google Meet) или событие во внешнем календаре (Google, Outlook, Yandex, Bitrix).

Ниже приведены запросы для получения справочника временных зон, чтения календаря и встреч, а также создания, обновления и удаления встреч.

Формат даты и времени

В операциях календаря дата и время представлены двумя способами:

  • Timestamp в UTC — количество миллисекунд, прошедших с 1 января 1970 года. В этом формате возвращаются поля startDate, endDate, createdAt, updatedAt и передаются аргументы start и end запроса calendarMeetings.
  • Локальное время — период встречи при создании и обновлении (period.start, period.end) в формате ISO-8601 без смещения (YYYY-MM-DDThh:mm:ss, например 2024-02-15T10:00:00). Временную зону, в которой интерпретируются эти значения, указывает period.timezoneId из справочника временных зон; сервер сам переводит время в UTC.

Справочник временных зон

Допустимые значения timezoneId для периода встречи возвращает запрос timezones.

query Timezones {
timezones {
items {
id
name
}
}
}

Посмотреть в playground

При успешном выполнении запрос вернёт

{
"data": {
"timezones": {
"items": [
{
"id": "europe/moscow",
"name": "(UTC+03:00) Москва, Санкт-Петербург"
},
{
"id": "europe/kaliningrad",
"name": "(UTC+02:00) Калининград"
},
{
"id": "asia/yekaterinburg",
"name": "(UTC+05:00) Екатеринбург"
}
]
}
}
}
подсказка

Идентификатор временной зоны (id) — это строковое значение вида europe/moscow, а не числовой идентификатор. Этот же идентификатор возвращается в поле timezone.id встречи.

Информация о календаре

Запрос calendar возвращает общую информацию о календаре текущего менеджера. Поле hasMeetings показывает, есть ли у менеджера хотя бы одна встреча.

query Calendar {
calendar {
hasMeetings
}
}

Посмотреть в playground

При успешном выполнении запрос вернёт

{
"data": {
"calendar": {
"hasMeetings": true
}
}
}

Получение списка встреч

Запрос calendarMeetings возвращает встречи за указанный диапазон дат. Границы периода start и end передаются как timestamp в UTC (см. Формат даты и времени).

примечание

Максимальный диапазон между start и end — 93 дня. При превышении вернётся ошибка VALIDATION.

Кандидаты (persons) и вакансии (vacancies) встречи возвращаются в виде union-типов: для доступных текущему менеджеру сущностей возвращается полный объект (PersonItem, VacancyItem), для недоступных — объект с ограниченным набором полей (PersonPublicItem, VacancyPublicItem), а если сущность не найдена — ошибка (PersonError, VacancyError).

query CalendarMeetings {
calendarMeetings(start: 1706745600000, end: 1709251200000) {
__typename
... on CalendarMeetingsItem {
items {
id
topic
place
startDate
endDate
canEdit
timezone {
id
name
}
externalVideoConference {
type
url
}
persons {
__typename
... on PersonItem {
id
firstName
lastName
}
... on PersonPublicItem {
id
firstName
lastName
}
... on PersonError {
errorType
}
}
vacancies {
__typename
... on VacancyItem {
id
title
}
... on VacancyPublicItem {
id
title
}
... on VacancyError {
errorType
}
}
creatorManager {
id
firstName
lastName
}
}
}
... on CalendarMeetingsError {
errorType
}
}
}

Посмотреть в playground

При успешном выполнении запрос вернёт

{
"data": {
"calendarMeetings": {
"__typename": "CalendarMeetingsItem",
"items": [
{
"id": 321,
"topic": "Собеседование с кандидатом",
"place": "Офис, переговорная №3",
"startDate": 1707980400000,
"endDate": 1707984000000,
"canEdit": true,
"timezone": {
"id": "europe/moscow",
"name": "(UTC+03:00) Москва, Санкт-Петербург"
},
"externalVideoConference": {
"type": "TELEMOST",
"url": "https://telemost.yandex.ru/j/00000000000000"
},
"persons": [
{
"__typename": "PersonItem",
"id": 123456,
"firstName": "Иван",
"lastName": "Иванов"
}
],
"vacancies": [
{
"__typename": "VacancyItem",
"id": 50000,
"title": "Java-разработчик"
}
],
"creatorManager": {
"id": 789,
"firstName": "Пётр",
"lastName": "Петров"
}
}
]
}
}
}

В случае возникновения ошибки вернётся ответ в формате JSON с типом ошибки

{
"data": {
"calendarMeetings": {
"__typename": "CalendarMeetingsError",
"errorType": "VALIDATION"
}
}
}

Возможные значения errorType:

  • VALIDATION — ошибка валидации данных (например, превышен максимальный диапазон дат)
подсказка

Подробное описание полей кандидатов и вакансий — в разделах Кандидаты и Вакансии.

Получение встречи по идентификатору

Запрос calendarMeeting возвращает одну встречу по её идентификатору. В дополнение к полям из списка можно запросить комментарий, информацию о событии во внешнем календаре, список приглашённых менеджеров и другие поля.

query CalendarMeeting {
calendarMeeting(id: 321) {
__typename
... on CalendarMeetingItem {
id
topic
place
comment
startDate
endDate
createdAt
updatedAt
canEdit
timezone {
id
name
}
externalVideoConference {
externalId
type
url
}
externalCalendarMeeting {
eventId
calendarType
}
persons {
__typename
... on PersonItem {
id
firstName
lastName
}
... on PersonPublicItem {
id
firstName
lastName
}
... on PersonError {
errorType
}
}
vacancies {
__typename
... on VacancyItem {
id
title
}
... on VacancyPublicItem {
id
title
}
... on VacancyError {
errorType
}
}
managers {
id
firstName
lastName
}
creatorManager {
id
firstName
lastName
}
}
... on CalendarMeetingError {
errorType
}
}
}

Посмотреть в playground

При успешном выполнении запрос вернёт

{
"data": {
"calendarMeeting": {
"__typename": "CalendarMeetingItem",
"id": 321,
"topic": "Собеседование с кандидатом",
"place": "Офис, переговорная №3",
"comment": "<p>Просьба подготовить тестовое задание</p>",
"startDate": 1707980400000,
"endDate": 1707984000000,
"createdAt": 1707900000000,
"updatedAt": 1707900000000,
"canEdit": true,
"timezone": {
"id": "europe/moscow",
"name": "(UTC+03:00) Москва, Санкт-Петербург"
},
"externalVideoConference": {
"externalId": "00000000000000",
"type": "TELEMOST",
"url": "https://telemost.yandex.ru/j/00000000000000"
},
"externalCalendarMeeting": null,
"persons": [
{
"__typename": "PersonItem",
"id": 123456,
"firstName": "Иван",
"lastName": "Иванов"
}
],
"vacancies": [
{
"__typename": "VacancyItem",
"id": 50000,
"title": "Java-разработчик"
}
],
"managers": [
{
"id": 789,
"firstName": "Пётр",
"lastName": "Петров"
}
],
"creatorManager": {
"id": 789,
"firstName": "Пётр",
"lastName": "Петров"
}
}
}
}

В случае возникновения ошибки вернётся ответ в формате JSON с типом ошибки

{
"data": {
"calendarMeeting": {
"__typename": "CalendarMeetingError",
"errorType": "MEETING_NOT_FOUND"
}
}
}

Возможные значения errorType:

  • MEETING_NOT_FOUND — встреча не найдена

Создание встречи

Создать встречу можно с помощью следующего запроса.

Период проведения (period) задаётся в локальном времени — см. Формат даты и времени.

Дополнительно при создании можно:

  • создать внешнюю видеоконференцию, указав externalVideoConferenceType (TELEMOST, ZOOM, GOOGLE_MEET);
  • создать событие во внешнем календаре, указав externalCalendarType (GOOGLE, OUTLOOK, YANDEX, BITRIX);
  • отправить кандидатам Email-уведомление (personEmail) и/или СМС (personSmsText);
  • отправить Email-уведомление менеджерам (sendEmailToManagers, по умолчанию true).
примечание

Создание внешней видеоконференции или события во внешнем календаре требует предварительно подключённой интеграции.

mutation CreateCalendarMeeting {
createCalendarMeeting(
input: {topic: "Собеседование с кандидатом", place: "Офис, переговорная №3", comment: "<p>Просьба подготовить тестовое задание</p>", period: {start: "2024-02-15T10:00:00", end: "2024-02-15T11:00:00", timezoneId: "europe/moscow"}, personIds: [123456], vacancyIds: [50000], managerIds: [789], externalVideoConferenceType: TELEMOST, personEmail: {subject: "Приглашение на собеседование", text: "<p>Здравствуйте! Приглашаем вас на собеседование.</p>"}, sendEmailToManagers: true}
) {
__typename
... on CalendarMeetingItem {
id
topic
startDate
endDate
externalVideoConference {
type
url
}
}
... on CalendarMeetingCreateError {
errorType
message
fieldErrors {
field
violatedConstraints
}
integrationError {
__typename
... on YandexTelemostError {
yandexTelemostErrorType
}
... on ZoomError {
zoomErrorType
}
... on GoogleMeetError {
googleMeetErrorType
}
}
}
}
}

Посмотреть в playground

При успешном выполнении запрос вернёт созданную встречу

{
"data": {
"createCalendarMeeting": {
"__typename": "CalendarMeetingItem",
"id": 321,
"topic": "Собеседование с кандидатом",
"startDate": 1707980400000,
"endDate": 1707984000000,
"externalVideoConference": {
"type": "TELEMOST",
"url": "https://telemost.yandex.ru/j/00000000000000"
}
}
}
}

В случае ошибки валидации вернётся тип ошибки и список полей с нарушенными ограничениями

{
"data": {
"createCalendarMeeting": {
"__typename": "CalendarMeetingCreateError",
"errorType": "VALIDATION",
"message": null,
"fieldErrors": [
{
"field": "period.timezoneId",
"violatedConstraints": ["ValidTimezone"]
}
],
"integrationError": null
}
}
}

Если ошибка возникла на стороне внешнего сервиса (видеоконференция или внешний календарь), тип ошибки будет INTEGRATION_ERROR, а детали — в поле integrationError. Его конкретный тип зависит от интеграции (например, ZoomError, YandexTelemostError, GoogleMeetError)

{
"data": {
"createCalendarMeeting": {
"__typename": "CalendarMeetingCreateError",
"errorType": "INTEGRATION_ERROR",
"message": null,
"fieldErrors": null,
"integrationError": {
"__typename": "YandexTelemostError",
"yandexTelemostErrorType": "ACCOUNT_NOT_FOUND"
}
}
}
}

Возможные значения errorType:

  • VALIDATION — ошибка валидации данных
  • ACCESS_DENIED — нет прав на создание встреч
  • INTEGRATION_ERROR — ошибка интеграции с внешней системой (детали в поле integrationError)
  • SEND_SMS_ACCESS_DENIED — нет прав для отправки СМС кандидатам
  • EMAIL_SERVER_NOT_AVAILABLE — почтовый сервер недоступен

Обновление встречи

Обновить встречу можно с помощью следующего запроса. В поле id передаётся идентификатор изменяемой встречи. Встреча перезаписывается переданными значениями, поэтому передавайте все поля, которые нужно сохранить.

mutation UpdateCalendarMeeting {
updateCalendarMeeting(
input: {id: 321, topic: "Собеседование с кандидатом (перенесено)", place: "Онлайн", period: {start: "2024-02-16T14:00:00", end: "2024-02-16T15:00:00", timezoneId: "europe/moscow"}, personIds: [123456], vacancyIds: [50000], managerIds: [789]}
) {
__typename
... on CalendarMeetingItem {
id
topic
startDate
endDate
updatedAt
}
... on CalendarMeetingUpdateError {
errorType
message
fieldErrors {
field
violatedConstraints
}
}
}
}

Посмотреть в playground

При успешном выполнении запрос вернёт обновлённую встречу

{
"data": {
"updateCalendarMeeting": {
"__typename": "CalendarMeetingItem",
"id": 321,
"topic": "Собеседование с кандидатом (перенесено)",
"startDate": 1708081200000,
"endDate": 1708084800000,
"updatedAt": 1707950000000
}
}
}

В случае возникновения ошибки вернётся ответ в формате JSON с типом ошибки

{
"data": {
"updateCalendarMeeting": {
"__typename": "CalendarMeetingUpdateError",
"errorType": "MEETING_NOT_FOUND",
"message": null,
"fieldErrors": null
}
}
}

Возможные значения errorType:

  • VALIDATION — ошибка валидации данных
  • MEETING_NOT_FOUND — встреча не найдена
  • ACCESS_DENIED — нет прав на изменение встречи

Удаление встречи

Удалить встречу можно с помощью следующего запроса. В поле id передаётся идентификатор удаляемой встречи.

mutation DeleteCalendarMeeting {
deleteCalendarMeeting(id: 321) {
__typename
... on CalendarMeetingDeleteSuccess {
id
}
... on CalendarMeetingDeleteError {
errorType
}
}
}

Посмотреть в playground

При успешном выполнении запрос вернёт идентификатор удалённой встречи

{
"data": {
"deleteCalendarMeeting": {
"__typename": "CalendarMeetingDeleteSuccess",
"id": 321
}
}
}

В случае возникновения ошибки вернётся ответ в формате JSON с типом ошибки

{
"data": {
"deleteCalendarMeeting": {
"__typename": "CalendarMeetingDeleteError",
"errorType": "MEETING_NOT_FOUND"
}
}
}

Возможные значения errorType:

  • MEETING_NOT_FOUND — встреча не найдена
  • ACCESS_DENIED — нет прав на удаление встречи