Этот скрипт демонстрирует, как автоматизировать создание и обновление контактов в Google Contacts, используя данные из Google Таблицы. Скрипт выполняет следующие действия:
Для работы скрипта требуется включить Google People API в проекте Apps Script.
/* exported contactsToGoogle */
/**
* Основная функция для обновления контактов Google из данных таблицы.
* Данные должны быть организованы в следующем формате:
* Колонка A: Фамилия
* Колонка B: Имя
* Колонка E: Номер телефона (без +)
*/
function contactsToGoogle() {
// Получение данных из таблицы
const sheet = SpreadsheetApp.getActive().getSheetByName('Для загрузки в контакты');
const data = sheet.getDataRange().getValues();
// Найти группу контактов или вернуть ошибку если группа не существует
const labelName = 'System Group: My Contacts';
const { contactGroups } = People.ContactGroups.list({ groupFields: 'memberCount,name', pageSize: 1000 });
const contactGroup = contactGroups.find(({ name }) => name == labelName);
if (!contactGroup) {
const message = `Ярлыка (группы) с именем ${labelName} не найдено. Создайте его вручную`;
throw new Error(message);
}
// Поиск всех существующих контактов с построением индексов
// Создаем два индекса: по имени и по номеру телефона для быстрого поиска
const contacts = {}; // индекс контактов по имени
const phones = {}; // индекс контактов по номеру телефона
let nextPageToken = null;
do {
// Получаем до 1000 контактов за один запрос с пагинацией
const response = People.People.Connections.list('people/me', {
pageSize: 1000,
personFields: 'names,phoneNumbers,memberships',
pageToken: nextPageToken || '',
});
// Если есть контакты, добавляем их в индексы
if (response.connections) {
response.connections.forEach((person) => {
if (person.names && person.names.length > 0) {
const name = person.names[0].displayName;
contacts[name] = person;
// Создаем дополнительный индекс по номеру телефона
person.phoneNumbers?.forEach((phone) => (phones[phone.canonicalForm] = contacts[name]));
}
});
}
nextPageToken = response.nextPageToken;
} while (nextPageToken); // Продолжаем, пока есть следующая страница результатов
// Обрабатываем каждую строку данных (пропускаем заголовки - первую строку)
data.slice(1).forEach((row, i) => {
// Проверяем, что есть все необходимые данные (фамилия, имя и телефон)
if ([row[0], row[1], row[4]].indexOf('') < 0) {
const middleScope = {
noteToSheet: '', // Сообщение для примечания
currentDate: Utilities.formatDate(new Date(), 'Europe/Moscow', 'yyyy-MM-dd hh:mm'), // Текущая дата и время
name: '', // Полное имя контакта
};
// Форматируем телефон и имя
const phoneNumber = `+${row[4]}`;
const fullName = `${row[1]} ${row[0]}`; // Имя Фамилия
middleScope.name = fullName;
// Ищем контакт по имени или телефону
if (contacts[fullName] || phones[phoneNumber]) {
// Обновляем существующий контакт
const person = contacts[fullName] || phones[phoneNumber];
const resourceName = person.resourceName;
// Формируем объект для обновления, сохраняя существующие данные
const updatePerson = {
names: [
{
givenName: row[1], // Имя
familyName: row[0], // Фамилия
displayName: fullName, // Отображаемое имя
},
// Сохраняем другие имена, если они существуют
...(person.names?.filter((name) => name.displayName !== fullName) ?? []),
],
phoneNumbers: [
{
value: phoneNumber,
type: 'work', // Устанавливаем тип "рабочий"
},
// Сохраняем другие телефоны, если они существуют
...(person.phoneNumbers?.filter((phone) => phone.canonicalForm !== phoneNumber) ?? []),
],
organizations: [
{
name: 'TrustTaxi',
title: 'Водитель',
},
// Сохраняем другие организации, если они существуют
...(person.organizations?.filter((organization) => organization.name !== 'TrustTaxi') ?? []),
],
memberships: [
{
contactGroupMembership: {
contactGroupResourceName: contactGroup.resourceName,
},
},
// Сохраняем другие группы, если они существуют
...(person.memberships?.filter(
(membership) => membership.contactGroupMembership.contactGroupResourceName !== contactGroup.resourceName,
) ?? []),
],
etag: person.etag, // Требуется для обновления контакта
};
try {
// Обновляем контакт используя People API
People.People.updateContact(updatePerson, resourceName, {
updatePersonFields: 'names,phoneNumbers,organizations,memberships',
});
middleScope.noteToSheet = 'Контакт обновлен';
} catch (e) {
console.error(`Failed to update ${fullName}: ${e.message}`);
middleScope.noteToSheet = 'Контакт не обновлен';
}
} else {
// Создаем новый контакт если не найден существующий
const newPerson = {
names: [
{
givenName: row[1], // Имя
familyName: row[0], // Фамилия
displayName: fullName, // Отображаемое имя
},
],
phoneNumbers: [
{
value: phoneNumber,
type: 'work', // Устанавливаем тип "рабочий"
},
],
organizations: [
{
name: 'TrustTaxi',
title: 'Водитель',
},
],
memberships: [
{
contactGroupMembership: {
contactGroupResourceName: contactGroup.resourceName,
},
},
],
};
try {
// Создаем новый контакт используя People API
People.People.createContact(newPerson);
middleScope.noteToSheet = 'Контакт создан';
} catch (e) {
console.error(`Failed to create ${fullName}: ${e.message}`);
middleScope.noteToSheet = 'Контакт не создан';
}
}
// Добавляем примечание к ячейке в таблице с информацией о результате операции
sheet.getRange(i + 2, 1).setNote(`${middleScope.currentDate} ${middleScope.noteToSheet} '${middleScope.name}'`);
} else {
// Если данные неполные, очищаем примечание
sheet.getRange(i + 2, 1).clearNote();
}
});
}